diff --git a/facebook/README.md b/facebook/README.md
index 8b06c9049..fcfc937a5 100644
--- a/facebook/README.md
+++ b/facebook/README.md
@@ -3,68 +3,22 @@ This open source Java library allows you to integrate Facebook into your Android
Getting Started
===============
-See our [Android SDK Getting Started Guide](http://developers.facebook.com/docs/guides/mobile#android)
+See our [Android SDK Getting Started Guide](https://developers.facebook.com/docs/mobile/android/build/)
Sample Applications
===============
-This library includes two sample applications to guide you in development.
+This library includes three sample applications to guide you in development.
* __simple__: A bare-bones app that demonstrates authorization, making API calls, and invoking a dialog.
* __stream__: This slightly beefier application lets you view your news feed.
-To install a sample application into Eclipse (3.5):
+* __Hackbook__: This includes Single Sign On implementation (SSO), sample API calls, and advanced features like Get new Permissions, Run sample FQL Query and Graph API Explorer. Check out [Hackbook for Android](https://developers.facebook.com/docs/mobile/android/hackbook/)
-* Create the sample application in your workspace:
-2. Select __File__ -> __New__ -> __Project__, choose __Android Project__, and then click __Next__.
- 3. Select "Create project from existing source".
- 4. Choose either __examples/simple__ or __examples/stream__. You should see the project properties populated.
- 5. Click Finish to continue.
-
-* Build the project: from the Project menu, select "Build Project".
-
-* Run the application: from the Run menu, select "Run Configurations...". Under Android Application, you can create a new run configuration: give it a name and select the simple Example project; use the default activity Launch Action. See http://developer.android.com/guide/developing/eclipse-adt.html#RunConfig for more details.
-
-
-Testing
-===============
-
-Here are some tips to help test your application:
-
-* You will need to have the Facebook application in your test environment. The SDK includes a developer release of the Facebook application that can be side-loaded for testing purposes. On an actual device, you can just download the latest version of the app from the Android Market, but on the emulator you will have to install it yourself:
-
- adb install FBAndroid.apk
-
-* Use a signed build. You can sign with a debug key, but make sure that the key you used to sign matches the __Key Hash__ field in the Facebook developer settings.
-
-* Make sure to test both with and without the Facebook application. The SDK will fall back to a Webview if the Facebook app is not installed.
-
-* You can use this [guide to developing on a device](http://developer.android.com/guide/developing/device.html).
-
-Debugging
-==========
-
-Here's a few common errors and their solutions.
-
-* __Build error: "missing gen files".__
-
- This should go away when you rebuild the project. If you have trouble, try running __Clean...__ from the __Project__ menu.
-
-* __Error: "invalid_key"__
-
- This error means that the Facebook server doesn't recognize your Android key hash. Make sure that you correctly generated and copy/pasted your key hash into the Facebook developer settings console (http://www.facebook.com/developers/apps.php), and make sure that your application has been signed with the same key you registered with Facebook.
-
-* __Dialog won't load or shows a blank screen.__
-
- This can be tricky to debug. If the logs don't give an indication of what's wrong, I suggest installing tcpdump on your device and getting a trace. Tutorial: http://www.vbsteven.be/blog/android-debugging-inspectin-network-traffic-with-tcpdump/
-
- If you still can't tell what's going on, then file an issue and please include the HTTP trace.
-
-* __I can't upload photos with photos.upload.__
-
- Make sure the Bundle value for the photo parameter is a byte array.
Report Issues/Bugs
===============
-[http://bugs.developers.facebook.net/enter_bug.cgi?product=SDKs](http://bugs.developers.facebook.net/enter_bug.cgi?product=SDKs)
+[Bugs](https://developers.facebook.com/bugs)
+
+[Questions](http://facebook.stackoverflow.com/questions/tagged/android)
diff --git a/facebook/examples/Hackbook/AndroidManifest.xml b/facebook/examples/Hackbook/AndroidManifest.xml
new file mode 100644
index 000000000..afd4c5307
--- /dev/null
+++ b/facebook/examples/Hackbook/AndroidManifest.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/README.md b/facebook/examples/Hackbook/README.md
new file mode 100644
index 000000000..3036a187e
--- /dev/null
+++ b/facebook/examples/Hackbook/README.md
@@ -0,0 +1,130 @@
+This 'Hackbook for Android' app includes Single Sign On implementation (SSO), sample API calls and Graph API Explorer and is targeted towards android developers who want to make their apps social using Facebook Social Graph. The Code provided here is to showcase how to implement the SSO and make the API calls. If you have any questiosn or comments related to this sample app, please post them here - http://facebook.stackoverflow.com/questions/tagged/hackbook-for-android
+
+Getting Started
+===============
+
+See Android tutorial - https://developers.facebook.com/docs/mobile/android/build/
+
+Configuring the app
+===============
+
+1. Launch Eclipse
+2. Ensure you have installed the Android plugin.
+3. Create Facebook SDK Project - follow the Step-1 instructions in the tutorial
+4. Create the Hackbook Project :
+ 4.1 Select __File__ -> __New__ -> __Project__, choose __Android Project__, and then click __Next__.
+ 4.2 Select "Create project from existing source".
+ 4.3. Choose examples/Hackbook. You should see the project properties populated.
+ 4.4. Click Finish to continue.
+5. Add reference to the Facebook SDK - follow the Step-3 instructions in the tutorial
+6. Create a Facebook app if you don't have one already and add the app id in the Hackbook.java->APP_ID
+
+Build the app
+===============
+
+7. And you are done and ready to compile the project:
+ 7.1 From the Project menu, select "Build Project".
+
+Run the app
+===============
+
+8. Hopefully project would compile fine. Next run the app on the emulator or on the phone (See http://developer.android.com/guide/developing/eclipse-adt.html#RunConfig for more details.)
+ 8.1 If you plan to run on emulator, ensure you have created an Android Virtual Device (AVD):
+ 8.1.1 Go to Window -> Android SDK and AVD Manager -> Click New
+ 8.1.2 Provide a Name (AVD 2.3 e.g.) and choose the Target (Android 2.3 if available).
+ 8.1.3 Click 'Create AVD' at the bottom and that should create an AVD which you can run the app on described next.
+
+ 8.2 Go to Run->Run Configurations->Android Application->create a new run configuration by clicking the icon with + button on it.
+ 8.3 Name it 'Hackbook'
+ 8.4 Under the Project, Browse and choose Hackbook
+ 8.5 Go to Target tab -> Choose manual if you wish to run on the phone, else choose Automatic and select an AVD created in step 8.1
+ 8.6 Click Run and your 'Hackbook for Android' app should be up and running.
+
+
+Installing the Facebook app
+===============
+
+You will need to have the Facebook application on the handset or the emulator to test the Single Sign On. The SDK includes a developer release of the Facebook application that can be side-loaded for testing purposes. On an actual device, you can just download the latest version of the app from the Android Market, but on the emulator you will have to install it yourself:
+
+ adb install FBAndroid.apk
+
+What's in there
+===============
+
+Note: The source tags are provided through out the code base to facilitate easy search for the relevant code. Do a project-wide search for the source tags to get straight to the relevant code. Refer below for source tags for each feature.
+
+1. Login button - This uses SSO to authorize the app. Clicking on Login should activate SSO (if the app is installed) or show OAuth dialog. When authorizing, no permissions are requested and the app will get basic permission by default.
+
+Source Tag - login_tag
+
+- Hackbook.java - this layout the login button and initialize it. Since this is also the calling acitivty, this overrides the onActivityResult() method.
+- LoginButton.java - this calls the mFb.authorize(mActivity, mPermissions, mActivityCode, new LoginDialogListener()) which authorizes the app via SSO or OAuth.
+- SessionStore.java - stores the access token and access expiry time for future app launch. This is important that you save the access token, else user will need to authorize your app each time they launch it which is annoying and user is likely to churn out.
+- SessionEvents.java - Authorization state tracker, calls the listener on login/logout success or error.
+------------------------
+
+2. Update Status - this allows user to update his status by calling the 'feed' dialog. More info on feed dialog - https://developers.facebook.com/docs/reference/dialogs/feed/
+
+Source Tag - update_status_tag, view_post_tag, delete_post_tag
+
+- Hackbook.java - Case 0: update status by calling the 'feed' dialog.
+- UpdateStatusResultDialog.java - shows the object-id returned in the dialog response. You can view or delete the post here.
+------------------------
+
+3. App Requests - this allows to send app requests to user's friends by calling the 'apprequests' dialog. More info - https://developers.facebook.com/docs/reference/dialogs/requests/
+
+Source Tag - app_requests_tag
+
+- Hackbook.java - Case 1: send the app requests by calling the the 'apprequests' dialog.
+------------------------
+
+4. Get Friends - Get user's friends via Graph API or FQL Query. User must be logged-in to use this. Also post on a friend's wall by clicking on his name in the list.
+
+Source Tag - get_friends_tag, friend_wall_tag
+
+- Hackbook.java - Case 2: Use Graph API 'me/friends' which returns friends sorted by UID, currently it's not possible to sort any other way in the Graph API. Use the FQL Query to sort by name - select name, current_location, uid, pic_square from user where uid in (select uid2 from friend where uid1=me()) order by name
+- FriendsList.java - displays the friends profile pic and names as returned by the api. Also post on friend's wall by clicking on the friend.
+- FriendsModel.java - run async tasks to fetch the profile picture limited to 15 tasks at any given time.
+
+5. Upload Photo - Upload a photo either from the media gallery or from a remote server. You require 'photo_upload' to upload photos on user profile.
+
+Source Tag - upload_photo, view_photo_tag, tag_photo_tag
+
+- Hackbook.java - Case 3: Photo is uploaded by posting byte-array or url to me/photos endpoint. Media Gallery is launched by invoking the MediaStore.Images.Media.EXTERNAL_CONTENT_URI intent and overriding the OnActivityResult() to get the picture from the media gallery. Photo from remote server is uploaded by simply providing the image url in the 'url' param in the graph.facebook.com/me/photos endpoint.
+- UploadPhotoResultDialog.java - shows the object-id returned after uploaded the photo. You can view or tag the photo here.
+------------------------
+
+
+6. Place Check-in - Fetch user's current location or use Times Square as the current location and get nearby places which user can check-in at.
+
+Source Tag - fetch_places_tag, check_in_tag
+
+- Hackbook.java - Case 4: Ask to fetch current location or use Times Square as the current location.
+- Places.java - Get user's current location and fetch the nearby places by calling the graph.facebook.com/search?type=places&distance=1000¢er=lat,lon. Check-in user at a place by calling the graph.facebook.com/me/checkins&place=&message=&coordinates={"latitude": , "longitude:": }
+------------------------
+
+7. Run FQL Query - Type and run any FQL Query and see the results.
+
+Source Tag - fql_query_tag
+
+- FQLQuery.java - Layout the FQL Query Dialog and run the query and show the results.
+------------------------
+
+8. Graph API Explorer - Explore user's social graph, see his and friends' connections and get new permissions. This is similar to the Graph Explorer dev tool - http://developers.facebook.com/tools/explorer/. The ObjectIDs in the API response are linkified and can be clicked to fetch object specific data.
+ - Click the 'x' button to clear the textfield
+ - Click the green up arrow button in the textfield to get the 'me' object data.
+ - Click on 'Get Permissions' to get new permissions including user's, his friends or extended permissions.
+ - Click on 'Fields/Connections' to see current object's fields and connections.
+ - On the Fields & Connections dialog, in the Fields tab, select the fields to view or in the Connections tab, click the connection to view it's content.
+
+Source Tag - graph_explorer
+
+- Hackbook.java - Case 5: Launch the GraphExplorer intent
+- GraphExplorer.java - Layout and execute the graph explorer
+- IntentUriHandler.java - Handle the fbgraphex: schema generated while linkifying the Object IDs in the graph explorer output
+
+
+
+Report Issues/Bugs
+===============
+Please report issues here - http://facebook.stackoverflow.com/questions/tagged/hackbook-for-android
diff --git a/facebook/examples/Hackbook/default.properties b/facebook/examples/Hackbook/default.properties
new file mode 100644
index 000000000..6805fb9fe
--- /dev/null
+++ b/facebook/examples/Hackbook/default.properties
@@ -0,0 +1,14 @@
+# 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 use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Indicates whether an apk should be generated for each density.
+split.density=false
+# Project target.
+target=android-8
+android.library.reference.1=../../../newdialog/facebook-android-sdk/facebook
diff --git a/facebook/examples/Hackbook/res/drawable-hdpi/splash.png b/facebook/examples/Hackbook/res/drawable-hdpi/splash.png
new file mode 100644
index 000000000..3efb5e80a
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable-hdpi/splash.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/icon.png b/facebook/examples/Hackbook/res/drawable/icon.png
new file mode 100644
index 000000000..7a2d0cbe4
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/icon.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/icon_hack.png b/facebook/examples/Hackbook/res/drawable/icon_hack.png
new file mode 100644
index 000000000..a812187e6
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/icon_hack.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/login.png b/facebook/examples/Hackbook/res/drawable/login.png
new file mode 100644
index 000000000..95c8dc156
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/login.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/login_button.xml b/facebook/examples/Hackbook/res/drawable/login_button.xml
new file mode 100644
index 000000000..73dc6c3ab
--- /dev/null
+++ b/facebook/examples/Hackbook/res/drawable/login_button.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/facebook/examples/Hackbook/res/drawable/login_down.png b/facebook/examples/Hackbook/res/drawable/login_down.png
new file mode 100644
index 000000000..10d216b3f
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/login_down.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/logout.png b/facebook/examples/Hackbook/res/drawable/logout.png
new file mode 100644
index 000000000..290272aa0
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/logout.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/logout_button.xml b/facebook/examples/Hackbook/res/drawable/logout_button.xml
new file mode 100644
index 000000000..58f57656b
--- /dev/null
+++ b/facebook/examples/Hackbook/res/drawable/logout_button.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/facebook/examples/Hackbook/res/drawable/logout_down.png b/facebook/examples/Hackbook/res/drawable/logout_down.png
new file mode 100644
index 000000000..1ab14b9dc
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/logout_down.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/me.png b/facebook/examples/Hackbook/res/drawable/me.png
new file mode 100644
index 000000000..413e20bb9
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/me.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/splash.png b/facebook/examples/Hackbook/res/drawable/splash.png
new file mode 100644
index 000000000..1892fcec6
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/splash.png differ
diff --git a/facebook/examples/Hackbook/res/drawable/x.png b/facebook/examples/Hackbook/res/drawable/x.png
new file mode 100644
index 000000000..f0978141d
Binary files /dev/null and b/facebook/examples/Hackbook/res/drawable/x.png differ
diff --git a/facebook/examples/Hackbook/res/layout/connection_item.xml b/facebook/examples/Hackbook/res/layout/connection_item.xml
new file mode 100644
index 000000000..e556c0685
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/connection_item.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/fields_connections_list.xml b/facebook/examples/Hackbook/res/layout/fields_connections_list.xml
new file mode 100644
index 000000000..06b48f89e
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/fields_connections_list.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/fields_item.xml b/facebook/examples/Hackbook/res/layout/fields_item.xml
new file mode 100644
index 000000000..c072d7bd2
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/fields_item.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/fql_query.xml b/facebook/examples/Hackbook/res/layout/fql_query.xml
new file mode 100644
index 000000000..ddda019b2
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/fql_query.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/friend_item.xml b/facebook/examples/Hackbook/res/layout/friend_item.xml
new file mode 100644
index 000000000..c1c6728ed
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/friend_item.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/friends_list.xml b/facebook/examples/Hackbook/res/layout/friends_list.xml
new file mode 100644
index 000000000..82e565181
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/friends_list.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/graph_explorer.xml b/facebook/examples/Hackbook/res/layout/graph_explorer.xml
new file mode 100644
index 000000000..a7ebee4fa
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/graph_explorer.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/main.xml b/facebook/examples/Hackbook/res/layout/main.xml
new file mode 100644
index 000000000..2dc8e244a
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/main.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/main_list_item.xml b/facebook/examples/Hackbook/res/layout/main_list_item.xml
new file mode 100644
index 000000000..2ac0fac97
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/main_list_item.xml
@@ -0,0 +1,9 @@
+
diff --git a/facebook/examples/Hackbook/res/layout/permission_item.xml b/facebook/examples/Hackbook/res/layout/permission_item.xml
new file mode 100644
index 000000000..57eb43a8b
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/permission_item.xml
@@ -0,0 +1,8 @@
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/permissions_list.xml b/facebook/examples/Hackbook/res/layout/permissions_list.xml
new file mode 100644
index 000000000..f5592c5ae
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/permissions_list.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/place_item.xml b/facebook/examples/Hackbook/res/layout/place_item.xml
new file mode 100644
index 000000000..cbc139e42
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/place_item.xml
@@ -0,0 +1,24 @@
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/places_list.xml b/facebook/examples/Hackbook/res/layout/places_list.xml
new file mode 100644
index 000000000..f63bb2884
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/places_list.xml
@@ -0,0 +1,11 @@
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/splash.xml b/facebook/examples/Hackbook/res/layout/splash.xml
new file mode 100644
index 000000000..211860639
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/splash.xml
@@ -0,0 +1,5 @@
+
diff --git a/facebook/examples/Hackbook/res/layout/token_refresh.xml b/facebook/examples/Hackbook/res/layout/token_refresh.xml
new file mode 100644
index 000000000..811cd598a
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/token_refresh.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/update_post_response.xml b/facebook/examples/Hackbook/res/layout/update_post_response.xml
new file mode 100644
index 000000000..2a0bd90a6
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/update_post_response.xml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/layout/upload_photo_response.xml b/facebook/examples/Hackbook/res/layout/upload_photo_response.xml
new file mode 100644
index 000000000..3b8bd7743
--- /dev/null
+++ b/facebook/examples/Hackbook/res/layout/upload_photo_response.xml
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/facebook/examples/Hackbook/res/values/colors.xml b/facebook/examples/Hackbook/res/values/colors.xml
new file mode 100644
index 000000000..cb999e5cc
--- /dev/null
+++ b/facebook/examples/Hackbook/res/values/colors.xml
@@ -0,0 +1,10 @@
+
+
+ #ffffff
+ #000000
+ #23cf34
+ #E47833
+ #4E78A0
+ #0000FF
+ #FF909090
+
\ No newline at end of file
diff --git a/facebook/examples/Hackbook/res/values/strings.xml b/facebook/examples/Hackbook/res/values/strings.xml
new file mode 100644
index 000000000..a2aeda13e
--- /dev/null
+++ b/facebook/examples/Hackbook/res/values/strings.xml
@@ -0,0 +1,88 @@
+
+
+ Hackbook for Android
+ Checkout out Hackbook for Android to learn how you can make your android apps social using Facebook Platform.
+ I am using the Hackbook for Android
+ Learn how to make your android apps social.
+ Request!
+ Upload PhotoWall Post!
+ Delete Post
+ Graph API Explorer
+ Get Permissions
+ Access Token:
+ https://graph.facebook.com/
+ Submit
+ Output:
+ Show metadata
+ Show picture
+ URL
+ Target URL:
+ Exception:
+ Tip:
+ Error
+ Facebook Error:
+ Api Response:
+ View Source
+ View Post
+ Delete Post
+ Source Code:
+ Please wait...
+ View Photo
+ Hide Photo
+ Tag Photo
+ Graph API
+ FQL Query
+ Source tag:
+ Source tag: \"perms_tag\"
+ Graph API or FQL Query?
+ Get friends using Graph or FQL Query?\n\nWith FQL query you can sort the list by names, whereas with Graph list will be ordered by UID and can\'t be changed.
+ Post on friend\'s wall
+ Friends list fetched. You can post on friend\'s wall by clicking on the item.
+ OK
+ Post on Wall?
+ Would you like to post on %1$s\'s wall
+ Yes
+ No
+ Save
+ Reset
+ Get Fields
+ Fields
+ Connections
+ Check-in
+ Cancel
+ User Data
+ Friends Data
+ Extended
+ Upload from gallery or remote?
+ Upload picture from phone\' gallery or remote server?
+ Gallery
+ Remote
+ Get Location?
+ Get current location or use Times Square as the location?
+ Current Location
+ Fetching current permissions...
+ Also, checkout the web-version of the Graph API Explorer tool
+ Fetching nearby places...
+ Times Square
+ Check-in?
+ Permissions
+ Back to parent
+ Fields \u0026 Connections
+ Select Permissions:
+ Checkout permissions reference doc
+ Fetching Location...
+ Would you like to check-in at %1$s?
+ \'read_stream\' permission is required to view and delete the post.\n\nUse SDK dialogs to publish stories or post on friends wall. More info\n\nLike and Comment on a post
+ Photos are by default uploaded to the app\'s album. Specify album_id to upload to specific album. E.g. https://graph.facebook.com/{album_id}/photos.\n\nMore Info: https://developers.facebook.com/docs/reference/api/photo
+ Enter FQL Query:
+ Enable GPS
+ Please enable GPS to get nearby places and check-in
+ GPS Settings
+ Refresh Token
+ Refresh
+ Refreshing…
+ In most cases the access token should be refreshed silently when the application is running (for example see Hackbook onResume method).
+ Binding to the Facebook Android Application failed (is it installed?).
+ Current access token:
+ Token expires at:
+
diff --git a/facebook/examples/Hackbook/src/com/facebook/android/BaseDialogListener.java b/facebook/examples/Hackbook/src/com/facebook/android/BaseDialogListener.java
new file mode 100644
index 000000000..dbd5b3360
--- /dev/null
+++ b/facebook/examples/Hackbook/src/com/facebook/android/BaseDialogListener.java
@@ -0,0 +1,25 @@
+package com.facebook.android;
+
+import com.facebook.android.Facebook.DialogListener;
+
+/**
+ * Skeleton base class for RequestListeners, providing default error handling.
+ * Applications should handle these error conditions.
+ */
+public abstract class BaseDialogListener implements DialogListener {
+
+ @Override
+ public void onFacebookError(FacebookError e) {
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onError(DialogError e) {
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onCancel() {
+ }
+
+}
\ No newline at end of file
diff --git a/facebook/examples/Hackbook/src/com/facebook/android/BaseRequestListener.java b/facebook/examples/Hackbook/src/com/facebook/android/BaseRequestListener.java
new file mode 100644
index 000000000..0e7809f07
--- /dev/null
+++ b/facebook/examples/Hackbook/src/com/facebook/android/BaseRequestListener.java
@@ -0,0 +1,41 @@
+package com.facebook.android;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.MalformedURLException;
+
+import android.util.Log;
+
+import com.facebook.android.AsyncFacebookRunner.RequestListener;
+
+/**
+ * Skeleton base class for RequestListeners, providing default error handling.
+ * Applications should handle these error conditions.
+ */
+public abstract class BaseRequestListener implements RequestListener {
+
+ @Override
+ public void onFacebookError(FacebookError e, final Object state) {
+ Log.e("Facebook", e.getMessage());
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onFileNotFoundException(FileNotFoundException e, final Object state) {
+ Log.e("Facebook", e.getMessage());
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onIOException(IOException e, final Object state) {
+ Log.e("Facebook", e.getMessage());
+ e.printStackTrace();
+ }
+
+ @Override
+ public void onMalformedURLException(MalformedURLException e, final Object state) {
+ Log.e("Facebook", e.getMessage());
+ e.printStackTrace();
+ }
+
+}
diff --git a/facebook/examples/Hackbook/src/com/facebook/android/FQLQuery.java b/facebook/examples/Hackbook/src/com/facebook/android/FQLQuery.java
new file mode 100644
index 000000000..1c2e92b3c
--- /dev/null
+++ b/facebook/examples/Hackbook/src/com/facebook/android/FQLQuery.java
@@ -0,0 +1,112 @@
+package com.facebook.android;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.app.Activity;
+import android.app.Dialog;
+import android.app.ProgressDialog;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup.LayoutParams;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+
+public class FQLQuery extends Dialog {
+
+ private EditText mFQLQuery;
+ private TextView mFQLOutput;
+ private Button mSubmitButton;
+ private Activity activity;
+ private Handler mHandler;
+ private ProgressDialog dialog;
+
+ public FQLQuery(Activity activity) {
+ super(activity);
+ this.activity = activity;
+ setTitle(R.string.fqlquery);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mHandler = new Handler();
+
+ setContentView(R.layout.fql_query);
+ LayoutParams params = getWindow().getAttributes();
+ params.width = LayoutParams.FILL_PARENT;
+ params.height = LayoutParams.FILL_PARENT;
+ getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
+
+ mFQLQuery = (EditText) findViewById(R.id.fqlquery);
+ mFQLOutput = (TextView) findViewById(R.id.fqlOutput);
+ mSubmitButton = (Button) findViewById(R.id.submit_button);
+
+ mSubmitButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ ((InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE))
+ .hideSoftInputFromWindow(mFQLQuery.getWindowToken(), 0);
+ dialog = ProgressDialog.show(FQLQuery.this.activity, "",
+ FQLQuery.this.activity.getString(R.string.please_wait), true, true);
+ /*
+ * Source tag: fql_query_tag
+ */
+ String query = mFQLQuery.getText().toString();
+ Bundle params = new Bundle();
+ params.putString("method", "fql.query");
+ params.putString("query", query);
+ Utility.mAsyncRunner.request(null, params, new FQLRequestListener());
+ }
+ });
+ }
+
+ public class FQLRequestListener extends BaseRequestListener {
+
+ @Override
+ public void onComplete(final String response, final Object state) {
+ dialog.dismiss();
+ /*
+ * Output can be a JSONArray or a JSONObject.
+ * Try JSONArray and if there's a JSONException, parse to JSONObject
+ */
+ try {
+ JSONArray json = new JSONArray(response);
+ setText(json.toString(2));
+ } catch (JSONException e) {
+ try {
+ /*
+ * JSONObject probably indicates there was some error
+ * Display that error, but for end user you should parse the
+ * error and show appropriate message
+ */
+ JSONObject json = new JSONObject(response);
+ setText(json.toString(2));
+ } catch (JSONException e1) {
+ setText(activity.getString(R.string.exception) + e1.getMessage());
+ }
+ }
+ }
+
+ public void onFacebookError(FacebookError error) {
+ dialog.dismiss();
+ setText(activity.getString(R.string.facebook_error) + error.getMessage());
+ }
+ }
+
+ public void setText(final String txt) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mFQLOutput.setText(txt);
+ mFQLOutput.setVisibility(View.VISIBLE);
+ }
+ });
+ }
+}
diff --git a/facebook/examples/Hackbook/src/com/facebook/android/FieldsConnectionsDialog.java b/facebook/examples/Hackbook/src/com/facebook/android/FieldsConnectionsDialog.java
new file mode 100644
index 000000000..9308301d4
--- /dev/null
+++ b/facebook/examples/Hackbook/src/com/facebook/android/FieldsConnectionsDialog.java
@@ -0,0 +1,305 @@
+package com.facebook.android;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Vector;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import android.app.Dialog;
+import android.os.Bundle;
+import android.text.SpannableString;
+import android.text.style.UnderlineSpan;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.ListView;
+import android.widget.TabHost;
+import android.widget.TabHost.TabSpec;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class FieldsConnectionsDialog extends Dialog {
+
+ private final static int TAB_HEIGHT = 50;
+
+ private Button mGetFieldsButton;
+ private ListView fieldsList, connectionsList;
+ private BaseAdapter fieldsAdapter, connectionsAdapter;
+
+ private GraphExplorer explorerActivity;
+
+ protected Vector fieldsVector;
+ private ArrayList fieldsArray;
+ private ArrayList connectionsArray;
+
+ public FieldsConnectionsDialog(GraphExplorer explorerActivity, JSONObject metadata) {
+ super(explorerActivity);
+ this.explorerActivity = explorerActivity;
+
+ /*
+ * Sort the fields and connections
+ */
+ try {
+ sortFields(metadata.getJSONArray("fields"));
+ sortConnections(metadata.getJSONObject("connections").names());
+ } catch (JSONException e) {
+ Toast.makeText(explorerActivity.getBaseContext(),
+ "Fields/Connections could not be fetched.", Toast.LENGTH_SHORT).show();
+ }
+
+ setTitle(explorerActivity.getString(R.string.fields_and_connections));
+ fieldsVector = new Vector();
+ }
+
+ /*
+ * Sort fields which are returned as JSONObject in the JSONArray
+ */
+ public void sortFields(JSONArray jsonFieldsArray) {
+ this.fieldsArray = new ArrayList(jsonFieldsArray.length());
+ for (int i = 0; i < jsonFieldsArray.length(); i++) {
+ try {
+ this.fieldsArray.add(jsonFieldsArray.getJSONObject(i));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ Collections.sort(this.fieldsArray, new Comparator() {
+ @Override
+ public int compare(JSONObject object1, JSONObject object2) {
+ try {
+ return object1.getString("name").compareToIgnoreCase(object2.getString("name"));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ return 0;
+ }
+ });
+ }
+
+ /*
+ * Sort the Connections returned in the JSONArray
+ */
+ public void sortConnections(JSONArray jsonConnectionsArray) {
+ this.connectionsArray = new ArrayList(jsonConnectionsArray.length());
+ for (int i = 0; i < jsonConnectionsArray.length(); i++) {
+ try {
+ this.connectionsArray.add(jsonConnectionsArray.get(i).toString());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ Collections.sort(this.connectionsArray);
+ }
+
+ /*
+ * Layout the dialog
+ */
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.fields_connections_list);
+ LayoutParams params = getWindow().getAttributes();
+ params.width = LayoutParams.FILL_PARENT;
+ params.height = LayoutParams.FILL_PARENT;
+ getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
+
+ fieldsList = (ListView) findViewById(R.id.fields_list);
+ connectionsList = (ListView) findViewById(R.id.connections_list);
+
+ fieldsAdapter = new FieldsListAdapter();
+ if (this.fieldsArray == null) {
+ fieldsList.setAdapter(new ArrayAdapter(explorerActivity,
+ android.R.layout.simple_list_item_1, new String[] { "No fields available" }));
+ } else {
+ fieldsList.setAdapter(fieldsAdapter);
+ }
+
+ connectionsAdapter = new ConnectionsListAdapter();
+ if (this.connectionsArray == null) {
+ connectionsList.setAdapter(new ArrayAdapter(explorerActivity,
+ android.R.layout.simple_list_item_1,
+ new String[] { "No connections available" }));
+ } else {
+ connectionsList.setAdapter(connectionsAdapter);
+ }
+
+ TabHost tabHost = (TabHost) findViewById(R.id.tabHost);
+ tabHost.setup();
+
+ TabSpec spec1 = tabHost.newTabSpec("Tab 1");
+ spec1.setIndicator(explorerActivity.getString(R.string.fields));
+ spec1.setContent(R.id.fields_layout);
+
+ TabSpec spec2 = tabHost.newTabSpec("Tab 2");
+ spec2.setIndicator(explorerActivity.getString(R.string.connections));
+ spec2.setContent(R.id.connections_list);
+
+ tabHost.addTab(spec1);
+ tabHost.addTab(spec2);
+ tabHost.setCurrentTab(0);
+ tabHost.getTabWidget().getChildAt(0).getLayoutParams().height = TAB_HEIGHT;
+ tabHost.getTabWidget().getChildAt(1).getLayoutParams().height = TAB_HEIGHT;
+
+ mGetFieldsButton = (Button) findViewById(R.id.get_fields_button);
+ mGetFieldsButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ /*
+ * Source Tag:
+ */
+ FieldsConnectionsDialog.this.dismiss();
+ if (!fieldsVector.isEmpty()) {
+ explorerActivity.getFields(fieldsVector);
+ } else {
+ Toast.makeText(explorerActivity.getBaseContext(), "No Fields selected.",
+ Toast.LENGTH_SHORT).show();
+ }
+ }
+ });
+
+ connectionsList.setOnItemClickListener(new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView> arg0, View v, int position, long arg3) {
+ FieldsConnectionsDialog.this.dismiss();
+ explorerActivity.getConnection(connectionsArray.get(position));
+ }
+ });
+ }
+
+ /**
+ * Definition of the list adapter
+ */
+ public class FieldsListAdapter extends BaseAdapter {
+ private LayoutInflater mInflater;
+ boolean[] isChecked;
+
+ public FieldsListAdapter() {
+ mInflater = LayoutInflater.from(explorerActivity.getBaseContext());
+ isChecked = new boolean[fieldsArray.size()];
+ }
+
+ @Override
+ public int getCount() {
+ return fieldsArray.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(final int position, View convertView, ViewGroup parent) {
+
+ View hView = convertView;
+ ViewHolder holder;
+ JSONObject fieldObject = null;
+ fieldObject = fieldsArray.get(position);
+
+ if (hView == null) {
+ hView = mInflater.inflate(R.layout.fields_item, null);
+ holder = new ViewHolder();
+ holder.checkbox = (CheckBox) hView.findViewById(R.id.fields_checkbox);
+ holder.fieldsInfo = (TextView) hView.findViewById(R.id.fields_info);
+ hView.setTag(holder);
+ } else {
+ holder = (ViewHolder) hView.getTag();
+ }
+ try {
+ holder.checkbox.setText(fieldObject.getString("name"));
+ } catch (JSONException e) {
+ holder.checkbox.setText("");
+ }
+ try {
+ holder.fieldsInfo.setText(fieldObject.getString("description"));
+ } catch (JSONException e) {
+ holder.fieldsInfo.setText("");
+ }
+ holder.checkbox.setId(position);
+ holder.checkbox.setChecked(isChecked[position]);
+ holder.checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
+ @Override
+ public void onCheckedChanged(CompoundButton button, boolean checked) {
+ isChecked[button.getId()] = checked;
+ String field = button.getText().toString();
+ if (checked) {
+ fieldsVector.add(field);
+ } else if (fieldsVector.contains(field)) {
+ fieldsVector.remove(field);
+ }
+ }
+ });
+
+ return hView;
+ }
+ }
+
+ class ViewHolder {
+ CheckBox checkbox;
+ TextView fieldsInfo;
+ }
+
+ /**
+ * Definition of the list adapter
+ */
+ public class ConnectionsListAdapter extends BaseAdapter {
+ private LayoutInflater mInflater;
+
+ public ConnectionsListAdapter() {
+ mInflater = LayoutInflater.from(explorerActivity.getBaseContext());
+ }
+
+ @Override
+ public int getCount() {
+ return connectionsArray.size();
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return 0;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View hView = convertView;
+ TextView connection;
+ if (hView == null) {
+ hView = mInflater.inflate(R.layout.connection_item, null);
+ connection = (TextView) hView.findViewById(R.id.connection_name);
+ hView.setTag(connection);
+ } else {
+ connection = (TextView) hView.getTag();
+ }
+ SpannableString name;
+ name = new SpannableString(connectionsArray.get(position));
+ name.setSpan(new UnderlineSpan(), 0, name.length(), 0);
+ connection.setText(name);
+ return hView;
+ }
+ }
+}
diff --git a/facebook/examples/Hackbook/src/com/facebook/android/FriendsGetProfilePics.java b/facebook/examples/Hackbook/src/com/facebook/android/FriendsGetProfilePics.java
new file mode 100644
index 000000000..b2bbd046c
--- /dev/null
+++ b/facebook/examples/Hackbook/src/com/facebook/android/FriendsGetProfilePics.java
@@ -0,0 +1,110 @@
+package com.facebook.android;
+
+import java.util.Hashtable;
+import java.util.Stack;
+
+import android.graphics.Bitmap;
+import android.os.AsyncTask;
+import android.widget.BaseAdapter;
+
+/*
+ * Fetch friends profile pictures request via AsyncTask
+ */
+public class FriendsGetProfilePics {
+
+ Hashtable friendsImages;
+ Hashtable positionRequested;
+ BaseAdapter listener;
+ int runningCount = 0;
+ Stack queue;
+
+ /*
+ * 15 max async tasks at any given time.
+ */
+ final static int MAX_ALLOWED_TASKS = 15;
+
+ public FriendsGetProfilePics() {
+ friendsImages = new Hashtable();
+ positionRequested = new Hashtable();
+ queue = new Stack();
+ }
+
+ /*
+ * Inform the listener when the image has been downloaded. listener is
+ * FriendsList here.
+ */
+ public void setListener(BaseAdapter listener) {
+ this.listener = listener;
+ reset();
+ }
+
+ public void reset() {
+ positionRequested.clear();
+ runningCount = 0;
+ queue.clear();
+ }
+
+ /*
+ * If the profile picture has already been downloaded and cached, return it
+ * else execute a new async task to fetch it - if total async tasks >15,
+ * queue the request.
+ */
+ public Bitmap getImage(String uid, String url) {
+ Bitmap image = friendsImages.get(uid);
+ if (image != null) {
+ return image;
+ }
+ if (!positionRequested.containsKey(uid)) {
+ positionRequested.put(uid, "");
+ if (runningCount >= MAX_ALLOWED_TASKS) {
+ queue.push(new ItemPair(uid, url));
+ } else {
+ runningCount++;
+ new GetProfilePicAsyncTask().execute(uid, url);
+ }
+ }
+ return null;
+ }
+
+ public void getNextImage() {
+ if (!queue.isEmpty()) {
+ ItemPair item = queue.pop();
+ new GetProfilePicAsyncTask().execute(item.uid, item.url);
+ }
+ }
+
+ /*
+ * Start a AsyncTask to fetch the request
+ */
+ private class GetProfilePicAsyncTask extends AsyncTask