diff --git a/.gitignore b/.gitignore index d522f94..837ab7c 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,7 @@ # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? # # Pods/ - +friend-smash/build/ +build/ +.idea/ +.gradle/ diff --git a/README.md b/README.md index f3fafe4..f0ae40d 100755 --- a/README.md +++ b/README.md @@ -1,26 +1,53 @@ -# Friend Smash sample Facebook app +# Friend Smash sample Facebook game Authors: -Peter Chang (peter78) -Phil Hewinson (philhewinson) -Ali Parr (aliparr) +- Peter Chang (peter78) +- Phil Hewinson (philhewinson) +- Ali Parr (aliparr) +- Jakub Pudelek (skoggkatt) ## Overview +To help better understand different products and services available to game developers, Facebook maintains a sample game called Friend Smash! -Friend Smash is a sample Android game that integrates with Facebook. A Canvas and iOS version is also available. +The game is implemented on different platforms: -## Installing +* Web using [Facebook SDK for Javascript](https://developers.facebook.com/docs/javascript) +* Mobile using Facebook's native SDKs for [iOS](https://developers.facebook.com/docs/ios) and [Android](https://developers.facebook.com/docs/android) +* It is also available as a Unity cross platform build using the [Facebook SDK for Unity](https://developers.facebook.com/docs/unity). -Before running the sample, please see the Getting Started on Android guide, available here: https://developers.facebook.com/docs/android/getting-started +There are minor differences between the four implementations, but overall the goal and structure of all is similar. This is the Android version of the game. +## What is “Friend Smash!”? +Friend Smash is a simple game which utilizes Facebook platform to enhance the gameplay by making it more fun and social. It uses variety of products and services, such as [Facebook Login](https://developers.facebook.com/docs/facebook-login), [Graph API](https://developers.facebook.com/docs/graph-api), [Game Requests](https://developers.facebook.com/docs/games/requests/) and [Sharing](https://developers.facebook.com/docs/games/sharing). The code examples serve as a guide of how they may be used in a games context. It also serves as an implementation guide - parts of source code relevant to Facebook integration are clearly separated from the pure gaming-logic and clearly documented with in code comments. -## Documentation +Please note that Friend Smash! was not designed as an example of how to design or code a game. The focus is on Facebook integration - other parts of the project may not be as clear and well designed and documented. -The accompanying tutorial for this sample app can be found here: https://developers.facebook.com/docs/games/mobile/android-tutorial +Friends Smash! is a game in which players are tasked with "smashing" (mouse-clicking or screen-tapping) pictures of a specific person while avoiding smashing pictures of anyone else. Player gets points for each correct picture smashed. Each miss or wrong smash causes the player to lose a heart. After losing 3 lives, the game is over. Player can also smash images of coins to collect them and later redeem these coins to buy bombs. In turn, bombs can be used in game to smash all correct pictures on the screen, helping to achieve a higher score. Additionally, the web version of the game allows players to purchase coins with Facebook Payments. -## Additional Resources +## Facebook integration +To make the experience more fun and social, players are asked to log in with Facebook and grant [user_friends](https://developers.facebook.com/docs/facebook-login/permissions/#reference-user_friends) permission. When granted, the game will have access to subset of player's friends data, specifically those who also logged in to Friend Smash! and granted user_friends permission. This means the game will use the profile picture of randomly selected friend as the picture the player is asked to smash. If user_friends permission hasn’t been granted or the player doesn't have friends who also logged in to Friend Smash! and granted user_friends permission, a picture of randomly selected celebrity is used instead. -Facebook SDK for Android documentation can be found at https://developers.facebook.com/android/ +At different points in the game player has an opportunity to share to Facebook. For example after the game is over, player can brag about the score achieved by posting a custom [Open Graph story](https://developers.facebook.com/docs/games/opengraph). The game also shows how to ask for [publish_actions](https://developers.facebook.com/docs/facebook-login/permissions/#reference-publish_actions) permission (which is required for API based sharing) and how to handle the case when publish_actions permission is not granted. If publish_actions permission is granted - the game uses [Scores API](https://developers.facebook.com/docs/games/scores) to publish and store the top score achieved by the player. -## Contributing +[Game Requests](https://developers.facebook.com/docs/games/requests/) are used in the game for two main purposes. First to let the player invite their friends who are not playing the game to try it. Second, to send a challenge to a friend who is already playing to bring them back to the game. +Additionally on the web version, the game uses [Facebook Payments](https://developers.facebook.com/docs/payments) to allow players to purchase in-game currency and [In-Game Gifting](https://developers.facebook.com/docs/payments/ingamegifting) to allow purchasing gifts for players’ friends. The web example also includes reference implementation of a payments server handling static pricing and payments verification. + +Friend Smash! also logs [App Events](https://developers.facebook.com/docs/app-events), which enables Facebook [Analytics for Apps](https://developers.facebook.com/docs/analytics) - a free tool allowing developers to learn how people use their app across all platforms and devices, get insights about the people using the app, and improve marketing. + +## How to use “Friend Smash!”? +All versions of Friend Smash! are available as part of [Facebook Platform Samples](https://github.com/fbsamples) on github: +[Web](https://github.com/fbsamples/web-friend-smash), [Android](https://github.com/fbsamples/android-friend-smash), [iOS](https://github.com/fbsamples/ios-friend-smash), [Unity](https://github.com/fbsamples/friendsmash-unity). + +The recommended way to explore the projects is to begin with how Facebook products are integrated. To make it easier code responsible for Facebook integration is separated and well documented with in code comments for all versions. You can find it here for different versions: Web, Android, iOS, Unity. The reference implementation of a payments server is included in the Web repository. + +To play Friend Smash! on Web, simply go to [apps.facebook.com/friendsmashsample](http://apps.facebook.com/friendsmashsample). To play it on mobile, download the Android, iOS or Unity project and build it from source and try on your device. +Please note it is likely that unless you have friends who also installed Friend Smash! you will not see any of your friends in the game. If this is the case, you can invite some of your friends to play Friend Smash! to fully explore how social integration works in Friend Smash! + +## Installing +Before running the sample, please see the [Getting Started on Android guide](https://developers.facebook.com/docs/android/getting-started) + +## Additional Resources +Facebook SDK for Android [documentation](https://developers.facebook.com/docs/android/) + +## Contributing All contributors must agree to and sign the [Facebook CLA](https://developers.facebook.com/opensource/cla) prior to submitting Pull Requests. We cannot accept Pull Requests until this document is signed and submitted. diff --git a/android-friend-smash-v2.iml b/android-friend-smash-v2.iml new file mode 100644 index 0000000..7f88201 --- /dev/null +++ b/android-friend-smash-v2.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..88d246d --- /dev/null +++ b/build.gradle @@ -0,0 +1,15 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:1.2.3' + } +} + +allprojects { + repositories { + jcenter() + } +} diff --git a/friend-smash-android.iml b/friend-smash-android.iml new file mode 100644 index 0000000..8973c4f --- /dev/null +++ b/friend-smash-android.iml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/friend-smash/build.gradle b/friend-smash/build.gradle new file mode 100644 index 0000000..f74122a --- /dev/null +++ b/friend-smash/build.gradle @@ -0,0 +1,32 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 19 + buildToolsVersion "21.1.2" + + defaultConfig { + applicationId "com.facebook.android.friendsmash" + minSdkVersion 15 + targetSdkVersion 23 + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' + } + } +} + +repositories { + mavenCentral() + flatDir{dirs 'libs'} +} + +dependencies { + compile files('libs/Parse-1.10.3.jar', 'libs/ParseFacebookUtilsV4-1.10.3.jar') + compile 'com.facebook.android:facebook-android-sdk:4.8.1' +} +repositories{ + +} \ No newline at end of file diff --git a/friend-smash/friend-smash.iml b/friend-smash/friend-smash.iml new file mode 100644 index 0000000..b67523f --- /dev/null +++ b/friend-smash/friend-smash.iml @@ -0,0 +1,95 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/friend-smash/libs/Parse-1.10.3.jar b/friend-smash/libs/Parse-1.10.3.jar new file mode 100644 index 0000000..c0a8ff9 Binary files /dev/null and b/friend-smash/libs/Parse-1.10.3.jar differ diff --git a/friend-smash/libs/ParseFacebookUtilsV4-1.10.3.jar b/friend-smash/libs/ParseFacebookUtilsV4-1.10.3.jar new file mode 100644 index 0000000..494ca5a Binary files /dev/null and b/friend-smash/libs/ParseFacebookUtilsV4-1.10.3.jar differ diff --git a/friendsmash_complete/lint.xml b/friend-smash/lint.xml similarity index 57% rename from friendsmash_complete/lint.xml rename to friend-smash/lint.xml index 6994aea..0b25ba2 100644 --- a/friendsmash_complete/lint.xml +++ b/friend-smash/lint.xml @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/friendsmash_complete/AndroidManifest.xml b/friend-smash/src/main/AndroidManifest.xml old mode 100755 new mode 100644 similarity index 64% rename from friendsmash_complete/AndroidManifest.xml rename to friend-smash/src/main/AndroidManifest.xml index 61309a7..285f5b9 --- a/friendsmash_complete/AndroidManifest.xml +++ b/friend-smash/src/main/AndroidManifest.xml @@ -21,8 +21,8 @@ android:versionName="1.0" > + android:minSdkVersion="15" + android:targetSdkVersion="23" /> @@ -31,10 +31,11 @@ android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" - android:name="com.facebook.android.friendsmash.FriendSmashApplication" > + android:name="com.facebook.android.friendsmash.FriendSmashApplication"> + android:label="@string/title_activity_home" + android:screenOrientation="portrait"> @@ -43,20 +44,25 @@ + android:hardwareAccelerated="true" + android:screenOrientation="portrait"> - - + android:label="@string/title_activity_home" + android:screenOrientation="portrait"> - - + android:name="com.facebook.FacebookActivity" + android:theme="@android:style/Theme.Translucent.NoTitleBar" + android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation" + android:label="@string/app_name" + /> + + + \ No newline at end of file diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java new file mode 100644 index 0000000..2506f72 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java @@ -0,0 +1,75 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; + +import com.facebook.login.widget.LoginButton; + +/** + * Fragment to be displayed if the user is logged out of Facebook + */ +public class FBLoggedOutHomeFragment extends Fragment { + + View progressContainer; + + @Override + public void onCreate(Bundle savedInstanceState) { + + super.onCreate(savedInstanceState); + setRetainInstance(true); + + getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup parent, + Bundle savedInstanceState) { + + View v = inflater.inflate(R.layout.fragment_home_fb_logged_out, parent, false); + + progressContainer = v.findViewById(R.id.progressContainer); + progressContainer.setVisibility(View.INVISIBLE); + + LoginButton loginButton = (LoginButton) v.findViewById(R.id.loginButton); + getHomeActivity().getFacebookLogin().setUpLoginButton(loginButton); + loginButton.setFragment(this); + + return v; + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + getHomeActivity().getFacebookLogin().getCallbackManager(). + onActivityResult(requestCode, resultCode, data); + } + + private HomeActivity getHomeActivity() { + return (HomeActivity)getActivity(); + } +} \ No newline at end of file diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/FriendSmashApplication.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/FriendSmashApplication.java new file mode 100644 index 0000000..b76bb01 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/FriendSmashApplication.java @@ -0,0 +1,233 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +import android.app.Application; +import android.content.SharedPreferences; + +import com.facebook.FacebookSdk; +import com.parse.Parse; +import com.parse.ParseFacebookUtils; +import com.parse.ParseUser; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; + +public class FriendSmashApplication extends Application { + + // Tag used when logging all messages with the same tag (e.g. for demoing purposes) + public static final String TAG = "FriendSmash"; + + public static int NEW_USER_BOMBS = 5; + public static int NEW_USER_COINS = 100; + public static int NUM_BOMBS_ALLOWED_IN_GAME = 3; + public static int NUM_COINS_PER_BOMB = 5; + private int score = 0; + private int bombs = 0; + private int coins = 0; + private int coinsCollected = 0; + private int topScore = 0; + + private boolean loggedIn = false; + public static final String LOGGED_IN_KEY = "logged_in"; + + private JSONObject currentFBUser; + public static final String CURRENT_FB_USER_KEY = "current_fb_user"; + + private JSONArray friends; + + public static final String FRIENDS_KEY = "friends"; + + private String lastFriendSmashedID = null; + + private String lastFriendSmashedName = null; + + private boolean hasDeniedFriendPermission = false; + + private ArrayList scoreboardEntriesList = null; + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + public int getBombs() { + return bombs; + } + + public void setBombs(int bombs) { + this.bombs = bombs; + } + + public int getCoins() { + return coins; + } + + public void setCoins(int coins) { + this.coins = coins; + } + + public int getCoinsCollected() { + return coinsCollected; + } + + public void setCoinsCollected(int coinsCollected) { + this.coinsCollected = coinsCollected; + } + + public int getTopScore() { return topScore; } + + public void setTopScore(int topScore) { this.topScore = topScore; } + + public boolean isLoggedIn() { + return loggedIn; + } + + public void setLoggedIn(boolean loggedIn) { + this.loggedIn = loggedIn; + if (!loggedIn) { + setScore(0); + setCurrentFBUser(null); + setFriends(null); + setLastFriendSmashedID(null); + setScoreboardEntriesList(null); + } + } + + public JSONObject getCurrentFBUser() { + return currentFBUser; + } + + public void setCurrentFBUser(JSONObject currentFBUser) { + this.currentFBUser = currentFBUser; + } + + public JSONArray getFriends() { + return friends; + } + + public ArrayList getFriendsAsArrayListOfStrings() { + ArrayList friendsAsArrayListOfStrings = new ArrayList(); + + int numFriends = friends.length(); + for (int i = 0; i < numFriends; i++) { + friendsAsArrayListOfStrings.add(getFriend(i).toString()); + } + + return friendsAsArrayListOfStrings; + } + + public JSONObject getFriend(int index) { + JSONObject friend = null; + if (friends != null && friends.length() > index) { + friend = friends.optJSONObject(index); + } + return friend; + } + + public void setFriends(JSONArray friends) { + this.friends = friends; + } + + public String getLastFriendSmashedID() { + return lastFriendSmashedID; + } + + public void setLastFriendSmashedID(String lastFriendSmashedID) { + this.lastFriendSmashedID = lastFriendSmashedID; + } + + public String getLastFriendSmashedName() { + return lastFriendSmashedName; + } + + public void setLastFriendSmashedName(String lastFriendSmashedName) { + this.lastFriendSmashedName = lastFriendSmashedName; + } + + public boolean hasDeniedFriendPermission() { + return hasDeniedFriendPermission; + } + + public void setHasDeniedFriendPermission(boolean hasDeniedFriendPermission) { + this.hasDeniedFriendPermission = hasDeniedFriendPermission; + } + + public ArrayList getScoreboardEntriesList() { + return scoreboardEntriesList; + } + + public void setScoreboardEntriesList(ArrayList scoreboardEntriesList) { + this.scoreboardEntriesList = scoreboardEntriesList; + } + + public String getFBAppID() { + return getString(R.string.facebook_app_id); + } + + public void saveInventory() { + SharedPreferences prefs = getApplicationContext().getSharedPreferences("Inventory", MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + editor.putInt("bombs", getBombs()); + editor.putInt("coins", getCoins()); + editor.putLong("lastSavedTime", System.currentTimeMillis()); + editor.commit(); + + if (ParseUser.getCurrentUser() != null) { + ParseUser.getCurrentUser().put("bombs", getBombs()); + ParseUser.getCurrentUser().put("coins", getCoins()); + ParseUser.getCurrentUser().saveInBackground(); + } + } + + public void loadInventory() { + if (ParseUser.getCurrentUser() != null) { + setBombs(ParseUser.getCurrentUser().getInt("bombs")); + setCoins(ParseUser.getCurrentUser().getInt("coins")); + } else { + SharedPreferences prefs = getApplicationContext().getSharedPreferences("Inventory", MODE_PRIVATE); + long lastSavedTime = prefs.getLong("lastSavedTime", 0); + + if (lastSavedTime == 0) { + setBombs(NEW_USER_BOMBS); + setCoins(NEW_USER_COINS); + } else { + setBombs(prefs.getInt("bombs", 0)); + setCoins(prefs.getInt("coins", 0)); + } + } + } + + public void onCreate() { + super.onCreate(); + Parse.initialize(this, getString(R.string.parse_app_id), getString(R.string.parse_client_key)); + ParseFacebookUtils.initialize(this); + FacebookSdk.sdkInitialize(this.getApplicationContext()); + loadInventory(); + } + + +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/GameActivity.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/GameActivity.java new file mode 100644 index 0000000..f49f607 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/GameActivity.java @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + + +import android.support.v4.app.Fragment; + +/** + * Activity used once a user starts a new game - all logic is within GameFragment + */ +public class GameActivity extends SingleFragmentActivity { + + @Override + Fragment createFragment() { + return new GameFragment(); + } +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/GameFragment.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/GameFragment.java new file mode 100644 index 0000000..85225a2 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/GameFragment.java @@ -0,0 +1,687 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +import android.animation.Animator; +import android.animation.Animator.AnimatorListener; +import android.app.Activity; +import android.content.Context; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Point; +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.util.Pair; +import android.view.Display; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; +import android.view.ViewGroup; +import android.view.WindowManager; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.facebook.FacebookRequestError; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.integration.GameRequest; +import com.facebook.android.friendsmash.integration.GraphAPICall; +import com.facebook.android.friendsmash.integration.GraphAPICallback; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.Random; + +/** + * Fragment shown once a user starts playing a game + */ +public class GameFragment extends Fragment { + + private static final Pair [] CELEBS = { + Pair.create("Einstein", "drawable/nonfriend_1"), + Pair.create("Xzibit", "drawable/nonfriend_2"), + Pair.create("Goldsmith", "drawable/nonfriend_3"), + Pair.create("Sinatra", "drawable/nonfriend_4"), + Pair.create("George", "drawable/nonfriend_5"), + Pair.create("Jacko", "drawable/nonfriend_6"), + Pair.create("Rick", "drawable/nonfriend_7"), + Pair.create("Keanu", "drawable/nonfriend_8"), + Pair.create("Arnie", "drawable/nonfriend_9"), + Pair.create("Jean-Luc", "drawable/nonfriend_10"), + }; + + private static final int CELEB_FREQUENCY = 5; + private static final int COIN_FREQUENCY = 8; + + private static final String TAG = GameFragment.class.getSimpleName(); + + private FrameLayout gameFrame; + private FrameLayout progressContainer; + private TextView smashPlayerNameTextView; + private TextView scoreTextView; + private LinearLayout livesContainer; + private LinearLayout bombsContainer; + private ImageView bombButton; + + private int iconWidth; + + private int screenWidth; + private int screenHeight; + + // Handler for putting messages on Main UI thread from background threads periodically + private Handler timerHandler; + + // Handler for putting messages on Main UI thread from background thread after fetching images + private Handler uiHandler; + + // Runnable task used to produce images to fly across the screen + private Runnable fireImageTask = null; + + private boolean imagesStartedFiring = false; + private boolean firstImagePendingFiring = false; + private boolean firstImageFired = false; + + private int friendToSmashIndex = -1; + private int celebToSmashIndex = -1; + private boolean isSocialMode = false; + + private String friendToSmashIDProvided = null; + private String friendToSmashFirstName = null; + private Bitmap friendToSmashBitmap; + + private int score = 0; + private int lives = 3; + private int bombsRemaining = FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME; + private int bombsUsed = 0; + private int coinsCollected = 0; + + private ArrayList userImageViews = new ArrayList(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + + timerHandler = new Handler(); + uiHandler = new Handler(); + + // Make sure there are non-zero friends. + JSONArray friends = ((FriendSmashApplication) getActivity().getApplication()).getFriends(); + if (friends != null && friends.length() > 0) { + isSocialMode = true; + friendToSmashIndex = getRandomFriendIndex(); + } else { + isSocialMode = false; + celebToSmashIndex = getRandomCelebIndex(); + + ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedID(null); + ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedName(CELEBS[celebToSmashIndex].first.toString()); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { + + View v = inflater.inflate(R.layout.fragment_game, parent, false); + + gameFrame = (FrameLayout)v.findViewById(R.id.gameFrame); + progressContainer = (FrameLayout)v.findViewById(R.id.progressContainer); + smashPlayerNameTextView = (TextView)v.findViewById(R.id.smashPlayerNameTextView); + scoreTextView = (TextView)v.findViewById(R.id.scoreTextView); + livesContainer = (LinearLayout)v.findViewById(R.id.livesContainer); + bombsContainer = (LinearLayout)v.findViewById(R.id.bombsContainer); + bombButton = (ImageView)v.findViewById(R.id.bombButton); + bombButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onBombButtonTouched(); + return false; + } + }); + + progressContainer.setVisibility(View.INVISIBLE); + + iconWidth = getResources().getDimensionPixelSize(R.dimen.icon_width); + + WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE); + Display display = wm.getDefaultDisplay(); + + Point size = new Point(); + display.getSize(size); + screenWidth = size.x; + screenHeight = size.y; + + fireImageTask = new Runnable() + { + public void run() + { + spawnImage(false); + } + }; + + setScore(getScore()); + setLives(getLives()); + setBombsRemaining(getBombsRemaining()); + + return v; + } + + private void onBombButtonTouched() { + if (getBombsRemaining() > 0) { + hideAllUserImageViews(); + markAllUserImageViewsAsVoid(); + + bombsUsed++; + + setBombsRemaining(getBombsRemaining() - 1); + } else { + setBombsRemaining(0); + } + } + + private void setSmashPlayerNameTextView() { + if (isSocialMode) { + if (friendToSmashFirstName == null) { + JSONObject friend = ((FriendSmashApplication) getActivity().getApplication()).getFriend(friendToSmashIndex); + friendToSmashFirstName = friend.optString("first_name"); + } + smashPlayerNameTextView.setText("Smash " + friendToSmashFirstName + " !"); + } else { + smashPlayerNameTextView.setText("Smash " + CELEBS[celebToSmashIndex].first + " !"); + } + } + + private int getRandomFriendIndex() { + Random randomGenerator = new Random(System.currentTimeMillis()); + int friendIndex = randomGenerator.nextInt(((FriendSmashApplication) getActivity().getApplication()).getFriends().length()); + return friendIndex; + } + + private int getRandomCelebIndex() { + Random randomGenerator = new Random(System.currentTimeMillis()); + int celebIndex = randomGenerator.nextInt(CELEBS.length); + return celebIndex; + } + + private void setFriendImageAndFire(UserImageView imageView, Bitmap friendBitmap, boolean extraImage) { + imageView.setImageBitmap(friendBitmap); + if (extraImage) { + imageView.setExtraPoints(1); + } + fireImage(imageView, extraImage); + } + + private void setCelebImageAndFire(UserImageView imageView, int celebIndex, boolean extraImage) { + int imageResource = getResources().getIdentifier((String) CELEBS[celebIndex].second, null, getActivity().getPackageName()); + + Drawable image = getResources().getDrawable(imageResource); + imageView.setImageDrawable(image); + + fireImage(imageView, extraImage); + } + + private void setCoinImageAndFire(UserImageView imageView, boolean extraImage) { + imageView.setImageResource(R.drawable.coin); + fireImage(imageView, extraImage); + } + + private void fireImage(final UserImageView imageView, boolean extraImage) { + imageView.setupAndStartAnimations(iconWidth, iconWidth, screenWidth, screenHeight, new AnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + if (!imageView.isWrongImageSmashed()) { + if (imageView.getVisibility() == View.VISIBLE && imageView.shouldSmash() && !imageView.isVoid() && !imageView.isCoin()) { + // Image is still visible, so user didn't smash it and they should have done (and it isn't void), so decrement the lives by one + setLives(getLives() - 1); + } + + hideAndRemove(imageView); + } + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + + @Override + public void onAnimationStart(Animator animation) { + } + }); + + if (!extraImage) { + fireAnotherImage(); + } + + firstImagePendingFiring = false; + } + + private void hideAndRemove(UserImageView userImageView) { + if (userImageView.getVisibility() == View.VISIBLE) { + userImageView.setVisibility(View.GONE); + } + + getGameFrame().removeView(userImageView); + + getUserImageViews().remove(userImageView); + } + + private void fireAnotherImage() { + if (fireImageTask != null) + { + timerHandler.postDelayed(fireImageTask, 700); + } + } + + private void fireFirstImage() { + if (isSocialMode) { + Bundle bundle = getActivity().getIntent().getExtras(); + + String requestID = null; + String userID = null; + int numBombsRemaining = 0; + if (bundle != null) { + requestID = bundle.getString("request_id"); + userID = bundle.getString("user_id"); + numBombsRemaining = bundle.getInt("num_bombs") <= FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME ? + bundle.getInt("num_bombs") : FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME; + setBombsRemaining(numBombsRemaining); + } + + if (requestID != null && friendToSmashIDProvided == null) { + progressContainer.setVisibility(View.VISIBLE); + fireFirstImageWithRequestID(requestID); + } else if (userID != null && friendToSmashIDProvided == null) { + progressContainer.setVisibility(View.VISIBLE); + fireFirstImageWithUserID(userID); + } else { + progressContainer.setVisibility(View.INVISIBLE); + setSmashPlayerNameTextView(); + + spawnImage(false); + } + } else { + progressContainer.setVisibility(View.INVISIBLE); + setSmashPlayerNameTextView(); + + spawnImage(false); + } + } + + private void fireFirstImageWithRequestID(String requestID) { + GameRequest.getUserDataFromRequest(requestID, new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + friendToSmashIDProvided = response.getJSONObject().optString("id"); + setFriendToSmashFromGraphAPIResponse(response); + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + closeAndHandleError(error); + } + }); + } + + private void fireFirstImageWithUserID(String userID) { + friendToSmashIDProvided = userID; + GraphAPICall userCall = GraphAPICall.callUser(friendToSmashIDProvided, "first_name", new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + setFriendToSmashFromGraphAPIResponse(response); + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + closeAndHandleError(error); + } + }); + userCall.executeAsync(); + } + + private void setFriendToSmashFromGraphAPIResponse (GraphResponse response) { + if (response != null) { + friendToSmashFirstName = response.getJSONObject().optString("first_name"); + } + if (friendToSmashFirstName != null) { + progressContainer.setVisibility(View.INVISIBLE); + setSmashPlayerNameTextView(); + spawnImage(false); + } + } + + private void spawnImage(final boolean extraImage) { + Random randomGenerator = new Random(System.currentTimeMillis()); + + boolean shouldSmash = true; + boolean isCoin = false; + if (firstImageFired) { + if (randomGenerator.nextInt(CELEB_FREQUENCY) == 0 && firstImageFired) { + shouldSmash = false; + } else if (randomGenerator.nextInt(COIN_FREQUENCY) == 0 && firstImageFired) { + isCoin = true; + } + } else { + shouldSmash = true; + firstImageFired = true; + } + + final UserImageView userImageView = (new UserImageView(getActivity(), shouldSmash, isCoin)); + userImageView.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (userImageView.shouldSmash()) { + if (userImageView.isCoin()) { + coinsCollected++; + } else { + setScore(getScore() + 1 + userImageView.getExtraPoints()); + } + + v.setVisibility(View.GONE); + + getUserImageViews().remove(v); + } else { + wrongImageSmashed(userImageView); + } + return false; + } + }); + userImageView.setLayoutParams(new LinearLayout.LayoutParams(iconWidth, iconWidth)); + gameFrame.addView(userImageView); + userImageViews.add(userImageView); + + if (userImageView.shouldSmash()) { + if (userImageView.isCoin()) { + setCoinImageAndFire(userImageView, extraImage); + } else { + if (isSocialMode) { + if (friendToSmashBitmap != null) { + setFriendImageAndFire(userImageView, friendToSmashBitmap, extraImage); + } else { + progressContainer.setVisibility(View.VISIBLE); + + final String friendToSmashID = friendToSmashIDProvided != null ? friendToSmashIDProvided : + ((FriendSmashApplication) getActivity().getApplication()).getFriend(friendToSmashIndex).optString("id"); + + fetchFriendBitmapAndFireImages(userImageView, friendToSmashID, extraImage); + } + } else { + setCelebImageAndFire(userImageView, celebToSmashIndex, extraImage); + } + } + } else { + int randomCelebToSmashIndex; + do { + randomCelebToSmashIndex = randomGenerator.nextInt(CELEBS.length); + } while (randomCelebToSmashIndex == celebToSmashIndex); + setCelebImageAndFire(userImageView, randomCelebToSmashIndex, extraImage); + } + } + + private void wrongImageSmashed(final UserImageView userImageView) { + userImageView.setWrongImageSmashed(true); + userImageView.stopMovementAnimations(); + hideAllUserImageViewsExcept(userImageView); + + userImageView.scaleUp(new AnimatorListener() { + @Override + public void onAnimationCancel(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + userImageView.stopRotationAnimation(); + setLives(0); + } + + @Override + public void onAnimationRepeat(Animator animation) { + } + + @Override + public void onAnimationStart(Animator animation) { + } + }); + + getGameFrame().bringChildToFront(userImageView); + } + + private void fetchFriendBitmapAndFireImages(final UserImageView userImageView, final String friendToSmashID, final boolean extraImage) { + AsyncTask.execute(new Runnable() { + public void run() { + URL bitmapURL; + try { + bitmapURL = new URL("http://graph.facebook.com/" + friendToSmashID + + "/picture?redirect=false&width=" + iconWidth + "&height=" + iconWidth); + InputStream bitmapURLInputStream = bitmapURL.openConnection().getInputStream(); + BufferedReader r = new BufferedReader(new InputStreamReader(bitmapURLInputStream)); + StringBuilder bitmapURLString = new StringBuilder(); + String line; + while ((line = r.readLine()) != null) { + bitmapURLString.append(line); + } + try { + + JSONObject obj = new JSONObject(bitmapURLString.toString()); + JSONObject jsonObject = obj.getJSONObject("data"); + String imageURLString = jsonObject.getString("url"); + URL imageURL = new URL(imageURLString); + friendToSmashBitmap = BitmapFactory.decodeStream(imageURL.openConnection().getInputStream()); + } catch (Exception e) { + Log.e(FriendSmashApplication.TAG, e.toString()); + closeAndShowError(getResources().getString(R.string.error_fetching_friend_bitmap)); + } + } catch (Exception e) { + Log.e(FriendSmashApplication.TAG, e.toString()); + } + + uiHandler.post(new Runnable() { + @Override + public void run() { + progressContainer.setVisibility(View.INVISIBLE); + + if (friendToSmashBitmap != null) { + setFriendImageAndFire(userImageView, friendToSmashBitmap, extraImage); + + // Also set the lastFriendSmashedID and lastFriendSmashedName in the application + ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedID(friendToSmashID); + ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedName(friendToSmashFirstName); + } else { + closeAndShowError(getResources().getString(R.string.error_fetching_friend_bitmap)); + } + } + }); + } + }); + } + + 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(); + } + + private void closeAndHandleError(FacebookRequestError error) { + getActivity().setResult(Activity.RESULT_CANCELED); + getActivity().finish(); + } + + void hideAllUserImageViews() { + Iterator userImageViewsIterator = userImageViews.iterator(); + while (userImageViewsIterator.hasNext()) { + UserImageView currentUserImageView = userImageViewsIterator.next(); + currentUserImageView.setVisibility(View.GONE); + } + } + + void hideAllUserImageViewsExcept(UserImageView userImageView) { + timerHandler.removeCallbacks(fireImageTask); + + Iterator userImageViewsIterator = userImageViews.iterator(); + while (userImageViewsIterator.hasNext()) { + UserImageView currentUserImageView = userImageViewsIterator.next(); + if (!currentUserImageView.equals(userImageView)) { + currentUserImageView.setVisibility(View.GONE); + } + } + } + + private void markAllUserImageViewsAsVoid() { + Iterator userImageViewsIterator = userImageViews.iterator(); + while (userImageViewsIterator.hasNext()) { + UserImageView currentUserImageView = userImageViewsIterator.next(); + currentUserImageView.setVoid(true); + } + } + + @Override + public void onPause() { + super.onPause(); + + stopTheFiringImages(); + } + + @Override + public void onResume() { + super.onResume(); + + stopTheFiringImages(); + + if (!imagesStartedFiring) { + if (isSocialMode) { + if (!firstImagePendingFiring) { + firstImagePendingFiring = true; + imagesStartedFiring = true; + fireFirstImage(); + } + } else { + imagesStartedFiring = true; + fireFirstImage(); + } + } + } + + private void stopTheFiringImages() { + markAllUserImageViewsAsVoid(); + + timerHandler.removeCallbacks(fireImageTask); + imagesStartedFiring = false; + } + + private int getScore() { + return score; + } + + private void setScore(int score) { + this.score = score; + + scoreTextView.setText("Score: " + score); + + if (score > 0 && score % 10 == 0) { + for (int i=0; i getUserImageViews() { + return userImageViews; + } +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/HomeActivity.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/HomeActivity.java new file mode 100644 index 0000000..1072524 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/HomeActivity.java @@ -0,0 +1,347 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentActivity; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.widget.Toast; + +import com.facebook.AccessToken; +import com.facebook.FacebookRequestError; +import com.facebook.GraphRequestBatch; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.integration.FacebookLogin; +import com.facebook.android.friendsmash.integration.FacebookLoginPermission; +import com.facebook.android.friendsmash.integration.FriendSmashEventsLogger; +import com.facebook.android.friendsmash.integration.GameRequest; +import com.facebook.android.friendsmash.integration.GraphAPICall; +import com.facebook.android.friendsmash.integration.GraphAPICallback; +import com.facebook.appevents.AppEventsLogger; +import com.facebook.login.LoginManager; +import com.parse.LogInCallback; +import com.parse.ParseException; +import com.parse.ParseFacebookUtils; +import com.parse.ParseUser; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * Entry point for the app that represents the home screen with the Play button etc. and + * also the login screen for the social version of the app - these screens will switch + * within this activity using Fragments. + */ +public class HomeActivity extends FragmentActivity { + private static final int FB_LOGGED_OUT_HOME = 0; + private static final int HOME = 1; + private static final int FRAGMENT_COUNT = HOME +1; + private Fragment[] fragments = new Fragment[FRAGMENT_COUNT]; + + private FriendSmashEventsLogger eventsLogger; + public FriendSmashEventsLogger getEventsLogger() { return eventsLogger; } + + private FacebookLogin facebookLogin; + public FacebookLogin getFacebookLogin() { return facebookLogin; } + + private GameRequest gameRequest; + public GameRequest getGameRequest() { return gameRequest; } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + facebookLogin = new FacebookLogin(this); + facebookLogin.init(); + eventsLogger = new FriendSmashEventsLogger(getApplicationContext()); + gameRequest = new GameRequest(this); + + setContentView(R.layout.home); + + FragmentManager fm = getSupportFragmentManager(); + fragments[FB_LOGGED_OUT_HOME] = fm.findFragmentById(R.id.fbLoggedOutHomeFragment); + fragments[HOME] = fm.findFragmentById(R.id.homeFragment); + + FragmentTransaction transaction = fm.beginTransaction(); + for(int i = 0; i < fragments.length; i++) { + transaction.hide(fragments[i]); + } + transaction.commit(); + + if (savedInstanceState != null) { + FriendSmashApplication app = (FriendSmashApplication)getApplication(); + boolean loggedInState = savedInstanceState.getBoolean(FriendSmashApplication.LOGGED_IN_KEY, false); + app.setLoggedIn(loggedInState); + + if (app.isLoggedIn() && (app.getFriends() == null || app.getCurrentFBUser() == null)) { + try { + String currentFBUserJSONString = savedInstanceState.getString(FriendSmashApplication.CURRENT_FB_USER_KEY); + if (currentFBUserJSONString != null) { + JSONObject currentFBUser = new JSONObject(currentFBUserJSONString); + app.setCurrentFBUser(currentFBUser); + } + + // friends + ArrayList friendsJSONStringArrayList = savedInstanceState.getStringArrayList(FriendSmashApplication.FRIENDS_KEY); + if (friendsJSONStringArrayList != null) { + JSONArray friends = new JSONArray(); + Iterator friendsJSONStringArrayListIterator = friendsJSONStringArrayList.iterator(); + while (friendsJSONStringArrayListIterator.hasNext()) { + friends.put(new JSONObject(friendsJSONStringArrayListIterator.next())); + } + app.setFriends(friends); + } + } catch (JSONException e) { + Log.e(FriendSmashApplication.TAG, e.toString()); + } + } + } else if (FacebookLogin.isAccessTokenValid()) { + fetchUserInformationAndLogin(); + } + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + facebookLogin.getCallbackManager().onActivityResult(requestCode, resultCode, data); + } + + protected void onResumeFragments() { + FriendSmashApplication application = (FriendSmashApplication) getApplication(); + if (FacebookLogin.isAccessTokenValid() && application.getCurrentFBUser() != null) { + showFragment(HOME); + } + else { + showFragment(FB_LOGGED_OUT_HOME); + } + } + + @Override + public void onResume() { + super.onResume(); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); + AppEventsLogger.activateApp(this); + facebookLogin.activate(); + } + + @Override + public void onPause() { + super.onPause(); + AppEventsLogger.deactivateApp(this); + facebookLogin.deactivate(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + FriendSmashApplication app = (FriendSmashApplication)getApplication(); + + outState.putBoolean(FriendSmashApplication.LOGGED_IN_KEY, app.isLoggedIn()); + + if (((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { + outState.putString(FriendSmashApplication.CURRENT_FB_USER_KEY, app.getCurrentFBUser().toString()); + } + + if (((FriendSmashApplication)getApplication()).getFriends() != null) { + outState.putStringArrayList(FriendSmashApplication.FRIENDS_KEY, app.getFriendsAsArrayListOfStrings()); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + facebookLogin.deactivate(); + } + + public void buyBombs() { + FriendSmashApplication app = (FriendSmashApplication) getApplication(); + if (app.getCoins() < FriendSmashApplication.NUM_COINS_PER_BOMB) { + Toast.makeText(this, "Not enough coins.", Toast.LENGTH_LONG).show(); + return; + } + + app.setBombs(app.getBombs()+1); + app.setCoins(app.getCoins()-FriendSmashApplication.NUM_COINS_PER_BOMB); + + app.saveInventory(); + + loadInventoryFragment(); + } + + private void showFragment(int fragmentIndex) { + FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); + for (int i = 0; i < fragments.length; i++) { + if (i == fragmentIndex) { + transaction.show(fragments[i]); + } else { + transaction.hide(fragments[i]); + } + } + transaction.commit(); + + switch (fragmentIndex) { + case FB_LOGGED_OUT_HOME: + if (fragments[FB_LOGGED_OUT_HOME] != null) { + ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer.setVisibility(View.INVISIBLE); + } + ((FriendSmashApplication)getApplication()).setLoggedIn(false); + break; + case HOME: + ((FriendSmashApplication)getApplication()).setLoggedIn(true); + break; + } + } + + public void onLoginStateChanged(AccessToken oldToken, AccessToken currentToken) { + boolean isLoggedIn = ((FriendSmashApplication) getApplication()).isLoggedIn(); + if (FacebookLogin.isAccessTokenValid() && !isLoggedIn && fragments[HOME] != null) { + fetchUserInformationAndLogin(); + } else if (!FacebookLogin.isAccessTokenValid() && isLoggedIn && fragments[FB_LOGGED_OUT_HOME] != null) { + logout(); + showFragment(FB_LOGGED_OUT_HOME); + } else if (FacebookLogin.testTokenHasPermission(currentToken, FacebookLoginPermission.USER_FRIENDS) && + !FacebookLogin.testTokenHasPermission(oldToken, FacebookLoginPermission.USER_FRIENDS)) { + ((HomeFragment)fragments[HOME]).onUserFriendsGranted(); + } else if (FacebookLogin.testTokenHasPermission(currentToken, FacebookLoginPermission.PUBLISH_ACTIONS) && + !FacebookLogin.testTokenHasPermission(oldToken, FacebookLoginPermission.PUBLISH_ACTIONS)) { + ((HomeFragment)fragments[HOME]).onPublishActionsGranted(); + } + } + + private void fetchUserInformationAndLogin() { + if (FacebookLogin.isAccessTokenValid()) { + if (fragments[FB_LOGGED_OUT_HOME] != null && + ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer != null) { + ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer.setVisibility(View.VISIBLE); + } + + GraphAPICall myFriendsCall = GraphAPICall.callMeFriends("name,first_name", new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + JSONArray friendsData = GraphAPICall.getDataFromResponse(response); + ((FriendSmashApplication) getApplication()).setFriends(friendsData); + } + + @Override + public void handleError(FacebookRequestError error) { + showError(error.toString()); + } + }); + + GraphAPICall meCall = GraphAPICall.callMe("first_name", new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + JSONObject user = response.getJSONObject(); + ((FriendSmashApplication) getApplication()).setCurrentFBUser(user); + //saveUserToParse(); + // it causes strange beaviour with AccessTokenTracker + } + + @Override + public void handleError(FacebookRequestError error) { + showError(error.toString()); + } + }); + + GraphAPICall meScoresCall = GraphAPICall.callMeScores(new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + JSONObject data = GraphAPICall.getDataFromResponse(response).optJSONObject(0); + if (data != null) { + int score = data.optInt("score"); + ((FriendSmashApplication) getApplication()).setTopScore(score); + } + } + + @Override + public void handleError(FacebookRequestError error) { + showError(error.toString()); + } + }); + + // Create a RequestBatch and add a callback once the batch of requests completes + GraphRequestBatch requestBatch = GraphAPICall.createRequestBatch(myFriendsCall, meCall, meScoresCall); + + requestBatch.addCallback(new GraphRequestBatch.Callback() { + @Override + public void onBatchCompleted(GraphRequestBatch batch) { + if (((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { + loadPersonalizedFragment(); + } else { + showError(getString(R.string.error_fetching_profile)); + } + } + }); + + requestBatch.executeAsync(); + } + } + + private void saveUserToParse() { + ParseFacebookUtils.logInInBackground(AccessToken.getCurrentAccessToken(), new LogInCallback() { + @Override + public void done(ParseUser parseUser, ParseException err) { + if (parseUser != null) { + if (parseUser.isNew()) { + FriendSmashApplication app = ((FriendSmashApplication) getApplication()); + app.saveInventory(); + } else { + FriendSmashApplication app = ((FriendSmashApplication) getApplication()); + app.loadInventory(); + } + + loadInventoryFragment(); + } else { + Log.d(FriendSmashApplication.TAG, "User was not saved to Parse: " + err.getMessage()); + } + } + }); + } + + private void loadInventoryFragment() { + ((HomeFragment) fragments[HOME]).loadInventory(); + } + + private void loadPersonalizedFragment() { + ((HomeFragment)fragments[HOME]).personalizeHomeFragment(); + showFragment(HOME); + } + + public void showError(String error) { + Toast.makeText(this, error, Toast.LENGTH_LONG).show(); + } + + private void logout() { + if (ParseUser.getCurrentUser() != null) + ParseUser.logOut(); + + LoginManager.getInstance().logOut(); + } +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/HomeFragment.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/HomeFragment.java new file mode 100644 index 0000000..d17a752 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/HomeFragment.java @@ -0,0 +1,666 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.FrameLayout; +import android.widget.GridView; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.RelativeLayout; +import android.widget.TextView; + +import com.facebook.CallbackManager; +import com.facebook.FacebookRequestError; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.integration.FacebookLogin; +import com.facebook.android.friendsmash.integration.FacebookLoginPermission; +import com.facebook.android.friendsmash.integration.GameRequest; +import com.facebook.android.friendsmash.integration.GraphAPICall; +import com.facebook.android.friendsmash.integration.GraphAPICallback; +import com.facebook.android.friendsmash.integration.Sharing; +import com.facebook.login.widget.LoginButton; +import com.facebook.login.widget.ProfilePictureView; + +import org.json.JSONArray; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/** + * Fragment to be shown once the user is logged in on the social version of the game or + * the start screen for the non-social version of the game + */ +public class HomeFragment extends Fragment { + + interface FriendsLoadedCallback { + void afterFriendsLoaded(); + } + private FriendSmashApplication application; + + private LinearLayout mainButtonsContainer; + private RelativeLayout challengeContainer; + private LinearLayout gameOverContainer; + private FrameLayout progressContainer; + + private TextView scoredTextView; + private ProfilePictureView userImage; + private ProfilePictureView youSmashedUserImage; + private TextView welcomeTextView; + + private GridView invitesGridView; + private GridView requestsGridView; + + private ImageView playButton; + private ImageView scoresButton; + private ImageView challengeButton; + private ImageView challengeRequestToggle; + + private TextView numBombs; + private TextView numCoins; + + private boolean gameOverMessageDisplaying = false; + private boolean gameLaunchedFromDeepLinking = false; + + private static final int FRIENDS_PLAY_PERMISSION_REQUEST_CODE = 101; + private static final int FRIENDS_LEADERBOARD_PERMISSION_REQUEST_CODE = 102; + private static final String GAME_OVER_MESSAGE_KEY = "gameOverMessageDisplaying"; + + private int latestPermissionRequestCode; + + private boolean invitesMode = true; + private List idsToRequest = new ArrayList(); + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setRetainInstance(true); + application = (FriendSmashApplication) getActivity().getApplication(); + + if (savedInstanceState != null) { + if (savedInstanceState.containsKey(GAME_OVER_MESSAGE_KEY)) + gameOverMessageDisplaying = savedInstanceState.getBoolean(GAME_OVER_MESSAGE_KEY); + } + checkForDeeplinkins(); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup parent, + Bundle savedInstanceState) { + + View v = inflater.inflate(R.layout.fragment_home_fb_logged_in, parent, false); + userImage = (ProfilePictureView) v.findViewById(R.id.userImage); + welcomeTextView = (TextView)v.findViewById(R.id.welcomeTextView); + + personalizeHomeFragment(); + + scoresButton = (ImageView)v.findViewById(R.id.scoresButton); + scoresButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onScoresButtonTouched(); + return false; + } + }); + + challengeButton = (ImageView)v.findViewById(R.id.challengeButton); + challengeButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onChallengeButtonTouched(); + return false; + } + }); + + ImageView gameOverChallengeButton = (ImageView)v.findViewById(R.id.gameOverChallengeButton); + gameOverChallengeButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onGameOverChallengeButtonTouched(); + return false; + } + }); + + ImageView gameOverBragButton = (ImageView)v.findViewById(R.id.gameOverBragButton); + gameOverBragButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onGameOverBragButtonTouched(); + return false; + } + }); + + challengeRequestToggle = (ImageView)v.findViewById(R.id.mfsClicker); + challengeRequestToggle.setOnTouchListener(new View.OnTouchListener() { + + @Override + public boolean onTouch(View v, MotionEvent event) { + if (invitesMode) { + invitesMode = false; + challengeRequestToggle.setImageResource(R.drawable.mfs_clicker_request); + invitesGridView.setVisibility(View.INVISIBLE); + requestsGridView.setVisibility(View.VISIBLE); + } else { + invitesMode = true; + challengeRequestToggle.setImageResource(R.drawable.mfs_clicker_invite); + invitesGridView.setVisibility(View.VISIBLE); + requestsGridView.setVisibility(View.INVISIBLE); + } + return false; + } + }); + + invitesGridView = (GridView)v.findViewById(R.id.invitesGridView); + requestsGridView = (GridView)v.findViewById(R.id.requestsGridView); + + requestsGridView.setVisibility(View.INVISIBLE); + + ImageView sendButton = (ImageView)v.findViewById(R.id.sendButton); + sendButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + if (invitesMode) { + sendInvite(); + } else { + sendDirectedRequest(idsToRequest); + } + + challengeContainer.setVisibility(View.INVISIBLE); + mainButtonsContainer.setVisibility(View.VISIBLE); + return false; + } + }); + + mainButtonsContainer = (LinearLayout)v.findViewById(R.id.mainButtonsContainer); + challengeContainer = (RelativeLayout)v.findViewById(R.id.challengeContainer); + + challengeContainer.setVisibility(View.INVISIBLE); + + numBombs = (TextView)v.findViewById(R.id.numBombs); + numCoins = (TextView)v.findViewById(R.id.numCoins); + loadInventory(); + + ImageView bombButton = (ImageView)v.findViewById(R.id.bombButton); + bombButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + HomeActivity homeActivity = (HomeActivity) getActivity(); + homeActivity.buyBombs(); + return false; + } + }); + + progressContainer = (FrameLayout)v.findViewById(R.id.progressContainer); + + playButton = (ImageView)v.findViewById(R.id.playButton); + playButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onPlayButtonTouched(); + return false; + } + }); + + LoginButton logoutButton = (LoginButton)v.findViewById(R.id.loginButton); + logoutButton.setFragment(this); + + gameOverContainer = (LinearLayout)v.findViewById(R.id.gameOverContainer); + youSmashedUserImage = (ProfilePictureView)v.findViewById(R.id.youSmashedUserImage); + scoredTextView = (TextView)v.findViewById(R.id.scoredTextView); + + ImageView gameOverCloseButton = (ImageView)v.findViewById(R.id.gameOverCloseButton); + gameOverCloseButton.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + onGameOverCloseButtonTouched(); + return false; + } + }); + + hideGameOverContainer(); + + progressContainer.setVisibility(View.INVISIBLE); + + return v; + } + + public void personalizeHomeFragment() { + if (application.getCurrentFBUser() != null) { + userImage.setProfileId(application.getCurrentFBUser().optString("id")); + userImage.setCropped(true); + welcomeTextView.setText("Welcome, " + application.getCurrentFBUser().optString("first_name")); + } + } + + public void loadInventory() { + FriendSmashApplication app = (FriendSmashApplication)getActivity().getApplication(); + numBombs.setText(String.valueOf(app.getBombs())); + numCoins.setText(String.valueOf(app.getCoins())); + } + + @Override + public void onResume() { + super.onResume(); + checkForDeeplinkins(); + } + + private void checkForDeeplinkins() { + if (!gameLaunchedFromDeepLinking) { + Uri target = getActivity().getIntent().getData(); + if (target != null) { + Intent i = new Intent(getActivity(), GameActivity.class); + + String graphRequestIDsForSendingUser = target.getQueryParameter("request_ids"); + String feedPostIDForSendingUser = target.getQueryParameter("challenge_brag"); + + if (graphRequestIDsForSendingUser != null) { + // Deep linked through a Request and use the latest request (request_id) if multiple requests have been sent + String [] graphRequestIDsForSendingUsers = graphRequestIDsForSendingUser.split(","); + String graphRequestIDForSendingUser = graphRequestIDsForSendingUsers[graphRequestIDsForSendingUsers.length-1]; + Bundle bundle = new Bundle(); + bundle.putString("request_id", graphRequestIDForSendingUser); + i.putExtras(bundle); + gameLaunchedFromDeepLinking = true; + startActivityForResult(i, 0); + + GameRequest.deleteRequest(graphRequestIDForSendingUser + "_" + application.getCurrentFBUser().optString("id")); + } else if (feedPostIDForSendingUser != null) { + // Deep linked through a feed post, so start the game smashing the user specified by the id attached to the + // challenge_brag parameter + Bundle bundle = new Bundle(); + bundle.putString("user_id", feedPostIDForSendingUser); + i.putExtras(bundle); + gameLaunchedFromDeepLinking = true; + startActivityForResult(i, 0); + } + } else { + // Launched with no deep-link Uri, so just continue as normal and load the home screen + } + + } + + if (!gameLaunchedFromDeepLinking && gameOverMessageDisplaying) { + // The game hasn't just been launched from deep linking and the game over message should still be displaying, so ... + completeGameOver(); + } + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putBoolean(GAME_OVER_MESSAGE_KEY, gameOverMessageDisplaying); + } + + private void askForFriendsForPlay() { + if (application.hasDeniedFriendPermission()) { + startGame(); + } else { + new AlertDialog.Builder(getActivity()) + .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + requestFriendsPermission(FRIENDS_PLAY_PERMISSION_REQUEST_CODE); + } + }) + .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + application.setHasDeniedFriendPermission(true); + startGame(); + } + }) + .setTitle(R.string.with_friends_dialog_title) + .setMessage(R.string.with_friends_dialog_message) + .show(); + } + } + + private void askForFriendsForLeaderboard() { + new AlertDialog.Builder(getActivity()) + .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + requestFriendsPermission(FRIENDS_LEADERBOARD_PERMISSION_REQUEST_CODE); + } + }) + .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + // nothing to do here + } + }) + .setTitle(R.string.leaderboard_dialog_title) + .setMessage(R.string.leaderboard_dialog_message) + .show(); + } + + private void askForPublishActionsForScores() { + new AlertDialog.Builder(getActivity()) + .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + requestPublishPermissions(); + } + }) + .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + hideGameOverContainer(); + } + }) + .setTitle(R.string.publish_scores_dialog_title) + .setMessage(R.string.publish_scores_dialog_message) + .show(); + } + + private void onPlayButtonTouched() { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + startGame(); + } else { + askForFriendsForPlay(); + } + } + + private void onChallengeButtonTouched() { + sendCustomChallenge(); + } + + private void sendInvite() { + getHomeActivity().getGameRequest().showDialogForInvites( + getString(R.string.game_request_dialog_title), getString(R.string.invite_dialog_message)); + } + + private void sendDirectedRequest(List recipients) { + getHomeActivity().getGameRequest().showDialogForDirectedRequests( + getString(R.string.game_request_dialog_title), + getString(R.string.request_dialog_message, application.getTopScore()), + recipients); + } + + private void sendDirectedChallenge(List recipient) { + getHomeActivity().getGameRequest().showDialogForDirectedRequests( + getString(R.string.game_request_dialog_title), + getString(R.string.challenge_dialog_message, application.getScore()), + recipient); + } + + private void onScoresButtonTouched() { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + Intent i = new Intent(getActivity(), ScoreboardActivity.class); + startActivityForResult(i, 0); + } else { + askForFriendsForLeaderboard(); + } + } + + private void onGameOverChallengeButtonTouched() { + sendDirectedChallenge(Arrays.asList(application.getLastFriendSmashedID())); + } + + private void onGameOverBragButtonTouched() { + sendBrag(); + } + + private void onGameOverCloseButtonTouched() { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.PUBLISH_ACTIONS)) { + Sharing.publishScore(application.getScore(), application.getTopScore()); + hideGameOverContainer(); + } else { + askForPublishActionsForScores(); + } + } + + private void showGameOverContainer() { + gameOverContainer.setVisibility(View.VISIBLE); + gameOverMessageDisplaying = true; + } + + private void hideGameOverContainer() { + gameOverContainer.setVisibility(View.INVISIBLE); + gameOverMessageDisplaying = false; + } + + private void loadFriendsForRequests() { + JSONArray friends = application.getFriends(); + + List listOfFriends = new ArrayList(); + // arbitrarily truncating the list of friends at 8 to simplify this a bit. + for (int i = 0; i < friends.length() && i < 8; i++) { + listOfFriends.add(friends.optJSONObject(i)); + } + + final RequestUserArrayAdapter adapter = new RequestUserArrayAdapter( + getActivity(), listOfFriends); + requestsGridView.setAdapter(adapter); + + requestsGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { + + @Override + public void onItemClick(AdapterView parent, final View view, + int position, long id) { + JSONObject clickedUser = application.getFriends().optJSONObject(position); + String uid = clickedUser.optString("id"); + // items act as toggles. + if (idsToRequest.contains(uid)) { + idsToRequest.remove(uid); + } else { + idsToRequest.add(uid); + } + } + + }); + } + + private void loadFriendsFromFacebook(final FriendsLoadedCallback callback) { + GraphAPICall friendsRequest = GraphAPICall.callMeFriends("name,first_name", new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + application.setFriends(GraphAPICall.getDataFromResponse(response)); + callback.afterFriendsLoaded(); + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + getHomeActivity().showError(error.toString()); + } + }); + friendsRequest.executeAsync(); + } + + @Override + public void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + CallbackManager manager = getHomeActivity().getFacebookLogin().getCallbackManager(); + manager.onActivityResult(requestCode, resultCode, data); + switch (resultCode) { + case Activity.RESULT_OK: + if (data != null) { + Bundle bundle = data.getExtras(); + application.setScore(bundle.getInt("score")); + int coinsCollected = (bundle.getInt("coins_collected")); + application.setCoinsCollected(coinsCollected); + if (coinsCollected > 0) { + application.setCoins(application.getCoins()+coinsCollected); + } + int bombsUsed = (bundle.getInt("bombs_used")); + if (bombsUsed > 0) { + application.setBombs(application.getBombs()-bombsUsed); + } + + application.saveInventory(); + loadInventory(); + + completeGameOver(); + + (getHomeActivity()).getEventsLogger().logGamePlayedEvent(application.getScore()); + } + break; + case Activity.RESULT_FIRST_USER: + if (data != null) { + startGame(data.getStringExtra("user_id")); + } + break; + case Activity.RESULT_CANCELED: + if (data != null) { + Bundle bundle = data.getExtras(); + String error = bundle.getString("error"); + if (error != null) { + getHomeActivity().showError(error); + } + } + } + } + + public void onUserFriendsGranted() { + if (latestPermissionRequestCode == FRIENDS_PLAY_PERMISSION_REQUEST_CODE) { + latestPermissionRequestCode = 0; + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + loadFriendsFromFacebook(new FriendsLoadedCallback() { + @Override + public void afterFriendsLoaded() { + startGame(); + } + }); + } else { + application.setHasDeniedFriendPermission(true); + startGame(); + } + } else if (latestPermissionRequestCode == FRIENDS_LEADERBOARD_PERMISSION_REQUEST_CODE) { + latestPermissionRequestCode = 0; + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + loadFriendsFromFacebook(new FriendsLoadedCallback() { + @Override + public void afterFriendsLoaded() { + Intent i = new Intent(getActivity(), ScoreboardActivity.class); + startActivityForResult(i, 0); + } + }); + } + } + } + + public void onPublishActionsGranted() { + Sharing.publishScore(application.getScore(), application.getTopScore()); + hideGameOverContainer(); + } + + private void startGame() { + Intent i = new Intent(getActivity(), GameActivity.class); + Bundle bundle = new Bundle(); + bundle.putInt("num_bombs", ((FriendSmashApplication) getActivity().getApplication()).getBombs()); + i.putExtras(bundle); + startActivityForResult(i, 0); + } + + private void startGame(String userId) { + Intent i = new Intent(getActivity(), GameActivity.class); + Bundle bundle = new Bundle(); + bundle.putString("user_id", userId); + bundle.putInt("num_bombs", ((FriendSmashApplication) getActivity().getApplication()).getBombs()); + i.putExtras(bundle); + startActivityForResult(i, 0); + } + + private void completeGameOver() { + // Set the scoreboardEntriesList to null so that the scoreboard is refreshed + application.setScoreboardEntriesList(null); + + if (application.getLastFriendSmashedID() != null) { + youSmashedUserImage.setProfileId(application.getLastFriendSmashedID()); + youSmashedUserImage.setCropped(true); + youSmashedUserImage.setVisibility(View.VISIBLE); + } else { + youSmashedUserImage.setVisibility(View.INVISIBLE); + } + + if (application.getScore() >= 0) { + scoredTextView.setText("You smashed " + application.getLastFriendSmashedName() + + " " + application.getScore() + (application.getScore() == 1 ? " time!" : " times!") + + "\n" + "Collected " + application.getCoinsCollected() + + (application.getCoinsCollected() == 1 ? " coin!" : " coins!")); + } + else { + scoredTextView.setText(getResources().getString(R.string.no_score)); + } + + showGameOverContainer(); + } + + private void sendChallenge() { + getHomeActivity().getGameRequest().showDialogForRequests( + getString(R.string.game_request_dialog_title), + getString(R.string.request_dialog_message, application.getTopScore()) + ); + } + + private void sendCustomChallenge() { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + loadFriendsForRequests(); + mainButtonsContainer.setVisibility(View.INVISIBLE); + challengeContainer.setVisibility(View.VISIBLE); + } else { + sendChallenge(); + } + } + + private void sendBrag() { + JSONObject currentFBUser = application.getCurrentFBUser(); + // This first parameter is used for deep linking so that anyone who clicks the link + // will start smashing this user who sent the post + String link = "https://apps.facebook.com/friendsmashsample/?challenge_brag="; + if (currentFBUser != null) { + link += currentFBUser.optString("id"); + } + + String name = getString(R.string.brag_share_name); + String description = getString(R.string.brag_share_description, application.getScore()); + String picture = getString(R.string.brag_share_picture); + + Sharing.shareViaDialog(getActivity(), name, description, picture, link); + } + + private void requestPublishPermissions() { + Log.d(FriendSmashApplication.TAG, "Requesting publish permissions."); + getHomeActivity().getFacebookLogin().requestPermission(FacebookLoginPermission.PUBLISH_ACTIONS); + } + + private void requestFriendsPermission(int requestCode) { + Log.d(FriendSmashApplication.TAG, "Requesting friends permissions."); + latestPermissionRequestCode = requestCode; + getHomeActivity().getFacebookLogin().requestPermission(FacebookLoginPermission.USER_FRIENDS); + } + + private HomeActivity getHomeActivity() { + return (HomeActivity) getActivity(); + } +} \ No newline at end of file diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/RequestUserArrayAdapter.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/RequestUserArrayAdapter.java similarity index 52% rename from friendsmash_complete/src/com/facebook/android/friendsmash/RequestUserArrayAdapter.java rename to friend-smash/src/main/java/com/facebook/android/friendsmash/RequestUserArrayAdapter.java index 7e628df..35921c9 100644 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/RequestUserArrayAdapter.java +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/RequestUserArrayAdapter.java @@ -1,3 +1,23 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + package com.facebook.android.friendsmash; import android.content.Context; @@ -9,16 +29,17 @@ import android.widget.ImageView; import android.widget.TextView; -import com.facebook.model.GraphUser; -import com.facebook.widget.ProfilePictureView; +import com.facebook.login.widget.ProfilePictureView; + +import org.json.JSONObject; import java.util.List; -public class RequestUserArrayAdapter extends ArrayAdapter { +public class RequestUserArrayAdapter extends ArrayAdapter { private final Context context; - private final List users; + private final List users; - public RequestUserArrayAdapter(Context context, List users) { + public RequestUserArrayAdapter(Context context, List users) { super(context, R.layout.request_list_item_view, users); this.context = context; this.users = users; @@ -34,11 +55,11 @@ public View getView(int position, View convertView, ViewGroup parent) { TextView nameView = (TextView) listItemView.findViewById(R.id.requestListItemName); final ImageView checkBox = (ImageView) listItemView.findViewById(R.id.requestListItemCheckbox); - GraphUser currentUser = users.get(position); + JSONObject currentUser = users.get(position); - profilePicView.setProfileId(currentUser.getId()); + profilePicView.setProfileId(currentUser.optString("id")); profilePicView.setCropped(true); - nameView.setText(currentUser.getFirstName()); + nameView.setText(currentUser.optString("first_name")); checkBox.setOnTouchListener(new View.OnTouchListener() { boolean checked = false; diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardActivity.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardActivity.java new file mode 100644 index 0000000..6ffff46 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardActivity.java @@ -0,0 +1,36 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +import android.support.v4.app.Fragment; + +/** + * Activity used once a user opens the Facebook scoreboard - all logic + * is within ScoreboardFragment + */ +public class ScoreboardActivity extends SingleFragmentActivity { + + @Override + protected Fragment createFragment() { + return new ScoreboardFragment(); + } + +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardEntry.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardEntry.java new file mode 100644 index 0000000..768703d --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardEntry.java @@ -0,0 +1,67 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash; + +/** + * Class representing an individual scoreboard entry + */ +public class ScoreboardEntry implements Comparable { + + private String id; + private String name; + private int score; + + public ScoreboardEntry (String id, String name, int score) { + setId(id); + setName(name); + setScore(score); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getScore() { + return score; + } + + public void setScore(int score) { + this.score = score; + } + + @Override + public int compareTo(ScoreboardEntry another) { + return this.score - another.score; + } + +} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardFragment.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardFragment.java similarity index 60% rename from friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardFragment.java rename to friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardFragment.java index cf42e88..eadb1bd 100644 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardFragment.java +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/ScoreboardFragment.java @@ -1,22 +1,25 @@ /** - * Copyright 2012 Facebook + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * - * 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 + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. * - * http://www.apache.org/licenses/LICENSE-2.0 + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. * - * 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. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.facebook.android.friendsmash; -import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; import android.graphics.drawable.Drawable; @@ -36,11 +39,10 @@ import android.widget.TextView; import com.facebook.FacebookRequestError; -import com.facebook.Request; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.model.GraphObject; -import com.facebook.widget.ProfilePictureView; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.integration.GraphAPICall; +import com.facebook.android.friendsmash.integration.GraphAPICallback; +import com.facebook.login.widget.ProfilePictureView; import org.json.JSONArray; import org.json.JSONObject; @@ -50,58 +52,40 @@ import java.util.Comparator; import java.util.Iterator; -/** - * 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); @@ -116,117 +100,83 @@ private void closeAndShowError(String error) { @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 () { - String fbAppID = application.getFBAppID(); - final Session session = Session.getActiveSession(); - - Request scoresGraphPathRequest = Request.newGraphPathRequest(session, - fbAppID + "/scores" , - new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(TAG, error.toString()); - // TODO: Show an error or handle it better. - //((ScoreboardActivity)getActivity()).handleError(error, false); - } else if (session == Session.getActiveSession()) { - if (response != null) { - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - ArrayList scoreboardEntriesList = new ArrayList(); - - for (int i=0; i< dataArray.length(); i++) { - JSONObject oneData = dataArray.optJSONObject(i); - int score = oneData.optInt("score"); - - JSONObject userObj = oneData.optJSONObject("user"); - String userID = userObj.optString("id"); - String userName = userObj.optString("name"); - - scoreboardEntriesList.add(new ScoreboardEntry(userID, userName, score)); - } - - Comparator 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(); - } - }); - } - } - } - }); - Request.executeBatchAsync(scoresGraphPathRequest); + GraphAPICall scoresCall = GraphAPICall.callAppScores(application.getFBAppID(), new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + JSONArray dataArray = GraphAPICall.getDataFromResponse(response); + + ArrayList scoreboardEntriesList = new ArrayList(); + + for (int i = 0; i < dataArray.length(); i++) { + JSONObject oneData = dataArray.optJSONObject(i); + int score = oneData.optInt("score"); + + JSONObject userObj = oneData.optJSONObject("user"); + String userID = userObj.optString("id"); + String userName = userObj.optString("name"); + + scoreboardEntriesList.add(new ScoreboardEntry(userID, userName, score)); + } + + Comparator 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(); + } + }); + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + } + }); + scoresCall.executeAsync(); } 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 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); @@ -234,24 +184,19 @@ private void populateScoreboard() { int backgroundImageViewMarginSide = getResources().getDimensionPixelSize(R.dimen.scoreboard_background_imageview_margin_side); if (index % 2 != 0) { - // Odd entry backgroundImageViewLayoutParams.setMargins(backgroundImageViewMarginSide, backgroundImageViewMarginTop, 0, 0); backgroundImageViewLayoutParams.gravity = Gravity.LEFT; } else { - // Even entry backgroundImageViewLayoutParams.setMargins(0, backgroundImageViewMarginTop, backgroundImageViewMarginSide, 0); 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; @@ -267,22 +212,16 @@ private void populateScoreboard() { 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); @@ -304,35 +243,26 @@ private void populateScoreboard() { } 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 @@ -353,8 +283,7 @@ public boolean onTouch(View v, MotionEvent event) { } }); - - // Increment the index before looping back + index++; } } diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/SingleFragmentActivity.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/SingleFragmentActivity.java old mode 100755 new mode 100644 similarity index 50% rename from friendsmash_incomplete/src/com/facebook/android/friendsmash/SingleFragmentActivity.java rename to friend-smash/src/main/java/com/facebook/android/friendsmash/SingleFragmentActivity.java index 8d933da..4a9aa8d --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/SingleFragmentActivity.java +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/SingleFragmentActivity.java @@ -1,22 +1,25 @@ /** - * Copyright 2012 Facebook + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * - * 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 + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. * - * http://www.apache.org/licenses/LICENSE-2.0 + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. * - * 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. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.facebook.android.friendsmash; -import com.facebook.AppEventsLogger; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; @@ -51,13 +54,7 @@ public void onCreate(Bundle savedInstanceState) { @Override protected void onResume() { super.onResume(); - - // Hide the notification bar getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - - // Measure mobile app install ads - // Ref: https://developers.facebook.com/docs/tutorials/mobile-app-ads/ - AppEventsLogger.activateApp(this, ((FriendSmashApplication)getApplication()).getString(R.string.app_id)); } } diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/UserImageView.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/UserImageView.java old mode 100755 new mode 100644 similarity index 78% rename from friendsmash_incomplete/src/com/facebook/android/friendsmash/UserImageView.java rename to friend-smash/src/main/java/com/facebook/android/friendsmash/UserImageView.java index 2b726c0..740098b --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/UserImageView.java +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/UserImageView.java @@ -1,23 +1,25 @@ /** - * Copyright 2012 Facebook + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * - * 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 + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. * - * http://www.apache.org/licenses/LICENSE-2.0 + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. * - * 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. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package com.facebook.android.friendsmash; -import java.util.Random; - import android.animation.Animator; import android.animation.Animator.AnimatorListener; import android.animation.AnimatorSet; @@ -30,6 +32,8 @@ import android.view.animation.LinearInterpolator; import android.widget.ImageView; +import java.util.Random; + /** * ImageViews of the users that the playing user has to smash. These can contain images of one * of the user's friends (in the social version only) or images of celebrities @@ -44,13 +48,11 @@ public class UserImageView extends ImageView { private AnimatorSet upMovementAnimatorSet; private AnimatorSet downMovementAnimatorSet; private ValueAnimator rotationAnimation; - - // Default Constructor - not used + public UserImageView(Context context, AttributeSet attrs) { super(context, attrs); } - - // Constructor used by GameFragment to pass in an instance of itself + public UserImageView(Context context, boolean shouldSmash, boolean isCoin) { super(context); @@ -60,72 +62,53 @@ public UserImageView(Context context, boolean shouldSmash, boolean isCoin) { upMovementAnimatorSet = new AnimatorSet(); downMovementAnimatorSet = new AnimatorSet(); } - - // Stop movement (not rotation) animations + void stopMovementAnimations() { upMovementAnimatorSet.cancel(); downMovementAnimatorSet.cancel(); } - - // Scale image up + void scaleUp(AnimatorListener animatorListener) { - // Create the scaling animations ValueAnimator scaleAnimationX = ObjectAnimator.ofFloat(this, "scaleX", 25f); ValueAnimator scaleAnimationY = ObjectAnimator.ofFloat(this, "scaleY", 25f); scaleAnimationX.setDuration(1000); scaleAnimationY.setDuration(1000); scaleAnimationX.setInterpolator(new LinearInterpolator()); scaleAnimationY.setInterpolator(new LinearInterpolator()); - - // Start the animations together + AnimatorSet animatorSet = new AnimatorSet(); animatorSet.playTogether(scaleAnimationX, scaleAnimationY); animatorSet.start(); - - // Set the listener on this animation + animatorSet.addListener(animatorListener); } - - // Stop rotation animation + void stopRotationAnimation() { rotationAnimation.cancel(); } - - // Start firing this UserImageView across the GameFragment view + void setupAndStartAnimations(int iconWidth, int iconHeight, int screenWidth, int screenHeight, AnimatorListener downAnimatorListener) { - // Animations with Property Animator - Android 3.0 onwards only ... - - // Instantiate Random Generator - Random randomGenerator = new Random(System.currentTimeMillis()); - - // Declare Animators + Random randomGenerator = new Random(System.currentTimeMillis()); + ValueAnimator upAnimationX; ValueAnimator upAnimationY; final ValueAnimator downAnimationX; final ValueAnimator downAnimationY; - - // Calculate coordinates ... - - // X Range: + int leftXExtreme = -iconWidth*3; int rightXExtreme = screenWidth+(iconWidth*2); - - // Y Range: + int bottomY = screenHeight+iconHeight; int topYLowerExtreme = (int) (screenHeight*0.3); int topYUpperExtreme = 0; - // Generate random centerX value int centerX = (screenWidth-iconWidth)/2 + iconWidth - randomGenerator.nextInt(iconWidth*2); - // Generate random leftX and rightX values int leftX = randomGenerator.nextInt(centerX-leftXExtreme) + leftXExtreme; int rightX = rightXExtreme - randomGenerator.nextInt(rightXExtreme-centerX); - // Generate random topY value int topY = randomGenerator.nextInt(topYLowerExtreme-topYUpperExtreme) + topYUpperExtreme; - // Generate random time taken to rotate fully (in ms) int rotationTime = randomGenerator.nextInt(2500) + 500; if (randomGenerator.nextInt(2) == 0) { @@ -152,7 +135,6 @@ void setupAndStartAnimations(int iconWidth, int iconHeight, int screenWidth, int upMovementAnimatorSet.playTogether(upAnimationX, upAnimationY); - // Rotation animations if (randomGenerator.nextInt(2) == 0) { rotationAnimation = ObjectAnimator.ofFloat(this, "rotation", 0f, 360f); } @@ -163,7 +145,6 @@ void setupAndStartAnimations(int iconWidth, int iconHeight, int screenWidth, int rotationAnimation.setDuration(rotationTime); rotationAnimation.setInterpolator(new LinearInterpolator()); - // Create a callback after the up animation has ended to start the down animation upAnimationY.addListener(new AnimatorListener() { @Override public void onAnimationCancel(Animator animation) { @@ -184,17 +165,12 @@ public void onAnimationStart(Animator animation) { } }); - // Create a callback after the animation has ended downAnimationY.addListener(downAnimatorListener); - // Play the animations upMovementAnimatorSet.start(); rotationAnimation.start(); } - - /* Standard Getters & Setters */ - public boolean shouldSmash() { return shouldSmash; } @@ -202,7 +178,7 @@ public boolean shouldSmash() { public void setShouldSmash(boolean shouldSmash) { this.shouldSmash = shouldSmash; } - + public boolean isCoin() { return isCoin; } diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FacebookLogin.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FacebookLogin.java new file mode 100644 index 0000000..bb2ac23 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FacebookLogin.java @@ -0,0 +1,189 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +import android.util.Log; + +import com.facebook.AccessToken; +import com.facebook.AccessTokenTracker; +import com.facebook.CallbackManager; +import com.facebook.FacebookCallback; +import com.facebook.FacebookException; +import com.facebook.android.friendsmash.FriendSmashApplication; +import com.facebook.android.friendsmash.HomeActivity; +import com.facebook.login.LoginManager; +import com.facebook.login.LoginResult; +import com.facebook.login.widget.LoginButton; + +import java.util.ArrayList; +import java.util.Collection; + +/** + * This class handles Facebook Login using LoginButton. + * For more information on Facebook Login for Android see + * https://developers.facebook.com/docs/facebook-login/android/ + */ +public class FacebookLogin { + + /** + * HomeActivity is the activity handling Facebook Login in the app. Needed here to send + * the signal back when user successfully logged in. + */ + private HomeActivity activity; + + /** + * CallbackManager is a Facebook SDK class managing the callbacks into the FacebookSdk from + * an Activity's or Fragment's onActivityResult() method. + * For more information see + * https://developers.facebook.com/docs/reference/android/current/interface/CallbackManager/ + */ + private CallbackManager callbackManager; + + /** + * CallbackManager is exposed here to so that onActivityResult() can be called from Activities + * and Fragments when required. This is necessary so that the login result is passed to the + * LoginManager + */ + public CallbackManager getCallbackManager() { return callbackManager; } + + /** + * AccessTokenTracker allows for tracking whenever the access token changes - whenever user logs + * in, logs out etc abstract method onCurrentAccessTokenChanged is called. + */ + private AccessTokenTracker tokenTracker; + + public FacebookLogin(HomeActivity activity) { + super(); + this.activity = activity; + } + + /** + * Needs to be called after Facebook SDK has been initialized with a FacebookSdk.sdkInitialize() + * It overrides a method in AccessTokenTracker to get notified whenever AccessToken is + * changed, which typically means user logged in, logged out or granted new permissions. + * For more information see + * https://developers.facebook.com/docs/reference/android/current/class/AccessTokenTracker/ + * https://developers.facebook.com/docs/reference/android/current/interface/FacebookCallback/ + */ + public void init() { + callbackManager = CallbackManager.Factory.create(); + tokenTracker = new AccessTokenTracker() { + @Override + protected void onCurrentAccessTokenChanged(AccessToken oldAccessToken, + AccessToken currentAccessToken) { + activity.onLoginStateChanged(oldAccessToken, currentAccessToken); + } + }; + } + + /** + * Called when HomeActivity resumes. Ensures tokenTracker tracks token changes + */ + public void activate() { + tokenTracker.startTracking(); + } + + /** + * Called when HomeActivity is paused. Ensures tokenTracker stops tracking + */ + public void deactivate() { + tokenTracker.stopTracking(); + } + + /** + * LoginButton can be used to trigger the login dialog asking for any permission so it is + * important to specify which permissions you want to request from a user. In Friend Smash case + * only user_friends is required to enable access to friends, so that the game can show friends' + * profile picture to make the experience more personal and engaging. + * For more info on permissions see + * https://developers.facebook.com/docs/facebook-login/android/permissions + * This method is called from onCreateView() of a Fragment displayed when user is logged out of + * Facebook. + */ + public void setUpLoginButton(LoginButton button) { + button.setReadPermissions(FacebookLoginPermission.USER_FRIENDS.toString()); + button.registerCallback(callbackManager, new FacebookCallback() { + @Override + public void onSuccess(LoginResult loginResult) { + Log.w("DEBUG", "onLoginButtonSuccess"); + activity.onLoginStateChanged(null, AccessToken.getCurrentAccessToken()); + } + + @Override + public void onCancel() { + Log.w("DEBUG", "on Login Cancel"); + } + + @Override + public void onError(FacebookException error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + } + }); + } + + /** + * Uses LoginManager to request additional permissions when needed, e.g. when user has finished + * the game and is trying to post score the game would call this method to request publish_actions + * See https://developers.facebook.com/docs/facebook-login/android/permissions for more info on + * Login permissions + */ + public void requestPermission (FacebookLoginPermission permission) { + if (!isPermissionGranted(permission)) { + Collection permissions = new ArrayList(1); + permissions.add(permission.toString()); + if (permission.isRead()) { + LoginManager.getInstance().logInWithReadPermissions(activity, permissions); + } else { + LoginManager.getInstance().logInWithPublishPermissions(activity, permissions); + } + } + } + + /** + * Helper function checking if user is logged in and access token hasn't expired. + */ + public static boolean isAccessTokenValid() { + return testAccessTokenValid(AccessToken.getCurrentAccessToken()); + } + /** + * Helper function checking if user has granted particular permission to the app + * For more info on permissions see + * https://developers.facebook.com/docs/facebook-login/android/permissions + */ + public static boolean isPermissionGranted(FacebookLoginPermission permission) { + return testTokenHasPermission(AccessToken.getCurrentAccessToken(), permission); + } + + /** + * Helper function checking if the given access token is valid + */ + public static boolean testAccessTokenValid(AccessToken token) { + return token != null && !token.isExpired(); + } + + /** + * Helper function checking if the given access token includes specified login permission + */ + public static boolean testTokenHasPermission(AccessToken token, FacebookLoginPermission permission) { + return testAccessTokenValid(token) && token.getPermissions().contains(permission.toString()); + } + +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FacebookLoginPermission.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FacebookLoginPermission.java new file mode 100644 index 0000000..18965db --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FacebookLoginPermission.java @@ -0,0 +1,57 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +/** + * Enum listing Login permissions used in Friend Smash! + * For full list of permissions see https://developers.facebook.com/docs/facebook-login/permissions/ + */ +public enum FacebookLoginPermission { + + USER_FRIENDS("user_friends", true), + PUBLISH_ACTIONS("publish_actions", false); + + private String permisison; + private boolean isRead; + + FacebookLoginPermission (String permission, boolean isRead) { + this.permisison = permission; + this.isRead = isRead; + } + + /** + * Checks if the permission is a read permission or write permission. In general read permissions + * Allow apps to read information about the user who grants them, write permissions allow apps + * to change user information on their behalf, for example publish_actions permission allows + * app to post on behalf of the user. It's needed because in some scenarios SDK provides + * different methods for working with read and write permissions. + */ + public boolean isRead() {return isRead;} + + /** + * String representation of the permission, as defined in + * https://developers.facebook.com/docs/facebook-login/permissions/ + */ + @Override + public String toString() { + return permisison; + } +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FriendSmashCustomAppEvent.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FriendSmashCustomAppEvent.java new file mode 100644 index 0000000..b0f8992 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FriendSmashCustomAppEvent.java @@ -0,0 +1,30 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +/** + * This class holds constants with the custom App Event name and its parameter that are logged in + * the game. For more details on App Events see: https://developers.facebook.com/docs/app-events + */ +public class FriendSmashCustomAppEvent { + public static String EVENT_NAME_GAME_PLAYED = "game_played"; + public static String EVENT_PARAM_SCORE = "score"; +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FriendSmashEventsLogger.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FriendSmashEventsLogger.java new file mode 100644 index 0000000..7facff7 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/FriendSmashEventsLogger.java @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +import android.content.Context; +import android.os.Bundle; + +import com.facebook.appevents.AppEventsLogger; + +/** + * Class responsible for logging AppEvents in Friend Smash! + */ +public class FriendSmashEventsLogger { + private AppEventsLogger logger; + + /** + * Context is needed to create an instance of AppEventsLogger. + * See https://developers.facebook.com/docs/reference/android/current/class/AppEventsLogger/ + */ + public FriendSmashEventsLogger(Context context) { + logger = AppEventsLogger.newLogger(context); + } + + /** + * Logs a custom App Event when player has completed the game with given score. + * To understand how to best use App Events see + * https://developers.facebook.com/docs/app-events/best-practices + */ + public void logGamePlayedEvent(int score) { + Bundle params = new Bundle(); + params.putInt(FriendSmashCustomAppEvent.EVENT_PARAM_SCORE, score); + logger.logEvent(FriendSmashCustomAppEvent.EVENT_NAME_GAME_PLAYED, params); + } +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GameRequest.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GameRequest.java new file mode 100644 index 0000000..0da4023 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GameRequest.java @@ -0,0 +1,175 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +import android.util.Log; + +import com.facebook.FacebookCallback; +import com.facebook.FacebookException; +import com.facebook.FacebookRequestError; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.FriendSmashApplication; +import com.facebook.android.friendsmash.HomeActivity; +import com.facebook.share.model.GameRequestContent; +import com.facebook.share.widget.GameRequestDialog; + +import org.json.JSONObject; + +import java.util.List; + +/** + * Class dealing with Game Requests: launching the Request Dialog, retrieving request data and + * deleting consumed requests. It implements FacebookCallback + * to be notified when the request dialog was closed. + * For more information about GameRequests see https://developers.facebook.com/docs/games/requests/ + */ +public class GameRequest implements FacebookCallback { + + /** + * This is the Request Dialog used to send requests. See + *https://developers.facebook.com/docs/reference/android/current/class/GameRequestDialog/ + */ + private GameRequestDialog dialog; + + /** + * Creates the dialog and register itself as the callback handler. HomeActivity is passed here + * as the dialog needs to be aware of the activity hosting it and the CallbackManager is needed + * to register the callback. + */ + public GameRequest(HomeActivity activity) { + dialog = new GameRequestDialog(activity); + dialog.registerCallback(activity.getFacebookLogin().getCallbackManager(), this); + } + + /** + * Shows the reqeust dialog with given title and message. The dialog will be populated with + * friends who are not currently playing the game and gives the player an opportunity + * to invite their friends to play. + */ + public void showDialogForInvites (String title, String message) { + GameRequestContent content = new GameRequestContent.Builder(). + setTitle(title). + setMessage(message). + setFilters(GameRequestContent.Filters.APP_NON_USERS). + build(); + dialog.show(content); + } + + /** + * Shows the request dialog with given title and message. The dialog will be populated with + * friends who are currently playing the game and gives the player an opportunity to challenge + * and re-engage the existing players + */ + public void showDialogForRequests (String title, String message) { + GameRequestContent content = new GameRequestContent.Builder(). + setTitle(title). + setMessage(message). + setFilters(GameRequestContent.Filters.APP_USERS). + build(); + dialog.show(content); + } + + /** + * Shows the request dialog with given title and message. The dialog will be populated with + * specified recipients giving the player an opportunity to challenge a specific friend + */ + public void showDialogForDirectedRequests (String title, String message, List recipients) { + GameRequestContent content = new GameRequestContent.Builder(). + setTitle(title). + setMessage(message). + setRecipients(recipients).build(); + dialog.show(content); + } + + /** + * Deletes the specified request. Once player has consumed a request (e.g. accepted a challenge) + * it should be deleted to remove it from Facebook channels. + */ + public static void deleteRequest (String requestId) { + GraphAPICall deleteRequestRequest = GraphAPICall.deleteRequest( + requestId, + new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + Log.i(FriendSmashApplication.TAG, "Consumed Request deleted"); + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, "Deleting consumed Request failed: " + error.getErrorMessage()); + } + }); + deleteRequestRequest.executeAsync(); + } + + /** + * Retrieves the user data from the specified request. + * In Friend Smash! when person accepts a challenge request they should enter the game directly + * to the game session set up to smash the friend who sent the request. In order to do this the + * game needs to know user id and the name of the sender. + * What's happening in the code below is: + * 1. Graph API call to retrieve request details. This call returns user id of the sender. + * See https://developers.facebook.com/docs/graph-api/reference/request + * 2. Graph API call to retrieve the first_name of the sender. Result of this call is passed + * back to the GraphAPICallback passed to this method as a parameter allowing the caller of + * this method to use the retrieved user data. + * See https://developers.facebook.com/docs/graph-api/reference/user + */ + public static void getUserDataFromRequest (String requestId, final GraphAPICallback callback) { + GraphAPICall requestCall = GraphAPICall.callRequest(requestId, new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + if (response != null) { + JSONObject fromObject = response.getJSONObject().optJSONObject("from"); + String userId = fromObject.optString("id"); + GraphAPICall userCall = GraphAPICall.callUser(userId, "first_name", callback); + userCall.executeAsync(); + } + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + } + }); + requestCall.executeAsync(); + } + + /** + * The 3 methods below are the implementation of FacebookCallback and + * get called when user successfully sent requests, canceled the flow or encountered an error. + */ + + @Override + public void onSuccess(GameRequestDialog.Result result) { + Log.i(FriendSmashApplication.TAG, "Game Request sent successfully, request id=" + result.getRequestId()); + } + + @Override + public void onCancel() { + Log.i(FriendSmashApplication.TAG, "Sending Game Request has been cancelled"); + } + + @Override + public void onError(FacebookException error) { + Log.e(FriendSmashApplication.TAG, error.toString()); + } +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GraphAPICall.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GraphAPICall.java new file mode 100644 index 0000000..5566bc8 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GraphAPICall.java @@ -0,0 +1,401 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +import android.os.Bundle; +import android.util.Log; + +import com.facebook.AccessToken; +import com.facebook.FacebookRequestError; +import com.facebook.GraphRequest; +import com.facebook.GraphRequestBatch; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.FriendSmashApplication; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +/** + * This class is handling all GraphAPI calls made in Friend Smash! + * Simply put it wraps Facebook SDK's GraphRequest class providing convenience methods to make calls + * and handle results through GraphApiCallback interface. + * See https://developers.facebook.com/docs/graph-api for overview of Graph API and + * https://developers.facebook.com/docs/android/graph for Android specific details. + */ +public class GraphAPICall { + + /** + * When making Graph API calls different parameters can be specified. fields is a common + * parameter used to specify which of the fields should be included in the response, as + * by default, not all the fields in a node or edge are returned when you make a query. + * This is really useful for making your API calls more efficient and fast. + */ + private static final String PARAM_FIELDS = "fields"; + + /** + * Facebook SDK's class for handling Graph API calls + * See https://developers.facebook.com/docs/reference/android/current/class/GraphRequest/ + */ + private GraphRequest graphRequest; + + /** + * Facebook SDK's class encapsulating the response of a Graph API call + * See https://developers.facebook.com/docs/reference/android/current/class/GraphResponse/ + */ + private GraphResponse graphResponse; + + /** + * Friend Smash! specific interface making it easier to handle Graph API responses + */ + private GraphAPICallback graphAPICallback; + + /** + * Private constructor to enforce usage of static convenience methods creatic a specific call + */ + private GraphAPICall(String path, GraphAPICallback callback) { + setUp(callback); + createPathRequest(path); + } + + /** + * Same as above + */ + private GraphAPICall(GraphAPICallback callback) { + setUp(callback); + } + + /** + * Executes the call asynchronously + */ + public void executeAsync() { + graphRequest.executeAsync(); + } + + /** + * Adds a parameter to the request. Parameters can be used for many different purposes, such + * as specifying fields to be included in the response, specifying number of results to be + * included in the response and many others. + * See https://developers.facebook.com/docs/graph-api/using-graph-api/ + */ + public void addParam (String param, String value) { + Bundle params = graphRequest.getParameters(); + params.putString(param, value); + graphRequest.setParameters(params); + } + + /** + * Registers callback and checks if valid access token is available, as it is + * required to make a Graph API call. + */ + private void setUp (GraphAPICallback callback) { + graphAPICallback = callback; + if (!FacebookLogin.isAccessTokenValid()) { + Log.e(FriendSmashApplication.TAG, "Cannot call Graph API without a valid AccessToken"); + } + } + + /** + * Creates a GraphRequest with the specified path + */ + private void createPathRequest (final String path) { + AccessToken token = AccessToken.getCurrentAccessToken(); + graphRequest = GraphRequest.newGraphPathRequest(token, + path, new GraphRequest.Callback() { + @Override + public void onCompleted(GraphResponse response) { + handleResponse(response); + } + }); + } + + /** + * Creates a GraphRequest for /me Graph API call + */ + private void createMeRequest () { + AccessToken token = AccessToken.getCurrentAccessToken(); + graphRequest = GraphRequest.newMeRequest(token, + new GraphRequest.GraphJSONObjectCallback() { + @Override + public void onCompleted(JSONObject jsonObject, GraphResponse graphResponse) { + handleResponse(graphResponse); + } + }); + } + + /** + * Creates a GraphRequest for /me/friends Graph API call + */ + private void createMyFriendsRequest () { + AccessToken token = AccessToken.getCurrentAccessToken(); + graphRequest = GraphRequest.newMyFriendsRequest(token, + new GraphRequest.GraphJSONArrayCallback() { + @Override + public void onCompleted(JSONArray users, GraphResponse response) { + handleResponse(response); + } + }); + } + + /** + * Creates a GraphRequest for a Graph API call to delete an object with given objectId. + * See https://developers.facebook.com/docs/graph-api/using-graph-api/#deleting to understand + * how deleting Graph API objects works. + */ + private void createDeleteObjectRequest(String objectId) { + AccessToken token = AccessToken.getCurrentAccessToken(); + graphRequest = GraphRequest.newDeleteObjectRequest(token, objectId, new GraphRequest.Callback() { + @Override + public void onCompleted(GraphResponse response) { + handleResponse(response); + } + }); + } + + /** + * Creates a GraphRequest to publish me/scores object with specified score parameter + * See https://developers.facebook.com/docs/graph-api/using-graph-api/#publishing to undersntad + * how publishing Graph API objects works. + */ + private void createPublishScoreRequest(int score) { + AccessToken token = AccessToken.getCurrentAccessToken(); + JSONObject object = new JSONObject(); + try { + object.put("score", score); + } catch (JSONException e) { + Log.w(FriendSmashApplication.TAG, "Error publishing score to Facebook"); + } + graphRequest = GraphRequest.newPostRequest(token, "me/scores", object, new GraphRequest.Callback() { + @Override + public void onCompleted(GraphResponse response) { + handleResponse(response); + } + }); + } + + /** + * Handles GraphResponse. Checks if there's next page available and makes another request + * if necessary. By default Graph API results are paged and return up to a specific number + * of objects. This number is called page size. For example if there's 40 objects to be returned + * and the page size is 25 the first call will return 25 objects. Calling next page will return + * the remaining 15 objects. + * You can specify page size using 'limit' parameter when making call. If page size is not + * specified it defaults to 25. + * See https://developers.facebook.com/docs/graph-api/using-graph-api/#paging for more details + * on paging. + */ + private void handleResponse (GraphResponse response) { + FacebookRequestError error = response.getError(); + if (error != null) { + Log.e(FriendSmashApplication.TAG, error.toString()); + graphAPICallback.handleError(error); + } else if (response != null) { + addDataToResponse(response); + if (hasNextPage(response)) { + callNextPage(response); + } else { + graphAPICallback.handleResponse(graphResponse); + } + } + } + + /** + * Checks if GraphResponse has the next page. + * See https://developers.facebook.com/docs/graph-api/using-graph-api/#paging for more details + * on paging. + */ + private boolean hasNextPage(GraphResponse response) { + return response.getRequestForPagedResults(GraphResponse.PagingDirection.NEXT) != null; + } + + /** + * Calls the next page for a given GraphResponse. + * See https://developers.facebook.com/docs/graph-api/using-graph-api/#paging for more details + * on paging. + */ + private void callNextPage (GraphResponse response) { + graphRequest = response.getRequestForPagedResults(GraphResponse.PagingDirection.NEXT); + if (graphRequest != null) { + graphRequest.setCallback(new GraphRequest.Callback() { + @Override + public void onCompleted(GraphResponse graphResponse) { + handleResponse(graphResponse); + } + }); + graphRequest.executeAsync(); + } + } + + /** + * Adds data from specified GraphResponse to stored graphResponse variable. This is used to + * combine the data from multiple pages into single GraphResponse object. + * See https://developers.facebook.com/docs/graph-api/using-graph-api/#paging for more details + * on paging. + */ + private void addDataToResponse(GraphResponse response) { + if (graphResponse == null) { + graphResponse = response; + } else { + JSONArray newData = response.getJSONObject().optJSONArray("data"); + JSONArray existingData = graphResponse.getJSONObject().optJSONArray("data"); + for (int i = 0; i < newData.length(); i++) { + existingData.put(newData.opt(i)); + } + } + } + + /** + * Creates GraphAPICall wrapper for GET /me call with specified fields. + * Response is passed to the specified GraphAPICallback. + * /me call returns the information about the current user + */ + public static GraphAPICall callMe (String fields, GraphAPICallback callback) { + GraphAPICall call = new GraphAPICall(callback); + call.createMeRequest(); + call.addParam(PARAM_FIELDS, fields); + return call; + } + + /** + * Creates GraphAPICall wrapper for GET /{user-Id} call with specified fields. + * Response is passed to the specified GraphAPICallback. + * /{user-id} returns the information about specific user + */ + public static GraphAPICall callUser (String userId, String fields, GraphAPICallback callback) { + GraphAPICall call = new GraphAPICall(userId, callback); + call.addParam(PARAM_FIELDS, fields); + return call; + } + + /** + * Creates GraphAPICall wrapper for GET /me/friends call with specified fields. + * Response is passed to the specified GraphAPICallback. + * Note user_friends permission is required to make this call + * /me/friends returns the information about current user's friends who are also playing the game + */ + public static GraphAPICall callMeFriends(String fields, GraphAPICallback callback) { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + GraphAPICall call = new GraphAPICall(callback); + call.createMyFriendsRequest(); + call.addParam(PARAM_FIELDS, fields); + return call; + } else { + Log.w(FriendSmashApplication.TAG, "Cannot call me/friends without user_friends permission"); + return null; + } + } + + /** + * Creates GraphAPICall wrapper for GET /me/scores call. + * Response is passed to the specified GraphAPICallback. + * /me/scores returns the current user's score in the app. + * See https://developers.facebook.com/docs/games/scores for details about Scores API + */ + public static GraphAPICall callMeScores(GraphAPICallback callback) { + GraphAPICall call = new GraphAPICall("me/scores", callback); + call.addParam(PARAM_FIELDS, "score"); + return call; + } + + /** + * Creates GraphAPICall wrapper for GET /{app-id}/scores call. + * Response is passed to the specified GraphAPICallback. + * Note user_friends permission is required to make this call + * /{app-id}/scores returns the current user friends' scores in the app. + * See https://developers.facebook.com/docs/games/scores for details about Scores API + */ + public static GraphAPICall callAppScores(String appId, GraphAPICallback callback) { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.USER_FRIENDS)) { + GraphAPICall call = new GraphAPICall(appId + "/scores", callback); + call.addParam("fields", "user,score"); + return call; + } else { + Log.w(FriendSmashApplication.TAG, "Cannot call app-id/scores without user_friends permisison"); + return null; + } + } + + /** + * Creates GraphAPICall wrapper for POST /me/scores call. + * Response is passed to the specified GraphAPICallback. + * Note publish_actions permission is required to make this call + * POST /me/scores publishes current user's score. Used in Friend Smash to track the top score. + * See https://developers.facebook.com/docs/games/scores for details about Scores API + */ + public static GraphAPICall publishScore (int score, GraphAPICallback callback) { + if (FacebookLogin.isPermissionGranted(FacebookLoginPermission.PUBLISH_ACTIONS)) { + GraphAPICall call = new GraphAPICall(callback); + call.createPublishScoreRequest(score); + return call; + } else { + Log.w(FriendSmashApplication.TAG, "Cannot publish scores without publish_actions permission"); + return null; + } + } + + /** + * Creates GraphAPICall wrapper for GET /{request-id} call. + * Response is passed to the specified GraphAPICallback. + * /{request-id} returns the information about specific request + */ + public static GraphAPICall callRequest(String requestId, GraphAPICallback callback) { + GraphAPICall call = new GraphAPICall(requestId, callback); + return call; + } + + /** + * Creates GraphAPICall wrapper for DELETE /{request-Id} call with specified fields. + * Response is passed to the specified GraphAPICallback. + * DELETE /{request-id} deletes specified request. + */ + public static GraphAPICall deleteRequest(String requestId, GraphAPICallback callback) { + GraphAPICall call = new GraphAPICall(callback); + call.createDeleteObjectRequest(requestId); + return call; + } + + /** + * Helper method to create a batch of multiple GraphAPICall objects. + * Batching allows to pass instructions for several operations in a single HTTP request. + * For more information on batching see + * https://developers.facebook.com/docs/graph-api/making-multiple-requests and + * https://developers.facebook.com/docs/reference/android/current/class/GraphRequestBatch/ + * for Android implementation. + */ + public static GraphRequestBatch createRequestBatch (GraphAPICall... requests) { + GraphRequestBatch batch = new GraphRequestBatch(); + for (GraphAPICall request : requests) { + if (request != null) { + batch.add(request.graphRequest); + } + } + return batch; + } + + /** + * Helper method to extract JSONArray with data returned in GraphResponse. + * Useful for example for extracting friends data returned in GraphResponse for /me/friends call + */ + public static JSONArray getDataFromResponse(GraphResponse response) { + JSONObject graphObject = response.getJSONObject(); + return graphObject.optJSONArray("data"); + } +} \ No newline at end of file diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GraphAPICallback.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GraphAPICallback.java new file mode 100644 index 0000000..6552cb0 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/GraphAPICallback.java @@ -0,0 +1,40 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +import com.facebook.FacebookRequestError; +import com.facebook.GraphResponse; + +/** + * Callback for Graph API calls made using GraphAPICall object to easily handle + * successful responses and errors. + */ +public interface GraphAPICallback { + /** + * Called when GraphAPICall returned successfully. + */ + void handleResponse (GraphResponse response); + + /** + * Called when GraphAPICall returned with an error. + */ + void handleError (FacebookRequestError error); +} diff --git a/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/Sharing.java b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/Sharing.java new file mode 100644 index 0000000..5aee804 --- /dev/null +++ b/friend-smash/src/main/java/com/facebook/android/friendsmash/integration/Sharing.java @@ -0,0 +1,84 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, + * copy, modify, and distribute this software in source code or binary form for use + * in connection with the web services and APIs provided by Facebook. + * + * As with any software that integrates with the Facebook platform, your use of + * this software is subject to the Facebook Developer Principles and Policies + * [http://developers.facebook.com/policy/]. This copyright notice shall be + * included in all copies or substantial portions of the software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +package com.facebook.android.friendsmash.integration; + +import android.app.Activity; +import android.net.Uri; +import android.util.Log; + +import com.facebook.FacebookRequestError; +import com.facebook.GraphResponse; +import com.facebook.android.friendsmash.FriendSmashApplication; +import com.facebook.share.model.ShareLinkContent; +import com.facebook.share.widget.ShareDialog; + +/** + * This class handles Facebook Sharing. In Android version of Friend Smash sharing is used + * for two purposes: publishing scores using Scores API and sharing completed game using + * Share Dialog. + * See https://developers.facebook.com/docs/games/scores and + * https://developers.facebook.com/docs/games/sharing for more details + */ +public class Sharing { + + /** + * Publishes the score if it is higher than the current topScore. + * This allows Friend Smash! to implement friends leader board keeping track of the top scores + * achieved by the player and their friends. + * See https://developers.facebook.com/docs/games/scores + */ + public static void publishScore(int score, int topScore) { + if (score > topScore) { + GraphAPICall publishScoreCall = GraphAPICall.publishScore(score, new GraphAPICallback() { + @Override + public void handleResponse(GraphResponse response) { + Log.i(FriendSmashApplication.TAG, "Score posted successfully to Facebook"); + } + + @Override + public void handleError(FacebookRequestError error) { + Log.e(FriendSmashApplication.TAG, "Posting Score to Facebook failed: " + error.getErrorMessage()); + } + }); + publishScoreCall.executeAsync(); + } + } + + /** + * Shares a story using ShareDialog. Story's name, description, picture and link can be specified. + * Activity hosting the dialog is also required to show the dialog. + * See https://developers.facebook.com/docs/reference/android/current/class/ShareDialog/ + */ + public static void shareViaDialog (Activity activity, String name, String description, + String picture, String link) { + if (ShareDialog.canShow(ShareLinkContent.class)) { + ShareDialog shareDialog = new ShareDialog(activity); + ShareLinkContent content = new ShareLinkContent.Builder() + .setContentUrl(Uri.parse(link)) + .setContentTitle(name) + .setContentDescription(description) + .setImageUrl(Uri.parse(picture)) + .build(); + + shareDialog.show(content); + } + } +} diff --git a/friendsmash_complete/res/drawable-hdpi/bomb.png b/friend-smash/src/main/res/drawable-hdpi/bomb.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/bomb.png rename to friend-smash/src/main/res/drawable-hdpi/bomb.png diff --git a/friendsmash_complete/res/drawable-hdpi/brag_button.png b/friend-smash/src/main/res/drawable-hdpi/brag_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/brag_button.png rename to friend-smash/src/main/res/drawable-hdpi/brag_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/challenge_button.png b/friend-smash/src/main/res/drawable-hdpi/challenge_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/challenge_button.png rename to friend-smash/src/main/res/drawable-hdpi/challenge_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/close_button.png b/friend-smash/src/main/res/drawable-hdpi/close_button.png similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/close_button.png rename to friend-smash/src/main/res/drawable-hdpi/close_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/coin.png b/friend-smash/src/main/res/drawable-hdpi/coin.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/coin.png rename to friend-smash/src/main/res/drawable-hdpi/coin.png diff --git a/friendsmash_complete/res/drawable-hdpi/frontscreen_background.png b/friend-smash/src/main/res/drawable-hdpi/frontscreen_background.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/frontscreen_background.png rename to friend-smash/src/main/res/drawable-hdpi/frontscreen_background.png diff --git a/friendsmash_complete/res/drawable-hdpi/frontscreen_background_land.png b/friend-smash/src/main/res/drawable-hdpi/frontscreen_background_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/frontscreen_background_land.png rename to friend-smash/src/main/res/drawable-hdpi/frontscreen_background_land.png diff --git a/friendsmash_complete/res/drawable-hdpi/heart_red.png b/friend-smash/src/main/res/drawable-hdpi/heart_red.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/heart_red.png rename to friend-smash/src/main/res/drawable-hdpi/heart_red.png diff --git a/friendsmash_complete/res/drawable-hdpi/ic_action_search.png b/friend-smash/src/main/res/drawable-hdpi/ic_action_search.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/ic_action_search.png rename to friend-smash/src/main/res/drawable-hdpi/ic_action_search.png diff --git a/friendsmash_complete/res/drawable-hdpi/ic_launcher.png b/friend-smash/src/main/res/drawable-hdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/ic_launcher.png rename to friend-smash/src/main/res/drawable-hdpi/ic_launcher.png diff --git a/friendsmash_complete/res/drawable-hdpi/leaderboard_button.png b/friend-smash/src/main/res/drawable-hdpi/leaderboard_button.png similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/leaderboard_button.png rename to friend-smash/src/main/res/drawable-hdpi/leaderboard_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/login_button.png b/friend-smash/src/main/res/drawable-hdpi/login_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/login_button.png rename to friend-smash/src/main/res/drawable-hdpi/login_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/logout_button.png b/friend-smash/src/main/res/drawable-hdpi/logout_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/logout_button.png rename to friend-smash/src/main/res/drawable-hdpi/logout_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_1.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_1.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_1.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_1.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_10.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_10.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_10.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_10.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_2.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_2.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_2.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_2.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_3.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_3.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_3.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_3.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_4.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_4.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_4.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_4.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_5.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_5.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_5.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_5.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_6.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_6.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_6.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_6.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_7.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_7.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_7.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_7.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_8.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_8.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_8.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_8.png diff --git a/friendsmash_complete/res/drawable-hdpi/nonfriend_9.png b/friend-smash/src/main/res/drawable-hdpi/nonfriend_9.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/nonfriend_9.png rename to friend-smash/src/main/res/drawable-hdpi/nonfriend_9.png diff --git a/friendsmash_complete/res/drawable-hdpi/playnow_button.png b/friend-smash/src/main/res/drawable-hdpi/playnow_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/playnow_button.png rename to friend-smash/src/main/res/drawable-hdpi/playnow_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/scores_button.png b/friend-smash/src/main/res/drawable-hdpi/scores_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/scores_button.png rename to friend-smash/src/main/res/drawable-hdpi/scores_button.png diff --git a/friendsmash_complete/res/drawable-hdpi/scores_stub_even.png b/friend-smash/src/main/res/drawable-hdpi/scores_stub_even.png similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/scores_stub_even.png rename to friend-smash/src/main/res/drawable-hdpi/scores_stub_even.png diff --git a/friendsmash_complete/res/drawable-hdpi/scores_stub_odd.png b/friend-smash/src/main/res/drawable-hdpi/scores_stub_odd.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/scores_stub_odd.png rename to friend-smash/src/main/res/drawable-hdpi/scores_stub_odd.png diff --git a/friendsmash_complete/res/drawable-hdpi/title_banner.png b/friend-smash/src/main/res/drawable-hdpi/title_banner.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/title_banner.png rename to friend-smash/src/main/res/drawable-hdpi/title_banner.png diff --git a/friendsmash_complete/res/drawable-hdpi/title_banner_land.png b/friend-smash/src/main/res/drawable-hdpi/title_banner_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/title_banner_land.png rename to friend-smash/src/main/res/drawable-hdpi/title_banner_land.png diff --git a/friendsmash_complete/res/drawable-hdpi/welcome_panel.png b/friend-smash/src/main/res/drawable-hdpi/welcome_panel.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/welcome_panel.png rename to friend-smash/src/main/res/drawable-hdpi/welcome_panel.png diff --git a/friendsmash_complete/res/drawable-hdpi/welcome_panel_blank.png b/friend-smash/src/main/res/drawable-hdpi/welcome_panel_blank.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-hdpi/welcome_panel_blank.png rename to friend-smash/src/main/res/drawable-hdpi/welcome_panel_blank.png diff --git a/friendsmash_complete/res/drawable-ldpi/brag_button.png b/friend-smash/src/main/res/drawable-ldpi/brag_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/brag_button.png rename to friend-smash/src/main/res/drawable-ldpi/brag_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/challenge_button.png b/friend-smash/src/main/res/drawable-ldpi/challenge_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/challenge_button.png rename to friend-smash/src/main/res/drawable-ldpi/challenge_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/close_button.png b/friend-smash/src/main/res/drawable-ldpi/close_button.png similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/close_button.png rename to friend-smash/src/main/res/drawable-ldpi/close_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/frontscreen_background.png b/friend-smash/src/main/res/drawable-ldpi/frontscreen_background.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/frontscreen_background.png rename to friend-smash/src/main/res/drawable-ldpi/frontscreen_background.png diff --git a/friendsmash_complete/res/drawable-ldpi/frontscreen_background_land.png b/friend-smash/src/main/res/drawable-ldpi/frontscreen_background_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/frontscreen_background_land.png rename to friend-smash/src/main/res/drawable-ldpi/frontscreen_background_land.png diff --git a/friendsmash_complete/res/drawable-ldpi/heart_red.png b/friend-smash/src/main/res/drawable-ldpi/heart_red.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/heart_red.png rename to friend-smash/src/main/res/drawable-ldpi/heart_red.png diff --git a/friendsmash_complete/res/drawable-ldpi/ic_launcher.png b/friend-smash/src/main/res/drawable-ldpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/ic_launcher.png rename to friend-smash/src/main/res/drawable-ldpi/ic_launcher.png diff --git a/friendsmash_complete/res/drawable-ldpi/leaderboard_button.png b/friend-smash/src/main/res/drawable-ldpi/leaderboard_button.png similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/leaderboard_button.png rename to friend-smash/src/main/res/drawable-ldpi/leaderboard_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/login_button.png b/friend-smash/src/main/res/drawable-ldpi/login_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/login_button.png rename to friend-smash/src/main/res/drawable-ldpi/login_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/logout_button.png b/friend-smash/src/main/res/drawable-ldpi/logout_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/logout_button.png rename to friend-smash/src/main/res/drawable-ldpi/logout_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_1.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_1.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_1.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_1.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_10.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_10.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_10.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_10.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_2.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_2.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_2.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_2.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_3.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_3.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_3.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_3.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_4.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_4.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_4.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_4.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_5.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_5.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_5.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_5.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_6.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_6.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_6.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_6.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_7.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_7.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_7.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_7.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_8.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_8.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_8.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_8.png diff --git a/friendsmash_complete/res/drawable-ldpi/nonfriend_9.png b/friend-smash/src/main/res/drawable-ldpi/nonfriend_9.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/nonfriend_9.png rename to friend-smash/src/main/res/drawable-ldpi/nonfriend_9.png diff --git a/friendsmash_complete/res/drawable-ldpi/playnow_button.png b/friend-smash/src/main/res/drawable-ldpi/playnow_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/playnow_button.png rename to friend-smash/src/main/res/drawable-ldpi/playnow_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/scores_button.png b/friend-smash/src/main/res/drawable-ldpi/scores_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/scores_button.png rename to friend-smash/src/main/res/drawable-ldpi/scores_button.png diff --git a/friendsmash_complete/res/drawable-ldpi/scores_stub_even.png b/friend-smash/src/main/res/drawable-ldpi/scores_stub_even.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/scores_stub_even.png rename to friend-smash/src/main/res/drawable-ldpi/scores_stub_even.png diff --git a/friendsmash_complete/res/drawable-ldpi/scores_stub_odd.png b/friend-smash/src/main/res/drawable-ldpi/scores_stub_odd.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/scores_stub_odd.png rename to friend-smash/src/main/res/drawable-ldpi/scores_stub_odd.png diff --git a/friendsmash_complete/res/drawable-ldpi/title_banner_land.png b/friend-smash/src/main/res/drawable-ldpi/title_banner_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/title_banner_land.png rename to friend-smash/src/main/res/drawable-ldpi/title_banner_land.png diff --git a/friendsmash_complete/res/drawable-ldpi/welcome_panel.png b/friend-smash/src/main/res/drawable-ldpi/welcome_panel.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/welcome_panel.png rename to friend-smash/src/main/res/drawable-ldpi/welcome_panel.png diff --git a/friendsmash_complete/res/drawable-ldpi/welcome_panel_blank.png b/friend-smash/src/main/res/drawable-ldpi/welcome_panel_blank.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-ldpi/welcome_panel_blank.png rename to friend-smash/src/main/res/drawable-ldpi/welcome_panel_blank.png diff --git a/friendsmash_complete/res/drawable-mdpi/brag_button.png b/friend-smash/src/main/res/drawable-mdpi/brag_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/brag_button.png rename to friend-smash/src/main/res/drawable-mdpi/brag_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/challenge_button.png b/friend-smash/src/main/res/drawable-mdpi/challenge_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/challenge_button.png rename to friend-smash/src/main/res/drawable-mdpi/challenge_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/close_button.png b/friend-smash/src/main/res/drawable-mdpi/close_button.png similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/close_button.png rename to friend-smash/src/main/res/drawable-mdpi/close_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/frontscreen_background.png b/friend-smash/src/main/res/drawable-mdpi/frontscreen_background.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/frontscreen_background.png rename to friend-smash/src/main/res/drawable-mdpi/frontscreen_background.png diff --git a/friendsmash_complete/res/drawable-mdpi/frontscreen_background_land.png b/friend-smash/src/main/res/drawable-mdpi/frontscreen_background_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/frontscreen_background_land.png rename to friend-smash/src/main/res/drawable-mdpi/frontscreen_background_land.png diff --git a/friendsmash_complete/res/drawable-mdpi/heart_red.png b/friend-smash/src/main/res/drawable-mdpi/heart_red.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/heart_red.png rename to friend-smash/src/main/res/drawable-mdpi/heart_red.png diff --git a/friendsmash_complete/res/drawable-mdpi/ic_action_search.png b/friend-smash/src/main/res/drawable-mdpi/ic_action_search.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/ic_action_search.png rename to friend-smash/src/main/res/drawable-mdpi/ic_action_search.png diff --git a/friendsmash_complete/res/drawable-mdpi/ic_launcher.png b/friend-smash/src/main/res/drawable-mdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/ic_launcher.png rename to friend-smash/src/main/res/drawable-mdpi/ic_launcher.png diff --git a/friendsmash_complete/res/drawable-mdpi/leaderboard_button.png b/friend-smash/src/main/res/drawable-mdpi/leaderboard_button.png similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/leaderboard_button.png rename to friend-smash/src/main/res/drawable-mdpi/leaderboard_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/login_button.png b/friend-smash/src/main/res/drawable-mdpi/login_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/login_button.png rename to friend-smash/src/main/res/drawable-mdpi/login_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/logout_button.png b/friend-smash/src/main/res/drawable-mdpi/logout_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/logout_button.png rename to friend-smash/src/main/res/drawable-mdpi/logout_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_1.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_1.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_1.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_1.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_10.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_10.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_10.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_10.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_2.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_2.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_2.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_2.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_3.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_3.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_3.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_3.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_4.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_4.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_4.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_4.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_5.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_5.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_5.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_5.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_6.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_6.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_6.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_6.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_7.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_7.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_7.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_7.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_8.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_8.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_8.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_8.png diff --git a/friendsmash_complete/res/drawable-mdpi/nonfriend_9.png b/friend-smash/src/main/res/drawable-mdpi/nonfriend_9.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/nonfriend_9.png rename to friend-smash/src/main/res/drawable-mdpi/nonfriend_9.png diff --git a/friendsmash_complete/res/drawable-mdpi/playnow_button.png b/friend-smash/src/main/res/drawable-mdpi/playnow_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/playnow_button.png rename to friend-smash/src/main/res/drawable-mdpi/playnow_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/scores_button.png b/friend-smash/src/main/res/drawable-mdpi/scores_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/scores_button.png rename to friend-smash/src/main/res/drawable-mdpi/scores_button.png diff --git a/friendsmash_complete/res/drawable-mdpi/scores_stub_even.png b/friend-smash/src/main/res/drawable-mdpi/scores_stub_even.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/scores_stub_even.png rename to friend-smash/src/main/res/drawable-mdpi/scores_stub_even.png diff --git a/friendsmash_complete/res/drawable-mdpi/scores_stub_odd.png b/friend-smash/src/main/res/drawable-mdpi/scores_stub_odd.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/scores_stub_odd.png rename to friend-smash/src/main/res/drawable-mdpi/scores_stub_odd.png diff --git a/friendsmash_complete/res/drawable-mdpi/title_banner_land.png b/friend-smash/src/main/res/drawable-mdpi/title_banner_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/title_banner_land.png rename to friend-smash/src/main/res/drawable-mdpi/title_banner_land.png diff --git a/friendsmash_complete/res/drawable-mdpi/welcome_panel.png b/friend-smash/src/main/res/drawable-mdpi/welcome_panel.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/welcome_panel.png rename to friend-smash/src/main/res/drawable-mdpi/welcome_panel.png diff --git a/friendsmash_complete/res/drawable-mdpi/welcome_panel_blank.png b/friend-smash/src/main/res/drawable-mdpi/welcome_panel_blank.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-mdpi/welcome_panel_blank.png rename to friend-smash/src/main/res/drawable-mdpi/welcome_panel_blank.png diff --git a/friendsmash_complete/res/drawable-xhdpi/bomb.png b/friend-smash/src/main/res/drawable-xhdpi/bomb.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/bomb.png rename to friend-smash/src/main/res/drawable-xhdpi/bomb.png diff --git a/friendsmash_complete/res/drawable-xhdpi/bomb_in_game.png b/friend-smash/src/main/res/drawable-xhdpi/bomb_in_game.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/bomb_in_game.png rename to friend-smash/src/main/res/drawable-xhdpi/bomb_in_game.png diff --git a/friendsmash_complete/res/drawable-xhdpi/bomb_large.png b/friend-smash/src/main/res/drawable-xhdpi/bomb_large.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/bomb_large.png rename to friend-smash/src/main/res/drawable-xhdpi/bomb_large.png diff --git a/friendsmash_complete/res/drawable-xhdpi/brag_button.png b/friend-smash/src/main/res/drawable-xhdpi/brag_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/brag_button.png rename to friend-smash/src/main/res/drawable-xhdpi/brag_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/challenge_button.png b/friend-smash/src/main/res/drawable-xhdpi/challenge_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/challenge_button.png rename to friend-smash/src/main/res/drawable-xhdpi/challenge_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/checkbox_cold.png b/friend-smash/src/main/res/drawable-xhdpi/checkbox_cold.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/checkbox_cold.png rename to friend-smash/src/main/res/drawable-xhdpi/checkbox_cold.png diff --git a/friendsmash_complete/res/drawable-xhdpi/checkbox_hot.png b/friend-smash/src/main/res/drawable-xhdpi/checkbox_hot.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/checkbox_hot.png rename to friend-smash/src/main/res/drawable-xhdpi/checkbox_hot.png diff --git a/friendsmash_complete/res/drawable-xhdpi/close_button.png b/friend-smash/src/main/res/drawable-xhdpi/close_button.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/close_button.png rename to friend-smash/src/main/res/drawable-xhdpi/close_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/coin.png b/friend-smash/src/main/res/drawable-xhdpi/coin.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/coin.png rename to friend-smash/src/main/res/drawable-xhdpi/coin.png diff --git a/friendsmash_complete/res/drawable-xhdpi/frontscreen_background.png b/friend-smash/src/main/res/drawable-xhdpi/frontscreen_background.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/frontscreen_background.png rename to friend-smash/src/main/res/drawable-xhdpi/frontscreen_background.png diff --git a/friendsmash_complete/res/drawable-xhdpi/frontscreen_background_land.png b/friend-smash/src/main/res/drawable-xhdpi/frontscreen_background_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/frontscreen_background_land.png rename to friend-smash/src/main/res/drawable-xhdpi/frontscreen_background_land.png diff --git a/friendsmash_complete/res/drawable-xhdpi/heart_red.png b/friend-smash/src/main/res/drawable-xhdpi/heart_red.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/heart_red.png rename to friend-smash/src/main/res/drawable-xhdpi/heart_red.png diff --git a/friendsmash_complete/res/drawable-xhdpi/ic_action_search.png b/friend-smash/src/main/res/drawable-xhdpi/ic_action_search.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/ic_action_search.png rename to friend-smash/src/main/res/drawable-xhdpi/ic_action_search.png diff --git a/friendsmash_complete/res/drawable-xhdpi/ic_launcher.png b/friend-smash/src/main/res/drawable-xhdpi/ic_launcher.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/ic_launcher.png rename to friend-smash/src/main/res/drawable-xhdpi/ic_launcher.png diff --git a/friendsmash_complete/res/drawable-xhdpi/leaderboard_button.png b/friend-smash/src/main/res/drawable-xhdpi/leaderboard_button.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/leaderboard_button.png rename to friend-smash/src/main/res/drawable-xhdpi/leaderboard_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/login_button.png b/friend-smash/src/main/res/drawable-xhdpi/login_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/login_button.png rename to friend-smash/src/main/res/drawable-xhdpi/login_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/logout_button.png b/friend-smash/src/main/res/drawable-xhdpi/logout_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/logout_button.png rename to friend-smash/src/main/res/drawable-xhdpi/logout_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/mfs_clicker_invite.png b/friend-smash/src/main/res/drawable-xhdpi/mfs_clicker_invite.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/mfs_clicker_invite.png rename to friend-smash/src/main/res/drawable-xhdpi/mfs_clicker_invite.png diff --git a/friendsmash_complete/res/drawable-xhdpi/mfs_clicker_request.png b/friend-smash/src/main/res/drawable-xhdpi/mfs_clicker_request.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/mfs_clicker_request.png rename to friend-smash/src/main/res/drawable-xhdpi/mfs_clicker_request.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_1.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_1.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_1.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_1.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_10.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_10.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_10.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_10.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_2.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_2.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_2.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_2.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_3.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_3.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_3.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_3.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_4.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_4.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_4.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_4.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_5.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_5.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_5.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_5.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_6.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_6.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_6.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_6.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_7.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_7.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_7.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_7.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_8.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_8.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_8.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_8.png diff --git a/friendsmash_complete/res/drawable-xhdpi/nonfriend_9.png b/friend-smash/src/main/res/drawable-xhdpi/nonfriend_9.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/nonfriend_9.png rename to friend-smash/src/main/res/drawable-xhdpi/nonfriend_9.png diff --git a/friendsmash_complete/res/drawable-xhdpi/playnow_button.png b/friend-smash/src/main/res/drawable-xhdpi/playnow_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/playnow_button.png rename to friend-smash/src/main/res/drawable-xhdpi/playnow_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/profile_holder_invert.png b/friend-smash/src/main/res/drawable-xhdpi/profile_holder_invert.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/profile_holder_invert.png rename to friend-smash/src/main/res/drawable-xhdpi/profile_holder_invert.png diff --git a/friendsmash_complete/res/drawable-xhdpi/scores_button.png b/friend-smash/src/main/res/drawable-xhdpi/scores_button.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/scores_button.png rename to friend-smash/src/main/res/drawable-xhdpi/scores_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/scores_stub_even.png b/friend-smash/src/main/res/drawable-xhdpi/scores_stub_even.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/scores_stub_even.png rename to friend-smash/src/main/res/drawable-xhdpi/scores_stub_even.png diff --git a/friendsmash_complete/res/drawable-xhdpi/scores_stub_odd.png b/friend-smash/src/main/res/drawable-xhdpi/scores_stub_odd.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/scores_stub_odd.png rename to friend-smash/src/main/res/drawable-xhdpi/scores_stub_odd.png diff --git a/friendsmash_complete/res/drawable-xhdpi/send_button.png b/friend-smash/src/main/res/drawable-xhdpi/send_button.png similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/send_button.png rename to friend-smash/src/main/res/drawable-xhdpi/send_button.png diff --git a/friendsmash_complete/res/drawable-xhdpi/title_banner.png b/friend-smash/src/main/res/drawable-xhdpi/title_banner.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/title_banner.png rename to friend-smash/src/main/res/drawable-xhdpi/title_banner.png diff --git a/friendsmash_complete/res/drawable-xhdpi/title_banner_land.png b/friend-smash/src/main/res/drawable-xhdpi/title_banner_land.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/title_banner_land.png rename to friend-smash/src/main/res/drawable-xhdpi/title_banner_land.png diff --git a/friendsmash_complete/res/drawable-xhdpi/welcome_panel.png b/friend-smash/src/main/res/drawable-xhdpi/welcome_panel.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/welcome_panel.png rename to friend-smash/src/main/res/drawable-xhdpi/welcome_panel.png diff --git a/friendsmash_complete/res/drawable-xhdpi/welcome_panel_blank.png b/friend-smash/src/main/res/drawable-xhdpi/welcome_panel_blank.png old mode 100755 new mode 100644 similarity index 100% rename from friendsmash_complete/res/drawable-xhdpi/welcome_panel_blank.png rename to friend-smash/src/main/res/drawable-xhdpi/welcome_panel_blank.png diff --git a/friendsmash_complete/res/layout-land/fragment_home.xml b/friend-smash/src/main/res/layout-land/fragment_home.xml old mode 100755 new mode 100644 similarity index 82% rename from friendsmash_complete/res/layout-land/fragment_home.xml rename to friend-smash/src/main/res/layout-land/fragment_home.xml index fedbca3..6513515 --- a/friendsmash_complete/res/layout-land/fragment_home.xml +++ b/friend-smash/src/main/res/layout-land/fragment_home.xml @@ -1,22 +1,26 @@ diff --git a/friendsmash_complete/res/layout-land/fragment_home_fb_logged_in.xml b/friend-smash/src/main/res/layout-land/fragment_home_fb_logged_in.xml old mode 100755 new mode 100644 similarity index 85% rename from friendsmash_complete/res/layout-land/fragment_home_fb_logged_in.xml rename to friend-smash/src/main/res/layout-land/fragment_home_fb_logged_in.xml index 87dfe24..20a8125 --- a/friendsmash_complete/res/layout-land/fragment_home_fb_logged_in.xml +++ b/friend-smash/src/main/res/layout-land/fragment_home_fb_logged_in.xml @@ -1,22 +1,26 @@ @@ -44,7 +48,7 @@ android:layout_gravity="left" android:paddingTop="68dp"> - - + android:layout_marginTop="70dp"/> @@ -185,7 +186,7 @@ android:layout_gravity="left"> - @@ -93,13 +97,10 @@ android:paddingTop="210dp" android:layout_marginLeft="150dp"> - + android:layout_height="wrap_content" /> diff --git a/friend-smash/src/main/res/layout/activity_fragment.xml b/friend-smash/src/main/res/layout/activity_fragment.xml new file mode 100644 index 0000000..4913b5c --- /dev/null +++ b/friend-smash/src/main/res/layout/activity_fragment.xml @@ -0,0 +1,26 @@ + + + + diff --git a/friendsmash_complete/res/layout/fragment_challenge.xml b/friend-smash/src/main/res/layout/fragment_challenge.xml similarity index 52% rename from friendsmash_complete/res/layout/fragment_challenge.xml rename to friend-smash/src/main/res/layout/fragment_challenge.xml index e8b4af0..faaf6fb 100644 --- a/friendsmash_complete/res/layout/fragment_challenge.xml +++ b/friend-smash/src/main/res/layout/fragment_challenge.xml @@ -1,4 +1,23 @@ + diff --git a/friendsmash_incomplete/res/layout/fragment_home_fb_logged_in.xml b/friend-smash/src/main/res/layout/fragment_home_fb_logged_in.xml old mode 100755 new mode 100644 similarity index 87% rename from friendsmash_incomplete/res/layout/fragment_home_fb_logged_in.xml rename to friend-smash/src/main/res/layout/fragment_home_fb_logged_in.xml index f9d3118..031e74b --- a/friendsmash_incomplete/res/layout/fragment_home_fb_logged_in.xml +++ b/friend-smash/src/main/res/layout/fragment_home_fb_logged_in.xml @@ -1,22 +1,26 @@ @@ -38,7 +42,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" > - - + android:layout_height="wrap_content"/> @@ -228,7 +229,7 @@ android:clickable="true" > - @@ -79,14 +83,11 @@ android:layout_height="match_parent" > - + android:layout_gravity="center"/> diff --git a/friendsmash_complete/res/layout/fragment_scoreboard.xml b/friend-smash/src/main/res/layout/fragment_scoreboard.xml old mode 100755 new mode 100644 similarity index 57% rename from friendsmash_complete/res/layout/fragment_scoreboard.xml rename to friend-smash/src/main/res/layout/fragment_scoreboard.xml index 0433864..e0f0165 --- a/friendsmash_complete/res/layout/fragment_scoreboard.xml +++ b/friend-smash/src/main/res/layout/fragment_scoreboard.xml @@ -1,18 +1,22 @@ + + + + + + + + diff --git a/friend-smash/src/main/res/layout/invite_list_item_view.xml b/friend-smash/src/main/res/layout/invite_list_item_view.xml new file mode 100644 index 0000000..64485ca --- /dev/null +++ b/friend-smash/src/main/res/layout/invite_list_item_view.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/friend-smash/src/main/res/layout/request_list_item_view.xml b/friend-smash/src/main/res/layout/request_list_item_view.xml new file mode 100644 index 0000000..daf8a86 --- /dev/null +++ b/friend-smash/src/main/res/layout/request_list_item_view.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/friend-smash/src/main/res/values-v11/styles.xml b/friend-smash/src/main/res/values-v11/styles.xml new file mode 100644 index 0000000..b77f5e3 --- /dev/null +++ b/friend-smash/src/main/res/values-v11/styles.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/friend-smash/src/main/res/values-v14/styles.xml b/friend-smash/src/main/res/values-v14/styles.xml new file mode 100644 index 0000000..22d16c8 --- /dev/null +++ b/friend-smash/src/main/res/values-v14/styles.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file diff --git a/friend-smash/src/main/res/values/dimensions.xml b/friend-smash/src/main/res/values/dimensions.xml new file mode 100644 index 0000000..4ee38f0 --- /dev/null +++ b/friend-smash/src/main/res/values/dimensions.xml @@ -0,0 +1,36 @@ + + + + + + 96dp + 4dp + 20dp + 20dp + 69dp + 9dp + 10dp + 10dp + 20dp + 86dp + 86dp + + \ No newline at end of file diff --git a/friend-smash/src/main/res/values/strings.xml b/friend-smash/src/main/res/values/strings.xml new file mode 100644 index 0000000..47a2194 --- /dev/null +++ b/friend-smash/src/main/res/values/strings.xml @@ -0,0 +1,53 @@ + + + + + + Friend Smash! + 480369938658210 + EMsUqEDE5YtM28UI6KQ9YmOwzNSMNLbUyLldUNLq + XbxKQWXHynWY9okrZXhVrbS0k79bkejbRbxMAu5q + Friend Smash! + Welcome, Player + + Smash Player ! + Score: 0 + Let\'s smash some friends! + Game Over! + Error fetching your user profile - Please try again + Error fetching your friend\'s profile picture - Please try again + "No scores to display" + Yes + No + Play with Friends + This game is better with friends! Would you like to play with your friends? + Social Leaderboard + This game needs access to your friends list to show their scores. Do you want to see your friends\' scores? + Save Score + Do you want to save your score to Facebook? + Friend Smash! + "Come join me in Friend Smash!" + I just smashed you %1$s times! Can you beat it? + My best score is %1$s! Can you beat it? + Checkout my Friend Smash greatness! + I just scored %1$s! Can you beat my score? + http://www.friendsmash.com/images/logo_large.jpg + \ No newline at end of file diff --git a/friendsmash_complete/res/values/styles.xml b/friend-smash/src/main/res/values/styles.xml old mode 100755 new mode 100644 similarity index 62% rename from friendsmash_complete/res/values/styles.xml rename to friend-smash/src/main/res/values/styles.xml index da7f22e..46de12c --- a/friendsmash_complete/res/values/styles.xml +++ b/friend-smash/src/main/res/values/styles.xml @@ -1,18 +1,22 @@ - - - - - - - - - diff --git a/friendsmash_complete/.project b/friendsmash_complete/.project deleted file mode 100755 index 608c694..0000000 --- a/friendsmash_complete/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - friendsmash_complete - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/friendsmash_complete/ic_launcher-web.png b/friendsmash_complete/ic_launcher-web.png deleted file mode 100755 index 08c8f3b..0000000 Binary files a/friendsmash_complete/ic_launcher-web.png and /dev/null differ diff --git a/friendsmash_complete/libs/Parse-1.4.3.jar b/friendsmash_complete/libs/Parse-1.4.3.jar deleted file mode 100644 index f01609e..0000000 Binary files a/friendsmash_complete/libs/Parse-1.4.3.jar and /dev/null differ diff --git a/friendsmash_complete/proguard-project.txt b/friendsmash_complete/proguard-project.txt deleted file mode 100755 index f2fe155..0000000 --- a/friendsmash_complete/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/friendsmash_complete/project.properties b/friendsmash_complete/project.properties deleted file mode 100755 index da4d5da..0000000 --- a/friendsmash_complete/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-19 -android.library.reference.1=../../facebook-android-sdk-3.23.0/facebook diff --git a/friendsmash_complete/res/layout/activity_fragment.xml b/friendsmash_complete/res/layout/activity_fragment.xml deleted file mode 100755 index 91e3a51..0000000 --- a/friendsmash_complete/res/layout/activity_fragment.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - diff --git a/friendsmash_complete/res/layout/fragment_home_fb_logged_in.xml b/friendsmash_complete/res/layout/fragment_home_fb_logged_in.xml deleted file mode 100755 index f9d3118..0000000 --- a/friendsmash_complete/res/layout/fragment_home_fb_logged_in.xml +++ /dev/null @@ -1,297 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_complete/res/layout/home.xml b/friendsmash_complete/res/layout/home.xml deleted file mode 100755 index 6f6d910..0000000 --- a/friendsmash_complete/res/layout/home.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - diff --git a/friendsmash_complete/res/layout/invite_list_item_view.xml b/friendsmash_complete/res/layout/invite_list_item_view.xml deleted file mode 100644 index 4cd280f..0000000 --- a/friendsmash_complete/res/layout/invite_list_item_view.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_complete/res/layout/request_list_item_view.xml b/friendsmash_complete/res/layout/request_list_item_view.xml deleted file mode 100644 index 5b8c1d5..0000000 --- a/friendsmash_complete/res/layout/request_list_item_view.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_complete/res/values-v11/styles.xml b/friendsmash_complete/res/values-v11/styles.xml deleted file mode 100755 index de6e165..0000000 --- a/friendsmash_complete/res/values-v11/styles.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/friendsmash_complete/res/values-v14/styles.xml b/friendsmash_complete/res/values-v14/styles.xml deleted file mode 100755 index 444520e..0000000 --- a/friendsmash_complete/res/values-v14/styles.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/friendsmash_complete/res/values/dimensions.xml b/friendsmash_complete/res/values/dimensions.xml deleted file mode 100755 index 5b3c4e6..0000000 --- a/friendsmash_complete/res/values/dimensions.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - 96dp - 4dp - 20dp - 20dp - 69dp - 9dp - 10dp - 10dp - 20dp - 86dp - 86dp - - \ No newline at end of file diff --git a/friendsmash_complete/res/values/strings.xml b/friendsmash_complete/res/values/strings.xml deleted file mode 100755 index ab1a726..0000000 --- a/friendsmash_complete/res/values/strings.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - FRIEND SMASH complete - 480369938658210 - EMsUqEDE5YtM28UI6KQ9YmOwzNSMNLbUyLldUNLq - XbxKQWXHynWY9okrZXhVrbS0k79bkejbRbxMAu5q - FRIEND SMASH - Welcome, Player - - Smash Player ! - Score: 0 - Let\'s smash some friends! - Please check your network connection - Game Over! - Error - OK - No response from server. - An error occurred that requires your attention. %1$s - An error occurred, please re-login. - Please allow us to post on your behalf. - The server is busy, please retry later. - An error occurred, please contact the developer with the following message: %1$s - An unknown error occurred, please contact the developer with the following message: %1$s - Error fetching your user profile - Please try again - Error fetching your friend\'s profile picture - Please try again - Error switching screens - Please try again - "No scores to display" - Yes - No - Play with Friends - This game is better with friends! Would you like to play with your friends? - Social Leaderboard - This game needs access to your friends list to show their scores. Do you want to see your friends\' scores? - Save Score - Do you want to save your score to Facebook? - - \ No newline at end of file diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java b/friendsmash_complete/src/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java deleted file mode 100644 index 9e66fd0..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java +++ /dev/null @@ -1,77 +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.android.friendsmash; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; - -import com.facebook.FacebookException; -import com.facebook.FacebookOperationCanceledException; -import com.facebook.widget.LoginButton; -import com.facebook.widget.LoginButton.OnErrorListener; - -/** - * Fragment to be displayed if the user is logged out of Facebook in the social version of the game - */ -public class FBLoggedOutHomeFragment extends Fragment { - - View progressContainer; - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - setRetainInstance(true); - - // Hide the notification bar - getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - - View v = inflater.inflate(R.layout.fragment_home_fb_logged_out, parent, false); - - progressContainer = v.findViewById(R.id.progressContainer); - progressContainer.setVisibility(View.INVISIBLE); - - // Set an error listener for the login button - LoginButton loginButton = (LoginButton) v.findViewById(R.id.loginButton); - loginButton.setReadPermissions("user_friends"); - if (loginButton != null) { - loginButton.setOnErrorListener(new OnErrorListener() { - - @Override - public void onError(FacebookException error) { - if (error != null && !(error instanceof FacebookOperationCanceledException)) { - // Failed probably due to network error (rather than user canceling dialog which would throw a FacebookOperationCanceledException) - ((HomeActivity)getActivity()).showError(getResources().getString(R.string.network_error), false); - } - } - - }); - } - - return v; - } - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashApplication.java b/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashApplication.java deleted file mode 100644 index 28094d8..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashApplication.java +++ /dev/null @@ -1,306 +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.android.friendsmash; - -import android.app.Application; -import android.content.SharedPreferences; - -import com.facebook.FacebookRequestError; -import com.facebook.model.GraphUser; -import com.parse.Parse; -import com.parse.ParseFacebookUtils; -import com.parse.ParseUser; - -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * Use a custom Application class to pass state data between Activities. - */ -public class FriendSmashApplication extends Application { - - /* Static Attributes */ - - // Tag used when logging all messages with the same tag (e.g. for demoing purposes) - static final String TAG = "FriendSmash"; - - // Switch between the non-social and social Facebook versions of the game - static final boolean IS_SOCIAL = true; - - - /* Friend Smash application attributes */ - - // Player inventory - public static int NEW_USER_BOMBS = 5; - public static int NEW_USER_COINS = 100; - public static int NUM_BOMBS_ALLOWED_IN_GAME = 3; - private int score = 0; - private int bombs = 0; - private int coins = 0; - private int coinsCollected = 0; - - /* Facebook application attributes */ - - // Logged in status of the user - private boolean loggedIn = false; - private static final String LOGGED_IN_KEY = "logged_in"; - - private String fbAppID = null; - - // Current logged in FB user and key for saving/restoring during the Activity lifecycle - private GraphUser currentFBUser; - private static final String CURRENT_FB_USER_KEY = "current_fb_user"; - - // List of the logged in user's friends and key for saving/restoring during the Activity lifecycle - private List friends; - - // List of friends the user can invite (have not installed the app). - private List invitableFriends; - - private static final String FRIENDS_KEY = "friends"; - - // ID of the last friend smashed (linked to the current score) - private String lastFriendSmashedID = null; - - // Name of the last friend smashed - private String lastFriendSmashedName = null; - - // Check to see whether user has said no when asked to play with friends. - private boolean hasDeniedFriendPermission = false; - - // List of ordered ScoreboardEntry objects in order from highest to lowest score to - // be shown in the ScoreboardFragment - private ArrayList scoreboardEntriesList = null; - - // FacebookRequestError to show when the GameFragment closes - private FacebookRequestError gameFragmentFBRequestError = null; - - - /* Friend Smash application attribute getters & setters */ - - public int getScore() { - return score; - } - - public void setScore(int score) { - this.score = score; - } - - public int getBombs() { - return bombs; - } - - public void setBombs(int bombs) { - this.bombs = bombs; - } - - public int getCoins() { - return coins; - } - - public void setCoins(int coins) { - this.coins = coins; - } - - public int getCoinsCollected() { - return coinsCollected; - } - - public void setCoinsCollected(int coinsCollected) { - this.coinsCollected = coinsCollected; - } - - /* Facebook attribute getters & setters */ - - public boolean isLoggedIn() { - return loggedIn; - } - - public void setLoggedIn(boolean loggedIn) { - this.loggedIn = loggedIn; - if (!loggedIn) { - // If the user is logged out, reset the score and nullify all the logged-in user's values - setScore(-1); - setCurrentFBUser(null); - setFriends(null); - setLastFriendSmashedID(null); - setScoreboardEntriesList(null); - } - } - - public GraphUser getCurrentFBUser() { - return currentFBUser; - } - - public void setCurrentFBUser(GraphUser currentFBUser) { - this.currentFBUser = currentFBUser; - } - - public List getFriends() { - return friends; - } - - // Method to get the list of friends in an ArrayList where each entry - // is an inner JSON objects of each friend represented as a string - used for - // saving/restoring each friend during the Activity lifecycle - public ArrayList getFriendsAsArrayListOfStrings() { - ArrayList friendsAsArrayListOfStrings = new ArrayList(); - - Iterator friendsIterator = friends.iterator(); - while (friendsIterator.hasNext()) { - friendsAsArrayListOfStrings.add(friendsIterator.next().getInnerJSONObject().toString()); - } - - return friendsAsArrayListOfStrings; - } - - public GraphUser getFriend(int index) { - if (friends != null && friends.size() > index) { - return friends.get(index); - } else { - return null; - } - } - - public void setFriends(List friends) { - this.friends = friends; - } - - public String getLastFriendSmashedID() { - return lastFriendSmashedID; - } - - public void setLastFriendSmashedID(String lastFriendSmashedID) { - this.lastFriendSmashedID = lastFriendSmashedID; - } - - public String getLastFriendSmashedName() { - return lastFriendSmashedName; - } - - public void setLastFriendSmashedName(String lastFriendSmashedName) { - this.lastFriendSmashedName = lastFriendSmashedName; - } - - public boolean hasDeniedFriendPermission() { - return hasDeniedFriendPermission; - } - - public void setHasDeniedFriendPermission(boolean hasDeniedFriendPermission) { - this.hasDeniedFriendPermission = hasDeniedFriendPermission; - } - - public ArrayList getScoreboardEntriesList() { - return scoreboardEntriesList; - } - - public void setScoreboardEntriesList(ArrayList scoreboardEntriesList) { - this.scoreboardEntriesList = scoreboardEntriesList; - } - - public FacebookRequestError getGameFragmentFBRequestError() { - return gameFragmentFBRequestError; - } - - public void setGameFragmentFBRequestError(FacebookRequestError gameFragmentFBRequestError) { - this.gameFragmentFBRequestError = gameFragmentFBRequestError; - } - - public static String getLoggedInKey() { - return LOGGED_IN_KEY; - } - - public String getFBAppID() { - return fbAppID; - } - - public static String getCurrentFbUserKey() { - return CURRENT_FB_USER_KEY; - } - - public static String getFriendsKey() { - return FRIENDS_KEY; - } - - public List getInvitableFriends() { - return invitableFriends; - } - - public void setInvitableFriends(List invitableFriends) { - this.invitableFriends = invitableFriends; - } - - public void saveInventory() { - SharedPreferences prefs = getApplicationContext().getSharedPreferences("Inventory", MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt("bombs", getBombs()); - editor.putInt("coins", getCoins()); - editor.putLong("lastSavedTime", System.currentTimeMillis()); - editor.commit(); - - // Store data to Parse too. - if (ParseUser.getCurrentUser() != null) { - ParseUser.getCurrentUser().put("bombs", getBombs()); - ParseUser.getCurrentUser().put("coins", getCoins()); - ParseUser.getCurrentUser().saveInBackground(); - } - } - - - /* - * The logic here is to check if we're connected to Parse. If we are, accept the data - * there as the authoritative source of data. If we are not connected, then look for - * data that is stored locally. If that doesn't exist, then use some default values. - * - * In your own project, you may want to have more sophisticated conflict resolution. - * For example, you may want to use lastSavedTime as a timestamp that could be - * compared to the timestamp of data pulled from Parse and then use whichever data - * was the most recent. You may want to do this if you want support offline gaming. - * - */ - public void loadInventory() { - if (ParseUser.getCurrentUser() != null) { - setBombs(ParseUser.getCurrentUser().getInt("bombs")); - setCoins(ParseUser.getCurrentUser().getInt("coins")); - } else { - SharedPreferences prefs = getApplicationContext().getSharedPreferences("Inventory", MODE_PRIVATE); - long lastSavedTime = prefs.getLong("lastSavedTime", 0); - - if (lastSavedTime == 0) { - // Have never saved state. Initialize. - setBombs(NEW_USER_BOMBS); - setCoins(NEW_USER_COINS); - } else { - setBombs(prefs.getInt("bombs", 0)); - setCoins(prefs.getInt("coins", 0)); - } - } - } - - public void onCreate() { - fbAppID = getString(R.string.app_id); - Parse.initialize(this, getString(R.string.parse_app_id), getString(R.string.parse_client_key)); - ParseFacebookUtils.initialize(fbAppID); - - loadInventory(); - } - - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashCustomAppEvent.java b/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashCustomAppEvent.java deleted file mode 100644 index 7f01f2d..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashCustomAppEvent.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.facebook.android.friendsmash; - -/** - * Created by jakubpudelek on 3/22/15. - */ -public class FriendSmashCustomAppEvent { - public static String EVENT_NAME_GAME_PLAYED = "game_played"; - public static String EVENT_PARAM_SCORE = "score"; -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashEventsLogger.java b/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashEventsLogger.java deleted file mode 100644 index 6e34770..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/FriendSmashEventsLogger.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.facebook.android.friendsmash; - -import android.os.Bundle; -import android.util.Log; - -import com.facebook.AppEventsLogger; - -public class FriendSmashEventsLogger { - AppEventsLogger logger; - - public FriendSmashEventsLogger(AppEventsLogger logger) { - this.logger = logger; - } - - public void logGamePlayedEvent(int score) { - Log.i(FriendSmashApplication.TAG, "GAME_PLAYED custom app event logged with param score=" + score); - Bundle params = new Bundle(); - params.putInt(FriendSmashCustomAppEvent.EVENT_PARAM_SCORE, score); - logger.logEvent(FriendSmashCustomAppEvent.EVENT_NAME_GAME_PLAYED, params); - } -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/GameActivity.java b/friendsmash_complete/src/com/facebook/android/friendsmash/GameActivity.java deleted file mode 100644 index d83fcfe..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/GameActivity.java +++ /dev/null @@ -1,31 +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.android.friendsmash; - -import android.support.v4.app.Fragment; - -/** - * Activity used once a user starts a new game - all logic is within GameFragment - */ -public class GameActivity extends SingleFragmentActivity { - - @Override - protected Fragment createFragment() { - return new GameFragment(); - } - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/GameFragment.java b/friendsmash_complete/src/com/facebook/android/friendsmash/GameFragment.java deleted file mode 100644 index 8188f1d..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/GameFragment.java +++ /dev/null @@ -1,967 +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.android.friendsmash; - -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.app.Fragment; -import android.util.Log; -import android.util.Pair; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.facebook.FacebookRequestError; -import com.facebook.Request; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphUser; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Random; - -/** - * Fragment shown once a user starts playing a game - */ -public class GameFragment extends Fragment { - - private static final Pair [] CELEBS = { - Pair.create("Einstein", "drawable/nonfriend_1"), - Pair.create("Xzibit", "drawable/nonfriend_2"), - Pair.create("Goldsmith", "drawable/nonfriend_3"), - Pair.create("Sinatra", "drawable/nonfriend_4"), - Pair.create("George", "drawable/nonfriend_5"), - Pair.create("Jacko", "drawable/nonfriend_6"), - Pair.create("Rick", "drawable/nonfriend_7"), - Pair.create("Keanu", "drawable/nonfriend_8"), - Pair.create("Arnie", "drawable/nonfriend_9"), - Pair.create("Jean-Luc", "drawable/nonfriend_10"), - }; - - // Tag used when logging messages - private static final String TAG = GameFragment.class.getSimpleName(); - - - // FrameLayout as the container for the game - private FrameLayout gameFrame; - - // FrameLayout of the progress container to show the spinner - private FrameLayout progressContainer; - - // TextView for the Smash Player title - private TextView smashPlayerNameTextView; - - // TextView for the score - private TextView scoreTextView; - - // LinearyLayout containing the lives images - private LinearLayout livesContainer; - - // LinearyLayout containing the bombs images - private LinearLayout bombsContainer; - - // ImageView acting as the button for exploding a bomb - private ImageView bombButton; - - // Icon width for the friend images to smash - private int iconWidth; - - // Screen Dimensions - private int screenWidth; - private int screenHeight; - - - // Handler for putting messages on Main UI thread from background threads periodically - private Handler timerHandler; - - // Handler for putting messages on Main UI thread from background thread after fetching images - private Handler uiHandler; - - // Runnable task used to produce images to fly across the screen - private Runnable fireImageTask = null; - - // Boolean indicating whether images have started firing - private boolean imagesStartedFiring = false; - - - // Index of the friend to smash (in the social game) - private int friendToSmashIndex = -1; - - // Index of the celeb to smash (in the non-social game) - private int celebToSmashIndex = -1; - - // ID of the friend to smash (if passed in as an attribute) - private String friendToSmashIDProvided = null; - - // Name of the friend to smash - private String friendToSmashFirstName = null; - - // Bitmap of the friend to smash - private Bitmap friendToSmashBitmap; - - - // Score for the user - private int score = 0; - - // Lives the user has remaining - private int lives = 3; - - // Bombs the user has remaining - private int bombsRemaining = FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME; - - // Bombs the user has used - private int bombsUsed = 0; - - // Coins the user has collected - private int coinsCollected = 0; - - // Boolean set to true if first image has been fired - private boolean firstImageFired = false; - - // Boolean indicating that the first image to be fired is pending (i.e. a Request is - // in the process of executing in a background thread to fetch the images / information) - private boolean firstImagePendingFiring = false; - - // List of UserImageView objects created and visible - private ArrayList userImageViews = new ArrayList(); - - // friend selection mode - private boolean isSocialMode = false; - - - @SuppressWarnings("unused") - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - - setRetainInstance(true); - - // Instantiate the handlers - timerHandler = new Handler(); - uiHandler = new Handler(); - - // Make sure there are non-zero friends. - List friends = ((FriendSmashApplication) getActivity().getApplication()).getFriends(); - if (FriendSmashApplication.IS_SOCIAL && friends != null && friends.size() > 0) { - // User is logged into FB, so choose a random FB friend to smash - isSocialMode = true; - friendToSmashIndex = getRandomFriendIndex(); - } else { - // User is not logged into FB, so choose a random celebrity to smash - isSocialMode = false; - celebToSmashIndex = getRandomCelebIndex(); - - // TODO: if using celeb, set the information for last smashed so game over fragment has right info. - // need to save image info as well. consider saving path to image and setting an ImageView while hiding the ProfilePicView. -// ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedID(null); -// ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedName(CELEBS[celebToSmashIndex].first.toString()); - } - } - - @SuppressWarnings({ "deprecation" }) - @TargetApi(13) - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - - View v = inflater.inflate(R.layout.fragment_game, parent, false); - - gameFrame = (FrameLayout)v.findViewById(R.id.gameFrame); - progressContainer = (FrameLayout)v.findViewById(R.id.progressContainer); - smashPlayerNameTextView = (TextView)v.findViewById(R.id.smashPlayerNameTextView); - scoreTextView = (TextView)v.findViewById(R.id.scoreTextView); - livesContainer = (LinearLayout)v.findViewById(R.id.livesContainer); - bombsContainer = (LinearLayout)v.findViewById(R.id.bombsContainer); - bombButton = (ImageView)v.findViewById(R.id.bombButton); - bombButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onBombButtonTouched(); - return false; - } - }); - - // Set the progressContainer as invisible by default - progressContainer.setVisibility(View.INVISIBLE); - - // Set the icon width (for the images to be smashed) - setIconWidth(getResources().getDimensionPixelSize(R.dimen.icon_width)); - - // Set the screen dimensions - WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - if (Build.VERSION.SDK_INT >= 13) { - Point size = new Point(); - display.getSize(size); - setScreenWidth(size.x); - setScreenHeight(size.y); - } - else { - setScreenWidth(display.getWidth()); - setScreenHeight(display.getHeight()); - } - - // Instantiate the fireImageTask for future fired images - fireImageTask = new Runnable() - { - public void run() - { - spawnImage(false); - } - }; - - // Refresh the score board - setScore(getScore()); - - // Refresh the lives - setLives(getLives()); - - // Refresh the bombs - setBombsRemaining(getBombsRemaining()); - - // Note: Images will start firing in the onResume method below - - return v; - } - - // Called when the Bombs button is touched - private void onBombButtonTouched() { - if (getBombsRemaining() > 0) { - // Hide all ImageViews and invalidate them - hideAllUserImageViews(); - markAllUserImageViewsAsVoid(); - - // Increment the bombsUsed integer - bombsUsed++; - - // Subtract a bomb - setBombsRemaining(getBombsRemaining() - 1); - } else { - // No bombs are remaining, so make sure they are all removed from the UI - setBombsRemaining(0); - } - } - - // Sets the name of the player to smash in the top left TextView - @SuppressWarnings("unused") - private void setSmashPlayerNameTextView() { - // Set the Smash Player Name title - if (isSocialMode) { - // User is logged into FB ... - if (friendToSmashFirstName == null) { - // A name hasn't been set yet (i.e. it hasn't been fetched through a passed in id, so - // a random friend needs to be used instead, so fetch this name - friendToSmashFirstName = ((FriendSmashApplication) getActivity().getApplication()).getFriend(friendToSmashIndex).getFirstName(); - } - smashPlayerNameTextView.setText("Smash " + friendToSmashFirstName + " !"); - } else { - // User is not logged into FB ... - smashPlayerNameTextView.setText("Smash " + CELEBS[celebToSmashIndex].first + " !"); - } - } - - // Select a random friend to smash - private int getRandomFriendIndex() { - Random randomGenerator = new Random(System.currentTimeMillis()); - int friendIndex = randomGenerator.nextInt(((FriendSmashApplication) getActivity().getApplication()).getFriends().size()); - return friendIndex; - } - - // Select a random celebrity to smash (in the non-social game) or avoid smashing (in the social game) - private int getRandomCelebIndex() { - Random randomGenerator = new Random(System.currentTimeMillis()); - int celebIndex = randomGenerator.nextInt(CELEBS.length); - return celebIndex; - } - - // Set the image on the UserImageView to the specified bitmap of the user's friend and fire it - private void setFriendImageAndFire(UserImageView imageView, Bitmap friendBitmap, boolean extraImage) { - imageView.setImageBitmap(friendBitmap); - - if (extraImage) { - // If this is an extra image, give it an extra point when smashed - imageView.setExtraPoints(1); - } - - fireImage(imageView, extraImage); - } - - // Set the image on the UserImageView to the celebrity and fire it - private void setCelebImageAndFire(UserImageView imageView, int celebIndex, boolean extraImage) { - int imageResource = getResources().getIdentifier((String) CELEBS[celebIndex].second, null, getActivity().getPackageName()); - - Drawable image = getResources().getDrawable(imageResource); - imageView.setImageDrawable(image); - - fireImage(imageView, extraImage); - } - - // Set the image on the UserImageView to the coin and fire it - private void setCoinImageAndFire(UserImageView imageView, boolean extraImage) { - imageView.setImageResource(R.drawable.coin); - fireImage(imageView, extraImage); - } - - // Fire the UserImageView and setup the timer to start another image shortly (as long as the image that - // is fired isn't an extra image) - private void fireImage(final UserImageView imageView, boolean extraImage) { - // Fire image - imageView.setupAndStartAnimations(iconWidth, iconWidth, screenWidth, screenHeight, new AnimatorListener() { - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - if (!imageView.isWrongImageSmashed()) { - if (imageView.getVisibility() == View.VISIBLE && imageView.shouldSmash() && !imageView.isVoid() && !imageView.isCoin()) { - // Image is still visible, so user didn't smash it and they should have done (and it isn't void), so decrement the lives by one - setLives(getLives() - 1); - } - - // Only hide this if the wrong image has not been smashed (otherwise, other logic will be run and image still needs to be shown) - hideAndRemove(imageView); - } - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationStart(Animator animation) { - } - }); - - if (!extraImage) { - // If this isn't an extra image spawned, fire another image shortly - fireAnotherImage(); - } - - // By this point, all network calls would have executed and the first image has fired with the next lined up - // , so set firstImagePendingFiring to false - firstImagePendingFiring = false; - } - - // If this UserImageView is currently visible, hide it and remove it from the GameFragment view - // and the list storing all UserImageViews - private void hideAndRemove(UserImageView userImageView) { - if (userImageView.getVisibility() == View.VISIBLE) { - // Ensure it is hidden - userImageView.setVisibility(View.GONE); - } - - // Remove the userImageView from the gameFrame - getGameFrame().removeView(userImageView); - - // Remove it from the userImageViews List in the gameFragment - getUserImageViews().remove(userImageView); - } - - // Fire another image shortly - private void fireAnotherImage() { - // Fire another image shortly ... - if (fireImageTask != null) - { - timerHandler.postDelayed(fireImageTask, 700); - } - } - - // Called when the first image should be fired (only called during onResume) - // If the game has been deep linked into (i.e. a user has clicked on a feed post or request in - // Facebook), then fetch the specific user that should be smashed - @SuppressWarnings("unused") - private void fireFirstImage() { - if (isSocialMode) { - // Get any bundle parameters there are - Bundle bundle = getActivity().getIntent().getExtras(); - - String requestID = null; - String userID = null; - int numBombsRemaining = 0; - if (bundle != null) { - requestID = bundle.getString("request_id"); - userID = bundle.getString("user_id"); - numBombsRemaining = bundle.getInt("num_bombs") <= FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME ? - bundle.getInt("num_bombs") : FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME; - setBombsRemaining(numBombsRemaining); - } - - if (requestID != null && friendToSmashIDProvided == null) { - // Deep linked from request - // Make a request to get a specific user to smash if they haven't been fetched already - - // Show the spinner for this part - progressContainer.setVisibility(View.VISIBLE); - - // Get and set the id of the friend to smash and start firing the image - fireFirstImageWithRequestID(requestID); - } else if (userID != null && friendToSmashIDProvided == null) { - // Deep linked from feed post - // Make a request to get a specific user to smash if they haven't been fetched already - - // Show the spinner for this part - progressContainer.setVisibility(View.VISIBLE); - - // Get and set the id of the friend to smash and start firing the image - fireFirstImageWithUserID(userID); - } else { - // requestID is null, userID is null or friendToSmashIDProvided is already set, - // so use the randomly generated friend of the user or the already set friendToSmashIDProvided - // So set the smashPlayerNameTextView text and hide the progress spinner as there is nothing to fetch - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } else { - // Non-social, so set the smashPlayerNameTextView text and hide the progress spinner as there is nothing to fetch - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } - - // Fires the first image in a game with a given request id (from a user deep linking by clicking - // on a request from a specific user) - private void fireFirstImageWithRequestID(String requestID) { - final Session session = Session.getActiveSession(); - Request requestIDGraphPathRequest = Request.newGraphPathRequest(session, requestID, new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - closeAndHandleError(error); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Extract the user id from the response - GraphObject graphObject = response.getGraphObject(); - JSONObject fromObject = (JSONObject)graphObject.getProperty("from"); - try { - friendToSmashIDProvided = fromObject.getString("id"); - } catch (JSONException e) { - Log.e(FriendSmashApplication.TAG, e.toString()); - closeAndShowError(getResources().getString(R.string.network_error)); - } - - // With the user id, fetch and set their name - Request userGraphPathRequest = Request.newGraphPathRequest(session, friendToSmashIDProvided, new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - closeAndHandleError(error); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Extract the user name from the response - friendToSmashFirstName = response.getGraphObjectAs(GraphUser.class).getFirstName(); - } - if (friendToSmashFirstName != null) { - // If the first name of the friend to smash has been set, set the text in the smashPlayerNameTextView - // and hide the progress spinner now that the user's details have been fetched - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } - } - }); - Request.executeBatchAsync(userGraphPathRequest); - } - } - } - }); - Request.executeBatchAsync(requestIDGraphPathRequest); - } - - // Fires the first image in a game with a given user id (from a user deep linking by clicking - // on a feed post from a specific user) - private void fireFirstImageWithUserID(String userID) { - final Session session = Session.getActiveSession(); - - // With the user id, fetch and set their name, then start the firing of images - friendToSmashIDProvided = userID; - Request userGraphPathRequest = Request.newGraphPathRequest(session, friendToSmashIDProvided, new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - closeAndHandleError(error); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Extract the user name from the response - friendToSmashFirstName = response.getGraphObjectAs(GraphUser.class).getFirstName(); - } - if (friendToSmashFirstName != null) { - // If the first name of the friend to smash has been set, set the text in the smashPlayerNameTextView - // and hide the progress spinner now that the user's details have been fetched - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } - } - }); - Request.executeBatchAsync(userGraphPathRequest); - } - - // Spawn a new UserImageView, set its bitmap (fetch it from Facebook if it hasn't already been fetched) - // and fire it once the image has been set (and fetched if appropriate) - @SuppressWarnings("unused") - private void spawnImage(final boolean extraImage) { - // Instantiate Random Generator - Random randomGenerator = new Random(System.currentTimeMillis()); - - // 1 in every 5 images should be a celebrity the user should not smash - calculate that here - // Unless it is the first image fired, in which case it should always be the smashable image - boolean shouldSmash = true; - boolean isCoin = false; - if (firstImageFired) { - if (randomGenerator.nextInt(5) == 4 && firstImageFired) { - shouldSmash = false; - } else if (randomGenerator.nextInt(8) == 7 && firstImageFired) { - isCoin = true; - } - } else if (!firstImageFired) { - shouldSmash = true; - firstImageFired = true; - } - - // Create a new ImageView with a user to smash - final UserImageView userImageView = (new UserImageView(getActivity(), shouldSmash, isCoin)); - userImageView.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (userImageView.shouldSmash()) { - // Smashed the right image ... - - if (userImageView.isCoin()) { - coinsCollected++; - } else { - // Increment the score - setScore(getScore() + 1 + userImageView.getExtraPoints()); - } - - // Hide the userImageView - v.setVisibility(View.GONE); - - // Remove it from the userImageViews List in this GameFragment - getUserImageViews().remove(v); - } else { - // Smashed the wrong image ... - wrongImageSmashed(userImageView); - } - return false; - } - }); - userImageView.setLayoutParams(new LinearLayout.LayoutParams(iconWidth, iconWidth)); - gameFrame.addView(userImageView); - userImageViews.add(userImageView); - - // Set the bitmap of the userImageView ... - if (userImageView.shouldSmash()) { - // The user should smash this image, so set the correct image - if (userImageView.isCoin()) { - setCoinImageAndFire(userImageView, extraImage); - } else { - if (isSocialMode) { - // User is logged into FB ... - if (friendToSmashBitmap != null) { - // Bitmap for the friend to smash has already been retrieved, so use this - setFriendImageAndFire(userImageView, friendToSmashBitmap, extraImage); - } else { - // Otherwise, the Bitmap for the friend to smash hasn't been retrieved, so retrieve it and set it - - // Show the spinner while retrieving - progressContainer.setVisibility(View.VISIBLE); - - // If a friend has been passed in, use that attribute, otherwise use the random friend that has been selected - final String friendToSmashID = friendToSmashIDProvided != null ? friendToSmashIDProvided : - ((FriendSmashApplication) getActivity().getApplication()).getFriend(friendToSmashIndex).getId(); - - // Fetch the bitmap and fire the image - fetchFriendBitmapAndFireImages(userImageView, friendToSmashID, extraImage); - } - } else { - // User is not logged into FB ... - setCelebImageAndFire(userImageView, celebToSmashIndex, extraImage); - } - } - } else { - // The user should not smash this image, so set it to a random celebrity (but not the one being shown if it's the non-social game) - int randomCelebToSmashIndex; - do { - randomCelebToSmashIndex = randomGenerator.nextInt(CELEBS.length); - } while (randomCelebToSmashIndex == celebToSmashIndex); - setCelebImageAndFire(userImageView, randomCelebToSmashIndex, extraImage); - } - } - - // Logic when the user smashes this image, but it turns out to be the wrong image - i.e. - // it's shouldSmash boolean is false - private void wrongImageSmashed(final UserImageView userImageView) { - // Set this flag for checking in the animation ended logic - userImageView.setWrongImageSmashed(true); - - // Stop all movement (not rotation) animations for this UserImageView - userImageView.stopMovementAnimations(); - - // Stop all animations for all other visible UserImageViews (and therefore hide them) - hideAllUserImageViewsExcept(userImageView); - - // Scale the image up - userImageView.scaleUp(new AnimatorListener() { - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - // Cancel rotation and exit to home screen - userImageView.stopRotationAnimation(); - setLives(0); - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationStart(Animator animation) { - } - }); - - // Ensure this UserImageView is in front - getGameFrame().bringChildToFront(userImageView); - } - - private void fetchFriendBitmapAndFireImages(final UserImageView userImageView, final String friendToSmashID, final boolean extraImage) { - AsyncTask.execute(new Runnable() { - public void run() { - - URL bitmapURL; - try { - bitmapURL = new URL("http://graph.facebook.com/" + friendToSmashID + - "/picture?redirect=false&width=" + iconWidth + "&height=" + iconWidth); - InputStream bitmapURLInputStream = bitmapURL.openConnection().getInputStream(); - BufferedReader r = new BufferedReader(new InputStreamReader(bitmapURLInputStream)); - StringBuilder bitmapURLString = new StringBuilder(); - String line; - while ((line = r.readLine()) != null) { - bitmapURLString.append(line); - } - try { - - JSONObject obj = new JSONObject(bitmapURLString.toString()); - JSONObject jsonObject = obj.getJSONObject("data"); - String imageURLString = jsonObject.getString("url"); - URL imageURL = new URL(imageURLString); - friendToSmashBitmap = BitmapFactory.decodeStream(imageURL.openConnection().getInputStream()); - } catch (Exception e) { - Log.e(FriendSmashApplication.TAG, e.toString()); - closeAndShowError(getResources().getString(R.string.error_fetching_friend_bitmap)); - } - } catch (Exception e) { - // Unknown error - Log.e(FriendSmashApplication.TAG, e.toString()); - } - - uiHandler.post(new Runnable() { - @Override - public void run() { - // Hide the spinner after retrieving - progressContainer.setVisibility(View.INVISIBLE); - - if (friendToSmashBitmap != null) { - setFriendImageAndFire(userImageView, friendToSmashBitmap, extraImage); - - // Also set the lastFriendSmashedID and lastFriendSmashedName in the application - ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedID(friendToSmashID); - ((FriendSmashApplication) getActivity().getApplication()).setLastFriendSmashedName(friendToSmashFirstName); - } else { - closeAndShowError(getResources().getString(R.string.error_fetching_friend_bitmap)); - } - } - }); - } - }); - } - - // 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(); - } - - // Close the game and show the specified FacebookRequestException to the user - private void closeAndHandleError(FacebookRequestError error) { - // Store the FacebookRequestError in the FacebookApplication before closing out this GameFragment so that - // it is shown to the user once exited - ((FriendSmashApplication) getActivity().getApplication()).setGameFragmentFBRequestError(error); - - getActivity().setResult(Activity.RESULT_CANCELED); - getActivity().finish(); - } - - // Hides all the UserImageViews currently on display - called when a bomb is detonated - void hideAllUserImageViews() { - Iterator userImageViewsIterator = userImageViews.iterator(); - while (userImageViewsIterator.hasNext()) { - UserImageView currentUserImageView = (UserImageView) userImageViewsIterator.next(); - currentUserImageView.setVisibility(View.GONE); - } - } - - // Hide all the UserImageViews currently on display except the one specified - // Called when the user has smashed the wrong image so that this is displayed large - void hideAllUserImageViewsExcept(UserImageView userImageView) { - // Stop new animations - timerHandler.removeCallbacks(fireImageTask); - - // Stop animations on all existing visible UserImageViews (which will hide them automatically) - Iterator userImageViewsIterator = userImageViews.iterator(); - while (userImageViewsIterator.hasNext()) { - UserImageView currentUserImageView = (UserImageView) userImageViewsIterator.next(); - if (!currentUserImageView.equals(userImageView)) { - currentUserImageView.setVisibility(View.GONE); - } - } - } - - // Mark all the existing visible UserImageViews as void (called when the game is paused) - private void markAllUserImageViewsAsVoid() { - Iterator userImageViewsIterator = userImageViews.iterator(); - while (userImageViewsIterator.hasNext()) { - UserImageView currentUserImageView = (UserImageView) userImageViewsIterator.next(); - currentUserImageView.setVoid(true); - } - } - - @Override - public void onPause() { - super.onPause(); - - // Stop the firing images - stopTheFiringImages(); - } - - @SuppressWarnings("unused") - @Override - public void onResume() { - super.onResume(); - - // Stop any firing images (even though this is called in onPause, there might be new firing images - // if they were pending while onPause was called - stopTheFiringImages(); - - if (!imagesStartedFiring) { - // Fire first image - if (isSocialMode) { - // Only fire for the social game if there isn't a first image pending firing - if (!firstImagePendingFiring) { - // ... and also set the firstImagePendingFiring to true - will be set back - // to false later once the images have actually started firing (i.e. all network - // calls have executed) - note, this is only relevant for the social version - firstImagePendingFiring = true; - imagesStartedFiring = true; - fireFirstImage(); - } - } else { - imagesStartedFiring = true; - fireFirstImage(); - } - } - } - - // Stop the firing of all images (and mark the existing ones as void) - called when the game is paused - private void stopTheFiringImages() { - // Mark all existing in flight UserImageViews as void (so they don't affect the user's lives once landed) - markAllUserImageViewsAsVoid(); - - // Stop new animations and indicate that images have not started firing - timerHandler.removeCallbacks(fireImageTask); - imagesStartedFiring = false; - } - - // Get the current score - int getScore() { - return score; - } - - // Set the score and if the score is divisible by 10, spawn more images ... - // ... the higher the score, the more images that will be spawned - void setScore(int score) { - this.score = score; - - // Update the scoreTextView - scoreTextView.setText("Score: " + score); - - // If they start scoring well, spawn more images - if (score > 0 && score % 10 == 0) { - // Every multiple of 10, spawn extra images ... - for (int i=0; i getUserImageViews() { - return userImageViews; - } -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/HomeActivity.java b/friendsmash_complete/src/com/facebook/android/friendsmash/HomeActivity.java deleted file mode 100644 index b06e0fc..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/HomeActivity.java +++ /dev/null @@ -1,624 +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.android.friendsmash; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.widget.Toast; - -import com.facebook.AppEventsLogger; -import com.facebook.FacebookRequestError; -import com.facebook.Request; -import com.facebook.RequestBatch; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.SessionState; -import com.facebook.UiLifecycleHelper; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphUser; -import com.facebook.widget.LoginButton; -import com.parse.LogInCallback; -import com.parse.ParseException; -import com.parse.ParseFacebookUtils; -import com.parse.ParseUser; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - * Entry point for the app that represents the home screen with the Play button etc. and - * also the login screen for the social version of the app - these screens will switch - * within this activity using Fragments. - */ -public class HomeActivity extends FragmentActivity { - - // Tag used when logging messages - private static final String TAG = HomeActivity.class.getSimpleName(); - - // Uri used in handleError() below - private static final Uri M_FACEBOOK_URL = Uri.parse("http://m.facebook.com"); - - // Declare the UiLifecycleHelper for Facebook session management - private UiLifecycleHelper fbUiLifecycleHelper; - - // App events logger - private FriendSmashEventsLogger eventsLogger; - - // Fragment attributes - private static final int FB_LOGGED_OUT_HOME = 0; - private static final int HOME = 1; - private static final int FRAGMENT_COUNT = HOME +1; - private Fragment[] fragments = new Fragment[FRAGMENT_COUNT]; - - // Boolean recording whether the activity has been resumed so that - // the logic in onSessionStateChange is only executed if this is the case - private boolean isResumed = false; - - // Constructor - public HomeActivity() { - super(); - } - - // Getter for the fbUiLifecycleHelper - public UiLifecycleHelper getFbUiLifecycleHelper() { - return fbUiLifecycleHelper; - } - - // Getter for the app eventsLogger - public FriendSmashEventsLogger getEventsLogger() { return eventsLogger; } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Instantiate the fbUiLifecycleHelper and call onCreate() on it - fbUiLifecycleHelper = new UiLifecycleHelper(this, new Session.StatusCallback() { - @Override - public void call(Session session, SessionState state, - Exception exception) { - // Add code here to accommodate session changes - Log.d(TAG, "Session state changed: " + state + " permissions: " + session.getPermissions()); - - if (exception != null) - Log.e(TAG, "UiLifecycleHelper exception: " + exception.getMessage()); - - updateView(); - if (fragments[HOME] != null) { - if (state.isOpened()) { - if (state.equals(SessionState.OPENED_TOKEN_UPDATED)) { - // Only callback if the opened token has been updated - i.e. the user - // has provided write permissions - ((HomeFragment) fragments[HOME]).tokenUpdated(); - - Log.d(TAG, "Session state changed: " + state + " permissions: " + session.getPermissions()); - Log.d(TAG, "Session state changed2222: " + state + " permissions: " + Session.getActiveSession().getPermissions()); - - } - } - } - } - }); - fbUiLifecycleHelper.onCreate(savedInstanceState); - eventsLogger = new FriendSmashEventsLogger(fbUiLifecycleHelper.getAppEventsLogger()); - - setContentView(R.layout.home); - - FragmentManager fm = getSupportFragmentManager(); - fragments[FB_LOGGED_OUT_HOME] = fm.findFragmentById(R.id.fbLoggedOutHomeFragment); - fragments[HOME] = fm.findFragmentById(R.id.homeFragment); - - FragmentTransaction transaction = fm.beginTransaction(); - for(int i = 0; i < fragments.length; i++) { - transaction.hide(fragments[i]); - } - transaction.commit(); - - // Restore the logged-in user's information if it has been saved and the existing data in the application - // has been destroyed (i.e. the app hasn't been used for a while and memory on the device is low) - // - only do this if the session is open for the social version only - if (FriendSmashApplication.IS_SOCIAL) { - // loggedIn - if (savedInstanceState != null) { - boolean loggedInState = savedInstanceState.getBoolean(FriendSmashApplication.getLoggedInKey(), false); - ((FriendSmashApplication)getApplication()).setLoggedIn(loggedInState); - - if ( ((FriendSmashApplication)getApplication()).isLoggedIn() && - ( ((FriendSmashApplication)getApplication()).getFriends() == null || - ((FriendSmashApplication)getApplication()).getCurrentFBUser() == null) ) { - try { - // currentFBUser - String currentFBUserJSONString = savedInstanceState.getString(FriendSmashApplication.getCurrentFbUserKey()); - if (currentFBUserJSONString != null) { - GraphUser currentFBUser = GraphObject.Factory.create(new JSONObject(currentFBUserJSONString), GraphUser.class); - ((FriendSmashApplication)getApplication()).setCurrentFBUser(currentFBUser); - } - - // friends - ArrayList friendsJSONStringArrayList = savedInstanceState.getStringArrayList(FriendSmashApplication.getFriendsKey()); - if (friendsJSONStringArrayList != null) { - ArrayList friends = new ArrayList(); - Iterator friendsJSONStringArrayListIterator = friendsJSONStringArrayList.iterator(); - while (friendsJSONStringArrayListIterator.hasNext()) { - friends.add(GraphObject.Factory.create(new JSONObject(friendsJSONStringArrayListIterator.next()), GraphUser.class)); - } - ((FriendSmashApplication)getApplication()).setFriends(friends); - } - } catch (JSONException e) { - Log.e(FriendSmashApplication.TAG, e.toString()); - } - } - } - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - // Call onActivityResult on fbUiLifecycleHelper - fbUiLifecycleHelper.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onResumeFragments() { - super.onResumeFragments(); - if (!FriendSmashApplication.IS_SOCIAL) { - showFragment(HOME, false); - } else { - Session session = Session.getActiveSession(); - if (session != null && session.isOpened() && ((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { - showFragment(HOME, false); - } else { - showFragment(FB_LOGGED_OUT_HOME, false); - } - } - } - - @Override - public void onResume() { - super.onResume(); - isResumed = true; - - // Call onResume on fbUiLifecycleHelper - fbUiLifecycleHelper.onResume(); - - // Hide the notification bar - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - - AppEventsLogger.activateApp(this); - } - - @Override - public void onPause() { - super.onPause(); - isResumed = false; - - // Call onPause on fbUiLifecycleHelper - fbUiLifecycleHelper.onPause(); - - AppEventsLogger.deactivateApp(this); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - // Call onSaveInstanceState on fbUiLifecycleHelper - fbUiLifecycleHelper.onSaveInstanceState(outState); - - // Save the logged-in state - outState.putBoolean(FriendSmashApplication.getLoggedInKey(), ((FriendSmashApplication)getApplication()).isLoggedIn()); - - // Save the currentFBUser - if (((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { - outState.putString(FriendSmashApplication.getCurrentFbUserKey(), - ((FriendSmashApplication)getApplication()).getCurrentFBUser().getInnerJSONObject().toString()); - } - - // Save the logged-in user's list of friends - if (((FriendSmashApplication)getApplication()).getFriends() != null) { - outState.putStringArrayList(FriendSmashApplication.getFriendsKey(), - ((FriendSmashApplication)getApplication()).getFriendsAsArrayListOfStrings()); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - - // Call onDestroy on fbUiLifecycleHelper - fbUiLifecycleHelper.onDestroy(); - } - - public void buyBombs() { - // Update bomb and coins count (5 coins per bomb). - FriendSmashApplication app = (FriendSmashApplication) getApplication(); - - // check to see that we have enough coins. - if (app.getCoins() - 5 < 0) { - Toast.makeText(this, "Not enough coins.", Toast.LENGTH_LONG).show(); - return; - } - - app.setBombs(app.getBombs()+1); - app.setCoins(app.getCoins()-5); - - // save inventory values - app.saveInventory(); - - // Reload inventory values in fragment. - loadInventoryFragment(); - } - - private void showFragment(int fragmentIndex, boolean addToBackStack) { - FragmentManager fm = getSupportFragmentManager(); - FragmentTransaction transaction = fm.beginTransaction(); - for (int i = 0; i < fragments.length; i++) { - if (i == fragmentIndex) { - transaction.show(fragments[i]); - } else { - transaction.hide(fragments[i]); - } - } - if (addToBackStack) { - transaction.addToBackStack(null); - } - transaction.commit(); - - // Do other changes depending on the fragment that is now showing - if (FriendSmashApplication.IS_SOCIAL) { - switch (fragmentIndex) { - case FB_LOGGED_OUT_HOME: - // Hide the progressContainer in FBLoggedOutHomeFragment - if (fragments[FB_LOGGED_OUT_HOME] != null && ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]) != null) { - ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer.setVisibility(View.INVISIBLE); - } - // Set the loggedIn attribute - ((FriendSmashApplication)getApplication()).setLoggedIn(false); - break; - case HOME: - // Set the loggedIn attribute - ((FriendSmashApplication)getApplication()).setLoggedIn(true); - break; - } - } - } - - /* Facebook Integration Only ... */ - - // Call back on HomeActivity when the session state changes to update the view accordingly - private void updateView() { - if (isResumed) { - Session session = Session.getActiveSession(); - if (session.isOpened() && !((FriendSmashApplication)getApplication()).isLoggedIn() && fragments[HOME] != null) { - // Not logged in, but should be, so fetch the user information and log in (load the HomeFragment) - fetchUserInformationAndLogin(); - } else if (session.isClosed() && ((FriendSmashApplication)getApplication()).isLoggedIn() && fragments[FB_LOGGED_OUT_HOME] != null) { - // Logged in, but shouldn't be, so load the FBLoggedOutHomeFragment - logout(); - showFragment(FB_LOGGED_OUT_HOME, false); - } - - // Note that error checking for failed logins is done as within an ErrorListener attached to the - // LoginButton within FBLoggedOutHomeFragment - } - } - - // Fetch user information and login (i.e switch to the personalized HomeFragment) - private void fetchUserInformationAndLogin() { - final Session session = Session.getActiveSession(); - if (session != null && session.isOpened()) { - // If the session is open, make an API call to get user information required for the app - - // Show the progress spinner during this network call - if (fragments[FB_LOGGED_OUT_HOME] != null && - ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer != null) { - ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer.setVisibility(View.VISIBLE); - } - - // Create a RequestBatch and add a callback once the batch of requests completes - RequestBatch requestBatch = new RequestBatch(); - - // Get a list of friends who have _not installed_ the game. - Request invitableFriendsRequest = Request.newGraphPathRequest(session, - "/me/invitable_friends", new Request.Callback() { - - @Override - public void onCompleted(Response response) { - - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - handleError(error, true); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Get the result - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - List invitableFriends = new ArrayList(); - if (dataArray.length() > 0) { - // Ensure the user has at least one friend ... - - for (int i=0; i users, Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - handleError(error, true); - } else if (session == Session.getActiveSession()) { - // Set the friends attribute - ((FriendSmashApplication)getApplication()).setFriends(users); - } - } - }); - Bundle params = new Bundle(); - params.putString("fields", "name,first_name,last_name"); - friendsRequest.setParameters(params); - requestBatch.add(friendsRequest); - } - - // Get current logged in user information - Request meRequest = Request.newMeRequest(session, - new Request.GraphUserCallback() { - - @Override - public void onCompleted(GraphUser user, Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - handleError(error, true); - } else if (session == Session.getActiveSession()) { - // Set the currentFBUser attribute - ((FriendSmashApplication)getApplication()).setCurrentFBUser(user); - - // Now save the user into Parse. - saveUserToParse(user, session); - } - } - }); - requestBatch.add(meRequest); - - requestBatch.addCallback(new RequestBatch.Callback() { - - @Override - public void onBatchCompleted(RequestBatch batch) { - if ( ((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { - // Login by switching to the personalized HomeFragment - loadPersonalizedFragment(); - } else { - showError(getString(R.string.error_fetching_profile), true); - } - } - }); - - // Execute the batch of requests asynchronously - requestBatch.executeAsync(); - } - } - - private void saveUserToParse(GraphUser fbUser, Session session) { - ParseFacebookUtils.logIn(fbUser.getId(), session.getAccessToken(), - session.getExpirationDate(), new LogInCallback() { - @Override - public void done(ParseUser parseUser, ParseException err) { - if (parseUser != null) { - // The user has been saved to Parse. - if (parseUser.isNew()) { - // This user was created during this session with Facebook Login. - Log.d(TAG, "ParseUser created."); - - // Call saveInventory() which will save data to Parse if connected. - FriendSmashApplication app = ((FriendSmashApplication)getApplication()); - app.saveInventory(); - } else { - Log.d(TAG, "User exists in Parse. Pull their values: " + parseUser); - - // This user existed before. Call loadInventory() which has logic - // to check Parse if connected. - FriendSmashApplication app = ((FriendSmashApplication)getApplication()); - app.loadInventory(); - } - - loadInventoryFragment(); - } else { - // The user wasn't saved. Check the exception. - Log.d(TAG, "User was not saved to Parse: " + err.getMessage()); - } - } - }); - } - - // Loads the inventory portion of the HomeFragment. - private void loadInventoryFragment() { - Log.d(TAG, "Loading inventory fragment"); - if (isResumed) { - ((HomeFragment)fragments[HOME]).loadInventory(); - } else { - showError(getString(R.string.error_switching_screens), true); - } - } - - // Switches to the personalized HomeFragment as the user has just logged in - private void loadPersonalizedFragment() { - if (isResumed) { - // Personalize the HomeFragment - ((HomeFragment)fragments[HOME]).personalizeHomeFragment(); - - // Load the HomeFragment personalized - showFragment(HOME, false); - } else { - showError(getString(R.string.error_switching_screens), true); - } - } - - void handleError(FacebookRequestError error, boolean logout) { - Log.d(TAG, "handleError: " + error.getErrorMessage()); - - DialogInterface.OnClickListener listener = null; - String dialogBody = null; - - if (error == null) { - dialogBody = getString(R.string.error_dialog_default_text); - } else { - switch (error.getCategory()) { - case AUTHENTICATION_RETRY: - // tell the user what happened by getting the message id, and - // retry the operation later - String userAction = (error.shouldNotifyUser()) ? "" : - getString(error.getUserActionMessageId()); - dialogBody = getString(R.string.error_authentication_retry, userAction); - listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Intent intent = new Intent(Intent.ACTION_VIEW, M_FACEBOOK_URL); - startActivity(intent); - } - }; - break; - - case AUTHENTICATION_REOPEN_SESSION: - // close the session and reopen it. - dialogBody = getString(R.string.error_authentication_reopen); - listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Session session = Session.getActiveSession(); - if (session != null && !session.isClosed()) { - session.closeAndClearTokenInformation(); - } - } - }; - break; - - case PERMISSION: - // request the publish permission - dialogBody = getString(R.string.error_permission); - listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (fragments[HOME] != null) { - ((HomeFragment) fragments[HOME]).setPendingPost(true); - ((HomeFragment) fragments[HOME]).requestPublishPermissions(); - } - } - }; - break; - - case SERVER: - case THROTTLING: - // this is usually temporary, don't clear the fields, and - // ask the user to try again - dialogBody = getString(R.string.error_server); - break; - - case BAD_REQUEST: - // this is likely a coding error, ask the user to file a bug - dialogBody = getString(R.string.error_bad_request, error.getErrorMessage()); - break; - - case CLIENT: - // this is likely an IO error, so tell the user they have a network issue - dialogBody = getString(R.string.network_error); - break; - - case OTHER: - default: - // an unknown issue occurred, this could be a code error, or - // a server side issue, log the issue, and either ask the - // user to retry, or file a bug - dialogBody = getString(R.string.error_unknown, error.getErrorMessage()); - break; - } - } - - new AlertDialog.Builder(this) - .setPositiveButton(R.string.error_dialog_button_text, listener) - .setTitle(R.string.error_dialog_title) - .setMessage(dialogBody) - .show(); - - if (logout) { - logout(); - } - } - - // Show user error message as a toast - void showError(String error, boolean logout) { - Toast.makeText(this, error, Toast.LENGTH_LONG).show(); - if (logout) { - logout(); - } - } - - private void logout() { - Log.d(TAG, "Logging user out."); - - // log user out of Parse - if (ParseUser.getCurrentUser() != null) - ParseUser.logOut(); - - // Close the session, which will cause a callback to show the logout screen - Session.getActiveSession().closeAndClearTokenInformation(); - - // Clear any permissions associated with the LoginButton - LoginButton loginButton = (LoginButton) findViewById(R.id.loginButton); - if (loginButton != null) { - loginButton.clearPermissions(); - } - } - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/HomeFragment.java b/friendsmash_complete/src/com/facebook/android/friendsmash/HomeFragment.java deleted file mode 100644 index ba7854e..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/HomeFragment.java +++ /dev/null @@ -1,1244 +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.android.friendsmash; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.text.TextUtils; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.FrameLayout; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.facebook.FacebookException; -import com.facebook.FacebookOperationCanceledException; -import com.facebook.FacebookRequestError; -import com.facebook.HttpMethod; -import com.facebook.Request; -import com.facebook.RequestBatch; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.SessionDefaultAudience; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphUser; -import com.facebook.widget.FacebookDialog; -import com.facebook.widget.ProfilePictureView; -import com.facebook.widget.WebDialog; - -import org.json.JSONArray; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -/** - * Fragment to be shown once the user is logged in on the social version of the game or - * the start screen for the non-social version of the game - */ -public class HomeFragment extends Fragment { - - interface FriendsLoadedCallback { - void afterFriendsLoaded(); - } - - // Tag used when logging errors - private static final String TAG = HomeFragment.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 of the mainButtonsContainer - private LinearLayout mainButtonsContainer; - - // LinearLayout of the gameOverContainer - private RelativeLayout challengeContainer; - - // LinearLayout of the gameOverContainer - private LinearLayout gameOverContainer; - - // FrameLayout of the progressContainer - private FrameLayout progressContainer; - - // TextView for the You Scored message - private TextView scoredTextView; - - // userImage ProfilePictureView to display the user's profile pic - private ProfilePictureView userImage; - - // profile pic of the user you smashed - private ProfilePictureView youSmashedUserImage; - - // TextView for the user's name - private TextView welcomeTextView; - - private GridView invitesGridView; - private GridView requestsGridView; - - // Buttons ... - private ImageView playButton; - private ImageView scoresButton; - private ImageView challengeButton; - private ImageView challengeRequestToggle; - - private TextView numBombs; - private TextView numCoins; - - // Parameters of a WebDialog that should be displayed - private WebDialog dialog = null; - private String dialogAction = null; - private Bundle dialogParams = null; - - // Boolean indicating whether or not the game over message is displaying - private boolean gameOverMessageDisplaying = false; - - // Boolean indicating if the game has been launched directly from deep linking already - // so that it isn't launched again when the view is created (e.g. on rotation) - private boolean gameLaunchedFromDeepLinking = false; - - // Attributes for posting back to Facebook - private static final List PERMISSIONS = Arrays.asList("publish_actions"); - private static final int AUTH_FRIENDS_PLAY_ACTIVITY_CODE = 101; - private static final int AUTH_FRIENDS_LEADERBOARD_ACTIVITY_CODE = 102; - private static final int AUTH_PUBLISH_ACTIONS_SCORES_ACTIVITY_CODE = 103; - private static final String PENDING_POST_KEY = "pendingPost"; - private boolean pendingPost = false; - - private boolean invitesMode = true; - private List idsToInvite = new ArrayList(); - private List idsToRequest = new ArrayList(); - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setRetainInstance(true); - - application = (FriendSmashApplication) getActivity().getApplication(); - - if (savedInstanceState != null) { - if (savedInstanceState.containsKey("gameOverMessageDisplaying")) - gameOverMessageDisplaying = savedInstanceState.getBoolean("gameOverMessageDisplaying"); - } - } - - @SuppressWarnings("unused") - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - - View v; - - if (!FriendSmashApplication.IS_SOCIAL) { - v = inflater.inflate(R.layout.fragment_home, parent, false); - - } else { - v = inflater.inflate(R.layout.fragment_home_fb_logged_in, parent, false); - - // Set the userImage ProfilePictureView - userImage = (ProfilePictureView) v.findViewById(R.id.userImage); - - // Set the welcomeTextView TextView - welcomeTextView = (TextView)v.findViewById(R.id.welcomeTextView); - - // Personalize this HomeFragment - personalizeHomeFragment(); - - scoresButton = (ImageView)v.findViewById(R.id.scoresButton); - scoresButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onScoresButtonTouched(); - return false; - } - }); - - challengeButton = (ImageView)v.findViewById(R.id.challengeButton); - challengeButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onChallengeButtonTouched(); - return false; - } - }); - - ImageView gameOverChallengeButton = (ImageView)v.findViewById(R.id.gameOverChallengeButton); - gameOverChallengeButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onGameOverChallengeButtonTouched(); - return false; - } - }); - - ImageView gameOverBragButton = (ImageView)v.findViewById(R.id.gameOverBragButton); - gameOverBragButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onGameOverBragButtonTouched(); - return false; - } - }); - - challengeRequestToggle = (ImageView)v.findViewById(R.id.mfsClicker); - challengeRequestToggle.setOnTouchListener(new View.OnTouchListener() { - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (invitesMode) { - invitesMode = false; - challengeRequestToggle.setImageResource(R.drawable.mfs_clicker_request); - invitesGridView.setVisibility(View.INVISIBLE); - requestsGridView.setVisibility(View.VISIBLE); - } else { - invitesMode = true; - challengeRequestToggle.setImageResource(R.drawable.mfs_clicker_invite); - invitesGridView.setVisibility(View.VISIBLE); - requestsGridView.setVisibility(View.INVISIBLE); - } - return false; - } - }); - - invitesGridView = (GridView)v.findViewById(R.id.invitesGridView); - requestsGridView = (GridView)v.findViewById(R.id.requestsGridView); - - requestsGridView.setVisibility(View.INVISIBLE); - - ImageView sendButton = (ImageView)v.findViewById(R.id.sendButton); - sendButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (invitesMode) { - sendDirectedInvite(idsToInvite); - } else { - sendDirectedRequest(idsToRequest); - } - - // hide the challenge view and show the main menu - challengeContainer.setVisibility(View.INVISIBLE); - mainButtonsContainer.setVisibility(View.VISIBLE); - return false; - } - }); - - mainButtonsContainer = (LinearLayout)v.findViewById(R.id.mainButtonsContainer); - challengeContainer = (RelativeLayout)v.findViewById(R.id.challengeContainer); - - // Hide the challengeContainer - challengeContainer.setVisibility(View.INVISIBLE); - } - - numBombs = (TextView)v.findViewById(R.id.numBombs); - numCoins = (TextView)v.findViewById(R.id.numCoins); - loadInventory(); - - ImageView bombButton = (ImageView)v.findViewById(R.id.bombButton); - bombButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - HomeActivity homeActivity = (HomeActivity) getActivity(); - homeActivity.buyBombs(); - return false; - } - }); - - - progressContainer = (FrameLayout)v.findViewById(R.id.progressContainer); - - playButton = (ImageView)v.findViewById(R.id.playButton); - playButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onPlayButtonTouched(); - return false; - } - }); - - gameOverContainer = (LinearLayout)v.findViewById(R.id.gameOverContainer); - youSmashedUserImage = (ProfilePictureView)v.findViewById(R.id.youSmashedUserImage); - scoredTextView = (TextView)v.findViewById(R.id.scoredTextView); - - ImageView gameOverCloseButton = (ImageView)v.findViewById(R.id.gameOverCloseButton); - gameOverCloseButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onGameOverCloseButtonTouched(); - return false; - } - }); - - - // Hide the gameOverContainer - hideGameOverContainer(); - - // Hide the progressContainer - progressContainer.setVisibility(View.INVISIBLE); - - // Restore the state - restoreState(savedInstanceState); - - return v; - } - - // Personalize this HomeFragment (social-version only) - void personalizeHomeFragment() { - if (application.getCurrentFBUser() != null) { - // Personalize this HomeFragment if the currentFBUser has been fetched - - // Set the id for the userImage ProfilePictureView - // that in turn displays the profile picture - userImage.setProfileId(application.getCurrentFBUser().getId()); - // and show the cropped (square) version ... - userImage.setCropped(true); - - // Set the welcomeTextView Textview's text to the user's name - welcomeTextView.setText("Welcome, " + application.getCurrentFBUser().getFirstName()); - } - } - - public void loadInventory() { - FriendSmashApplication app = (FriendSmashApplication)getActivity().getApplication(); - numBombs.setText(String.valueOf(app.getBombs())); - numCoins.setText(String.valueOf(app.getCoins())); - } - - // Restores the state during onCreateView - private void restoreState(Bundle savedInstanceState) { - if (savedInstanceState != null) { - pendingPost = savedInstanceState.getBoolean(PENDING_POST_KEY, false); - } - } - - @Override - public void onPause() { - super.onPause(); - - // Hide the gameOverContainer - //gameOverContainer.setVisibility(View.INVISIBLE); - } - - @Override - public void onResume() { - super.onResume(); - - if (application.getCurrentFBUser() != null && !gameLaunchedFromDeepLinking) { - // As long as the user is logged in and the game hasn't been launched yet - // from deep linking, see if it has been deep linked and launch the game appropriately - Uri target = getActivity().getIntent().getData(); - if (target != null) { - Intent i = new Intent(getActivity(), GameActivity.class); - - // Target is the deep-link Uri, so skip loading this home screen and load the game - // directly with the sending user's picture to smash - String graphRequestIDsForSendingUser = target.getQueryParameter("request_ids"); - String feedPostIDForSendingUser = target.getQueryParameter("challenge_brag"); - - if (graphRequestIDsForSendingUser != null) { - // Deep linked through a Request and use the latest request (request_id) if multiple requests have been sent - String [] graphRequestIDsForSendingUsers = graphRequestIDsForSendingUser.split(","); - String graphRequestIDForSendingUser = graphRequestIDsForSendingUsers[graphRequestIDsForSendingUsers.length-1]; - Bundle bundle = new Bundle(); - bundle.putString("request_id", graphRequestIDForSendingUser); - i.putExtras(bundle); - gameLaunchedFromDeepLinking = true; - startActivityForResult(i, 0); - - // Delete the Request now it has been consumed and processed - Request deleteFBRequestRequest = new Request(Session.getActiveSession(), - graphRequestIDForSendingUser + "_" + application.getCurrentFBUser().getId(), - new Bundle(), - HttpMethod.DELETE, - new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, "Deleting consumed Request failed: " + error.getErrorMessage()); - } else { - Log.i(FriendSmashApplication.TAG, "Consumed Request deleted"); - } - } - }); - Request.executeBatchAsync(deleteFBRequestRequest); - } else if (feedPostIDForSendingUser != null) { - // Deep linked through a feed post, so start the game smashing the user specified by the id attached to the - // challenge_brag parameter - Bundle bundle = new Bundle(); - bundle.putString("user_id", feedPostIDForSendingUser); - i.putExtras(bundle); - gameLaunchedFromDeepLinking = true; - startActivityForResult(i, 0); - } - } else { - // Launched with no deep-link Uri, so just continue as normal and load the home screen - } - - } - - if (!gameLaunchedFromDeepLinking && gameOverMessageDisplaying) { - // The game hasn't just been launched from deep linking and the game over message should still be displaying, so ... - - // Complete the game over logic - completeGameOver(); - } - } - - @Override - public void onStart() { - super.onStart(); - - // If a dialog exists, create a new dialog (as the screen may have rotated so needs - // new dimensions) and show it - if (dialog != null) { - showDialogWithoutNotificationBar(dialogAction, dialogParams); - } - } - - @Override - public void onStop() { - super.onStop(); - - // If a dialog exists and is showing, dismiss it - if (dialog != null) { - dialog.dismiss(); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean(PENDING_POST_KEY, pendingPost); - outState.putBoolean("gameOverMessageDisplaying", gameOverMessageDisplaying); - } - - // Show a dialog prompting the user with an explanation of why we're asking for the - // user_friends permission before we play. - private void askForFriendsForPlay(final Session session) { - // user has already said no once this session. - if (application.hasDeniedFriendPermission()) { - startGame(); - } else { - new AlertDialog.Builder(getActivity()) - .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // User hit OK. Request Facebook friends permission. - requestFriendsPermission(AUTH_FRIENDS_PLAY_ACTIVITY_CODE); - } - }) - .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User hit cancel. Keep track of deny so that we only ask once per session - // and then just play the game. - application.setHasDeniedFriendPermission(true); - startGame(); - } - }) - .setTitle(R.string.with_friends_dialog_title) - .setMessage(R.string.with_friends_dialog_message) - .show(); - } - } - - // Show a dialog prompting the user with an explanation of why we're asking for the - // user_friends permission before we show the leaderboard. - private void askForFriendsForLeaderboard() { - new AlertDialog.Builder(getActivity()) - .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // User hit OK. Request Facebook friends permission. - requestFriendsPermission(AUTH_FRIENDS_LEADERBOARD_ACTIVITY_CODE); - } - }) - .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User hit cancel. - // do nothing. - } - }) - .setTitle(R.string.leaderboard_dialog_title) - .setMessage(R.string.leaderboard_dialog_message) - .show(); - } - - - // Show a dialog prompting the user with an explanation of why we're asking for the - // publish_actions permission in order to save their scores. - private void askForPublishActionsForScores() { - new AlertDialog.Builder(getActivity()) - .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // User hit OK. Request Facebook friends permission. - requestPublishPermissions(); - } - }) - .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User hit cancel. - // Hide the gameOverContainer - hideGameOverContainer(); - } - }) - .setTitle(R.string.publish_scores_dialog_title) - .setMessage(R.string.publish_scores_dialog_message) - .show(); - } - - // Called when the Play button is touched - private void onPlayButtonTouched() { - if (application.IS_SOCIAL == true) { - - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - - // check to see that the user granted the user_friends permission. - List permissions = session.getPermissions(); - if (!permissions.contains("user_friends")) { - // the user didn't grant this permission, so we need to prompt them. - askForFriendsForPlay(session); - return; - } - - if (application.getFriends() != null && application.getFriends().size() <= 0) { - ((HomeActivity)getActivity()).showError("You don't have any friends to smash!", false); - } else { - startGame(); - } - } else { - startGame(); - } - } - - private void startGame() { - Intent i = new Intent(getActivity(), GameActivity.class); - Bundle bundle = new Bundle(); - bundle.putInt("num_bombs", ((FriendSmashApplication) getActivity().getApplication()).getBombs()); - i.putExtras(bundle); - startActivityForResult(i, 0); - } - - // Called when the Challenge button is touched - private void onChallengeButtonTouched() { - sendCustomChallenge(); - } - - // Send a request to a specific player(s) - private void sendDirectedInvite(List invitableTokens) { - Bundle params = new Bundle(); - params.putString("message", "Come join me in the friend smash times!"); - params.putString("to", TextUtils.join(",", invitableTokens)); - showDialogWithoutNotificationBar("apprequests", params); - } - - // Send a request to a specific player(s) - private void sendDirectedRequest(List fbUIDs) { - Bundle params = new Bundle(); - params.putString("message", "I just scored " + application.getScore() + "! Can you beat it?"); - params.putString("to", TextUtils.join(",", fbUIDs)); - showDialogWithoutNotificationBar("apprequests", params); - } - - // Called when the Scores button is touched - private void onScoresButtonTouched() { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - List permissions = session.getPermissions(); - - // check to see that the user granted the user_friends permission. - if (!permissions.contains("user_friends")) { - // the user didn't grant this permission, so we need to prompt them. - askForFriendsForLeaderboard(); - return; - } else { - Intent i = new Intent(getActivity(), ScoreboardActivity.class); - startActivityForResult(i, 0); - } - } - - private void onGameOverChallengeButtonTouched() { - sendDirectedRequest(Arrays.asList(application.getLastFriendSmashedID())); - } - - private void onGameOverBragButtonTouched() { - sendBrag(); - } - - private void onGameOverCloseButtonTouched() { - // check if the user wants to post their score to facebook - // which requires the publish_actions permissions - - if (!FriendSmashApplication.IS_SOCIAL) { - hideGameOverContainer(); - return; - } - - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - List permissions = session.getPermissions(); - - // check to see that the user granted the publish_actions permission. - if (!permissions.contains("publish_actions")) { - // the user didn't grant this permission, so we need to prompt them. - askForPublishActionsForScores(); - return; - } else { - // Save score and hide the gameOverContainer - postScore(); - hideGameOverContainer(); - } - } - - private void showGameOverContainer() { - gameOverContainer.setVisibility(View.VISIBLE); - gameOverMessageDisplaying = true; - } - - private void hideGameOverContainer() { - gameOverContainer.setVisibility(View.INVISIBLE); - gameOverMessageDisplaying = false; - } - - private void loadInvitableFriendsForInvites() { - - final List invitableFriends; - if (application.getInvitableFriends().size() > 8) { - // Truncating list to first 8 to simplify our UI. - invitableFriends = application.getInvitableFriends().subList(0, 8); - } else { - invitableFriends = application.getInvitableFriends(); - - } - - final InviteUserArrayAdapter adapter = new InviteUserArrayAdapter(getActivity(), - invitableFriends); - invitesGridView.setAdapter(adapter); - - invitesGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, final View view, - int position, long id) { - - JSONObject clickedUser = invitableFriends.get(position); - String invitableToken = clickedUser.optString("id"); - - // items act as toggles. so check to see if item exists. if it does - // then remove. otherwise, add it. - if (idsToInvite.contains(invitableToken)) { - idsToInvite.remove(invitableToken); - } else { - idsToInvite.add(invitableToken); - } - } - }); - } - - private void loadFriendsForRequests() { - - // assumes friends have been loaded - List friends = application.getFriends(); - - // arbitrarily truncating the list of friends at 8 to simplify this a bit. - if (friends.size() > 8 ) - friends = friends.subList(0, 8); - - final RequestUserArrayAdapter adapter = new RequestUserArrayAdapter(getActivity(), - friends); - requestsGridView.setAdapter(adapter); - - requestsGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, final View view, - int position, long id) { - - GraphUser clickedUser = application.getFriends().get(position); - String uid = clickedUser.getId(); - - // items act as toggles. so check to see if item exists. if it does - // then remove. otherwise, add it. - if (idsToRequest.contains(uid)) { - idsToRequest.remove(uid); - } else { - idsToRequest.add(uid); - } - } - - }); - - } - - /* - * Now that user_friends is granted, load /me/invitable_friends to get - * friends who have not installed the game. Also load /me/friends which - * returns friends that have installed the game (if using Platform v2.0). - * - */ - private void loadFriendsFromFacebook(final FriendsLoadedCallback callback) { - final Session session = Session.getActiveSession(); - - RequestBatch requestBatch = new RequestBatch(); - - // Get a list of friends who have _not installed_ the game. - Request invitableFriendsRequest = Request.newGraphPathRequest(session, - "/me/invitable_friends", new Request.Callback() { - - @Override - public void onCompleted(Response response) { - - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - //handleError(error, true); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Get the result - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - List invitableFriends = new ArrayList(); - if (dataArray.length() > 0) { - // Ensure the user has at least one friend ... - - for (int i=0; i users, Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - //handleError(error, true); - } else if (session == Session.getActiveSession()) { - // Set the friends attribute - application.setFriends(users); - callback.afterFriendsLoaded(); - } - } - }); - - Bundle params = new Bundle(); - params.putString("fields", "id,first_name"); - friendsRequest.setParameters(params); - requestBatch.add(friendsRequest); - - // Execute the batch of requests asynchronously - requestBatch.executeAsync(); - } - - /* - * Called when and Activity returns. Checks for the following scenarios: - * - * == Returning from a Facebook dialog asking for the user_friends permission after the user hit - * the Play button. - * - * == Returning from a Facebook dialog asking for the user_friends permission after the user hit - * the Leaderbaord button. - * - * == Returning from a Facebook dialog asking for the publish_actions permission after the user hit - * the close button on the Game Over dialog. - * - * == Returns from a finished game - test status with resultCode and if successfully ended, update - * their score and complete the game over process, otherwise show an error if there is one - * - */ - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == AUTH_FRIENDS_PLAY_ACTIVITY_CODE) { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - session.onActivityResult(getActivity(), requestCode, resultCode, data); - - if (session.getPermissions().contains("user_friends")) { - loadFriendsFromFacebook(new FriendsLoadedCallback() { - - @Override - public void afterFriendsLoaded() { - startGame(); - } - - }); - } else { - application.setHasDeniedFriendPermission(true); - startGame(); - } - } else if (requestCode == AUTH_FRIENDS_LEADERBOARD_ACTIVITY_CODE) { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - session.onActivityResult(getActivity(), requestCode, resultCode, data); - - if (session.getPermissions().contains("user_friends")) { - loadFriendsFromFacebook(new FriendsLoadedCallback() { - - @Override - public void afterFriendsLoaded() { - Intent i = new Intent(getActivity(), ScoreboardActivity.class); - startActivityForResult(i, 0); - } - - }); - } else { - // do nothing - } - - } else if (requestCode == AUTH_PUBLISH_ACTIONS_SCORES_ACTIVITY_CODE) { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - session.onActivityResult(getActivity(), requestCode, resultCode, data); - - if (session.getPermissions().contains("publish_actions")) { - postScore(); - } - - // Hide the gameOverContainer - hideGameOverContainer(); - - } else if (resultCode == Activity.RESULT_OK && data != null) { - // Finished a game - // Get the parameters passed through including the score - Bundle bundle = data.getExtras(); - application.setScore(bundle.getInt("score")); - - // Save coins and bombs data to parse - int coinsCollected = (bundle.getInt("coins_collected")); - application.setCoinsCollected(coinsCollected); - if (coinsCollected > 0) { - application.setCoins(application.getCoins()+coinsCollected); - } - int bombsUsed = (bundle.getInt("bombs_used")); - if (bombsUsed > 0) { - application.setBombs(application.getBombs()-bombsUsed); - } - - // Save inventory values - application.saveInventory(); - - // Reload inventory values - loadInventory(); - - // Update the UI - completeGameOver(); - - // log GAME_PLAYED event - ((HomeActivity)getActivity()).getEventsLogger().logGamePlayedEvent(application.getScore()); - - } else if (resultCode == Activity.RESULT_FIRST_USER && data != null) { - // Came from the ScoreboardFragment, so start a game with the specific user who has been clicked - Intent i = new Intent(getActivity(), GameActivity.class); - Bundle bundle = new Bundle(); - bundle.putString("user_id", data.getStringExtra("user_id")); - i.putExtras(bundle); - startActivityForResult(i, 0); - } else if (resultCode == Activity.RESULT_CANCELED && data != null) { - Bundle bundle = data.getExtras(); - ((HomeActivity)getActivity()).showError(bundle.getString("error"), false); - } else if (resultCode == Activity.RESULT_CANCELED && - ((FriendSmashApplication) getActivity().getApplication()).getGameFragmentFBRequestError() != null) { - ((HomeActivity)getActivity()).handleError( - ((FriendSmashApplication) getActivity().getApplication()).getGameFragmentFBRequestError(), - false); - ((FriendSmashApplication) getActivity().getApplication()).setGameFragmentFBRequestError(null); - } - } - - // Start a Game with a specified user id (called from the ScoreboardFragment) - void startGame(String userId) { - Intent i = new Intent(getActivity(), GameActivity.class); - Bundle bundle = new Bundle(); - bundle.putString("user_id", userId); - bundle.putInt("num_bombs", ((FriendSmashApplication) getActivity().getApplication()).getBombs()); - i.putExtras(bundle); - startActivityForResult(i, 0); - } - - // Complete the game over process - private void completeGameOver() { - // Set the scoreboardEntriesList to null so that the scoreboard is refreshed - // now that the player has played another game in case they have a higher score or - // any of their friends have a higher score - application.setScoreboardEntriesList(null); - - if (FriendSmashApplication.IS_SOCIAL) { - youSmashedUserImage.setProfileId(application.getLastFriendSmashedID()); - youSmashedUserImage.setCropped(true); - } else { - youSmashedUserImage.setVisibility(View.INVISIBLE); - } - - if (application.getScore() >= 0) { - scoredTextView.setText("You smashed " + application.getLastFriendSmashedName() + - " " + application.getScore() + (application.getScore() == 1 ? " time!" : " times!") + - "\n" + "Collected " + application.getCoinsCollected() + - (application.getCoinsCollected() == 1 ? " coin!" : " coins!")); - } - else { - scoredTextView.setText(getResources().getString(R.string.no_score)); - } - - // Show the gameOverContainer - showGameOverContainer(); - - } - - - /* Facebook Integration */ - - // Pop up a request dialog for the user to invite their friends to smash them back in Friend Smash - private void sendChallenge() { - Bundle params = new Bundle(); - - // Uncomment following link once uploaded on Google Play for deep linking - // params.putString("link", "https://play.google.com/store/apps/details?id=com.facebook.android.friendsmash"); - - // 1. No additional parameters provided - enables generic Multi-friend selector - params.putString("message", "I just smashed " + application.getScore() + " friends! Can you beat it?"); - - // 2. Optionally provide a 'to' param to direct the request at a specific user -// params.putString("to", "515768651"); - - // 3. Suggest friends the user may want to request - could be game specific - // e.g. players you are in a match with, or players who recently played the game etc. - // Normally this won't be hardcoded as follows but will be context specific -// String [] suggestedFriends = { -// "695755709", -// "685145706", -// "569496010", -// "286400088", -// "627802916", -// }; -// params.putString("suggestions", TextUtils.join(",", suggestedFriends)); -// - // Show FBDialog without a notification bar - showDialogWithoutNotificationBar("apprequests", params); - } - - // Pop up a filtered request dialog for the user to invite their friends that have Android devices - // to smash them back in Friend Smash - private void sendFilteredChallenge() { - // Okay, we're going to filter our friends by their device, we're looking for friends with an Android device - - // Show the progressContainer during the network call - progressContainer.setVisibility(View.VISIBLE); - - // Get a list of the user's friends' names and devices - final Session session = Session.getActiveSession(); - Request friendDevicesGraphPathRequest = Request.newGraphPathRequest(session, "me/friends", new Request.Callback() { - @Override - public void onCompleted(Response response) { - // Hide the progressContainer now that the network call has completed - progressContainer.setVisibility(View.INVISIBLE); - - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - ((HomeActivity)getActivity()).handleError(error, false); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Get the result - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - if (dataArray.length() > 0) { - // Ensure the user has at least one friend ... - - // Store the filtered friend ids in the following List - ArrayList filteredFriendIDs = new ArrayList(); - - for (int i=0; i validSuggestedFriends = new ArrayList(); - - // So, we loop through each suggested friend - for (String suggestedFriend : suggestedFriends) - { - // If they are on our device filtered list, we know they have an Android device - if (filteredFriendIDs.contains(suggestedFriend)) - { - // So we can call them valid - validSuggestedFriends.add(suggestedFriend); - } - } - params.putString("suggestions", TextUtils.join(",", validSuggestedFriends.toArray(new String[validSuggestedFriends.size()]))); - - // Show FBDialog without a notification bar - showDialogWithoutNotificationBar("apprequests", params); - } - } - } - } - }); - // Pass in the fields as extra parameters, then execute the Request - Bundle extraParamsBundle = new Bundle(); - extraParamsBundle.putString("fields", "name,devices"); - friendDevicesGraphPathRequest.setParameters(extraParamsBundle); - Request.executeBatchAsync(friendDevicesGraphPathRequest); - } - - private void sendCustomChallenge() { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - - // check to see that the user granted the user_friends permission. - List permissions = session.getPermissions(); - if (!permissions.contains("user_friends")) { - // if the user hasn't granted user_friends, we'll just fallback - // to showing the request dialog without customization. - sendChallenge(); - } else { - loadInvitableFriendsForInvites(); - loadFriendsForRequests(); - - // Hide the buttons container and show the challenge container - mainButtonsContainer.setVisibility(View.INVISIBLE); - challengeContainer.setVisibility(View.VISIBLE); - } - } - - // Pop up a feed dialog for the user to brag to their friends about their score and to offer - // them the opportunity to smash them back in Friend Smash - private void sendBrag() { - // This function will invoke the Feed Dialog to post to a user's Timeline and News Feed - // It will attempt to use the Facebook Native Share dialog - // If that's not supported we'll fall back to the web based dialog. - - GraphUser currentFBUser = application.getCurrentFBUser(); - - // This first parameter is used for deep linking so that anyone who clicks the link will start smashing this user - // who sent the post - String link = "https://apps.facebook.com/friendsmashsample/?challenge_brag="; - if (currentFBUser != null) { - link += currentFBUser.getId(); - } - - // Define the other parameters - String name = "Checkout my Friend Smash greatness!"; - String caption = "Come smash me back!"; - String description = "I just scored " + application.getScore() + "! Can you beat my score?"; - String picture = "http://www.friendsmash.com/images/logo_large.jpg"; - - if (FacebookDialog.canPresentShareDialog(getActivity(), FacebookDialog.ShareDialogFeature.SHARE_DIALOG)) { - // Create the Native Share dialog - FacebookDialog shareDialog = new FacebookDialog.ShareDialogBuilder(getActivity()) - .setLink(link) - .setName(name) - .setCaption(caption) - .setPicture(picture) - .build(); - - // Show the Native Share dialog - ((HomeActivity)getActivity()).getFbUiLifecycleHelper().trackPendingDialogCall(shareDialog.present()); - } else { - // Prepare the web dialog parameters - Bundle params = new Bundle(); - params.putString("link", link); - params.putString("name", caption); - params.putString("caption", caption); - params.putString("description", description); - params.putString("picture", picture); - - // Show FBDialog without a notification bar - showDialogWithoutNotificationBar("feed", params); - } - } - - // Show a dialog (feed or request) without a notification bar (i.e. full screen) - private void showDialogWithoutNotificationBar(String action, Bundle params) { - // Create the dialog - dialog = new WebDialog.Builder(getActivity(), Session.getActiveSession(), action, params).setOnCompleteListener( - new WebDialog.OnCompleteListener() { - - @Override - public void onComplete(Bundle values, FacebookException error) { - if (error != null && !(error instanceof FacebookOperationCanceledException)) { - ((HomeActivity)getActivity()).showError(getResources().getString(R.string.network_error), false); - } - dialog = null; - dialogAction = null; - dialogParams = null; - } - }).build(); - - // Hide the notification bar and resize to full screen - Window dialog_window = dialog.getWindow(); - dialog_window.setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - - // Store the dialog information in attributes - dialogAction = action; - dialogParams = params; - - // Show the dialog - dialog.show(); - } - - // Called when the session state has changed - void tokenUpdated() { - // Optional place to take action after the token has been updated (typically after a new permission has - // been granted) - } - - void requestPublishPermissions() { - Log.d(TAG, "Requesting publish permissions."); - final Session session = Session.getActiveSession(); - if (session != null) { - Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, PERMISSIONS) - // demonstrate how to set an audience for the publish permissions, - // if none are set, this defaults to FRIENDS - .setDefaultAudience(SessionDefaultAudience.FRIENDS) - .setRequestCode(AUTH_PUBLISH_ACTIONS_SCORES_ACTIVITY_CODE); - session.requestNewPublishPermissions(newPermissionsRequest); - } - } - - private void requestFriendsPermission(int requestCode) { - Log.d(TAG, "Requesting friends permissions."); - Session.NewPermissionsRequest newFriendsPermissionsRequest = new Session.NewPermissionsRequest(this, "user_friends") - .setRequestCode(requestCode); - Session.getActiveSession().requestNewReadPermissions(newFriendsPermissionsRequest); - - } - - // Post score to Facebook - private void postScore() { - final int score = application.getScore(); - if (score > 0) { - // Only post the score if they smashed at least one friend! - - // Post the score to FB (for score stories and distribution) - Bundle fbParams = new Bundle(); - fbParams.putString("score", "" + score); - Request postScoreRequest = new Request(Session.getActiveSession(), - "me/scores", - fbParams, - HttpMethod.POST, - new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, "Posting Score to Facebook failed: " + error.getErrorMessage()); - ((HomeActivity)getActivity()).handleError(error, false); - } else { - Log.i(FriendSmashApplication.TAG, "Score posted successfully to Facebook"); - } - } - }); - Request.executeBatchAsync(postScoreRequest); - } - } - - // Getters & Setters - - public boolean isPendingPost() { - return pendingPost; - } - - public void setPendingPost(boolean pendingPost) { - this.pendingPost = pendingPost; - } - - - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/InviteUserArrayAdapter.java b/friendsmash_complete/src/com/facebook/android/friendsmash/InviteUserArrayAdapter.java deleted file mode 100644 index 8dc69d0..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/InviteUserArrayAdapter.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.facebook.android.friendsmash; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -import org.json.JSONObject; - -import java.io.InputStream; -import java.util.List; - -public class InviteUserArrayAdapter extends ArrayAdapter { - private final Context context; - private final List invitableFriends; - private ImageView profilePicView; - - public InviteUserArrayAdapter(Context context, List invitableFriends) { - super(context, R.layout.invite_list_item_view, invitableFriends); - this.context = context; - this.invitableFriends = invitableFriends; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - View listItemView = inflater.inflate(R.layout.invite_list_item_view, parent, false); - - profilePicView = (ImageView) listItemView.findViewById(R.id.inviteListItemProfilePic); - TextView nameView = (TextView) listItemView.findViewById(R.id.inviteListItemName); - final ImageView checkBox = (ImageView) listItemView.findViewById(R.id.inviteListItemCheckbox); - - JSONObject currentUser = invitableFriends.get(position); - - JSONObject pictureJson = currentUser.optJSONObject("picture") - .optJSONObject("data"); - new ImageDownloader(profilePicView).execute(pictureJson.optString("url")); - - nameView.setText(currentUser.optString("first_name")); - - checkBox.setOnTouchListener(new View.OnTouchListener() { - boolean checked = false; - - @Override - public boolean onTouch(View v, MotionEvent event) { - // toggle image - if (checked) { - checked = false; - checkBox.setImageResource(R.drawable.checkbox_cold); - } else { - checked = true; - checkBox.setImageResource(R.drawable.checkbox_hot); - } - return false; - } - }); - - return listItemView; - } - - class ImageDownloader extends AsyncTask { - ImageView bmImage; - - public ImageDownloader(ImageView bmImage) { - this.bmImage = bmImage; - } - - protected Bitmap doInBackground(String... urls) { - String url = urls[0]; - Bitmap mIcon = null; - try { - InputStream in = new java.net.URL(url).openStream(); - mIcon = BitmapFactory.decodeStream(in); - } catch (Exception e) { - Log.e("Error", e.getMessage()); - } - return mIcon; - } - - protected void onPostExecute(Bitmap result) { - bmImage.setImageBitmap(result); - } - } -} - diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardActivity.java b/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardActivity.java deleted file mode 100644 index 5cc01dc..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardActivity.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.android.friendsmash; - -import android.support.v4.app.Fragment; - -/** - * Activity used once a user opens the Facebook scoreboard - all logic - * is within ScoreboardFragment - */ -public class ScoreboardActivity extends SingleFragmentActivity { - - @Override - protected Fragment createFragment() { - return new ScoreboardFragment(); - } - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardEntry.java b/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardEntry.java deleted file mode 100644 index e5bd973..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/ScoreboardEntry.java +++ /dev/null @@ -1,66 +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.android.friendsmash; - -/** - * Class representing an individual scoreboard entry - */ -public class ScoreboardEntry implements Comparable { - - // Attributes for a ScoreboardEntry - private String id; - private String name; - private int score; - - public ScoreboardEntry (String id, String name, int score) { - setId(id); - setName(name); - setScore(score); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getScore() { - return score; - } - - public void setScore(int score) { - this.score = score; - } - - @Override - public int compareTo(ScoreboardEntry another) { - // Returns a negative integer, zero, or a positive integer as this object - // is less than, equal to, or greater than the specified object. - return this.score - another.score; - } - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/SingleFragmentActivity.java b/friendsmash_complete/src/com/facebook/android/friendsmash/SingleFragmentActivity.java deleted file mode 100644 index d167da9..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/SingleFragmentActivity.java +++ /dev/null @@ -1,64 +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.android.friendsmash; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.view.WindowManager; - -import com.facebook.AppEventsLogger; - -/** - * Only used by Activities where a single Fragment is used and not changed (i.e. used by - * all Activities except HomeActivity - */ -public abstract class SingleFragmentActivity extends FragmentActivity { - - abstract Fragment createFragment(); - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_fragment); - FragmentManager manager = getSupportFragmentManager(); - Fragment fragment = manager.findFragmentById(R.id.fragmentContainer); - - if (fragment == null) - { - fragment = createFragment(); - manager.beginTransaction() - .add(R.id.fragmentContainer, fragment) - .commit(); - } - } - - @Override - protected void onResume() { - super.onResume(); - - // Hide the notification bar - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - - // Measure mobile app install ads - // Ref: https://developers.facebook.com/docs/tutorials/mobile-app-ads/ - AppEventsLogger.activateApp(this, ((FriendSmashApplication)getApplication()).getString(R.string.app_id)); - } - -} diff --git a/friendsmash_complete/src/com/facebook/android/friendsmash/UserImageView.java b/friendsmash_complete/src/com/facebook/android/friendsmash/UserImageView.java deleted file mode 100644 index a5cfa09..0000000 --- a/friendsmash_complete/src/com/facebook/android/friendsmash/UserImageView.java +++ /dev/null @@ -1,238 +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.android.friendsmash; - -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; -import android.content.Context; -import android.util.AttributeSet; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.LinearInterpolator; -import android.widget.ImageView; - -import java.util.Random; - -/** - * ImageViews of the users that the playing user has to smash. These can contain images of one - * of the user's friends (in the social version only) or images of celebrities - */ -public class UserImageView extends ImageView { - - private boolean shouldSmash; - private boolean isCoin; - private boolean wrongImageSmashed = false; - private boolean isVoid = false; - private int extraPoints = 0; - private AnimatorSet upMovementAnimatorSet; - private AnimatorSet downMovementAnimatorSet; - private ValueAnimator rotationAnimation; - - // Default Constructor - not used - public UserImageView(Context context, AttributeSet attrs) { - super(context, attrs); - } - - // Constructor used by GameFragment to pass in an instance of itself - public UserImageView(Context context, boolean shouldSmash, boolean isCoin) { - super(context); - - setShouldSmash(shouldSmash); - setIsCoin(isCoin); - - upMovementAnimatorSet = new AnimatorSet(); - downMovementAnimatorSet = new AnimatorSet(); - } - - // Stop movement (not rotation) animations - void stopMovementAnimations() { - upMovementAnimatorSet.cancel(); - downMovementAnimatorSet.cancel(); - } - - // Scale image up - void scaleUp(AnimatorListener animatorListener) { - // Create the scaling animations - ValueAnimator scaleAnimationX = ObjectAnimator.ofFloat(this, "scaleX", 25f); - ValueAnimator scaleAnimationY = ObjectAnimator.ofFloat(this, "scaleY", 25f); - scaleAnimationX.setDuration(1000); - scaleAnimationY.setDuration(1000); - scaleAnimationX.setInterpolator(new LinearInterpolator()); - scaleAnimationY.setInterpolator(new LinearInterpolator()); - - // Start the animations together - AnimatorSet animatorSet = new AnimatorSet(); - animatorSet.playTogether(scaleAnimationX, scaleAnimationY); - animatorSet.start(); - - // Set the listener on this animation - animatorSet.addListener(animatorListener); - } - - // Stop rotation animation - void stopRotationAnimation() { - rotationAnimation.cancel(); - } - - // Start firing this UserImageView across the GameFragment view - void setupAndStartAnimations(int iconWidth, int iconHeight, int screenWidth, int screenHeight, AnimatorListener downAnimatorListener) { - // Animations with Property Animator - Android 3.0 onwards only ... - - // Instantiate Random Generator - Random randomGenerator = new Random(System.currentTimeMillis()); - - // Declare Animators - ValueAnimator upAnimationX; - ValueAnimator upAnimationY; - final ValueAnimator downAnimationX; - final ValueAnimator downAnimationY; - - // Calculate coordinates ... - - // X Range: - int leftXExtreme = -iconWidth*3; - int rightXExtreme = screenWidth+(iconWidth*2); - - // Y Range: - int bottomY = screenHeight+iconHeight; - int topYLowerExtreme = (int) (screenHeight*0.3); - int topYUpperExtreme = 0; - - // Generate random centerX value - int centerX = (screenWidth-iconWidth)/2 + iconWidth - randomGenerator.nextInt(iconWidth*2); - - // Generate random leftX and rightX values - int leftX = randomGenerator.nextInt(centerX-leftXExtreme) + leftXExtreme; - int rightX = rightXExtreme - randomGenerator.nextInt(rightXExtreme-centerX); - - // Generate random topY value - int topY = randomGenerator.nextInt(topYLowerExtreme-topYUpperExtreme) + topYUpperExtreme; - - // Generate random time taken to rotate fully (in ms) - int rotationTime = randomGenerator.nextInt(2500) + 500; - - if (randomGenerator.nextInt(2) == 0) { - upAnimationX = ObjectAnimator.ofFloat(this, "x", leftX, centerX); - upAnimationY = ObjectAnimator.ofFloat(this, "y", bottomY, topY); - downAnimationX = ObjectAnimator.ofFloat(this, "x", centerX, centerX+(centerX-leftX)); - downAnimationY = ObjectAnimator.ofFloat(this, "y", topY, bottomY); - } else { - upAnimationX = ObjectAnimator.ofFloat(this, "x", rightX, centerX); - upAnimationY = ObjectAnimator.ofFloat(this, "y", bottomY, topY); - downAnimationX = ObjectAnimator.ofFloat(this, "x", centerX, centerX-(rightX-centerX)); - downAnimationY = ObjectAnimator.ofFloat(this, "y", topY, bottomY); - } - - upAnimationX.setDuration(1500); - upAnimationY.setDuration(1500); - upAnimationX.setInterpolator(new LinearInterpolator()); - upAnimationY.setInterpolator(new DecelerateInterpolator()); - - downAnimationX.setDuration(1500); - downAnimationY.setDuration(1500); - downAnimationX.setInterpolator(new LinearInterpolator()); - downAnimationY.setInterpolator(new AccelerateInterpolator()); - - upMovementAnimatorSet.playTogether(upAnimationX, upAnimationY); - - // Rotation animations - if (randomGenerator.nextInt(2) == 0) { - rotationAnimation = ObjectAnimator.ofFloat(this, "rotation", 0f, 360f); - } - else { - rotationAnimation = ObjectAnimator.ofFloat(this, "rotation", 0f, -360f); - } - rotationAnimation.setRepeatCount(ValueAnimator.INFINITE); - rotationAnimation.setDuration(rotationTime); - rotationAnimation.setInterpolator(new LinearInterpolator()); - - // Create a callback after the up animation has ended to start the down animation - upAnimationY.addListener(new AnimatorListener() { - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - downMovementAnimatorSet.playTogether(downAnimationX, downAnimationY); - downMovementAnimatorSet.start(); - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationStart(Animator animation) { - } - }); - - // Create a callback after the animation has ended - downAnimationY.addListener(downAnimatorListener); - - // Play the animations - upMovementAnimatorSet.start(); - rotationAnimation.start(); - } - - - /* Standard Getters & Setters */ - - public boolean shouldSmash() { - return shouldSmash; - } - - public void setShouldSmash(boolean shouldSmash) { - this.shouldSmash = shouldSmash; - } - - public boolean isCoin() { - return isCoin; - } - - public void setIsCoin(boolean isCoin) { - this.isCoin = isCoin; - } - - public boolean isVoid() { - return isVoid; - } - - public void setVoid(boolean isVoid) { - this.isVoid = isVoid; - } - - public int getExtraPoints() { - return extraPoints; - } - - public void setExtraPoints(int extraPoints) { - this.extraPoints = extraPoints; - } - - public boolean isWrongImageSmashed() { - return wrongImageSmashed; - } - - public void setWrongImageSmashed(boolean wrongImageSmashed) { - this.wrongImageSmashed = wrongImageSmashed; - } - -} diff --git a/friendsmash_incomplete/.classpath b/friendsmash_incomplete/.classpath deleted file mode 100755 index 5613f33..0000000 --- a/friendsmash_incomplete/.classpath +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/friendsmash_incomplete/.project b/friendsmash_incomplete/.project deleted file mode 100755 index 36e01e7..0000000 --- a/friendsmash_incomplete/.project +++ /dev/null @@ -1,33 +0,0 @@ - - - friendsmash_incomplete - - - - - - com.android.ide.eclipse.adt.ResourceManagerBuilder - - - - - com.android.ide.eclipse.adt.PreCompilerBuilder - - - - - org.eclipse.jdt.core.javabuilder - - - - - com.android.ide.eclipse.adt.ApkBuilder - - - - - - com.android.ide.eclipse.adt.AndroidNature - org.eclipse.jdt.core.javanature - - diff --git a/friendsmash_incomplete/AndroidManifest.xml b/friendsmash_incomplete/AndroidManifest.xml deleted file mode 100755 index ed38009..0000000 --- a/friendsmash_incomplete/AndroidManifest.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/ic_launcher-web.png b/friendsmash_incomplete/ic_launcher-web.png deleted file mode 100755 index 08c8f3b..0000000 Binary files a/friendsmash_incomplete/ic_launcher-web.png and /dev/null differ diff --git a/friendsmash_incomplete/lint.xml b/friendsmash_incomplete/lint.xml deleted file mode 100644 index 6994aea..0000000 --- a/friendsmash_incomplete/lint.xml +++ /dev/null @@ -1,4 +0,0 @@ - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/proguard-project.txt b/friendsmash_incomplete/proguard-project.txt deleted file mode 100755 index f2fe155..0000000 --- a/friendsmash_incomplete/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# To enable ProGuard in your project, edit project.properties -# to define the proguard.config property as described in that file. -# -# Add project specific ProGuard rules here. -# By default, the flags in this file are appended to flags specified -# in ${sdk.dir}/tools/proguard/proguard-android.txt -# You can edit the include path and order by changing the ProGuard -# include property in project.properties. -# -# For more details, see -# http://developer.android.com/guide/developing/tools/proguard.html - -# Add any project specific keep options here: - -# If your project uses WebView with JS, uncomment the following -# and specify the fully qualified class name to the JavaScript interface -# class: -#-keepclassmembers class fqcn.of.javascript.interface.for.webview { -# public *; -#} diff --git a/friendsmash_incomplete/project.properties b/friendsmash_incomplete/project.properties deleted file mode 100755 index b0d923e..0000000 --- a/friendsmash_incomplete/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - -# Project target. -target=android-17 -android.library.reference.1=../../facebook-android-sdk-3.14-6/facebook diff --git a/friendsmash_incomplete/res/drawable-hdpi/bomb.png b/friendsmash_incomplete/res/drawable-hdpi/bomb.png deleted file mode 100755 index e5c897b..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/bomb.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/brag_button.png b/friendsmash_incomplete/res/drawable-hdpi/brag_button.png deleted file mode 100755 index a96abea..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/brag_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/challenge_button.png b/friendsmash_incomplete/res/drawable-hdpi/challenge_button.png deleted file mode 100755 index 947b537..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/challenge_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/close_button.png b/friendsmash_incomplete/res/drawable-hdpi/close_button.png deleted file mode 100644 index 9ff7ac1..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/close_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/coin.png b/friendsmash_incomplete/res/drawable-hdpi/coin.png deleted file mode 100755 index d5086af..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/coin.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/frontscreen_background.png b/friendsmash_incomplete/res/drawable-hdpi/frontscreen_background.png deleted file mode 100755 index b389715..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/frontscreen_background.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/frontscreen_background_land.png b/friendsmash_incomplete/res/drawable-hdpi/frontscreen_background_land.png deleted file mode 100755 index 7673eb4..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/frontscreen_background_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/heart_red.png b/friendsmash_incomplete/res/drawable-hdpi/heart_red.png deleted file mode 100755 index 0252cda..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/heart_red.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/ic_action_search.png b/friendsmash_incomplete/res/drawable-hdpi/ic_action_search.png deleted file mode 100755 index 67de12d..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/ic_action_search.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/ic_launcher.png b/friendsmash_incomplete/res/drawable-hdpi/ic_launcher.png deleted file mode 100755 index d2b9774..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/leaderboard_button.png b/friendsmash_incomplete/res/drawable-hdpi/leaderboard_button.png deleted file mode 100644 index 3e074c1..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/leaderboard_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/login_button.png b/friendsmash_incomplete/res/drawable-hdpi/login_button.png deleted file mode 100755 index 2d8d5cd..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/login_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/logout_button.png b/friendsmash_incomplete/res/drawable-hdpi/logout_button.png deleted file mode 100755 index 55a42a3..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/logout_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_1.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_1.png deleted file mode 100755 index c8cec11..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_1.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_10.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_10.png deleted file mode 100755 index 840b54a..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_10.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_2.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_2.png deleted file mode 100755 index 064c6a5..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_2.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_3.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_3.png deleted file mode 100755 index 952ae15..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_3.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_4.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_4.png deleted file mode 100755 index b5320a9..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_4.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_5.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_5.png deleted file mode 100755 index 82088cd..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_5.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_6.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_6.png deleted file mode 100755 index 7cb8920..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_6.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_7.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_7.png deleted file mode 100755 index 483aa64..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_7.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_8.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_8.png deleted file mode 100755 index 9a1bbab..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_8.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_9.png b/friendsmash_incomplete/res/drawable-hdpi/nonfriend_9.png deleted file mode 100755 index ca0a1a9..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/nonfriend_9.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/playnow_button.png b/friendsmash_incomplete/res/drawable-hdpi/playnow_button.png deleted file mode 100755 index 6112e2a..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/playnow_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/scores_button.png b/friendsmash_incomplete/res/drawable-hdpi/scores_button.png deleted file mode 100755 index 6ab2266..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/scores_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/scores_stub_even.png b/friendsmash_incomplete/res/drawable-hdpi/scores_stub_even.png deleted file mode 100644 index e4aa378..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/scores_stub_even.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/scores_stub_odd.png b/friendsmash_incomplete/res/drawable-hdpi/scores_stub_odd.png deleted file mode 100755 index 9610631..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/scores_stub_odd.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/title_banner.png b/friendsmash_incomplete/res/drawable-hdpi/title_banner.png deleted file mode 100755 index cc7d96a..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/title_banner.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/title_banner_land.png b/friendsmash_incomplete/res/drawable-hdpi/title_banner_land.png deleted file mode 100755 index 7f55afb..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/title_banner_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/welcome_panel.png b/friendsmash_incomplete/res/drawable-hdpi/welcome_panel.png deleted file mode 100755 index 96375e9..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/welcome_panel.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-hdpi/welcome_panel_blank.png b/friendsmash_incomplete/res/drawable-hdpi/welcome_panel_blank.png deleted file mode 100755 index 984674e..0000000 Binary files a/friendsmash_incomplete/res/drawable-hdpi/welcome_panel_blank.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/brag_button.png b/friendsmash_incomplete/res/drawable-ldpi/brag_button.png deleted file mode 100755 index c603dbd..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/brag_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/challenge_button.png b/friendsmash_incomplete/res/drawable-ldpi/challenge_button.png deleted file mode 100755 index 89121d7..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/challenge_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/close_button.png b/friendsmash_incomplete/res/drawable-ldpi/close_button.png deleted file mode 100644 index 76b4c0e..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/close_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/frontscreen_background.png b/friendsmash_incomplete/res/drawable-ldpi/frontscreen_background.png deleted file mode 100755 index 24c0662..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/frontscreen_background.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/frontscreen_background_land.png b/friendsmash_incomplete/res/drawable-ldpi/frontscreen_background_land.png deleted file mode 100755 index 9340497..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/frontscreen_background_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/heart_red.png b/friendsmash_incomplete/res/drawable-ldpi/heart_red.png deleted file mode 100755 index 819f258..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/heart_red.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/ic_launcher.png b/friendsmash_incomplete/res/drawable-ldpi/ic_launcher.png deleted file mode 100755 index e3b2ba7..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/ic_launcher.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/leaderboard_button.png b/friendsmash_incomplete/res/drawable-ldpi/leaderboard_button.png deleted file mode 100644 index 068d251..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/leaderboard_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/login_button.png b/friendsmash_incomplete/res/drawable-ldpi/login_button.png deleted file mode 100755 index 6e0fc75..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/login_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/logout_button.png b/friendsmash_incomplete/res/drawable-ldpi/logout_button.png deleted file mode 100755 index 1609887..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/logout_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_1.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_1.png deleted file mode 100755 index 0e89ae1..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_1.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_10.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_10.png deleted file mode 100755 index 11fb837..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_10.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_2.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_2.png deleted file mode 100755 index 319a578..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_2.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_3.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_3.png deleted file mode 100755 index 38d8b60..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_3.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_4.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_4.png deleted file mode 100755 index b3eb2c2..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_4.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_5.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_5.png deleted file mode 100755 index 626193d..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_5.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_6.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_6.png deleted file mode 100755 index e5732a6..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_6.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_7.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_7.png deleted file mode 100755 index a9231a5..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_7.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_8.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_8.png deleted file mode 100755 index 066f1e2..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_8.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_9.png b/friendsmash_incomplete/res/drawable-ldpi/nonfriend_9.png deleted file mode 100755 index 9614fa7..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/nonfriend_9.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/playnow_button.png b/friendsmash_incomplete/res/drawable-ldpi/playnow_button.png deleted file mode 100755 index be79b7e..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/playnow_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/scores_button.png b/friendsmash_incomplete/res/drawable-ldpi/scores_button.png deleted file mode 100755 index 9b685fd..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/scores_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/scores_stub_even.png b/friendsmash_incomplete/res/drawable-ldpi/scores_stub_even.png deleted file mode 100755 index d66bd57..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/scores_stub_even.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/scores_stub_odd.png b/friendsmash_incomplete/res/drawable-ldpi/scores_stub_odd.png deleted file mode 100755 index 5c17b0c..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/scores_stub_odd.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/title_banner_land.png b/friendsmash_incomplete/res/drawable-ldpi/title_banner_land.png deleted file mode 100755 index bfb1829..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/title_banner_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/welcome_panel.png b/friendsmash_incomplete/res/drawable-ldpi/welcome_panel.png deleted file mode 100755 index 3cba9de..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/welcome_panel.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-ldpi/welcome_panel_blank.png b/friendsmash_incomplete/res/drawable-ldpi/welcome_panel_blank.png deleted file mode 100755 index 2d6ca77..0000000 Binary files a/friendsmash_incomplete/res/drawable-ldpi/welcome_panel_blank.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/brag_button.png b/friendsmash_incomplete/res/drawable-mdpi/brag_button.png deleted file mode 100755 index db60e82..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/brag_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/challenge_button.png b/friendsmash_incomplete/res/drawable-mdpi/challenge_button.png deleted file mode 100755 index 57bd797..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/challenge_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/close_button.png b/friendsmash_incomplete/res/drawable-mdpi/close_button.png deleted file mode 100644 index a4795fb..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/close_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/frontscreen_background.png b/friendsmash_incomplete/res/drawable-mdpi/frontscreen_background.png deleted file mode 100755 index 61852b2..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/frontscreen_background.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/frontscreen_background_land.png b/friendsmash_incomplete/res/drawable-mdpi/frontscreen_background_land.png deleted file mode 100755 index 3893ec0..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/frontscreen_background_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/heart_red.png b/friendsmash_incomplete/res/drawable-mdpi/heart_red.png deleted file mode 100755 index 0dd876e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/heart_red.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/ic_action_search.png b/friendsmash_incomplete/res/drawable-mdpi/ic_action_search.png deleted file mode 100755 index 134d549..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/ic_action_search.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/ic_launcher.png b/friendsmash_incomplete/res/drawable-mdpi/ic_launcher.png deleted file mode 100755 index 2bfd06e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/leaderboard_button.png b/friendsmash_incomplete/res/drawable-mdpi/leaderboard_button.png deleted file mode 100644 index 05165ae..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/leaderboard_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/login_button.png b/friendsmash_incomplete/res/drawable-mdpi/login_button.png deleted file mode 100755 index fc1397c..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/login_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/logout_button.png b/friendsmash_incomplete/res/drawable-mdpi/logout_button.png deleted file mode 100755 index 31552dc..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/logout_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_1.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_1.png deleted file mode 100755 index 765e92e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_1.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_10.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_10.png deleted file mode 100755 index ccb65bc..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_10.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_2.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_2.png deleted file mode 100755 index edb92eb..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_2.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_3.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_3.png deleted file mode 100755 index 7b8542e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_3.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_4.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_4.png deleted file mode 100755 index fd3ea8e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_4.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_5.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_5.png deleted file mode 100755 index a7dac6e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_5.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_6.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_6.png deleted file mode 100755 index dd1fdf3..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_6.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_7.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_7.png deleted file mode 100755 index 04280d2..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_7.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_8.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_8.png deleted file mode 100755 index a0f8c2f..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_8.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_9.png b/friendsmash_incomplete/res/drawable-mdpi/nonfriend_9.png deleted file mode 100755 index 2fe9ec3..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/nonfriend_9.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/playnow_button.png b/friendsmash_incomplete/res/drawable-mdpi/playnow_button.png deleted file mode 100755 index 3b3e650..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/playnow_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/scores_button.png b/friendsmash_incomplete/res/drawable-mdpi/scores_button.png deleted file mode 100755 index 22ad303..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/scores_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/scores_stub_even.png b/friendsmash_incomplete/res/drawable-mdpi/scores_stub_even.png deleted file mode 100755 index c49c76e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/scores_stub_even.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/scores_stub_odd.png b/friendsmash_incomplete/res/drawable-mdpi/scores_stub_odd.png deleted file mode 100755 index a65573e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/scores_stub_odd.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/title_banner_land.png b/friendsmash_incomplete/res/drawable-mdpi/title_banner_land.png deleted file mode 100755 index 2a9d582..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/title_banner_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/welcome_panel.png b/friendsmash_incomplete/res/drawable-mdpi/welcome_panel.png deleted file mode 100755 index 596524e..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/welcome_panel.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-mdpi/welcome_panel_blank.png b/friendsmash_incomplete/res/drawable-mdpi/welcome_panel_blank.png deleted file mode 100755 index 12ab1cc..0000000 Binary files a/friendsmash_incomplete/res/drawable-mdpi/welcome_panel_blank.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/action_bar_background.png b/friendsmash_incomplete/res/drawable-xhdpi/action_bar_background.png deleted file mode 100755 index b8c9e2b..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/action_bar_background.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/bomb.png b/friendsmash_incomplete/res/drawable-xhdpi/bomb.png deleted file mode 100755 index db58793..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/bomb.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/bomb_in_game.png b/friendsmash_incomplete/res/drawable-xhdpi/bomb_in_game.png deleted file mode 100755 index 2bd23bf..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/bomb_in_game.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/bomb_large.png b/friendsmash_incomplete/res/drawable-xhdpi/bomb_large.png deleted file mode 100755 index 5e29b27..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/bomb_large.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/brag_button.png b/friendsmash_incomplete/res/drawable-xhdpi/brag_button.png deleted file mode 100755 index 2d7b9b6..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/brag_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/challenge_button.png b/friendsmash_incomplete/res/drawable-xhdpi/challenge_button.png deleted file mode 100755 index b39835f..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/challenge_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/checkbox_cold.png b/friendsmash_incomplete/res/drawable-xhdpi/checkbox_cold.png deleted file mode 100644 index 99958b9..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/checkbox_cold.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/checkbox_hot.png b/friendsmash_incomplete/res/drawable-xhdpi/checkbox_hot.png deleted file mode 100644 index 2c76700..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/checkbox_hot.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/close_button.png b/friendsmash_incomplete/res/drawable-xhdpi/close_button.png deleted file mode 100644 index 63b7e3c..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/close_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/coin.png b/friendsmash_incomplete/res/drawable-xhdpi/coin.png deleted file mode 100755 index ccef736..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/coin.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/frontscreen_background.png b/friendsmash_incomplete/res/drawable-xhdpi/frontscreen_background.png deleted file mode 100755 index 227bc0a..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/frontscreen_background.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/frontscreen_background_land.png b/friendsmash_incomplete/res/drawable-xhdpi/frontscreen_background_land.png deleted file mode 100755 index 7e522ce..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/frontscreen_background_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/heart_red.png b/friendsmash_incomplete/res/drawable-xhdpi/heart_red.png deleted file mode 100755 index bab2a36..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/heart_red.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/ic_action_search.png b/friendsmash_incomplete/res/drawable-xhdpi/ic_action_search.png deleted file mode 100755 index d699c6b..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/ic_action_search.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/ic_launcher.png b/friendsmash_incomplete/res/drawable-xhdpi/ic_launcher.png deleted file mode 100755 index 0f8d052..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/leaderboard_button.png b/friendsmash_incomplete/res/drawable-xhdpi/leaderboard_button.png deleted file mode 100644 index 09b7785..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/leaderboard_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/login_button.png b/friendsmash_incomplete/res/drawable-xhdpi/login_button.png deleted file mode 100755 index c08bd8b..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/login_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/logo.png b/friendsmash_incomplete/res/drawable-xhdpi/logo.png deleted file mode 100755 index b1640ad..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/logo.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/logout_button.png b/friendsmash_incomplete/res/drawable-xhdpi/logout_button.png deleted file mode 100755 index 906e185..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/logout_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/mfs_clicker_invite.png b/friendsmash_incomplete/res/drawable-xhdpi/mfs_clicker_invite.png deleted file mode 100644 index 8ffe074..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/mfs_clicker_invite.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/mfs_clicker_request.png b/friendsmash_incomplete/res/drawable-xhdpi/mfs_clicker_request.png deleted file mode 100644 index d6c5971..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/mfs_clicker_request.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_1.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_1.png deleted file mode 100755 index 730c573..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_1.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_10.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_10.png deleted file mode 100755 index c84a17b..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_10.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_2.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_2.png deleted file mode 100755 index 6430766..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_2.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_3.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_3.png deleted file mode 100755 index a9d427a..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_3.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_4.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_4.png deleted file mode 100755 index 41dfdcd..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_4.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_5.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_5.png deleted file mode 100755 index 6b69f0d..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_5.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_6.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_6.png deleted file mode 100755 index 74fa439..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_6.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_7.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_7.png deleted file mode 100755 index 4b06e1d..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_7.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_8.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_8.png deleted file mode 100755 index b437113..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_8.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_9.png b/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_9.png deleted file mode 100755 index 2e255e4..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/nonfriend_9.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/playnow_button.png b/friendsmash_incomplete/res/drawable-xhdpi/playnow_button.png deleted file mode 100755 index c194cf8..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/playnow_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/profile_holder_invert.png b/friendsmash_incomplete/res/drawable-xhdpi/profile_holder_invert.png deleted file mode 100644 index 4c7ee82..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/profile_holder_invert.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/scores_button.png b/friendsmash_incomplete/res/drawable-xhdpi/scores_button.png deleted file mode 100755 index 46a9edf..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/scores_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/scores_stub_even.png b/friendsmash_incomplete/res/drawable-xhdpi/scores_stub_even.png deleted file mode 100755 index 81a6688..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/scores_stub_even.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/scores_stub_odd.png b/friendsmash_incomplete/res/drawable-xhdpi/scores_stub_odd.png deleted file mode 100755 index 8b841b2..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/scores_stub_odd.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/send_button.png b/friendsmash_incomplete/res/drawable-xhdpi/send_button.png deleted file mode 100644 index 8bfbfdc..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/send_button.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/title_banner.png b/friendsmash_incomplete/res/drawable-xhdpi/title_banner.png deleted file mode 100755 index d7b05e6..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/title_banner.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/title_banner_land.png b/friendsmash_incomplete/res/drawable-xhdpi/title_banner_land.png deleted file mode 100755 index 03aab69..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/title_banner_land.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/welcome_panel.png b/friendsmash_incomplete/res/drawable-xhdpi/welcome_panel.png deleted file mode 100755 index 911b772..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/welcome_panel.png and /dev/null differ diff --git a/friendsmash_incomplete/res/drawable-xhdpi/welcome_panel_blank.png b/friendsmash_incomplete/res/drawable-xhdpi/welcome_panel_blank.png deleted file mode 100755 index 1dbd029..0000000 Binary files a/friendsmash_incomplete/res/drawable-xhdpi/welcome_panel_blank.png and /dev/null differ diff --git a/friendsmash_incomplete/res/layout-land/fragment_home.xml b/friendsmash_incomplete/res/layout-land/fragment_home.xml deleted file mode 100755 index fedbca3..0000000 --- a/friendsmash_incomplete/res/layout-land/fragment_home.xml +++ /dev/null @@ -1,179 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout-land/fragment_home_fb_logged_in.xml b/friendsmash_incomplete/res/layout-land/fragment_home_fb_logged_in.xml deleted file mode 100755 index 4d4bbac..0000000 --- a/friendsmash_incomplete/res/layout-land/fragment_home_fb_logged_in.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout-land/fragment_home_fb_logged_out.xml b/friendsmash_incomplete/res/layout-land/fragment_home_fb_logged_out.xml deleted file mode 100755 index 07983ca..0000000 --- a/friendsmash_incomplete/res/layout-land/fragment_home_fb_logged_out.xml +++ /dev/null @@ -1,165 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout/activity_fragment.xml b/friendsmash_incomplete/res/layout/activity_fragment.xml deleted file mode 100755 index 91e3a51..0000000 --- a/friendsmash_incomplete/res/layout/activity_fragment.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - diff --git a/friendsmash_incomplete/res/layout/fragment_game.xml b/friendsmash_incomplete/res/layout/fragment_game.xml deleted file mode 100755 index 4d1ba70..0000000 --- a/friendsmash_incomplete/res/layout/fragment_game.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout/fragment_home.xml b/friendsmash_incomplete/res/layout/fragment_home.xml deleted file mode 100755 index bb4096a..0000000 --- a/friendsmash_incomplete/res/layout/fragment_home.xml +++ /dev/null @@ -1,176 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout/fragment_home_fb_logged_out.xml b/friendsmash_incomplete/res/layout/fragment_home_fb_logged_out.xml deleted file mode 100755 index 8ad14c0..0000000 --- a/friendsmash_incomplete/res/layout/fragment_home_fb_logged_out.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout/fragment_scoreboard.xml b/friendsmash_incomplete/res/layout/fragment_scoreboard.xml deleted file mode 100755 index 0433864..0000000 --- a/friendsmash_incomplete/res/layout/fragment_scoreboard.xml +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout/home.xml b/friendsmash_incomplete/res/layout/home.xml deleted file mode 100755 index 6f6d910..0000000 --- a/friendsmash_incomplete/res/layout/home.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - diff --git a/friendsmash_incomplete/res/layout/invite_list_item_view.xml b/friendsmash_incomplete/res/layout/invite_list_item_view.xml deleted file mode 100644 index 4cd280f..0000000 --- a/friendsmash_incomplete/res/layout/invite_list_item_view.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/layout/request_list_item_view.xml b/friendsmash_incomplete/res/layout/request_list_item_view.xml deleted file mode 100644 index 5b8c1d5..0000000 --- a/friendsmash_incomplete/res/layout/request_list_item_view.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/values-v11/styles.xml b/friendsmash_incomplete/res/values-v11/styles.xml deleted file mode 100755 index 177df9b..0000000 --- a/friendsmash_incomplete/res/values-v11/styles.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/values-v14/styles.xml b/friendsmash_incomplete/res/values-v14/styles.xml deleted file mode 100755 index fbf6b98..0000000 --- a/friendsmash_incomplete/res/values-v14/styles.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/values/dimensions.xml b/friendsmash_incomplete/res/values/dimensions.xml deleted file mode 100755 index 5b3c4e6..0000000 --- a/friendsmash_incomplete/res/values/dimensions.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - 96dp - 4dp - 20dp - 20dp - 69dp - 9dp - 10dp - 10dp - 20dp - 86dp - 86dp - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/values/strings.xml b/friendsmash_incomplete/res/values/strings.xml deleted file mode 100755 index 8f5fcfd..0000000 --- a/friendsmash_incomplete/res/values/strings.xml +++ /dev/null @@ -1,54 +0,0 @@ - - - - - - FRIEND SMASH incomplete - 480369938658210 - EMsUqEDE5YtM28UI6KQ9YmOwzNSMNLbUyLldUNLq - XbxKQWXHynWY9okrZXhVrbS0k79bkejbRbxMAu5q - FRIEND SMASH - Welcome, Player - - Smash Player ! - Score: 0 - Let\'s smash some friends! - Please check your network connection - Game Over! - Error - OK - No response from server. - An error occurred that requires your attention. %1$s - An error occurred, please re-login. - Please allow us to post on your behalf. - The server is busy, please retry later. - An error occurred, please contact the developer with the following message: %1$s - An unknown error occurred, please contact the developer with the following message: %1$s - Error fetching your user profile - Please try again - Error fetching your friend\'s profile picture - Please try again - Error switching screens - Please try again - "No scores to display" - Yes - No - Play with Friends - This game is better with friends! Would you like to play with your friends? - Social Leaderboard - This game needs access to your friends list to show their scores. Do you want to see your friends\' scores? - Save Score - Do you want to save your score to Facebook? - - \ No newline at end of file diff --git a/friendsmash_incomplete/res/values/styles.xml b/friendsmash_incomplete/res/values/styles.xml deleted file mode 100755 index 40537f0..0000000 --- a/friendsmash_incomplete/res/values/styles.xml +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java deleted file mode 100755 index 9e66fd0..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/FBLoggedOutHomeFragment.java +++ /dev/null @@ -1,77 +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.android.friendsmash; - -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.view.WindowManager; - -import com.facebook.FacebookException; -import com.facebook.FacebookOperationCanceledException; -import com.facebook.widget.LoginButton; -import com.facebook.widget.LoginButton.OnErrorListener; - -/** - * Fragment to be displayed if the user is logged out of Facebook in the social version of the game - */ -public class FBLoggedOutHomeFragment extends Fragment { - - View progressContainer; - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - setRetainInstance(true); - - // Hide the notification bar - getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - - View v = inflater.inflate(R.layout.fragment_home_fb_logged_out, parent, false); - - progressContainer = v.findViewById(R.id.progressContainer); - progressContainer.setVisibility(View.INVISIBLE); - - // Set an error listener for the login button - LoginButton loginButton = (LoginButton) v.findViewById(R.id.loginButton); - loginButton.setReadPermissions("user_friends"); - if (loginButton != null) { - loginButton.setOnErrorListener(new OnErrorListener() { - - @Override - public void onError(FacebookException error) { - if (error != null && !(error instanceof FacebookOperationCanceledException)) { - // Failed probably due to network error (rather than user canceling dialog which would throw a FacebookOperationCanceledException) - ((HomeActivity)getActivity()).showError(getResources().getString(R.string.network_error), false); - } - } - - }); - } - - return v; - } - -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/FriendSmashApplication.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/FriendSmashApplication.java deleted file mode 100755 index cab3459..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/FriendSmashApplication.java +++ /dev/null @@ -1,278 +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.android.friendsmash; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.json.JSONObject; - -import android.app.Application; -import android.content.Context; -import android.content.SharedPreferences; - -import com.facebook.FacebookRequestError; -import com.facebook.model.GraphUser; - -/** - * Use a custom Application class to pass state data between Activities. - */ -public class FriendSmashApplication extends Application { - - /* Static Attributes */ - - // Tag used when logging all messages with the same tag (e.g. for demoing purposes) - static final String TAG = "FriendSmash"; - - // Switch between the non-social and social Facebook versions of the game - static final boolean IS_SOCIAL = false; - - - /* Friend Smash application attributes */ - - // Player inventory - public static int NEW_USER_BOMBS = 5; - public static int NEW_USER_COINS = 100; - public static int NUM_BOMBS_ALLOWED_IN_GAME = 3; - private int score = -1; - private int bombs = 0; - private int coins = 0; - private int coinsCollected = 0; - - /* Facebook application attributes */ - - // Logged in status of the user - private boolean loggedIn = false; - private static final String LOGGED_IN_KEY = "logged_in"; - - private String fbAppID = null; - - // Current logged in FB user and key for saving/restoring during the Activity lifecycle - private GraphUser currentFBUser; - private static final String CURRENT_FB_USER_KEY = "current_fb_user"; - - // List of the logged in user's friends and key for saving/restoring during the Activity lifecycle - private List friends; - - // List of friends the user can invite (have not installed the app). - private List invitableFriends; - - private static final String FRIENDS_KEY = "friends"; - - // ID of the last friend smashed (linked to the current score) - private String lastFriendSmashedID = null; - - // Name of the last friend smashed - private String lastFriendSmashedName = null; - - // Check to see whether user has said no when asked to play with friends. - private boolean hasDeniedFriendPermission = false; - - // List of ordered ScoreboardEntry objects in order from highest to lowest score to - // be shown in the ScoreboardFragment - private ArrayList scoreboardEntriesList = null; - - // FacebookRequestError to show when the GameFragment closes - private FacebookRequestError gameFragmentFBRequestError = null; - - - /* Friend Smash application attribute getters & setters */ - - public int getScore() { - return score; - } - - public void setScore(int score) { - this.score = score; - } - - public int getBombs() { - return bombs; - } - - public void setBombs(int bombs) { - this.bombs = bombs; - } - - public int getCoins() { - return coins; - } - - public void setCoins(int coins) { - this.coins = coins; - } - - public int getCoinsCollected() { - return coinsCollected; - } - - public void setCoinsCollected(int coinsCollected) { - this.coinsCollected = coinsCollected; - } - - /* Facebook attribute getters & setters */ - - public boolean isLoggedIn() { - return loggedIn; - } - - public void setLoggedIn(boolean loggedIn) { - this.loggedIn = loggedIn; - if (!loggedIn) { - // If the user is logged out, reset the score and nullify all the logged-in user's values - setScore(-1); - setCurrentFBUser(null); - setFriends(null); - setLastFriendSmashedID(null); - setScoreboardEntriesList(null); - } - } - - public GraphUser getCurrentFBUser() { - return currentFBUser; - } - - public void setCurrentFBUser(GraphUser currentFBUser) { - this.currentFBUser = currentFBUser; - } - - public List getFriends() { - return friends; - } - - // Method to get the list of friends in an ArrayList where each entry - // is an inner JSON objects of each friend represented as a string - used for - // saving/restoring each friend during the Activity lifecycle - public ArrayList getFriendsAsArrayListOfStrings() { - ArrayList friendsAsArrayListOfStrings = new ArrayList(); - - Iterator friendsIterator = friends.iterator(); - while (friendsIterator.hasNext()) { - friendsAsArrayListOfStrings.add(friendsIterator.next().getInnerJSONObject().toString()); - } - - return friendsAsArrayListOfStrings; - } - - public GraphUser getFriend(int index) { - if (friends != null && friends.size() > index) { - return friends.get(index); - } else { - return null; - } - } - - public void setFriends(List friends) { - this.friends = friends; - } - - public String getLastFriendSmashedID() { - return lastFriendSmashedID; - } - - public void setLastFriendSmashedID(String lastFriendSmashedID) { - this.lastFriendSmashedID = lastFriendSmashedID; - } - - public String getLastFriendSmashedName() { - return lastFriendSmashedName; - } - - public void setLastFriendSmashedName(String lastFriendSmashedName) { - this.lastFriendSmashedName = lastFriendSmashedName; - } - - public boolean hasDeniedFriendPermission() { - return hasDeniedFriendPermission; - } - - public void setHasDeniedFriendPermission(boolean hasDeniedFriendPermission) { - this.hasDeniedFriendPermission = hasDeniedFriendPermission; - } - - - public ArrayList getScoreboardEntriesList() { - return scoreboardEntriesList; - } - - public void setScoreboardEntriesList(ArrayList scoreboardEntriesList) { - this.scoreboardEntriesList = scoreboardEntriesList; - } - - public FacebookRequestError getGameFragmentFBRequestError() { - return gameFragmentFBRequestError; - } - - public void setGameFragmentFBRequestError(FacebookRequestError gameFragmentFBRequestError) { - this.gameFragmentFBRequestError = gameFragmentFBRequestError; - } - - public static String getLoggedInKey() { - return LOGGED_IN_KEY; - } - - public String getFBAppID() { - return fbAppID; - } - - public static String getCurrentFbUserKey() { - return CURRENT_FB_USER_KEY; - } - - public static String getFriendsKey() { - return FRIENDS_KEY; - } - - public List getInvitableFriends() { - return invitableFriends; - } - - public void setInvitableFriends(List invitableFriends) { - this.invitableFriends = invitableFriends; - } - - - public void saveInventory() { - SharedPreferences prefs = getApplicationContext().getSharedPreferences("Inventory", MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - editor.putInt("bombs", getBombs()); - editor.putInt("coins", getCoins()); - editor.putLong("lastSavedTime", System.currentTimeMillis()); - editor.commit(); - } - - public void loadInventory() { - SharedPreferences prefs = getApplicationContext().getSharedPreferences("Inventory", MODE_PRIVATE); - long lastSavedTime = prefs.getLong("lastSavedTime", 0); - - if (lastSavedTime == 0) { - // Have never saved state. Initialize. - setBombs(NEW_USER_BOMBS); - setCoins(NEW_USER_COINS); - } else { - setBombs(prefs.getInt("bombs", 0)); - setCoins(prefs.getInt("coins", 0)); - } - } - - public void onCreate() { - fbAppID = getString(R.string.app_id); - - loadInventory(); - } -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/GameActivity.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/GameActivity.java deleted file mode 100755 index d83fcfe..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/GameActivity.java +++ /dev/null @@ -1,31 +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.android.friendsmash; - -import android.support.v4.app.Fragment; - -/** - * Activity used once a user starts a new game - all logic is within GameFragment - */ -public class GameActivity extends SingleFragmentActivity { - - @Override - protected Fragment createFragment() { - return new GameFragment(); - } - -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/GameFragment.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/GameFragment.java deleted file mode 100755 index 66fa0b0..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/GameFragment.java +++ /dev/null @@ -1,905 +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.android.friendsmash; - -import java.net.URL; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.Random; - -import org.json.JSONException; -import org.json.JSONObject; - -import android.animation.Animator; -import android.animation.Animator.AnimatorListener; -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.app.Fragment; -import android.util.Log; -import android.util.Pair; -import android.view.Display; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.View.OnTouchListener; -import android.view.ViewGroup; -import android.view.WindowManager; -import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.TextView; - -import com.facebook.FacebookRequestError; -import com.facebook.Request; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphUser; - -/** - * Fragment shown once a user starts playing a game - */ -public class GameFragment extends Fragment { - - private static final Pair [] CELEBS = { - Pair.create("Einstein", "drawable/nonfriend_1"), - Pair.create("Xzibit", "drawable/nonfriend_2"), - Pair.create("Goldsmith", "drawable/nonfriend_3"), - Pair.create("Sinatra", "drawable/nonfriend_4"), - Pair.create("George", "drawable/nonfriend_5"), - Pair.create("Jacko", "drawable/nonfriend_6"), - Pair.create("Rick", "drawable/nonfriend_7"), - Pair.create("Keanu", "drawable/nonfriend_8"), - Pair.create("Arnie", "drawable/nonfriend_9"), - Pair.create("Jean-Luc", "drawable/nonfriend_10"), - }; - - // Tag used when logging messages - private static final String TAG = GameFragment.class.getSimpleName(); - - - // FrameLayout as the container for the game - private FrameLayout gameFrame; - - // FrameLayout of the progress container to show the spinner - private FrameLayout progressContainer; - - // TextView for the Smash Player title - private TextView smashPlayerNameTextView; - - // TextView for the score - private TextView scoreTextView; - - // LinearyLayout containing the lives images - private LinearLayout livesContainer; - - // LinearyLayout containing the bombs images - private LinearLayout bombsContainer; - - // ImageView acting as the button for exploding a bomb - private ImageView bombButton; - - // Icon width for the friend images to smash - private int iconWidth; - - // Screen Dimensions - private int screenWidth; - private int screenHeight; - - - // Handler for putting messages on Main UI thread from background threads periodically - private Handler timerHandler; - - // Handler for putting messages on Main UI thread from background thread after fetching images - private Handler uiHandler; - - // Runnable task used to produce images to fly across the screen - private Runnable fireImageTask = null; - - // Boolean indicating whether images have started firing - private boolean imagesStartedFiring = false; - - - // Index of the friend to smash (in the social game) - private int friendToSmashIndex = -1; - - // Index of the celeb to smash (in the non-social game) - private int celebToSmashIndex = -1; - - // ID of the friend to smash (if passed in as an attribute) - private String friendToSmashIDProvided = null; - - // Name of the friend to smash - private String friendToSmashFirstName = null; - - // Bitmap of the friend to smash - private Bitmap friendToSmashBitmap; - - - // Score for the user - private int score = 0; - - // Lives the user has remaining - private int lives = 3; - - // Bombs the user has remaining - private int bombsRemaining = FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME; - - // Bombs the user has used - private int bombsUsed = 0; - - // Coins the user has collected - private int coinsCollected = 0; - - // Boolean set to true if first image has been fired - private boolean firstImageFired = false; - - // Boolean indicating that the first image to be fired is pending (i.e. a Request is - // in the process of executing in a background thread to fetch the images / information) - private boolean firstImagePendingFiring = false; - - - // List of UserImageView objects created and visible - private ArrayList userImageViews = new ArrayList(); - - - @SuppressWarnings("unused") - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - - setRetainInstance(true); - - // Instantiate the handlers - timerHandler = new Handler(); - uiHandler = new Handler(); - - // Get the friend to smash bitmap and name - if (FriendSmashApplication.IS_SOCIAL) { - // User is logged into FB, so choose a random FB friend to smash - friendToSmashIndex = getRandomFriendIndex(); - } else { - // User is not logged into FB, so choose a random celebrity to smash - celebToSmashIndex = getRandomCelebIndex(); - } - } - - @SuppressWarnings({ "deprecation" }) - @TargetApi(13) - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - - View v = inflater.inflate(R.layout.fragment_game, parent, false); - - gameFrame = (FrameLayout)v.findViewById(R.id.gameFrame); - progressContainer = (FrameLayout)v.findViewById(R.id.progressContainer); - smashPlayerNameTextView = (TextView)v.findViewById(R.id.smashPlayerNameTextView); - scoreTextView = (TextView)v.findViewById(R.id.scoreTextView); - livesContainer = (LinearLayout)v.findViewById(R.id.livesContainer); - bombsContainer = (LinearLayout)v.findViewById(R.id.bombsContainer); - bombButton = (ImageView)v.findViewById(R.id.bombButton); - bombButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onBombButtonTouched(); - return false; - } - }); - - // Set the progressContainer as invisible by default - progressContainer.setVisibility(View.INVISIBLE); - - // Set the icon width (for the images to be smashed) - setIconWidth(getResources().getDimensionPixelSize(R.dimen.icon_width)); - - // Set the screen dimensions - WindowManager wm = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE); - Display display = wm.getDefaultDisplay(); - if (Build.VERSION.SDK_INT >= 13) { - Point size = new Point(); - display.getSize(size); - setScreenWidth(size.x); - setScreenHeight(size.y); - } - else { - setScreenWidth(display.getWidth()); - setScreenHeight(display.getHeight()); - } - - // Instantiate the fireImageTask for future fired images - fireImageTask = new Runnable() - { - public void run() - { - spawnImage(false); - } - }; - - // Refresh the score board - setScore(getScore()); - - // Refresh the lives - setLives(getLives()); - - // Refresh the bombs - setBombsRemaining(getBombsRemaining()); - - // Note: Images will start firing in the onResume method below - - return v; - } - - // Called when the Bombs button is touched - private void onBombButtonTouched() { - if (getBombsRemaining() > 0) { - // Hide all ImageViews and invalidate them - hideAllUserImageViews(); - markAllUserImageViewsAsVoid(); - - // Increment the bombsUsed integer - bombsUsed++; - - // Subtract a bomb - setBombsRemaining(getBombsRemaining() - 1); - } else { - // No bombs are remaining, so make sure they are all removed from the UI - setBombsRemaining(0); - } - } - - // Sets the name of the player to smash in the top left TextView - @SuppressWarnings("unused") - private void setSmashPlayerNameTextView() { - // Set the Smash Player Name title - if (FriendSmashApplication.IS_SOCIAL) { - // User is logged into FB ... - if (friendToSmashFirstName == null) { - // A name hasn't been set yet (i.e. it hasn't been fetched through a passed in id, so - // a random friend needs to be used instead, so fetch this name - String friendToSmashName = ((FriendSmashApplication) getActivity().getApplication()).getFriend(friendToSmashIndex).getName(); - friendToSmashFirstName = friendToSmashName.split(" ")[0]; - } - smashPlayerNameTextView.setText("Smash " + friendToSmashFirstName + " !"); - } else { - // User is not logged into FB ... - smashPlayerNameTextView.setText("Smash " + CELEBS[celebToSmashIndex].first + " !"); - } - } - - // Select a random friend to smash - private int getRandomFriendIndex() { - Random randomGenerator = new Random(System.currentTimeMillis()); - int friendIndex = randomGenerator.nextInt(((FriendSmashApplication) getActivity().getApplication()).getFriends().size()); - return friendIndex; - } - - // Select a random celebrity to smash (in the non-social game) or avoid smashing (in the social game) - private int getRandomCelebIndex() { - Random randomGenerator = new Random(System.currentTimeMillis()); - int celebIndex = randomGenerator.nextInt(CELEBS.length); - return celebIndex; - } - - // Set the image on the UserImageView to the specified bitmap of the user's friend and fire it - private void setFriendImageAndFire(UserImageView imageView, Bitmap friendBitmap, boolean extraImage) { - imageView.setImageBitmap(friendBitmap); - - if (extraImage) { - // If this is an extra image, give it an extra point when smashed - imageView.setExtraPoints(1); - } - - fireImage(imageView, extraImage); - } - - // Set the image on the UserImageView to the celebrity and fire it - private void setCelebImageAndFire(UserImageView imageView, int celebIndex, boolean extraImage) { - int imageResource = getResources().getIdentifier((String) CELEBS[celebIndex].second, null, getActivity().getPackageName()); - - Drawable image = getResources().getDrawable(imageResource); - imageView.setImageDrawable(image); - - fireImage(imageView, extraImage); - } - - // Set the image on the UserImageView to the coin and fire it - private void setCoinImageAndFire(UserImageView imageView, boolean extraImage) { - imageView.setImageResource(R.drawable.coin); - fireImage(imageView, extraImage); - } - - // Fire the UserImageView and setup the timer to start another image shortly (as long as the image that - // is fired isn't an extra image) - private void fireImage(final UserImageView imageView, boolean extraImage) { - // Fire image - imageView.setupAndStartAnimations(iconWidth, iconWidth, screenWidth, screenHeight, new AnimatorListener() { - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - if (!imageView.isWrongImageSmashed()) { - if (imageView.getVisibility() == View.VISIBLE && imageView.shouldSmash() && !imageView.isVoid() && !imageView.isCoin()) { - // Image is still visible, so user didn't smash it and they should have done (and it isn't void), so decrement the lives by one - setLives(getLives() - 1); - } - - // Only hide this if the wrong image has not been smashed (otherwise, other logic will be run and image still needs to be shown) - hideAndRemove(imageView); - } - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationStart(Animator animation) { - } - }); - - if (!extraImage) { - // If this isn't an extra image spawned, fire another image shortly - fireAnotherImage(); - } - - // By this point, all network calls would have executed and the first image has fired with the next lined up - // , so set firstImagePendingFiring to false - firstImagePendingFiring = false; - } - - // If this UserImageView is currently visible, hide it and remove it from the GameFragment view - // and the list storing all UserImageViews - private void hideAndRemove(UserImageView userImageView) { - if (userImageView.getVisibility() == View.VISIBLE) { - // Ensure it is hidden - userImageView.setVisibility(View.GONE); - } - - // Remove the userImageView from the gameFrame - getGameFrame().removeView(userImageView); - - // Remove it from the userImageViews List in the gameFragment - getUserImageViews().remove(userImageView); - } - - // Fire another image shortly - private void fireAnotherImage() { - // Fire another image shortly ... - if (fireImageTask != null) - { - timerHandler.postDelayed(fireImageTask, 700); - } - } - - // Called when the first image should be fired (only called during onResume) - // If the game has been deep linked into (i.e. a user has clicked on a feed post or request in - // Facebook), then fetch the specific user that should be smashed - @SuppressWarnings("unused") - private void fireFirstImage() { - if (FriendSmashApplication.IS_SOCIAL) { - // Get any bundle parameters there are - Bundle bundle = getActivity().getIntent().getExtras(); - - String requestID = null; - String userID = null; - int numBombsRemaining = 0; - if (bundle != null) { - requestID = bundle.getString("request_id"); - userID = bundle.getString("user_id"); - numBombsRemaining = bundle.getInt("num_bombs") <= FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME ? - bundle.getInt("num_bombs") : FriendSmashApplication.NUM_BOMBS_ALLOWED_IN_GAME; - setBombsRemaining(numBombsRemaining); - } - - if (requestID != null && friendToSmashIDProvided == null) { - // Deep linked from request - // Make a request to get a specific user to smash if they haven't been fetched already - - // Show the spinner for this part - progressContainer.setVisibility(View.VISIBLE); - - // Get and set the id of the friend to smash and start firing the image - fireFirstImageWithRequestID(requestID); - } else if (userID != null && friendToSmashIDProvided == null) { - // Deep linked from feed post - // Make a request to get a specific user to smash if they haven't been fetched already - - // Show the spinner for this part - progressContainer.setVisibility(View.VISIBLE); - - // Get and set the id of the friend to smash and start firing the image - fireFirstImageWithUserID(userID); - } else { - // requestID is null, userID is null or friendToSmashIDProvided is already set, - // so use the randomly generated friend of the user or the already set friendToSmashIDProvided - // So set the smashPlayerNameTextView text and hide the progress spinner as there is nothing to fetch - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } else { - // Non-social, so set the smashPlayerNameTextView text and hide the progress spinner as there is nothing to fetch - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } - - // Fires the first image in a game with a given request id (from a user deep linking by clicking - // on a request from a specific user) - private void fireFirstImageWithRequestID(String requestID) { - final Session session = Session.getActiveSession(); - Request requestIDGraphPathRequest = Request.newGraphPathRequest(session, requestID, new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - closeAndHandleError(error); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Extract the user id from the response - GraphObject graphObject = response.getGraphObject(); - JSONObject fromObject = (JSONObject)graphObject.getProperty("from"); - try { - friendToSmashIDProvided = fromObject.getString("id"); - } catch (JSONException e) { - Log.e(FriendSmashApplication.TAG, e.toString()); - closeAndShowError(getResources().getString(R.string.network_error)); - } - - // With the user id, fetch and set their name - Request userGraphPathRequest = Request.newGraphPathRequest(session, friendToSmashIDProvided, new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - closeAndHandleError(error); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Extract the user name from the response - friendToSmashFirstName = response.getGraphObjectAs(GraphUser.class).getFirstName(); - } - if (friendToSmashFirstName != null) { - // If the first name of the friend to smash has been set, set the text in the smashPlayerNameTextView - // and hide the progress spinner now that the user's details have been fetched - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } - } - }); - Request.executeBatchAsync(userGraphPathRequest); - } - } - } - }); - Request.executeBatchAsync(requestIDGraphPathRequest); - } - - // Fires the first image in a game with a given user id (from a user deep linking by clicking - // on a feed post from a specific user) - private void fireFirstImageWithUserID(String userID) { - final Session session = Session.getActiveSession(); - - // With the user id, fetch and set their name, then start the firing of images - friendToSmashIDProvided = userID; - Request userGraphPathRequest = Request.newGraphPathRequest(session, friendToSmashIDProvided, new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - closeAndHandleError(error); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Extract the user name from the response - friendToSmashFirstName = response.getGraphObjectAs(GraphUser.class).getFirstName(); - } - if (friendToSmashFirstName != null) { - // If the first name of the friend to smash has been set, set the text in the smashPlayerNameTextView - // and hide the progress spinner now that the user's details have been fetched - progressContainer.setVisibility(View.INVISIBLE); - setSmashPlayerNameTextView(); - - // Now you're ready to fire the first image - spawnImage(false); - } - } - } - }); - Request.executeBatchAsync(userGraphPathRequest); - } - - // Spawn a new UserImageView, set its bitmap (fetch it from Facebook if it hasn't already been fetched) - // and fire it once the image has been set (and fetched if appropriate) - @SuppressWarnings("unused") - private void spawnImage(final boolean extraImage) { - // Instantiate Random Generator - Random randomGenerator = new Random(System.currentTimeMillis()); - - // 1 in every 5 images should be a celebrity the user should not smash - calculate that here - // Unless it is the first image fired, in which case it should always be the smashable image - boolean shouldSmash = true; - boolean isCoin = false; - if (firstImageFired) { - if (randomGenerator.nextInt(5) == 4 && firstImageFired) { - shouldSmash = false; - } else if (randomGenerator.nextInt(8) == 7 && firstImageFired) { - isCoin = true; - } - } else if (!firstImageFired) { - shouldSmash = true; - firstImageFired = true; - } - - // Create a new ImageView with a user to smash - final UserImageView userImageView = (new UserImageView(getActivity(), shouldSmash, isCoin)); - userImageView.setOnTouchListener(new OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (userImageView.shouldSmash()) { - // Smashed the right image ... - - if (userImageView.isCoin()) { - coinsCollected++; - } else { - // Increment the score - setScore(getScore() + 1 + userImageView.getExtraPoints()); - } - - // Hide the userImageView - v.setVisibility(View.GONE); - - // Remove it from the userImageViews List in this GameFragment - getUserImageViews().remove(v); - } else { - // Smashed the wrong image ... - wrongImageSmashed(userImageView); - } - return false; - } - }); - userImageView.setLayoutParams(new LinearLayout.LayoutParams(iconWidth, iconWidth)); - gameFrame.addView(userImageView); - userImageViews.add(userImageView); - - // Set the bitmap of the userImageView ... - if (userImageView.shouldSmash()) { - // The user should smash this image, so set the correct image - if (userImageView.isCoin()) { - setCoinImageAndFire(userImageView, extraImage); - } else { - if (FriendSmashApplication.IS_SOCIAL) { - // User is logged into FB ... - if (friendToSmashBitmap != null) { - // Bitmap for the friend to smash has already been retrieved, so use this - setFriendImageAndFire(userImageView, friendToSmashBitmap, extraImage); - } else { - // Otherwise, the Bitmap for the friend to smash hasn't been retrieved, so retrieve it and set it - - // Show the spinner while retrieving - progressContainer.setVisibility(View.VISIBLE); - - // If a friend has been passed in, use that attribute, otherwise use the random friend that has been selected - final String friendToSmashID = friendToSmashIDProvided != null ? friendToSmashIDProvided : - ((FriendSmashApplication) getActivity().getApplication()).getFriend(friendToSmashIndex).getId(); - - // Fetch the bitmap and fire the image - fetchFriendBitmapAndFireImages(userImageView, friendToSmashID, extraImage); - } - } else { - // User is not logged into FB ... - setCelebImageAndFire(userImageView, celebToSmashIndex, extraImage); - } - } - } else { - // The user should not smash this image, so set it to a random celebrity (but not the one being shown if it's the non-social game) - int randomCelebToSmashIndex; - do { - randomCelebToSmashIndex = randomGenerator.nextInt(CELEBS.length); - } while (randomCelebToSmashIndex == celebToSmashIndex); - setCelebImageAndFire(userImageView, randomCelebToSmashIndex, extraImage); - } - } - - // Logic when the user smashes this image, but it turns out to be the wrong image - i.e. - // it's shouldSmash boolean is false - private void wrongImageSmashed(final UserImageView userImageView) { - // Set this flag for checking in the animation ended logic - userImageView.setWrongImageSmashed(true); - - // Stop all movement (not rotation) animations for this UserImageView - userImageView.stopMovementAnimations(); - - // Stop all animations for all other visible UserImageViews (and therefore hide them) - hideAllUserImageViewsExcept(userImageView); - - // Scale the image up - userImageView.scaleUp(new AnimatorListener() { - @Override - public void onAnimationCancel(Animator animation) { - } - - @Override - public void onAnimationEnd(Animator animation) { - // Cancel rotation and exit to home screen - userImageView.stopRotationAnimation(); - setLives(0); - } - - @Override - public void onAnimationRepeat(Animator animation) { - } - - @Override - public void onAnimationStart(Animator animation) { - } - }); - - // Ensure this UserImageView is in front - getGameFrame().bringChildToFront(userImageView); - } - - private void fetchFriendBitmapAndFireImages(final UserImageView userImageView, final String friendToSmashID, final boolean extraImage) { - closeAndShowError("Complete the Personalize Chapter of the Friend Smash Tutorial first!"); - } - - // 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(); - } - - // Close the game and show the specified FacebookRequestException to the user - private void closeAndHandleError(FacebookRequestError error) { - // Store the FacebookRequestError in the FacebookApplication before closing out this GameFragment so that - // it is shown to the user once exited - ((FriendSmashApplication) getActivity().getApplication()).setGameFragmentFBRequestError(error); - - getActivity().setResult(Activity.RESULT_CANCELED); - getActivity().finish(); - } - - // Hides all the UserImageViews currently on display - called when a bomb is detonated - void hideAllUserImageViews() { - Iterator userImageViewsIterator = userImageViews.iterator(); - while (userImageViewsIterator.hasNext()) { - UserImageView currentUserImageView = (UserImageView) userImageViewsIterator.next(); - currentUserImageView.setVisibility(View.GONE); - } - } - - // Hide all the UserImageViews currently on display except the one specified - // Called when the user has smashed the wrong image so that this is displayed large - void hideAllUserImageViewsExcept(UserImageView userImageView) { - // Stop new animations - timerHandler.removeCallbacks(fireImageTask); - - // Stop animations on all existing visible UserImageViews (which will hide them automatically) - Iterator userImageViewsIterator = userImageViews.iterator(); - while (userImageViewsIterator.hasNext()) { - UserImageView currentUserImageView = (UserImageView) userImageViewsIterator.next(); - if (!currentUserImageView.equals(userImageView)) { - currentUserImageView.setVisibility(View.GONE); - } - } - } - - // Mark all the existing visible UserImageViews as void (called when the game is paused) - private void markAllUserImageViewsAsVoid() { - Iterator userImageViewsIterator = userImageViews.iterator(); - while (userImageViewsIterator.hasNext()) { - UserImageView currentUserImageView = (UserImageView) userImageViewsIterator.next(); - currentUserImageView.setVoid(true); - } - } - - @Override - public void onPause() { - super.onPause(); - - // Stop the firing images - stopTheFiringImages(); - } - - @SuppressWarnings("unused") - @Override - public void onResume() { - super.onResume(); - - // Stop any firing images (even though this is called in onPause, there might be new firing images - // if they were pending while onPause was called - stopTheFiringImages(); - - if (!imagesStartedFiring) { - // Fire first image - if (FriendSmashApplication.IS_SOCIAL) { - // Only fire for the social game if there isn't a first image pending firing - if (!firstImagePendingFiring) { - // ... and also set the firstImagePendingFiring to true - will be set back - // to false later once the images have actually started firing (i.e. all network - // calls have executed) - note, this is only relevant for the social version - firstImagePendingFiring = true; - imagesStartedFiring = true; - fireFirstImage(); - } - } else { - imagesStartedFiring = true; - fireFirstImage(); - } - } - } - - // Stop the firing of all images (and mark the existing ones as void) - called when the game is paused - private void stopTheFiringImages() { - // Mark all existing in flight UserImageViews as void (so they don't affect the user's lives once landed) - markAllUserImageViewsAsVoid(); - - // Stop new animations and indicate that images have not started firing - timerHandler.removeCallbacks(fireImageTask); - imagesStartedFiring = false; - } - - // Get the current score - int getScore() { - return score; - } - - // Set the score and if the score is divisible by 10, spawn more images ... - // ... the higher the score, the more images that will be spawned - void setScore(int score) { - this.score = score; - - // Update the scoreTextView - scoreTextView.setText("Score: " + score); - - // If they start scoring well, spawn more images - if (score > 0 && score % 10 == 0) { - // Every multiple of 10, spawn extra images ... - for (int i=0; i getUserImageViews() { - return userImageViews; - } -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/HomeActivity.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/HomeActivity.java deleted file mode 100755 index 2dfac1a..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/HomeActivity.java +++ /dev/null @@ -1,401 +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.android.friendsmash; - -import java.util.ArrayList; -import java.util.Iterator; - -import org.json.JSONException; -import org.json.JSONObject; - -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentActivity; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.util.Log; -import android.view.View; -import android.view.WindowManager; -import android.widget.Toast; - -import com.facebook.AppEventsLogger; -import com.facebook.FacebookRequestError; -import com.facebook.Session; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphUser; -import com.facebook.widget.LoginButton; - -/** - * Entry point for the app that represents the home screen with the Play button etc. and - * also the login screen for the social version of the app - these screens will switch - * within this activity using Fragments. - */ -public class HomeActivity extends FragmentActivity { - - // Tag used when logging messages - private static final String TAG = HomeActivity.class.getSimpleName(); - - // Uri used in handleError() below - private static final Uri M_FACEBOOK_URL = Uri.parse("http://m.facebook.com"); - - // Fragment attributes - private static final int FB_LOGGED_OUT_HOME = 0; - private static final int HOME = 1; - private static final int FRAGMENT_COUNT = HOME +1; - private Fragment[] fragments = new Fragment[FRAGMENT_COUNT]; - - // Boolean recording whether the activity has been resumed so that - // the logic in onSessionStateChange is only executed if this is the case - private boolean isResumed = false; - - // Constructor - public HomeActivity() { - super(); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - setContentView(R.layout.home); - - FragmentManager fm = getSupportFragmentManager(); - fragments[FB_LOGGED_OUT_HOME] = fm.findFragmentById(R.id.fbLoggedOutHomeFragment); - fragments[HOME] = fm.findFragmentById(R.id.homeFragment); - - FragmentTransaction transaction = fm.beginTransaction(); - for(int i = 0; i < fragments.length; i++) { - transaction.hide(fragments[i]); - } - transaction.commit(); - - // Restore the logged-in user's information if it has been saved and the existing data in the application - // has been destroyed (i.e. the app hasn't been used for a while and memory on the device is low) - // - only do this if the session is open for the social version only - if (FriendSmashApplication.IS_SOCIAL) { - // loggedIn - if (savedInstanceState != null) { - boolean loggedInState = savedInstanceState.getBoolean(FriendSmashApplication.getLoggedInKey(), false); - ((FriendSmashApplication)getApplication()).setLoggedIn(loggedInState); - - if ( ((FriendSmashApplication)getApplication()).isLoggedIn() && - ( ((FriendSmashApplication)getApplication()).getFriends() == null || - ((FriendSmashApplication)getApplication()).getCurrentFBUser() == null) ) { - try { - // currentFBUser - String currentFBUserJSONString = savedInstanceState.getString(FriendSmashApplication.getCurrentFbUserKey()); - if (currentFBUserJSONString != null) { - GraphUser currentFBUser = GraphObject.Factory.create(new JSONObject(currentFBUserJSONString), GraphUser.class); - ((FriendSmashApplication)getApplication()).setCurrentFBUser(currentFBUser); - } - - // friends - ArrayList friendsJSONStringArrayList = savedInstanceState.getStringArrayList(FriendSmashApplication.getFriendsKey()); - if (friendsJSONStringArrayList != null) { - ArrayList friends = new ArrayList(); - Iterator friendsJSONStringArrayListIterator = friendsJSONStringArrayList.iterator(); - while (friendsJSONStringArrayListIterator.hasNext()) { - friends.add(GraphObject.Factory.create(new JSONObject(friendsJSONStringArrayListIterator.next()), GraphUser.class)); - } - ((FriendSmashApplication)getApplication()).setFriends(friends); - } - } catch (JSONException e) { - Log.e(FriendSmashApplication.TAG, e.toString()); - } - } - } - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - } - - @Override - protected void onResumeFragments() { - super.onResumeFragments(); - if (!FriendSmashApplication.IS_SOCIAL) { - showFragment(HOME, false); - } else { - Session session = Session.getActiveSession(); - if (session != null && session.isOpened() && ((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { - showFragment(HOME, false); - } else { - showFragment(FB_LOGGED_OUT_HOME, false); - } - } - } - - @Override - public void onResume() { - super.onResume(); - isResumed = true; - - // Hide the notification bar - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - - // Measure mobile app install ads - // Ref: https://developers.facebook.com/docs/tutorials/mobile-app-ads/ - AppEventsLogger.activateApp(this, ((FriendSmashApplication)getApplication()).getString(R.string.app_id)); - } - - @Override - public void onPause() { - super.onPause(); - isResumed = false; - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - // Save the logged-in state - outState.putBoolean(FriendSmashApplication.getLoggedInKey(), ((FriendSmashApplication)getApplication()).isLoggedIn()); - - // Save the currentFBUser - if (((FriendSmashApplication)getApplication()).getCurrentFBUser() != null) { - outState.putString(FriendSmashApplication.getCurrentFbUserKey(), - ((FriendSmashApplication)getApplication()).getCurrentFBUser().getInnerJSONObject().toString()); - } - - // Save the logged-in user's list of friends - if (((FriendSmashApplication)getApplication()).getFriends() != null) { - outState.putStringArrayList(FriendSmashApplication.getFriendsKey(), - ((FriendSmashApplication)getApplication()).getFriendsAsArrayListOfStrings()); - } - } - - @Override - public void onDestroy() { - super.onDestroy(); - } - - public void buyBombs() { - // update bomb and coins count (5 coins per bomb) - FriendSmashApplication app = (FriendSmashApplication) getApplication(); - - // check to see that we have enough coins. - if (app.getCoins() - 5 < 0) { - Toast.makeText(this, "Not enough coins.", Toast.LENGTH_LONG).show(); - return; - } - - app.setBombs(app.getBombs()+1); - app.setCoins(app.getCoins()-5); - - // save inventory values - app.saveInventory(); - - // reload inventory values in fragment - loadInventoryFragment(); - } - - private void showFragment(int fragmentIndex, boolean addToBackStack) { - FragmentManager fm = getSupportFragmentManager(); - FragmentTransaction transaction = fm.beginTransaction(); - for (int i = 0; i < fragments.length; i++) { - if (i == fragmentIndex) { - transaction.show(fragments[i]); - } else { - transaction.hide(fragments[i]); - } - } - if (addToBackStack) { - transaction.addToBackStack(null); - } - transaction.commit(); - - // Do other changes depending on the fragment that is now showing - if (FriendSmashApplication.IS_SOCIAL) { - switch (fragmentIndex) { - case FB_LOGGED_OUT_HOME: - // Hide the progressContainer in FBLoggedOutHomeFragment - if (fragments[FB_LOGGED_OUT_HOME] != null && ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]) != null) { - ((FBLoggedOutHomeFragment)fragments[FB_LOGGED_OUT_HOME]).progressContainer.setVisibility(View.INVISIBLE); - } - // Set the loggedIn attribute - ((FriendSmashApplication)getApplication()).setLoggedIn(false); - break; - case HOME: - // Set the loggedIn attribute - ((FriendSmashApplication)getApplication()).setLoggedIn(true); - break; - } - } - } - - /* Facebook Integration Only ... */ - - // Call back on HomeActivity when the session state changes to update the view accordingly - private void updateView() { - if (isResumed) { - Session session = Session.getActiveSession(); - if (session.isOpened() && !((FriendSmashApplication)getApplication()).isLoggedIn() && fragments[HOME] != null) { - // Not logged in, but should be, so fetch the user information and log in (load the HomeFragment) - fetchUserInformationAndLogin(); - } else if (session.isClosed() && ((FriendSmashApplication)getApplication()).isLoggedIn() && fragments[FB_LOGGED_OUT_HOME] != null) { - // Logged in, but shouldn't be, so load the FBLoggedOutHomeFragment - showFragment(FB_LOGGED_OUT_HOME, false); - } - - // Note that error checking for failed logins is done as within an ErrorListener attached to the - // LoginButton within FBLoggedOutHomeFragment - } - } - - // Fetch user information and login (i.e switch to the personalized HomeFragment) - private void fetchUserInformationAndLogin() { - loadPersonalizedFragment(); - } - - // Loads the inventory portion of the HomeFragment. - private void loadInventoryFragment() { - Log.d(TAG, "Loading inventory fragment"); - if (isResumed) { - ((HomeFragment)fragments[HOME]).loadInventory(); - } else { - showError(getString(R.string.error_switching_screens), true); - } - } - - // Switches to the personalized HomeFragment as the user has just logged in - private void loadPersonalizedFragment() { - if (isResumed) { - // Personalize the HomeFragment - ((HomeFragment)fragments[HOME]).personalizeHomeFragment(); - - // Load the HomeFragment personalized - showFragment(HOME, false); - } else { - showError(getString(R.string.error_switching_screens), true); - } - } - - void handleError(FacebookRequestError error, boolean logout) { - DialogInterface.OnClickListener listener = null; - String dialogBody = null; - - if (error == null) { - dialogBody = getString(R.string.error_dialog_default_text); - } else { - switch (error.getCategory()) { - case AUTHENTICATION_RETRY: - // tell the user what happened by getting the message id, and - // retry the operation later - String userAction = (error.shouldNotifyUser()) ? "" : - getString(error.getUserActionMessageId()); - dialogBody = getString(R.string.error_authentication_retry, userAction); - listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Intent intent = new Intent(Intent.ACTION_VIEW, M_FACEBOOK_URL); - startActivity(intent); - } - }; - break; - - case AUTHENTICATION_REOPEN_SESSION: - // close the session and reopen it. - dialogBody = getString(R.string.error_authentication_reopen); - listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - Session session = Session.getActiveSession(); - if (session != null && !session.isClosed()) { - session.closeAndClearTokenInformation(); - } - } - }; - break; - - case PERMISSION: - // request the publish permission - dialogBody = getString(R.string.error_permission); - listener = new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - if (fragments[HOME] != null) { - ((HomeFragment) fragments[HOME]).setPendingPost(true); - ((HomeFragment) fragments[HOME]).requestPublishPermissions(); - } - } - }; - break; - - case SERVER: - case THROTTLING: - // this is usually temporary, don't clear the fields, and - // ask the user to try again - dialogBody = getString(R.string.error_server); - break; - - case BAD_REQUEST: - // this is likely a coding error, ask the user to file a bug - dialogBody = getString(R.string.error_bad_request, error.getErrorMessage()); - break; - - case CLIENT: - // this is likely an IO error, so tell the user they have a network issue - dialogBody = getString(R.string.network_error); - break; - - case OTHER: - default: - // an unknown issue occurred, this could be a code error, or - // a server side issue, log the issue, and either ask the - // user to retry, or file a bug - dialogBody = getString(R.string.error_unknown, error.getErrorMessage()); - break; - } - } - - new AlertDialog.Builder(this) - .setPositiveButton(R.string.error_dialog_button_text, listener) - .setTitle(R.string.error_dialog_title) - .setMessage(dialogBody) - .show(); - - if (logout) { - logout(); - } - } - - // Show user error message as a toast - void showError(String error, boolean logout) { - Toast.makeText(this, error, Toast.LENGTH_LONG).show(); - if (logout) { - logout(); - } - } - - private void logout() { - // Close the session, which will cause a callback to show the logout screen - Session.getActiveSession().closeAndClearTokenInformation(); - - // Clear any permissions associated with the LoginButton - LoginButton loginButton = (LoginButton) findViewById(R.id.loginButton); - if (loginButton != null) { - loginButton.clearPermissions(); - } - } - -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/HomeFragment.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/HomeFragment.java deleted file mode 100755 index 9653c53..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/HomeFragment.java +++ /dev/null @@ -1,1066 +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.android.friendsmash; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.NameValuePair; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.message.BasicNameValuePair; -import org.apache.http.util.EntityUtils; -import org.json.JSONArray; -import org.json.JSONObject; - -import android.app.Activity; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.os.AsyncTask; -import android.os.Bundle; -import android.os.Handler; -import android.support.v4.app.Fragment; -import android.text.TextUtils; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.AdapterView; -import android.widget.FrameLayout; -import android.widget.GridView; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.TextView; - -import com.facebook.FacebookException; -import com.facebook.FacebookOperationCanceledException; -import com.facebook.FacebookRequestError; -import com.facebook.HttpMethod; -import com.facebook.Request; -import com.facebook.RequestBatch; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.SessionDefaultAudience; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphUser; -import com.facebook.widget.FacebookDialog; -import com.facebook.widget.ProfilePictureView; -import com.facebook.widget.WebDialog; - -/** - * Fragment to be shown once the user is logged in on the social version of the game or - * the start screen for the non-social version of the game - */ -public class HomeFragment extends Fragment { - - interface FriendsLoadedCallback { - void afterFriendsLoaded(); - } - - // Tag used when logging errors - private static final String TAG = HomeFragment.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 of the mainButtonsContainer - private LinearLayout mainButtonsContainer; - - // LinearLayout of the gameOverContainer - private RelativeLayout challengeContainer; - - // LinearLayout of the gameOverContainer - private LinearLayout gameOverContainer; - - // FrameLayout of the progressContainer - private FrameLayout progressContainer; - - // TextView for the You Scored message - private TextView scoredTextView; - - // profile pic of the user you smashed - private ProfilePictureView youSmashedUserImage; - - private GridView invitesGridView; - private GridView requestsGridView; - - // Buttons ... - private ImageView playButton; - private ImageView scoresButton; - private ImageView challengeButton; - private ImageView challengeRequestToggle; - - - private TextView numBombs; - private TextView numCoins; - - // Parameters of a WebDialog that should be displayed - private WebDialog dialog = null; - private String dialogAction = null; - private Bundle dialogParams = null; - - // Boolean indicating whether or not the game over message is displaying - private boolean gameOverMessageDisplaying = false; - - // Boolean indicating if the game has been launched directly from deep linking already - // so that it isn't launched again when the view is created (e.g. on rotation) - private boolean gameLaunchedFromDeepLinking = false; - - // Attributes for posting back to Facebook - private static final List PERMISSIONS = Arrays.asList("publish_actions"); - private static final int AUTH_FRIENDS_PLAY_ACTIVITY_CODE = 101; - private static final int AUTH_FRIENDS_LEADERBOARD_ACTIVITY_CODE = 102; - private static final int AUTH_PUBLISH_ACTIONS_SCORES_ACTIVITY_CODE = 103; - private static final String PENDING_POST_KEY = "pendingPost"; - private boolean pendingPost = false; - - private boolean invitesMode = true; - private List idsToInvite = new ArrayList(); - private List idsToRequest = new ArrayList(); - - @Override - public void onCreate(Bundle savedInstanceState) { - - super.onCreate(savedInstanceState); - setRetainInstance(true); - - application = (FriendSmashApplication) getActivity().getApplication(); - } - - @SuppressWarnings("unused") - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup parent, - Bundle savedInstanceState) { - - Log.e(TAG, "onCreateView"); - - View v; - - if (!FriendSmashApplication.IS_SOCIAL) { - v = inflater.inflate(R.layout.fragment_home, parent, false); - } else { - v = inflater.inflate(R.layout.fragment_home_fb_logged_in, parent, false); - - scoresButton = (ImageView)v.findViewById(R.id.scoresButton); - scoresButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onScoresButtonTouched(); - return false; - } - }); - - challengeButton = (ImageView)v.findViewById(R.id.challengeButton); - challengeButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onChallengeButtonTouched(); - return false; - } - }); - - ImageView gameOverChallengeButton = (ImageView)v.findViewById(R.id.gameOverChallengeButton); - gameOverChallengeButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onGameOverChallengeButtonTouched(); - return false; - } - }); - - ImageView gameOverBragButton = (ImageView)v.findViewById(R.id.gameOverBragButton); - gameOverBragButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onGameOverBragButtonTouched(); - return false; - } - }); - - challengeRequestToggle = (ImageView)v.findViewById(R.id.mfsClicker); - challengeRequestToggle.setOnTouchListener(new View.OnTouchListener() { - - @Override - public boolean onTouch(View v, MotionEvent event) { - if (invitesMode) { - invitesMode = false; - challengeRequestToggle.setImageResource(R.drawable.mfs_clicker_request); - invitesGridView.setVisibility(View.INVISIBLE); - requestsGridView.setVisibility(View.VISIBLE); - } else { - invitesMode = true; - challengeRequestToggle.setImageResource(R.drawable.mfs_clicker_invite); - invitesGridView.setVisibility(View.VISIBLE); - requestsGridView.setVisibility(View.INVISIBLE); - } - return false; - } - }); - - invitesGridView = (GridView)v.findViewById(R.id.invitesGridView); - requestsGridView = (GridView)v.findViewById(R.id.requestsGridView); - - requestsGridView.setVisibility(View.INVISIBLE); - - ImageView sendButton = (ImageView)v.findViewById(R.id.sendButton); - sendButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - if (invitesMode) { - sendDirectedInvite(idsToInvite); - } else { - sendDirectedRequest(idsToRequest); - } - - // hide the challenge view and show the main menu - challengeContainer.setVisibility(View.INVISIBLE); - mainButtonsContainer.setVisibility(View.VISIBLE); - return false; - } - }); - - mainButtonsContainer = (LinearLayout)v.findViewById(R.id.mainButtonsContainer); - challengeContainer = (RelativeLayout)v.findViewById(R.id.challengeContainer); - - // Hide the challengeContainer - challengeContainer.setVisibility(View.INVISIBLE); - } - - numBombs = (TextView)v.findViewById(R.id.numBombs); - numCoins = (TextView)v.findViewById(R.id.numCoins); - loadInventory(); - - ImageView bombButton = (ImageView)v.findViewById(R.id.bombButton); - bombButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - HomeActivity homeActivity = (HomeActivity) getActivity(); - homeActivity.buyBombs(); - return false; - } - }); - - progressContainer = (FrameLayout)v.findViewById(R.id.progressContainer); - - playButton = (ImageView)v.findViewById(R.id.playButton); - playButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onPlayButtonTouched(); - return false; - } - }); - - gameOverContainer = (LinearLayout)v.findViewById(R.id.gameOverContainer); - youSmashedUserImage = (ProfilePictureView)v.findViewById(R.id.youSmashedUserImage); - scoredTextView = (TextView)v.findViewById(R.id.scoredTextView); - - ImageView gameOverCloseButton = (ImageView)v.findViewById(R.id.gameOverCloseButton); - gameOverCloseButton.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - onGameOverCloseButtonTouched(); - return false; - } - }); - - // Hide the gameOverContainer - gameOverContainer.setVisibility(View.INVISIBLE); - - // Hide the progressContainer - progressContainer.setVisibility(View.INVISIBLE); - - // Restore the state - restoreState(savedInstanceState); - - return v; - } - - // Personalize this HomeFragment (social-version only) - void personalizeHomeFragment() { - } - - public void loadInventory() { - FriendSmashApplication app = (FriendSmashApplication)getActivity().getApplication(); - numBombs.setText(String.valueOf(app.getBombs())); - numCoins.setText(String.valueOf(app.getCoins())); - } - - // Restores the state during onCreateView - private void restoreState(Bundle savedInstanceState) { - if (savedInstanceState != null) { - pendingPost = savedInstanceState.getBoolean(PENDING_POST_KEY, false); - } - } - - @Override - public void onPause() { - super.onPause(); - - Log.e(TAG, "onPause"); - - // Hide the gameOverContainer - gameOverContainer.setVisibility(View.INVISIBLE); - } - - @Override - public void onResume() { - super.onResume(); - - if (!gameLaunchedFromDeepLinking && gameOverMessageDisplaying) { - // The game hasn't just been launched from deep linking and the game over message should still be displaying, so ... - - // Complete the game over logic - completeGameOver(); - } - } - - @Override - public void onStart() { - super.onStart(); - - // If a dialog exists, create a new dialog (as the screen may have rotated so needs - // new dimensions) and show it - if (dialog != null) { - showDialogWithoutNotificationBar(dialogAction, dialogParams); - } - } - - @Override - public void onStop() { - super.onStop(); - - // If a dialog exists and is showing, dismiss it - if (dialog != null) { - dialog.dismiss(); - } - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean(PENDING_POST_KEY, pendingPost); - outState.putBoolean("gameOverMessageDisplaying", gameOverMessageDisplaying); - } - - // Show a dialog prompting the user with an explanation of why we're asking for the - // user_friends permission before we play. - private void askForFriendsForPlay(final Session session) { - // user has already said no once this session. - if (application.hasDeniedFriendPermission()) { - startGame(); - } else { - new AlertDialog.Builder(getActivity()) - .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // User hit OK. Request Facebook friends permission. - requestFriendsPermission(AUTH_FRIENDS_PLAY_ACTIVITY_CODE); - } - }) - .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User hit cancel. Keep track of deny so that we only ask once per session - // and then just play the game. - application.setHasDeniedFriendPermission(true); - startGame(); - } - }) - .setTitle(R.string.with_friends_dialog_title) - .setMessage(R.string.with_friends_dialog_message) - .show(); - } - } - - // Show a dialog prompting the user with an explanation of why we're asking for the - // user_friends permission before we show the leaderboard. - private void askForFriendsForLeaderboard() { - new AlertDialog.Builder(getActivity()) - .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // User hit OK. Request Facebook friends permission. - requestFriendsPermission(AUTH_FRIENDS_LEADERBOARD_ACTIVITY_CODE); - } - }) - .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User hit cancel. - // do nothing. - } - }) - .setTitle(R.string.leaderboard_dialog_title) - .setMessage(R.string.leaderboard_dialog_message) - .show(); - } - - // Show a dialog prompting the user with an explanation of why we're asking for the - // publish_actions permission in order to save their scores. - private void askForPublishActionsForScores() { - new AlertDialog.Builder(getActivity()) - .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - // User hit OK. Request Facebook friends permission. - requestPublishPermissions(); - } - }) - .setNegativeButton(R.string.dialog_no, new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int id) { - // User hit cancel. - // Hide the gameOverContainer - gameOverContainer.setVisibility(View.INVISIBLE); - } - }) - .setTitle(R.string.publish_scores_dialog_title) - .setMessage(R.string.publish_scores_dialog_message) - .show(); - } - - // Called when the Play button is touched - private void onPlayButtonTouched() { - if (application.IS_SOCIAL == true) { - - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - - // check to see that the user granted the user_friends permission. - List permissions = session.getPermissions(); - if (!permissions.contains("user_friends")) { - // the user didn't grant this permission, so we need to prompt them. - askForFriendsForPlay(session); - return; - } - - if (application.getFriends() != null && application.getFriends().size() <= 0) { - ((HomeActivity)getActivity()).showError("You don't have any friends to smash!", false); - } else { - startGame(); - } - } else { - startGame(); - } - } - - private void startGame() { - Intent i = new Intent(getActivity(), GameActivity.class); - Bundle bundle = new Bundle(); - bundle.putInt("num_bombs", ((FriendSmashApplication) getActivity().getApplication()).getBombs()); - i.putExtras(bundle); - startActivityForResult(i, 0); - } - - // Called when the Challenge button is touched - private void onChallengeButtonTouched() { - sendChallenge(); - } - - // Send a request to a specific player(s) - private void sendDirectedInvite(List invitableTokens) { - Bundle params = new Bundle(); - params.putString("message", "Come join me in the friend smash times!"); - params.putString("to", TextUtils.join(",", invitableTokens)); - showDialogWithoutNotificationBar("apprequests", params); - } - - // Send a request to a specific player(s) - private void sendDirectedRequest(List fbUIDs) { - Bundle params = new Bundle(); - params.putString("message", "I just scored " + application.getScore() + "! Can you beat it?"); - params.putString("to", TextUtils.join(",", fbUIDs)); - showDialogWithoutNotificationBar("apprequests", params); - } - - // Called when the Scores button is touched - private void onScoresButtonTouched() { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - List permissions = session.getPermissions(); - - // check to see that the user granted the user_friends permission. - if (!permissions.contains("user_friends")) { - // the user didn't grant this permission, so we need to prompt them. - askForFriendsForLeaderboard(); - return; - } else { - Intent i = new Intent(getActivity(), ScoreboardActivity.class); - startActivityForResult(i, 0); - } - } - - private void onGameOverChallengeButtonTouched() { - sendDirectedRequest(Arrays.asList(application.getLastFriendSmashedID())); - } - - private void onGameOverBragButtonTouched() { - sendBrag(); - } - - private void onGameOverCloseButtonTouched() { - // check if the user wants to post their score to facebook - // which requires the publish_actions permissions - - if (!FriendSmashApplication.IS_SOCIAL) { - gameOverContainer.setVisibility(View.INVISIBLE); - return; - } - - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - List permissions = session.getPermissions(); - - // check to see that the user granted the publish_actions permission. - if (!permissions.contains("publish_actions")) { - // the user didn't grant this permission, so we need to prompt them. - askForPublishActionsForScores(); - return; - } else { - // Save score and hide the gameOverContainer - postScore(); - gameOverContainer.setVisibility(View.INVISIBLE); - } - } - - private void loadInvitableFriendsForInvites() { - - // Truncating list to first 8 to simplify our UI. - final List invitableFriends = application.getInvitableFriends().subList(0, 8); - final InviteUserArrayAdapter adapter = new InviteUserArrayAdapter(getActivity(), - invitableFriends); - invitesGridView.setAdapter(adapter); - - invitesGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, final View view, - int position, long id) { - - JSONObject clickedUser = invitableFriends.get(position); - String invitableToken = clickedUser.optString("id"); - - // items act as toggles. so check to see if item exists. if it does - // then remove. otherwise, add it. - if (idsToInvite.contains(invitableToken)) { - idsToInvite.remove(invitableToken); - } else { - idsToInvite.add(invitableToken); - } - } - }); - } - - private void loadFriendsForRequests() { - - // assumes friends have been loaded - - // arbitrarily truncating the list of friends at 8 to simplify this a bit. - final RequestUserArrayAdapter adapter = new RequestUserArrayAdapter(getActivity(), - application.getFriends().subList(0, 8)); - requestsGridView.setAdapter(adapter); - - requestsGridView.setOnItemClickListener(new AdapterView.OnItemClickListener() { - - @Override - public void onItemClick(AdapterView parent, final View view, - int position, long id) { - - GraphUser clickedUser = application.getFriends().get(position); - String uid = clickedUser.getId(); - - // items act as toggles. so check to see if item exists. if it does - // then remove. otherwise, add it. - if (idsToRequest.contains(uid)) { - idsToRequest.remove(uid); - } else { - idsToRequest.add(uid); - } - } - - }); - } - - /* - * Now that user_friends is granted, load /me/invitable_friends to get - * friends who have not installed the game. Also load /me/friends which - * returns friends that have installed the game (if using Platform v2.0). - * - */ - - private void loadFriendsFromFacebook(final FriendsLoadedCallback callback) { - final Session session = Session.getActiveSession(); - - RequestBatch requestBatch = new RequestBatch(); - - // Get a list of friends who have _not installed_ the game. - Request invitableFriendsRequest = Request.newGraphPathRequest(session, - "/me/invitable_friends", new Request.Callback() { - - @Override - public void onCompleted(Response response) { - - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - //handleError(error, true); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Get the result - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - List invitableFriends = new ArrayList(); - if (dataArray.length() > 0) { - // Ensure the user has at least one friend ... - - for (int i=0; i users, Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - //handleError(error, true); - } else if (session == Session.getActiveSession()) { - // Set the friends attribute - application.setFriends(users); - callback.afterFriendsLoaded(); - } - } - }); - - Bundle params = new Bundle(); - params.putString("fields", "id,first_name"); - friendsRequest.setParameters(params); - requestBatch.add(friendsRequest); - - // Execute the batch of requests asynchronously - requestBatch.executeAsync(); - } - - /* - * Called when and Activity returns. Checks for the following scenarios: - * - * == Returning from a Facebook dialog asking for the user_friends permission after the user hit - * the Play button. - * - * == Returning from a Facebook dialog asking for the user_friends permission after the user hit - * the Leaderbaord button. - * - * == Returning from a Facebook dialog asking for the publish_actions permission after the user hit - * the close button on the Game Over dialog. - * - * == Returns from a finished game - test status with resultCode and if successfully ended, update - * their score and complete the game over process, otherwise show an error if there is one - * - */ - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - - if (requestCode == AUTH_FRIENDS_PLAY_ACTIVITY_CODE) { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - session.onActivityResult(getActivity(), requestCode, resultCode, data); - - if (session.getPermissions().contains("user_friends")) { - loadFriendsFromFacebook(new FriendsLoadedCallback() { - - @Override - public void afterFriendsLoaded() { - startGame(); - } - - }); - } else { - application.setHasDeniedFriendPermission(true); - startGame(); - } - } else if (requestCode == AUTH_FRIENDS_LEADERBOARD_ACTIVITY_CODE) { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - session.onActivityResult(getActivity(), requestCode, resultCode, data); - - if (session.getPermissions().contains("user_friends")) { - loadFriendsFromFacebook(new FriendsLoadedCallback() { - - @Override - public void afterFriendsLoaded() { - Intent i = new Intent(getActivity(), ScoreboardActivity.class); - startActivityForResult(i, 0); - } - - }); - } else { - // do nothing - } - - } else if (requestCode == AUTH_PUBLISH_ACTIONS_SCORES_ACTIVITY_CODE) { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - session.onActivityResult(getActivity(), requestCode, resultCode, data); - - if (session.getPermissions().contains("publish_actions")) { - postScore(); - } - - // Hide the gameOverContainer - gameOverContainer.setVisibility(View.INVISIBLE); - gameOverMessageDisplaying = false; - - } else if (resultCode == Activity.RESULT_OK && data != null) { - // Finished a game - - // Get the parameters passed through including the score - Bundle bundle = data.getExtras(); - application.setScore(bundle.getInt("score")); - - // Save coins and bombs data to parse - int coinsCollected = (bundle.getInt("coins_collected")); - application.setCoinsCollected(coinsCollected); - if (coinsCollected > 0) { - application.setCoins(application.getCoins()+coinsCollected); - } - int bombsUsed = (bundle.getInt("bombs_used")); - if (bombsUsed > 0) { - application.setBombs(application.getBombs()-bombsUsed); - } - - // Save inventory values - application.saveInventory(); - - // Reload inventory values - loadInventory(); - - // Update the UI - completeGameOver(); - } else if (resultCode == Activity.RESULT_FIRST_USER && data != null) { - // Came from the ScoreboardFragment, so start a game with the specific user who has been clicked - Intent i = new Intent(getActivity(), GameActivity.class); - Bundle bundle = new Bundle(); - bundle.putString("user_id", data.getStringExtra("user_id")); - i.putExtras(bundle); - startActivityForResult(i, 0); - } else if (resultCode == Activity.RESULT_CANCELED && data != null) { - Bundle bundle = data.getExtras(); - ((HomeActivity)getActivity()).showError(bundle.getString("error"), false); - } else if (resultCode == Activity.RESULT_CANCELED && - ((FriendSmashApplication) getActivity().getApplication()).getGameFragmentFBRequestError() != null) { - ((HomeActivity)getActivity()).handleError( - ((FriendSmashApplication) getActivity().getApplication()).getGameFragmentFBRequestError(), - false); - ((FriendSmashApplication) getActivity().getApplication()).setGameFragmentFBRequestError(null); - } - } - - // Start a Game with a specified user id (called from the ScoreboardFragment) - void startGame(String userId) { - Intent i = new Intent(getActivity(), GameActivity.class); - Bundle bundle = new Bundle(); - bundle.putString("user_id", userId); - bundle.putInt("num_bombs", ((FriendSmashApplication) getActivity().getApplication()).getBombs()); - i.putExtras(bundle); - startActivityForResult(i, 0); - } - - // Complete the game over process - private void completeGameOver() { - Log.e(TAG, "completeGameOver"); - - // Set the scoreboardEntriesList to null so that the scoreboard is refreshed - // now that the player has played another game in case they have a higher score or - // any of their friends have a higher score - application.setScoreboardEntriesList(null); - - if (FriendSmashApplication.IS_SOCIAL) { - youSmashedUserImage.setProfileId(application.getLastFriendSmashedID()); - youSmashedUserImage.setCropped(true); - - if (application.getScore() >= 0) { - scoredTextView.setText("You smashed " + application.getLastFriendSmashedName() + - " " + application.getScore() + (application.getScore() == 1 ? " time!" : " times!") + - "\n" + "Collected " + application.getCoinsCollected() + - (application.getCoinsCollected() == 1 ? " coin!" : " coins!")); - } - else { - scoredTextView.setText(getResources().getString(R.string.no_score)); - } - - } else { - youSmashedUserImage.setVisibility(View.INVISIBLE); - - scoredTextView.setText("You smashed a person " + application.getScore() - + (application.getScore() == 1 ? " time!" : " times!") + - "\n" + "Collected " + application.getCoinsCollected() + - (application.getCoinsCollected() == 1 ? " coin!" : " coins!")); - } - - - // Show the gameOverContainer - gameOverContainer.setVisibility(View.VISIBLE); - - // Set the gameOverMessageDisplaying boolean to true - gameOverMessageDisplaying = true; - - } - - - /* Facebook Integration */ - - // Pop up a request dialog for the user to invite their friends to smash them back in Friend Smash - private void sendChallenge() { - } - - // Pop up a filtered request dialog for the user to invite their friends that have Android devices - // to smash them back in Friend Smash - private void sendFilteredChallenge() { - // Okay, we're going to filter our friends by their device, we're looking for friends with an Android device - - // Show the progressContainer during the network call - progressContainer.setVisibility(View.VISIBLE); - - // Get a list of the user's friends' names and devices - final Session session = Session.getActiveSession(); - Request friendDevicesGraphPathRequest = Request.newGraphPathRequest(session, "me/friends", new Request.Callback() { - @Override - public void onCompleted(Response response) { - // Hide the progressContainer now that the network call has completed - progressContainer.setVisibility(View.INVISIBLE); - - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(FriendSmashApplication.TAG, error.toString()); - ((HomeActivity)getActivity()).handleError(error, false); - } else if (session == Session.getActiveSession()) { - if (response != null) { - // Get the result - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - if (dataArray.length() > 0) { - // Ensure the user has at least one friend ... - - // Store the filtered friend ids in the following List - ArrayList filteredFriendIDs = new ArrayList(); - - for (int i=0; i validSuggestedFriends = new ArrayList(); - - // So, we loop through each suggested friend - for (String suggestedFriend : suggestedFriends) - { - // If they are on our device filtered list, we know they have an Android device - if (filteredFriendIDs.contains(suggestedFriend)) - { - // So we can call them valid - validSuggestedFriends.add(suggestedFriend); - } - } - params.putString("suggestions", TextUtils.join(",", validSuggestedFriends.toArray(new String[validSuggestedFriends.size()]))); - - // Show FBDialog without a notification bar - showDialogWithoutNotificationBar("apprequests", params); - } - } - } - } - }); - // Pass in the fields as extra parameters, then execute the Request - Bundle extraParamsBundle = new Bundle(); - extraParamsBundle.putString("fields", "name,devices"); - friendDevicesGraphPathRequest.setParameters(extraParamsBundle); - Request.executeBatchAsync(friendDevicesGraphPathRequest); - } - - private void sendCustomChallenge() { - Session session = Session.getActiveSession(); - if (session == null || !session.isOpened()) { - return; - } - - // check to see that the user granted the user_friends permission. - List permissions = session.getPermissions(); - if (!permissions.contains("user_friends")) { - // if the user hasn't granted user_friends, we'll just fallback - // to showing the request dialog without customization. - sendChallenge(); - } else { - loadInvitableFriendsForInvites(); - loadFriendsForRequests(); - - // Hide the buttons container and show the challenge container - mainButtonsContainer.setVisibility(View.INVISIBLE); - challengeContainer.setVisibility(View.VISIBLE); - } - } - - // Pop up a feed dialog for the user to brag to their friends about their score and to offer - // them the opportunity to smash them back in Friend Smash - private void sendBrag() { - } - - // Show a dialog (feed or request) without a notification bar (i.e. full screen) - private void showDialogWithoutNotificationBar(String action, Bundle params) { - } - - // Called when the session state has changed - void tokenUpdated() { - // Optional place to take action after the token has been updated (typically after a new permission has - // been granted) - } - - void requestPublishPermissions() { - Log.d(TAG, "Requesting publish permissions."); - final Session session = Session.getActiveSession(); - if (session != null) { - Session.NewPermissionsRequest newPermissionsRequest = new Session.NewPermissionsRequest(this, PERMISSIONS) - // demonstrate how to set an audience for the publish permissions, - // if none are set, this defaults to FRIENDS - .setDefaultAudience(SessionDefaultAudience.FRIENDS) - .setRequestCode(AUTH_PUBLISH_ACTIONS_SCORES_ACTIVITY_CODE); - session.requestNewPublishPermissions(newPermissionsRequest); - } - } - - private void requestFriendsPermission(int requestCode) { - Log.d(TAG, "Requesting friends permissions."); - Session.NewPermissionsRequest newFriendsPermissionsRequest = new Session.NewPermissionsRequest(this, "user_friends") - .setRequestCode(requestCode); - Session.getActiveSession().requestNewReadPermissions(newFriendsPermissionsRequest); - - } - - // Post score to Facebook - private void postScore() { - final int score = application.getScore(); - if (score > 0) { - // Only post the score if they smashed at least one friend! - - // Post the score to our servers for the high score table - AsyncTask.execute(new Runnable() { - public void run() { - HttpClient httpClient = new DefaultHttpClient(); - HttpPost httpPost = new HttpPost("http://www.friendsmash.com/scores"); - try { - // Add data - List nameValuePairs = new ArrayList(2); - nameValuePairs.add(new BasicNameValuePair("fbid", application.getCurrentFBUser().getId())); - nameValuePairs.add(new BasicNameValuePair("score", "" + score)); - httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); - - // Execute the HTTP Post request and log the result - HttpResponse responsePost = httpClient.execute(httpPost); - HttpEntity responseEntity = responsePost.getEntity(); - String response = EntityUtils.toString(responseEntity); - Log.i(FriendSmashApplication.TAG, "Score post to server: " + response); - } catch (Exception e) { - Log.e(FriendSmashApplication.TAG, e.toString()); - Log.e(FriendSmashApplication.TAG, "Posting Score to Server failed: " + e.getMessage()); - } - } - }); - } - } - - // Getters & Setters - - public boolean isPendingPost() { - return pendingPost; - } - - public void setPendingPost(boolean pendingPost) { - this.pendingPost = pendingPost; - } -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/InviteUserArrayAdapter.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/InviteUserArrayAdapter.java deleted file mode 100644 index 26dd354..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/InviteUserArrayAdapter.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.facebook.android.friendsmash; - -import java.io.InputStream; -import java.util.List; - -import org.json.JSONArray; -import org.json.JSONObject; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.util.Log; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -public class InviteUserArrayAdapter extends ArrayAdapter { - private final Context context; - private final List invitableFriends; - private ImageView profilePicView; - - public InviteUserArrayAdapter(Context context, List invitableFriends) { - super(context, R.layout.invite_list_item_view, invitableFriends); - this.context = context; - this.invitableFriends = invitableFriends; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - View listItemView = inflater.inflate(R.layout.invite_list_item_view, parent, false); - - profilePicView = (ImageView) listItemView.findViewById(R.id.inviteListItemProfilePic); - TextView nameView = (TextView) listItemView.findViewById(R.id.inviteListItemName); - final ImageView checkBox = (ImageView) listItemView.findViewById(R.id.inviteListItemCheckbox); - - JSONObject currentUser = invitableFriends.get(position); - - JSONObject pictureJson = currentUser.optJSONObject("picture") - .optJSONObject("data"); - new ImageDownloader(profilePicView).execute(pictureJson.optString("url")); - - nameView.setText(currentUser.optString("first_name")); - - checkBox.setOnTouchListener(new View.OnTouchListener() { - boolean checked = false; - - @Override - public boolean onTouch(View v, MotionEvent event) { - // toggle image - if (checked) { - checked = false; - checkBox.setImageResource(R.drawable.checkbox_cold); - } else { - checked = true; - checkBox.setImageResource(R.drawable.checkbox_hot); - } - return false; - } - }); - - return listItemView; - } - - class ImageDownloader extends AsyncTask { - ImageView bmImage; - - public ImageDownloader(ImageView bmImage) { - this.bmImage = bmImage; - } - - protected Bitmap doInBackground(String... urls) { - String url = urls[0]; - Bitmap mIcon = null; - try { - InputStream in = new java.net.URL(url).openStream(); - mIcon = BitmapFactory.decodeStream(in); - } catch (Exception e) { - Log.e("Error", e.getMessage()); - } - return mIcon; - } - - protected void onPostExecute(Bitmap result) { - bmImage.setImageBitmap(result); - } - } -} - diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/RequestUserArrayAdapter.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/RequestUserArrayAdapter.java deleted file mode 100644 index 69bc321..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/RequestUserArrayAdapter.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.facebook.android.friendsmash; - -import java.util.List; - -import com.facebook.model.GraphUser; -import com.facebook.widget.ProfilePictureView; - -import android.content.Context; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ArrayAdapter; -import android.widget.ImageView; -import android.widget.TextView; - -public class RequestUserArrayAdapter extends ArrayAdapter { - private final Context context; - private final List users; - - public RequestUserArrayAdapter(Context context, List users) { - super(context, R.layout.request_list_item_view, users); - this.context = context; - this.users = users; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - LayoutInflater inflater = (LayoutInflater) context - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - - View listItemView = inflater.inflate(R.layout.request_list_item_view, parent, false); - ProfilePictureView profilePicView = (ProfilePictureView) listItemView.findViewById(R.id.requestListItemProfilePic); - TextView nameView = (TextView) listItemView.findViewById(R.id.requestListItemName); - final ImageView checkBox = (ImageView) listItemView.findViewById(R.id.requestListItemCheckbox); - - GraphUser currentUser = users.get(position); - - profilePicView.setProfileId(currentUser.getId()); - profilePicView.setCropped(true); - nameView.setText(currentUser.getFirstName()); - - checkBox.setOnTouchListener(new View.OnTouchListener() { - boolean checked = false; - - @Override - public boolean onTouch(View v, MotionEvent event) { - // toggle image - if (checked) { - checked = false; - checkBox.setImageResource(R.drawable.checkbox_cold); - } else { - checked = true; - checkBox.setImageResource(R.drawable.checkbox_hot); - } - return false; - } - }); - - return listItemView; - } -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardActivity.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardActivity.java deleted file mode 100755 index 5cc01dc..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardActivity.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.android.friendsmash; - -import android.support.v4.app.Fragment; - -/** - * Activity used once a user opens the Facebook scoreboard - all logic - * is within ScoreboardFragment - */ -public class ScoreboardActivity extends SingleFragmentActivity { - - @Override - protected Fragment createFragment() { - return new ScoreboardFragment(); - } - -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardEntry.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardEntry.java deleted file mode 100755 index e5bd973..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardEntry.java +++ /dev/null @@ -1,66 +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.android.friendsmash; - -/** - * Class representing an individual scoreboard entry - */ -public class ScoreboardEntry implements Comparable { - - // Attributes for a ScoreboardEntry - private String id; - private String name; - private int score; - - public ScoreboardEntry (String id, String name, int score) { - setId(id); - setName(name); - setScore(score); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public int getScore() { - return score; - } - - public void setScore(int score) { - this.score = score; - } - - @Override - public int compareTo(ScoreboardEntry another) { - // Returns a negative integer, zero, or a positive integer as this object - // is less than, equal to, or greater than the specified object. - return this.score - another.score; - } - -} diff --git a/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardFragment.java b/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardFragment.java deleted file mode 100755 index b5d65ae..0000000 --- a/friendsmash_incomplete/src/com/facebook/android/friendsmash/ScoreboardFragment.java +++ /dev/null @@ -1,373 +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.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.JSONException; -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.FacebookRequestError; -import com.facebook.HttpMethod; -import com.facebook.Request; -import com.facebook.Response; -import com.facebook.Session; -import com.facebook.model.GraphObject; -import com.facebook.model.GraphObjectList; -import com.facebook.model.GraphUser; -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 () { - String fbAppID = application.getFBAppID(); - final Session session = Session.getActiveSession(); - - Request scoresGraphPathRequest = Request.newGraphPathRequest(session, - fbAppID + "/scores" , - new Request.Callback() { - - @Override - public void onCompleted(Response response) { - FacebookRequestError error = response.getError(); - if (error != null) { - Log.e(TAG, error.toString()); - // TODO: Show an error or handle it better. - //((ScoreboardActivity)getActivity()).handleError(error, false); - } else if (session == Session.getActiveSession()) { - if (response != null) { - GraphObject graphObject = response.getGraphObject(); - JSONArray dataArray = (JSONArray)graphObject.getProperty("data"); - - ArrayList scoreboardEntriesList = new ArrayList(); - - for (int i=0; i< dataArray.length(); i++) { - JSONObject oneData = dataArray.optJSONObject(i); - int score = oneData.optInt("score"); - - JSONObject userObj = oneData.optJSONObject("user"); - String userID = userObj.optString("id"); - String userName = userObj.optString("name"); - - scoreboardEntriesList.add(new ScoreboardEntry(userID, userName, score)); - } - - Comparator 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(); - } - }); - } - } - } - }); - Request.executeBatchAsync(scoresGraphPathRequest); - } - - 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 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); - int backgroundImageViewMarginSide = getResources().getDimensionPixelSize(R.dimen.scoreboard_background_imageview_margin_side); - - if (index % 2 != 0) { - // Odd entry - backgroundImageViewLayoutParams.setMargins(backgroundImageViewMarginSide, backgroundImageViewMarginTop, 0, 0); - backgroundImageViewLayoutParams.gravity = Gravity.LEFT; - } else { - // Even entry - backgroundImageViewLayoutParams.setMargins(0, backgroundImageViewMarginTop, backgroundImageViewMarginSide, 0); - 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++; - } - } - } -} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..8c0fb64 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0c71e76 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Apr 10 15:27:10 PDT 2013 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..aec9973 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/local.properties b/local.properties new file mode 100644 index 0000000..33dc363 --- /dev/null +++ b/local.properties @@ -0,0 +1,11 @@ +## This file is automatically generated by Android Studio. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Tue Nov 03 15:58:25 GMT 2015 +sdk.dir=/Users/jakubpudelek/Library/Android/sdk diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..a887c88 --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':friend-smash'