Update facebook project to version 1.2.1, commit 5a72863
@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.facebook.android"
|
||||
android:versionCode="1"
|
||||
android:versionName="1.0">
|
||||
<supports-screens
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
android:largeScreens="true"
|
||||
android:anyDensity="true" />
|
||||
<application android:icon="@drawable/icon"
|
||||
android:label="@string/app_name"
|
||||
android:debuggable="true">
|
||||
<activity android:name=".SplashActivity"
|
||||
android:label="@string/app_name"
|
||||
android:screenOrientation="portrait">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".Hackbook"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="keyboardHidden"
|
||||
android:screenOrientation="portrait">
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".GraphExplorer"
|
||||
android:windowSoftInputMode="stateHidden"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity android:name=".IntentUriHandler">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<data android:scheme="fbgraphex" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".FriendsList"
|
||||
android:screenOrientation="portrait" />
|
||||
<activity
|
||||
android:name=".Places"
|
||||
android:screenOrientation="portrait" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
|
||||
<uses-sdk android:minSdkVersion="3" />
|
||||
</manifest>
|
@ -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=<place_id_>&message=<message>&coordinates={"latitude": <lat>, "longitude:": <lon>}
|
||||
------------------------
|
||||
|
||||
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
|
@ -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
|
After Width: | Height: | Size: 46 KiB |
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 1.9 KiB |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/login_down" />
|
||||
<item android:drawable="@drawable/login" /> <!-- default -->
|
||||
</selector>
|
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 1.6 KiB |
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@drawable/logout_down" />
|
||||
<item android:drawable="@drawable/logout" /> <!-- default -->
|
||||
</selector>
|
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 384 B |
@ -0,0 +1,11 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight">
|
||||
<TextView
|
||||
android:id="@+id/connection_name"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:textSize="26sp"
|
||||
android:textColor="@color/lite_blue"
|
||||
android:paddingLeft="5dp" />
|
||||
</RelativeLayout>
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<TabHost
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/tabHost">
|
||||
<RelativeLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent">
|
||||
<TabWidget
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@android:id/tabs" />
|
||||
<FrameLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@android:id/tabcontent"
|
||||
android:layout_below="@android:id/tabs">
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/fields_layout">
|
||||
<Button android:id="@+id/get_fields_button"
|
||||
android:text="@string/get_fields"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
<ListView
|
||||
android:id="@+id/fields_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</LinearLayout>
|
||||
<ListView
|
||||
android:id="@+id/connections_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</FrameLayout>
|
||||
</RelativeLayout>
|
||||
</TabHost>
|
||||
</LinearLayout>
|
@ -0,0 +1,14 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<CheckBox
|
||||
android:id="@+id/fields_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<TextView
|
||||
android:id="@+id/fields_info"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
@ -0,0 +1,41 @@
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:orientation="vertical"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<EditText
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="240dp"
|
||||
android:layout_weight="1"
|
||||
android:textSize="25px"
|
||||
android:gravity="left|center"
|
||||
android:id="@+id/fqlquery" />
|
||||
<Button android:id="@+id/submit_button"
|
||||
android:text="@string/submit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:padding="10dp" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="3dip"
|
||||
android:background="@color/grey" />
|
||||
<ScrollView
|
||||
android:id="@+id/ScrollView01"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent">
|
||||
<TextView
|
||||
android:id="@+id/fqlOutput"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp"
|
||||
android:visibility="invisible"
|
||||
android:background="@color/grey" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
@ -0,0 +1,33 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:padding="6dip"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:id="@+id/friend_item">
|
||||
<ImageView
|
||||
android:id="@+id/profile_pic"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginRight="6dip" />
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/profile_pic"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:gravity="center_vertical" />
|
||||
<TextView
|
||||
android:id="@+id/info"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/profile_pic"
|
||||
android:layout_below="@id/name"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee" />
|
||||
</RelativeLayout>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<ListView
|
||||
android:id="@+id/friends_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</LinearLayout>
|
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" >
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/accessTokenButton"
|
||||
android:text="@string/get_permissions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<TextView
|
||||
android:id="@+id/graphDomain"
|
||||
android:text="@string/graph_domain"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingRight="5dp"
|
||||
android:paddingLeft="5dp" />
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<EditText android:id="@+id/inputId"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="240dp"
|
||||
android:layout_weight="1"
|
||||
android:textSize="25px"
|
||||
android:gravity="left"
|
||||
android:hint="Enter Object ID" />
|
||||
<Button
|
||||
android:id="@+id/meButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="30dip"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:background="@drawable/me"
|
||||
android:visibility="invisible" />
|
||||
<Button
|
||||
android:id="@+id/textDeleteButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="5dip"
|
||||
android:layout_gravity="right|center_vertical"
|
||||
android:background="@drawable/x" />
|
||||
</FrameLayout>
|
||||
<Button
|
||||
android:id="@+id/submitButton"
|
||||
android:text="@string/submit"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<Button android:id="@+id/fieldsAndConnectionsButton"
|
||||
android:text="@string/fields_and_connections"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:visibility="invisible" />
|
||||
<Button android:id="@+id/viewURLButton"
|
||||
android:text="@string/view_url"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:visibility="invisible" />
|
||||
<Button android:id="@+id/backParentButton"
|
||||
android:text="@string/back_parent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp"
|
||||
android:visibility="invisible" />
|
||||
</LinearLayout>
|
||||
<ScrollView
|
||||
android:id="@+id/ScrollView01"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_width="fill_parent">
|
||||
<TextView android:id="@+id/output"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp"
|
||||
android:textSize="16sp"
|
||||
android:visibility="invisible"
|
||||
android:background="@color/grey" />
|
||||
</ScrollView>
|
||||
</LinearLayout>
|
@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:gravity="center_horizontal">
|
||||
<RelativeLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:padding="6dip"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight">
|
||||
<ImageView
|
||||
android:id="@+id/user_pic"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginRight="6dip" />
|
||||
<TextView
|
||||
android:id="@+id/txt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toRightOf="@id/user_pic" />
|
||||
<com.facebook.android.LoginButton
|
||||
android:id="@+id/login"
|
||||
android:src="@drawable/login_button"
|
||||
android:layout_toRightOf="@id/user_pic"
|
||||
android:layout_below="@id/txt"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:background="@color/grey" />
|
||||
<ListView
|
||||
android:id="@+id/main_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="1dip"
|
||||
android:background="@color/grey" />
|
||||
</LinearLayout>
|
@ -0,0 +1,9 @@
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/main_api_item"
|
||||
android:padding="10dip"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="20sp" />
|
@ -0,0 +1,8 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight">
|
||||
<CheckBox
|
||||
android:id="@+id/permission_checkbox"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</RelativeLayout>
|
@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<TextView
|
||||
android:id="@+id/permission_detail"
|
||||
android:text="@string/permission_detail"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center_vertical"
|
||||
android:textSize="16sp" />
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<Button
|
||||
android:id="@+id/get_permissions_button"
|
||||
android:text="@string/get_permissions"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<TabHost
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:id="@+id/tabHost">
|
||||
<RelativeLayout
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent">
|
||||
<TabWidget
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@android:id/tabs" />
|
||||
<FrameLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:id="@android:id/tabcontent"
|
||||
android:layout_below="@android:id/tabs">
|
||||
<ListView
|
||||
android:id="@+id/user_permissions_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<ListView
|
||||
android:id="@+id/friend_permissions_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
<ListView
|
||||
android:id="@+id/extended_permissions_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
</FrameLayout>
|
||||
</RelativeLayout>
|
||||
</TabHost>
|
||||
</LinearLayout>
|
@ -0,0 +1,24 @@
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:padding="6dip"
|
||||
android:layout_height="?android:attr/listPreferredItemHeight"
|
||||
android:id="@+id/friend_item">
|
||||
<TextView
|
||||
android:id="@+id/place_name"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:gravity="center_vertical" />
|
||||
<TextView
|
||||
android:id="@+id/place_location"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/place_name"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignWithParentIfMissing="true"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="marquee" />
|
||||
</RelativeLayout>
|
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<ListView
|
||||
android:id="@+id/places_list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
</LinearLayout>
|
@ -0,0 +1,5 @@
|
||||
<ImageView android:id="@+id/imageView1" xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/splash"
|
||||
android:scaleType="fitXY"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<TextView
|
||||
android:id="@+id/tokenLabel"
|
||||
android:text="@string/access_token_label"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
<EditText
|
||||
android:id="@+id/tokenEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false" />
|
||||
<TextView
|
||||
android:id="@+id/tokenExpiresLabel"
|
||||
android:text="@string/access_token_expires_label"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
<EditText
|
||||
android:id="@+id/tokenExpiresEdit"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:editable="false" />
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/refresh_button"
|
||||
android:text="@string/refresh_button"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<TextView
|
||||
android:id="@+id/tip_label"
|
||||
android:text="@string/tip_label"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
<TextView
|
||||
android:id="@+id/usefulTip"
|
||||
android:text="@string/refresh_token_tip"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingLeft="3dp" />
|
||||
</LinearLayout>
|
@ -0,0 +1,67 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<TextView
|
||||
android:id="@+id/apiOutputLabel"
|
||||
android:text="@string/api_response"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
<ScrollView
|
||||
android:id="@+id/ScrollView01"
|
||||
android:layout_height="140dp"
|
||||
android:layout_width="fill_parent">
|
||||
<TextView android:id="@+id/apiOutput"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp"
|
||||
android:background="@color/grey" />
|
||||
</ScrollView>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/view_post_button"
|
||||
android:text="@string/view_post"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
<Button
|
||||
android:id="@+id/delete_post_button"
|
||||
android:text="@string/delete_post"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
</LinearLayout>
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<TextView
|
||||
android:id="@+id/tip_label"
|
||||
android:text="@string/tip_label"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
<TextView
|
||||
android:id="@+id/usefulTip"
|
||||
android:text="@string/post_tip"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingLeft="3dp" />
|
||||
</LinearLayout>
|
@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@color/black">
|
||||
<TextView
|
||||
android:id="@+id/apiOutputLabel"
|
||||
android:text="@string/api_response"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
<ScrollView
|
||||
android:id="@+id/ScrollView01"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="fill_parent"
|
||||
android:paddingBottom="3dp">
|
||||
<TextView android:id="@+id/apiOutput"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp"
|
||||
android:background="@color/grey" />
|
||||
</ScrollView>
|
||||
<View
|
||||
android:paddingTop="3dp"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:background="@color/grey" />
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
<Button
|
||||
android:id="@+id/view_photo_button"
|
||||
android:text="@string/view_photo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
<Button
|
||||
android:id="@+id/tag_photo_button"
|
||||
android:text="@string/tag_photo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="10dp" />
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/uploadedPhoto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingBottom="3dp" />
|
||||
<TextView
|
||||
android:id="@+id/tip_label"
|
||||
android:text="@string/tip_label"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="3dp"
|
||||
android:paddingLeft="3dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/usefulTip"
|
||||
android:textColor="@color/white"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingTop="5dp"
|
||||
android:paddingLeft="3dp" />
|
||||
</LinearLayout>
|
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="white">#ffffff</color>
|
||||
<color name="black">#000000</color>
|
||||
<color name="green">#23cf34</color>
|
||||
<color name="orange">#E47833</color>
|
||||
<color name="lite_blue">#4E78A0</color>
|
||||
<color name="blue">#0000FF</color>
|
||||
<color name="grey">#FF909090</color>
|
||||
</resources>
|
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="app_name">Hackbook for Android</string>
|
||||
<string name="app_desc">Checkout out Hackbook for Android to learn how you can make your android apps social using Facebook Platform.</string>
|
||||
<string name="app_action">I am using the Hackbook for Android</string>
|
||||
<string name="request_message">Learn how to make your android apps social.</string>
|
||||
<string name="request">Request!</string>
|
||||
<string name="upload">Upload Photo</string><string name="post">Wall Post!</string>
|
||||
<string name="delete">Delete Post</string>
|
||||
<string name="no_login">Graph API Explorer</string>
|
||||
<string name="get_permissions">Get Permissions</string>
|
||||
<string name="access_token">Access Token:</string>
|
||||
<string name="graph_domain">https://graph.facebook.com/</string>
|
||||
<string name="submit">Submit</string>
|
||||
<string name="label_output">Output:</string>
|
||||
<string name="show_metadata">Show metadata</string>
|
||||
<string name="show_picture">Show picture</string>
|
||||
<string name="view_url">URL</string>
|
||||
<string name="target_url">Target URL:</string>
|
||||
<string name="exception">Exception: </string>
|
||||
<string name="tip_label">Tip:</string>
|
||||
<string name="error">Error</string>
|
||||
<string name="facebook_error">Facebook Error: </string>
|
||||
<string name="api_response">Api Response:</string>
|
||||
<string name="view_source">View Source</string>
|
||||
<string name="view_post">View Post</string>
|
||||
<string name="delete_post">Delete Post</string>
|
||||
<string name="source_code">Source Code:</string>
|
||||
<string name="please_wait">Please wait...</string>
|
||||
<string name="view_photo">View Photo</string>
|
||||
<string name="hide_photo">Hide Photo</string>
|
||||
<string name="tag_photo">Tag Photo</string>
|
||||
<string name="graph_button">Graph API</string>
|
||||
<string name="fql_button">FQL Query</string>
|
||||
<string name="source_tag">Source tag:</string>
|
||||
<string name="permission_source_tag">Source tag: \"perms_tag\"</string>
|
||||
<string name="Graph_FQL_title">Graph API or FQL Query?</string>
|
||||
<string name="Graph_FQL_msg">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.</string>
|
||||
<string name="can_post_on_wall_title">Post on friend\'s wall</string>
|
||||
<string name="can_post_on_wall">Friends list fetched. You can post on friend\'s wall by clicking on the item.</string>
|
||||
<string name="ok">OK</string>
|
||||
<string name="post_on_wall_title">Post on Wall?</string>
|
||||
<string name="post_on_wall">Would you like to post on %1$s\'s wall</string>
|
||||
<string name="yes">Yes</string>
|
||||
<string name="no">No</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="reset">Reset</string>
|
||||
<string name="get_fields">Get Fields</string>
|
||||
<string name="fields">Fields</string>
|
||||
<string name="connections">Connections</string>
|
||||
<string name="checkin">Check-in</string>
|
||||
<string name="cancel">Cancel</string>
|
||||
<string name="user">User Data</string>
|
||||
<string name="friend">Friends Data</string>
|
||||
<string name="extended">Extended</string>
|
||||
<string name="gallery_remote_title">Upload from gallery or remote?</string>
|
||||
<string name="gallery_remote_msg">Upload picture from phone\' gallery or remote server?</string>
|
||||
<string name="gallery_button">Gallery</string>
|
||||
<string name="remote_button">Remote</string>
|
||||
<string name="get_location">Get Location?</string>
|
||||
<string name="get_default_or_new_location">Get current location or use Times Square as the location?</string>
|
||||
<string name="current_location_button">Current Location</string>
|
||||
<string name="fetching_current_permissions">Fetching current permissions...</string>
|
||||
<string name="explorer_message">Also, checkout the web-version of the <a href="http://developers.facebook.com/tools/explorer">Graph API Explorer tool</a></string>
|
||||
<string name="nearby_places">Fetching nearby places...</string>
|
||||
<string name="times_square_button">Times Square</string>
|
||||
<string name="check_in_title">Check-in?</string>
|
||||
<string name="permissions">Permissions</string>
|
||||
<string name="back_parent">Back to parent</string>
|
||||
<string name="fields_and_connections">Fields \u0026 Connections</string>
|
||||
<string name="permissions_request">Select Permissions:</string>
|
||||
<string name="permission_detail">Checkout <a href="https://developers.facebook.com/docs/authentication/permissions/">permissions reference doc</a></string>
|
||||
<string name="fetching_location">Fetching Location...</string>
|
||||
<string name="check_in_at">Would you like to check-in at %1$s?</string>
|
||||
<string name="post_tip">\'read_stream\' permission is required to view and delete the post.\n\nUse SDK dialogs to publish stories or post on friends wall. <a href="https://developers.facebook.com/docs/reference/dialogs">More info</a>\n\n<a href="https://developers.facebook.com/docs/reference/api/Comment">Like and Comment on a post</a></string>
|
||||
<string name="photo_tip">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</string>
|
||||
<string name="fqlquery">Enter FQL Query:</string>
|
||||
<string name="enable_gps_title">Enable GPS</string>
|
||||
<string name="enable_gps">Please enable GPS to get nearby places and check-in</string>
|
||||
<string name="gps_settings">GPS Settings</string>
|
||||
<string name="refresh_token_title">Refresh Token</string>
|
||||
<string name="refresh_button">Refresh</string>
|
||||
<string name="refresh_button_pending">Refreshing…</string>
|
||||
<string name="refresh_token_tip">In most cases the access token should be refreshed silently when the application is running (for example see Hackbook onResume method).</string>
|
||||
<string name="refresh_token_binding_error">Binding to the Facebook Android Application failed (is it installed?).</string>
|
||||
<string name="access_token_label">Current access token:</string>
|
||||
<string name="access_token_expires_label">Token expires at:</string>
|
||||
</resources>
|
@ -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() {
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -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<String> fieldsVector;
|
||||
private ArrayList<JSONObject> fieldsArray;
|
||||
private ArrayList<String> 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<String>();
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort fields which are returned as JSONObject in the JSONArray
|
||||
*/
|
||||
public void sortFields(JSONArray jsonFieldsArray) {
|
||||
this.fieldsArray = new ArrayList<JSONObject>(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<JSONObject>() {
|
||||
@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<String>(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<String>(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<String>(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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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<String, Bitmap> friendsImages;
|
||||
Hashtable<String, String> positionRequested;
|
||||
BaseAdapter listener;
|
||||
int runningCount = 0;
|
||||
Stack<ItemPair> queue;
|
||||
|
||||
/*
|
||||
* 15 max async tasks at any given time.
|
||||
*/
|
||||
final static int MAX_ALLOWED_TASKS = 15;
|
||||
|
||||
public FriendsGetProfilePics() {
|
||||
friendsImages = new Hashtable<String, Bitmap>();
|
||||
positionRequested = new Hashtable<String, String>();
|
||||
queue = new Stack<ItemPair>();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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<Object, Void, Bitmap> {
|
||||
String uid;
|
||||
|
||||
@Override
|
||||
protected Bitmap doInBackground(Object... params) {
|
||||
this.uid = (String) params[0];
|
||||
String url = (String) params[1];
|
||||
return Utility.getBitmap(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap result) {
|
||||
runningCount--;
|
||||
if (result != null) {
|
||||
friendsImages.put(uid, result);
|
||||
listener.notifyDataSetChanged();
|
||||
getNextImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ItemPair {
|
||||
String uid;
|
||||
String url;
|
||||
|
||||
public ItemPair(String uid, String url) {
|
||||
this.uid = uid;
|
||||
this.url = url;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class FriendsList extends Activity implements OnItemClickListener {
|
||||
private Handler mHandler;
|
||||
|
||||
protected ListView friendsList;
|
||||
protected static JSONArray jsonArray;
|
||||
protected String graph_or_fql;
|
||||
|
||||
/*
|
||||
* Layout the friends' list
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mHandler = new Handler();
|
||||
setContentView(R.layout.friends_list);
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
String apiResponse = extras.getString("API_RESPONSE");
|
||||
graph_or_fql = extras.getString("METHOD");
|
||||
try {
|
||||
if (graph_or_fql.equals("graph")) {
|
||||
jsonArray = new JSONObject(apiResponse).getJSONArray("data");
|
||||
} else {
|
||||
jsonArray = new JSONArray(apiResponse);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
showToast("Error: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
friendsList = (ListView) findViewById(R.id.friends_list);
|
||||
friendsList.setOnItemClickListener(this);
|
||||
friendsList.setAdapter(new FriendListAdapter(this));
|
||||
|
||||
showToast(getString(R.string.can_post_on_wall));
|
||||
}
|
||||
|
||||
/*
|
||||
* Clicking on a friend should popup a dialog for user to post on friend's
|
||||
* wall.
|
||||
*/
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
|
||||
try {
|
||||
final long friendId;
|
||||
if (graph_or_fql.equals("graph")) {
|
||||
friendId = jsonArray.getJSONObject(position).getLong("id");
|
||||
} else {
|
||||
friendId = jsonArray.getJSONObject(position).getLong("uid");
|
||||
}
|
||||
String name = jsonArray.getJSONObject(position).getString("name");
|
||||
|
||||
new AlertDialog.Builder(this).setTitle(R.string.post_on_wall_title)
|
||||
.setMessage(String.format(getString(R.string.post_on_wall), name))
|
||||
.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Bundle params = new Bundle();
|
||||
/*
|
||||
* Source Tag: friend_wall_tag To write on a friend's wall,
|
||||
* provide friend's UID in the 'to' parameter.
|
||||
* More info on feed dialog:
|
||||
* https://developers.facebook.com/docs/reference/dialogs/feed/
|
||||
*/
|
||||
params.putString("to", String.valueOf(friendId));
|
||||
params.putString("caption", getString(R.string.app_name));
|
||||
params.putString("description", getString(R.string.app_desc));
|
||||
params.putString("picture", Utility.HACK_ICON_URL);
|
||||
params.putString("name", getString(R.string.app_action));
|
||||
Utility.mFacebook.dialog(FriendsList.this, "feed", params,
|
||||
new PostDialogListener());
|
||||
}
|
||||
|
||||
}).setNegativeButton(R.string.no, null).show();
|
||||
} catch (JSONException e) {
|
||||
showToast("Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback after the message has been posted on friend's wall.
|
||||
*/
|
||||
public class PostDialogListener extends BaseDialogListener {
|
||||
@Override
|
||||
public void onComplete(Bundle values) {
|
||||
final String postId = values.getString("post_id");
|
||||
if (postId != null) {
|
||||
showToast("Message posted on the wall.");
|
||||
} else {
|
||||
showToast("No message posted on the wall.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void showToast(final String msg) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast toast = Toast.makeText(FriendsList.this, msg, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition of the list adapter
|
||||
*/
|
||||
public class FriendListAdapter extends BaseAdapter {
|
||||
private LayoutInflater mInflater;
|
||||
FriendsList friendsList;
|
||||
|
||||
public FriendListAdapter(FriendsList friendsList) {
|
||||
this.friendsList = friendsList;
|
||||
if (Utility.model == null) {
|
||||
Utility.model = new FriendsGetProfilePics();
|
||||
}
|
||||
Utility.model.setListener(this);
|
||||
mInflater = LayoutInflater.from(friendsList.getBaseContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return jsonArray.length();
|
||||
}
|
||||
|
||||
@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) {
|
||||
JSONObject jsonObject = null;
|
||||
try {
|
||||
jsonObject = jsonArray.getJSONObject(position);
|
||||
} catch (JSONException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
View hView = convertView;
|
||||
if (convertView == null) {
|
||||
hView = mInflater.inflate(R.layout.friend_item, null);
|
||||
ViewHolder holder = new ViewHolder();
|
||||
holder.profile_pic = (ImageView) hView.findViewById(R.id.profile_pic);
|
||||
holder.name = (TextView) hView.findViewById(R.id.name);
|
||||
holder.info = (TextView) hView.findViewById(R.id.info);
|
||||
hView.setTag(holder);
|
||||
}
|
||||
|
||||
ViewHolder holder = (ViewHolder) hView.getTag();
|
||||
try {
|
||||
if (graph_or_fql.equals("graph")) {
|
||||
holder.profile_pic.setImageBitmap(Utility.model.getImage(
|
||||
jsonObject.getString("id"), jsonObject.getString("picture")));
|
||||
} else {
|
||||
holder.profile_pic.setImageBitmap(Utility.model.getImage(
|
||||
jsonObject.getString("uid"), jsonObject.getString("pic_square")));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
holder.name.setText("");
|
||||
}
|
||||
try {
|
||||
holder.name.setText(jsonObject.getString("name"));
|
||||
} catch (JSONException e) {
|
||||
holder.name.setText("");
|
||||
}
|
||||
try {
|
||||
if (graph_or_fql.equals("graph")) {
|
||||
holder.info.setText(jsonObject.getJSONObject("location").getString("name"));
|
||||
} else {
|
||||
JSONObject location = jsonObject.getJSONObject("current_location");
|
||||
holder.info.setText(location.getString("city") + ", "
|
||||
+ location.getString("state"));
|
||||
}
|
||||
|
||||
} catch (JSONException e) {
|
||||
holder.info.setText("");
|
||||
}
|
||||
return hView;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
ImageView profile_pic;
|
||||
TextView name;
|
||||
TextView info;
|
||||
}
|
||||
}
|
@ -0,0 +1,359 @@
|
||||
package com.facebook.android;
|
||||
|
||||
/*
|
||||
* The me, delete and back_parent buttons are downloaded from http://icongal.com/
|
||||
*/
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Vector;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.text.util.Linkify.TransformFilter;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.inputmethod.InputMethodManager;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.ScrollView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class GraphExplorer extends Activity {
|
||||
private Button mSubmitButton, mViewURLButton;
|
||||
private Button mGetPermissionsButton;
|
||||
private Button mTextDeleteButton, mMeButton;
|
||||
private Button mFieldsConnectionsButton, mBackParentButton;
|
||||
private TextView mOutput;
|
||||
private EditText mInputId;
|
||||
private Bundle params;
|
||||
private String url, mParentObjectId;
|
||||
private ProgressDialog dialog;
|
||||
private String rootString;
|
||||
private ScrollView mScrollView;
|
||||
private Handler mHandler;
|
||||
private final static String BASE_GRAPH_URL = "https://graph.facebook.com";
|
||||
|
||||
private JSONObject metadataObject;
|
||||
|
||||
/*
|
||||
* Layout the Graph Explorer
|
||||
*/
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mHandler = new Handler();
|
||||
|
||||
setContentView(R.layout.graph_explorer);
|
||||
|
||||
url = BASE_GRAPH_URL; // Base URL
|
||||
|
||||
mInputId = (EditText) findViewById(R.id.inputId);
|
||||
mOutput = (TextView) findViewById(R.id.output);
|
||||
mSubmitButton = (Button) findViewById(R.id.submitButton);
|
||||
mViewURLButton = (Button) findViewById(R.id.viewURLButton);
|
||||
mGetPermissionsButton = (Button) findViewById(R.id.accessTokenButton);
|
||||
mFieldsConnectionsButton = (Button) findViewById(R.id.fieldsAndConnectionsButton);
|
||||
mBackParentButton = (Button) findViewById(R.id.backParentButton);
|
||||
|
||||
mScrollView = (ScrollView) findViewById(R.id.ScrollView01);
|
||||
|
||||
mTextDeleteButton = (Button) findViewById(R.id.textDeleteButton);
|
||||
mMeButton = (Button) findViewById(R.id.meButton);
|
||||
if (Utility.mFacebook.isSessionValid()) {
|
||||
mMeButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
params = new Bundle();
|
||||
mSubmitButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
|
||||
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
|
||||
.hideSoftInputFromWindow(mInputId.getWindowToken(), 0);
|
||||
|
||||
// Prepare the URL to be shown on 'View URL' click action. This
|
||||
// is not used by the SDK
|
||||
url = BASE_GRAPH_URL; // Base URL
|
||||
|
||||
/*
|
||||
* Source Tag: graph_explorer
|
||||
*/
|
||||
rootString = mInputId.getText().toString();
|
||||
if (!TextUtils.isEmpty(rootString)) {
|
||||
dialog = ProgressDialog.show(GraphExplorer.this, "",
|
||||
getString(R.string.please_wait), true, true);
|
||||
params.putString("metadata", "1");
|
||||
Utility.mAsyncRunner.request(rootString, params, new graphApiRequestListener());
|
||||
url += "/" + rootString; // Relative Path provided by you
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
mViewURLButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
setText(url);
|
||||
Linkify.addLinks(mOutput, Linkify.WEB_URLS);
|
||||
}
|
||||
});
|
||||
|
||||
mGetPermissionsButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (Utility.mFacebook.isSessionValid()) {
|
||||
dialog = ProgressDialog.show(GraphExplorer.this, "",
|
||||
getString(R.string.fetching_current_permissions), true, true);
|
||||
Bundle params = new Bundle();
|
||||
params.putString("access_token", Utility.mFacebook.getAccessToken());
|
||||
Utility.mAsyncRunner.request("me/permissions", params,
|
||||
new permissionsRequestListener());
|
||||
} else {
|
||||
new PermissionsDialog(GraphExplorer.this).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mFieldsConnectionsButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (metadataObject == null) {
|
||||
makeToast("No fields, connections availalbe for this object.");
|
||||
} else {
|
||||
new FieldsConnectionsDialog(GraphExplorer.this, metadataObject).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
mTextDeleteButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
url = BASE_GRAPH_URL; // Base URL
|
||||
mParentObjectId = "";
|
||||
mInputId.setText("");
|
||||
params.clear();
|
||||
metadataObject = null;
|
||||
setText("");
|
||||
mBackParentButton.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
});
|
||||
|
||||
mMeButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mInputId.setText("me");
|
||||
mSubmitButton.performClick();
|
||||
}
|
||||
});
|
||||
|
||||
mBackParentButton.setOnClickListener(new OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mInputId.setText(mParentObjectId);
|
||||
mParentObjectId = "";
|
||||
mSubmitButton.performClick();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if (Utility.mFacebook.isSessionValid()) {
|
||||
mMeButton.setVisibility(View.VISIBLE);
|
||||
}
|
||||
if (Utility.objectID != null) {
|
||||
mInputId.setText(Utility.objectID);
|
||||
Utility.objectID = null;
|
||||
mSubmitButton.performClick();
|
||||
}
|
||||
}
|
||||
|
||||
protected void processIntent(Intent incomingIntent) {
|
||||
Uri intentUri = incomingIntent.getData();
|
||||
if (intentUri == null) {
|
||||
return;
|
||||
}
|
||||
String objectID = intentUri.getHost();
|
||||
mInputId.setText(objectID);
|
||||
mSubmitButton.performClick();
|
||||
}
|
||||
|
||||
public void getConnection(String connection) {
|
||||
mInputId.setText(rootString + "/" + connection);
|
||||
mParentObjectId = rootString;
|
||||
mSubmitButton.performClick();
|
||||
}
|
||||
|
||||
public void getFields(Vector<String> fieldsVector) {
|
||||
String fields = "";
|
||||
int count = 0;
|
||||
for (String field : fieldsVector) {
|
||||
fields += field;
|
||||
if (++count < fieldsVector.size()) {
|
||||
fields += ",";
|
||||
}
|
||||
}
|
||||
params.putString("fields", fields);
|
||||
mSubmitButton.performClick();
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for the permission OAuth Dialog
|
||||
*/
|
||||
public class permissionsRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
dialog.dismiss();
|
||||
/*
|
||||
* Clear the current permission list and repopulate with new
|
||||
* permissions. This is used to mark assigned permission green and
|
||||
* unclickable.
|
||||
*/
|
||||
Utility.currentPermissions.clear();
|
||||
try {
|
||||
JSONObject jsonObject = new JSONObject(response).getJSONArray("data")
|
||||
.getJSONObject(0);
|
||||
Iterator<?> iterator = jsonObject.keys();
|
||||
String permission;
|
||||
while (iterator.hasNext()) {
|
||||
permission = (String) iterator.next();
|
||||
Utility.currentPermissions.put(permission,
|
||||
String.valueOf(jsonObject.getInt(permission)));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
makeToast("Permissions could not be fetched, none will be selected by default.");
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new PermissionsDialog(GraphExplorer.this).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
makeToast("Permissions could not be fetched, none will be selected by default.");
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new PermissionsDialog(GraphExplorer.this).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
Utility.mFacebook.authorizeCallback(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback after a given Graph API request is executed Get the response and
|
||||
* show it.
|
||||
*/
|
||||
public class graphApiRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
dialog.dismiss();
|
||||
// access token is appended by Facebook object, hence params are
|
||||
// added here after request is complete
|
||||
if (!params.isEmpty()) {
|
||||
url += "?" + Util.encodeUrl(params); // Params
|
||||
}
|
||||
metadataObject = null;
|
||||
params.clear();
|
||||
try {
|
||||
JSONObject json = Util.parseJson(response);
|
||||
if (json.has("metadata")) {
|
||||
metadataObject = json.getJSONObject("metadata");
|
||||
json.remove("metadata");
|
||||
} else {
|
||||
metadataObject = null;
|
||||
}
|
||||
setText(json.toString(2));
|
||||
} catch (JSONException e) {
|
||||
setText(e.getMessage());
|
||||
e.printStackTrace();
|
||||
} catch (FacebookError e) {
|
||||
setText(e.getMessage());
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
setText(error.getMessage());
|
||||
params.clear();
|
||||
metadataObject = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setText(final String txt) {
|
||||
mHandler.post(new Runnable() {
|
||||
|
||||
/*
|
||||
* A transform filter that simply returns just the text captured by
|
||||
* the first regular expression group.
|
||||
*/
|
||||
TransformFilter idFilter = new TransformFilter() {
|
||||
@Override
|
||||
public final String transformUrl(final Matcher match, String url) {
|
||||
return match.group(1);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
mViewURLButton.setVisibility(
|
||||
TextUtils.isEmpty(txt) ? View.INVISIBLE : View.VISIBLE);
|
||||
mFieldsConnectionsButton.setVisibility(TextUtils.isEmpty(txt) ? View.INVISIBLE
|
||||
: View.VISIBLE);
|
||||
mOutput.setVisibility(TextUtils.isEmpty(txt) ? View.INVISIBLE : View.VISIBLE);
|
||||
mBackParentButton.setVisibility(
|
||||
TextUtils.isEmpty(mParentObjectId) ? View.INVISIBLE : View.VISIBLE);
|
||||
|
||||
String convertedTxt = txt.replace("\\/", "/");
|
||||
mOutput.setText(convertedTxt);
|
||||
mScrollView.scrollTo(0, 0);
|
||||
|
||||
Linkify.addLinks(mOutput, Linkify.WEB_URLS);
|
||||
/*
|
||||
* Linkify the object ids so they can be clicked. match pattern:
|
||||
* "id" : "objectid" (objectid can be int or int_int)
|
||||
*/
|
||||
Pattern pattern = Pattern.compile("\"id\": \"(\\d*_?\\d*)\"");
|
||||
String scheme = "fbGraphEx://";
|
||||
Linkify.addLinks(mOutput, pattern, scheme, null, idFilter);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void makeToast(final String msg) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(GraphExplorer.this, msg, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,627 @@
|
||||
/*
|
||||
* Copyright 2004 - Present Facebook, Inc.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.provider.MediaStore;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.facebook.android.SessionEvents.AuthListener;
|
||||
import com.facebook.android.SessionEvents.LogoutListener;
|
||||
|
||||
public class Hackbook extends Activity implements OnItemClickListener {
|
||||
|
||||
/*
|
||||
* Your Facebook Application ID must be set before running this example See
|
||||
* http://www.facebook.com/developers/createapp.php
|
||||
*/
|
||||
public static final String APP_ID = "157111564357680";
|
||||
|
||||
private LoginButton mLoginButton;
|
||||
private TextView mText;
|
||||
private ImageView mUserPic;
|
||||
private Handler mHandler;
|
||||
ProgressDialog dialog;
|
||||
|
||||
final static int AUTHORIZE_ACTIVITY_RESULT_CODE = 0;
|
||||
final static int PICK_EXISTING_PHOTO_RESULT_CODE = 1;
|
||||
|
||||
private String graph_or_fql;
|
||||
|
||||
private ListView list;
|
||||
String[] main_items = { "Update Status", "App Requests", "Get Friends", "Upload Photo",
|
||||
"Place Check-in", "Run FQL Query", "Graph API Explorer", "Token Refresh" };
|
||||
String[] permissions = { "offline_access", "publish_stream", "user_photos", "publish_checkins",
|
||||
"photo_upload" };
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if (APP_ID == null) {
|
||||
Util.showAlert(this, "Warning", "Facebook Applicaton ID must be "
|
||||
+ "specified before running this example: see FbAPIs.java");
|
||||
return;
|
||||
}
|
||||
|
||||
setContentView(R.layout.main);
|
||||
mHandler = new Handler();
|
||||
|
||||
mText = (TextView) Hackbook.this.findViewById(R.id.txt);
|
||||
mUserPic = (ImageView) Hackbook.this.findViewById(R.id.user_pic);
|
||||
|
||||
// Create the Facebook Object using the app id.
|
||||
Utility.mFacebook = new Facebook(APP_ID);
|
||||
// Instantiate the asynrunner object for asynchronous api calls.
|
||||
Utility.mAsyncRunner = new AsyncFacebookRunner(Utility.mFacebook);
|
||||
|
||||
mLoginButton = (LoginButton) findViewById(R.id.login);
|
||||
|
||||
// restore session if one exists
|
||||
SessionStore.restore(Utility.mFacebook, this);
|
||||
SessionEvents.addAuthListener(new FbAPIsAuthListener());
|
||||
SessionEvents.addLogoutListener(new FbAPIsLogoutListener());
|
||||
|
||||
/*
|
||||
* Source Tag: login_tag
|
||||
*/
|
||||
mLoginButton.init(this, AUTHORIZE_ACTIVITY_RESULT_CODE, Utility.mFacebook, permissions);
|
||||
|
||||
if (Utility.mFacebook.isSessionValid()) {
|
||||
requestUserData();
|
||||
}
|
||||
|
||||
list = (ListView) findViewById(R.id.main_list);
|
||||
|
||||
list.setOnItemClickListener(this);
|
||||
list.setAdapter(new ArrayAdapter<String>(this, R.layout.main_list_item, main_items));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
if(Utility.mFacebook != null) {
|
||||
if (!Utility.mFacebook.isSessionValid()) {
|
||||
mText.setText("You are logged out! ");
|
||||
mUserPic.setImageBitmap(null);
|
||||
} else {
|
||||
Utility.mFacebook.extendAccessTokenIfNeeded(this, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
switch (requestCode) {
|
||||
/*
|
||||
* if this is the activity result from authorization flow, do a call
|
||||
* back to authorizeCallback Source Tag: login_tag
|
||||
*/
|
||||
case AUTHORIZE_ACTIVITY_RESULT_CODE: {
|
||||
Utility.mFacebook.authorizeCallback(requestCode, resultCode, data);
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* if this is the result for a photo picker from the gallery, upload
|
||||
* the image after scaling it. You can use the Utility.scaleImage()
|
||||
* function for scaling
|
||||
*/
|
||||
case PICK_EXISTING_PHOTO_RESULT_CODE: {
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Uri photoUri = data.getData();
|
||||
if (photoUri != null) {
|
||||
Bundle params = new Bundle();
|
||||
try {
|
||||
params.putByteArray("photo",
|
||||
Utility.scaleImage(getApplicationContext(), photoUri));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
params.putString("caption", "FbAPIs Sample App photo upload");
|
||||
Utility.mAsyncRunner.request("me/photos", params, "POST",
|
||||
new PhotoUploadListener(), null);
|
||||
} else {
|
||||
Toast.makeText(getApplicationContext(),
|
||||
"Error selecting image from the gallery.", Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
} else {
|
||||
Toast.makeText(getApplicationContext(), "No image selected for upload.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
|
||||
switch (position) {
|
||||
/*
|
||||
* Source Tag: update_status_tag Update user's status by invoking the
|
||||
* feed dialog To post to a friend's wall, provide his uid in the 'to'
|
||||
* parameter Refer to
|
||||
* https://developers.facebook.com/docs/reference/dialogs/feed/ for more
|
||||
* info.
|
||||
*/
|
||||
case 0: {
|
||||
Bundle params = new Bundle();
|
||||
params.putString("caption", getString(R.string.app_name));
|
||||
params.putString("description", getString(R.string.app_desc));
|
||||
params.putString("picture", Utility.HACK_ICON_URL);
|
||||
params.putString("name", getString(R.string.app_action));
|
||||
|
||||
Utility.mFacebook.dialog(Hackbook.this, "feed", params, new UpdateStatusListener());
|
||||
String access_token = Utility.mFacebook.getAccessToken();
|
||||
System.out.println(access_token);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Source Tag: app_requests Send an app request to friends. If no
|
||||
* friend is specified, the user will see a friend selector and will
|
||||
* be able to select a maximum of 50 recipients. To send request to
|
||||
* specific friend, provide the uid in the 'to' parameter Refer to
|
||||
* https://developers.facebook.com/docs/reference/dialogs/requests/
|
||||
* for more info.
|
||||
*/
|
||||
case 1: {
|
||||
Bundle params = new Bundle();
|
||||
params.putString("message", getString(R.string.request_message));
|
||||
Utility.mFacebook.dialog(Hackbook.this, "apprequests", params,
|
||||
new AppRequestsListener());
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Source Tag: friends_tag You can get friends using
|
||||
* graph.facebook.com/me/friends, this returns the list sorted by
|
||||
* UID OR using the friend table. With this you can sort the way you
|
||||
* want it.
|
||||
* Friend table - https://developers.facebook.com/docs/reference/fql/friend/
|
||||
* User table - https://developers.facebook.com/docs/reference/fql/user/
|
||||
*/
|
||||
case 2: {
|
||||
if (!Utility.mFacebook.isSessionValid()) {
|
||||
Util.showAlert(this, "Warning", "You must first log in.");
|
||||
} else {
|
||||
dialog = ProgressDialog.show(Hackbook.this, "",
|
||||
getString(R.string.please_wait), true, true);
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.Graph_FQL_title)
|
||||
.setMessage(R.string.Graph_FQL_msg)
|
||||
.setPositiveButton(R.string.graph_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
graph_or_fql = "graph";
|
||||
Bundle params = new Bundle();
|
||||
params.putString("fields", "name, picture, location");
|
||||
Utility.mAsyncRunner.request("me/friends", params,
|
||||
new FriendsRequestListener());
|
||||
}
|
||||
|
||||
})
|
||||
.setNegativeButton(R.string.fql_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
graph_or_fql = "fql";
|
||||
String query = "select name, current_location, uid, pic_square from user where uid in (select uid2 from friend where uid1=me()) order by name";
|
||||
Bundle params = new Bundle();
|
||||
params.putString("method", "fql.query");
|
||||
params.putString("query", query);
|
||||
Utility.mAsyncRunner.request(null, params,
|
||||
new FriendsRequestListener());
|
||||
}
|
||||
|
||||
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface d) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Source Tag: upload_photo You can upload a photo from the media
|
||||
* gallery or from a remote server How to upload photo:
|
||||
* https://developers.facebook.com/blog/post/498/
|
||||
*/
|
||||
case 3: {
|
||||
if (!Utility.mFacebook.isSessionValid()) {
|
||||
Util.showAlert(this, "Warning", "You must first log in.");
|
||||
} else {
|
||||
dialog = ProgressDialog.show(Hackbook.this, "",
|
||||
getString(R.string.please_wait), true, true);
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.gallery_remote_title)
|
||||
.setMessage(R.string.gallery_remote_msg)
|
||||
.setPositiveButton(R.string.gallery_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Intent intent = new Intent(Intent.ACTION_PICK,
|
||||
(MediaStore.Images.Media.EXTERNAL_CONTENT_URI));
|
||||
startActivityForResult(intent,
|
||||
PICK_EXISTING_PHOTO_RESULT_CODE);
|
||||
}
|
||||
|
||||
})
|
||||
.setNegativeButton(R.string.remote_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
/*
|
||||
* Source tag: upload_photo_tag
|
||||
*/
|
||||
Bundle params = new Bundle();
|
||||
params.putString("url",
|
||||
"http://www.facebook.com/images/devsite/iphone_connect_btn.jpg");
|
||||
params.putString("caption",
|
||||
"FbAPIs Sample App photo upload");
|
||||
Utility.mAsyncRunner.request("me/photos", params,
|
||||
"POST", new PhotoUploadListener(), null);
|
||||
}
|
||||
|
||||
}).setOnCancelListener(new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface d) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* User can check-in to a place, you require publish_checkins
|
||||
* permission for that. You can use the default Times Square
|
||||
* location or fetch user's current location. Get user's checkins:
|
||||
* https://developers.facebook.com/docs/reference/api/checkin/
|
||||
*/
|
||||
case 4: {
|
||||
final Intent myIntent = new Intent(getApplicationContext(), Places.class);
|
||||
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(R.string.get_location)
|
||||
.setMessage(R.string.get_default_or_new_location)
|
||||
.setPositiveButton(R.string.current_location_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
myIntent.putExtra("LOCATION", "current");
|
||||
startActivity(myIntent);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.times_square_button,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
myIntent.putExtra("LOCATION", "times_square");
|
||||
startActivity(myIntent);
|
||||
}
|
||||
|
||||
}).show();
|
||||
break;
|
||||
}
|
||||
|
||||
case 5: {
|
||||
if (!Utility.mFacebook.isSessionValid()) {
|
||||
Util.showAlert(this, "Warning", "You must first log in.");
|
||||
} else {
|
||||
new FQLQuery(Hackbook.this).show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* This is advanced feature where you can request new permissions
|
||||
* Browser user's graph, his fields and connections. This is similar
|
||||
* to the www version:
|
||||
* http://developers.facebook.com/tools/explorer/
|
||||
*/
|
||||
case 6: {
|
||||
Intent myIntent = new Intent(getApplicationContext(), GraphExplorer.class);
|
||||
if (Utility.mFacebook.isSessionValid()) {
|
||||
Utility.objectID = "me";
|
||||
}
|
||||
startActivity(myIntent);
|
||||
break;
|
||||
}
|
||||
|
||||
case 7: {
|
||||
if(!Utility.mFacebook.isSessionValid()) {
|
||||
Util.showAlert(this, "Warning", "You must first log in.");
|
||||
} else {
|
||||
new TokenRefreshDialog(Hackbook.this).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* callback for the feed dialog which updates the profile status
|
||||
*/
|
||||
public class UpdateStatusListener extends BaseDialogListener {
|
||||
@Override
|
||||
public void onComplete(Bundle values) {
|
||||
final String postId = values.getString("post_id");
|
||||
if (postId != null) {
|
||||
new UpdateStatusResultDialog(Hackbook.this, "Update Status executed", values)
|
||||
.show();
|
||||
} else {
|
||||
Toast toast = Toast.makeText(getApplicationContext(), "No wall post made",
|
||||
Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFacebookError(FacebookError error) {
|
||||
Toast.makeText(getApplicationContext(), "Facebook Error: " + error.getMessage(),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Toast toast = Toast.makeText(getApplicationContext(), "Update status cancelled",
|
||||
Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* callback for the apprequests dialog which sends an app request to user's
|
||||
* friends.
|
||||
*/
|
||||
public class AppRequestsListener extends BaseDialogListener {
|
||||
@Override
|
||||
public void onComplete(Bundle values) {
|
||||
Toast toast = Toast.makeText(getApplicationContext(), "App request sent",
|
||||
Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFacebookError(FacebookError error) {
|
||||
Toast.makeText(getApplicationContext(), "Facebook Error: " + error.getMessage(),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Toast toast = Toast.makeText(getApplicationContext(), "App request cancelled",
|
||||
Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* callback after friends are fetched via me/friends or fql query.
|
||||
*/
|
||||
public class FriendsRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
dialog.dismiss();
|
||||
Intent myIntent = new Intent(getApplicationContext(), FriendsList.class);
|
||||
myIntent.putExtra("API_RESPONSE", response);
|
||||
myIntent.putExtra("METHOD", graph_or_fql);
|
||||
startActivity(myIntent);
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
Toast.makeText(getApplicationContext(), "Facebook Error: " + error.getMessage(),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* callback for the photo upload
|
||||
*/
|
||||
public class PhotoUploadListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
dialog.dismiss();
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new UploadPhotoResultDialog(Hackbook.this, "Upload Photo executed", response)
|
||||
.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
Toast.makeText(getApplicationContext(), "Facebook Error: " + error.getMessage(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
public class FQLRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(getApplicationContext(), "Response: " + response,
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
Toast.makeText(getApplicationContext(), "Facebook Error: " + error.getMessage(),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback for fetching current user's name, picture, uid.
|
||||
*/
|
||||
public class UserRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
JSONObject jsonObject;
|
||||
try {
|
||||
jsonObject = new JSONObject(response);
|
||||
|
||||
final String picURL = jsonObject.getString("picture");
|
||||
final String name = jsonObject.getString("name");
|
||||
Utility.userUID = jsonObject.getString("id");
|
||||
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mText.setText("Welcome " + name + "!");
|
||||
mUserPic.setImageBitmap(Utility.getBitmap(picURL));
|
||||
}
|
||||
});
|
||||
|
||||
} catch (JSONException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* The Callback for notifying the application when authorization succeeds or
|
||||
* fails.
|
||||
*/
|
||||
|
||||
public class FbAPIsAuthListener implements AuthListener {
|
||||
|
||||
@Override
|
||||
public void onAuthSucceed() {
|
||||
requestUserData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthFail(String error) {
|
||||
mText.setText("Login Failed: " + error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The Callback for notifying the application when log out starts and
|
||||
* finishes.
|
||||
*/
|
||||
public class FbAPIsLogoutListener implements LogoutListener {
|
||||
@Override
|
||||
public void onLogoutBegin() {
|
||||
mText.setText("Logging out...");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutFinish() {
|
||||
mText.setText("You have logged out! ");
|
||||
mUserPic.setImageBitmap(null);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Request user name, and picture to show on the main screen.
|
||||
*/
|
||||
public void requestUserData() {
|
||||
mText.setText("Fetching user name, profile pic...");
|
||||
Bundle params = new Bundle();
|
||||
params.putString("fields", "name, picture");
|
||||
Utility.mAsyncRunner.request("me", params, new UserRequestListener());
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition of the list adapter
|
||||
*/
|
||||
public class MainListAdapter extends BaseAdapter {
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
public MainListAdapter() {
|
||||
mInflater = LayoutInflater.from(Hackbook.this.getBaseContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return main_items.length;
|
||||
}
|
||||
|
||||
@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;
|
||||
if (convertView == null) {
|
||||
hView = mInflater.inflate(R.layout.main_list_item, null);
|
||||
ViewHolder holder = new ViewHolder();
|
||||
holder.main_list_item = (TextView) hView.findViewById(R.id.main_api_item);
|
||||
hView.setTag(holder);
|
||||
}
|
||||
|
||||
ViewHolder holder = (ViewHolder) hView.getTag();
|
||||
|
||||
holder.main_list_item.setText(main_items[position]);
|
||||
|
||||
return hView;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
TextView main_list_item;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
/**
|
||||
* A transient activity which handles fbgraphex: URIs and passes those to the
|
||||
* GraphExplorer class This is used to linkify the Object IDs in the graph api
|
||||
* response
|
||||
*/
|
||||
public class IntentUriHandler extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Intent incomingIntent = getIntent();
|
||||
if (incomingIntent != null) {
|
||||
Uri intentUri = incomingIntent.getData();
|
||||
if (intentUri != null) {
|
||||
Utility.objectID = intentUri.getHost();
|
||||
Intent graphIntent = new Intent(getApplicationContext(), GraphExplorer.class);
|
||||
graphIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
|
||||
startActivity(graphIntent);
|
||||
}
|
||||
finish();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright 2010 Facebook, Inc.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
|
||||
import com.facebook.android.Facebook.DialogListener;
|
||||
import com.facebook.android.SessionEvents.AuthListener;
|
||||
import com.facebook.android.SessionEvents.LogoutListener;
|
||||
|
||||
public class LoginButton extends ImageButton {
|
||||
|
||||
private Facebook mFb;
|
||||
private Handler mHandler;
|
||||
private SessionListener mSessionListener = new SessionListener();
|
||||
private String[] mPermissions;
|
||||
private Activity mActivity;
|
||||
private int mActivityCode;
|
||||
|
||||
public LoginButton(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public LoginButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public LoginButton(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
}
|
||||
|
||||
public void init(final Activity activity, final int activityCode, final Facebook fb) {
|
||||
init(activity, activityCode, fb, new String[] {});
|
||||
}
|
||||
|
||||
public void init(final Activity activity, final int activityCode, final Facebook fb,
|
||||
final String[] permissions) {
|
||||
mActivity = activity;
|
||||
mActivityCode = activityCode;
|
||||
mFb = fb;
|
||||
mPermissions = permissions;
|
||||
mHandler = new Handler();
|
||||
|
||||
setBackgroundColor(Color.TRANSPARENT);
|
||||
setImageResource(fb.isSessionValid() ? R.drawable.logout_button : R.drawable.login_button);
|
||||
drawableStateChanged();
|
||||
|
||||
SessionEvents.addAuthListener(mSessionListener);
|
||||
SessionEvents.addLogoutListener(mSessionListener);
|
||||
setOnClickListener(new ButtonOnClickListener());
|
||||
}
|
||||
|
||||
private final class ButtonOnClickListener implements OnClickListener {
|
||||
/*
|
||||
* Source Tag: login_tag
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View arg0) {
|
||||
if (mFb.isSessionValid()) {
|
||||
SessionEvents.onLogoutBegin();
|
||||
AsyncFacebookRunner asyncRunner = new AsyncFacebookRunner(mFb);
|
||||
asyncRunner.logout(getContext(), new LogoutRequestListener());
|
||||
} else {
|
||||
mFb.authorize(mActivity, mPermissions, mActivityCode, new LoginDialogListener());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final class LoginDialogListener implements DialogListener {
|
||||
@Override
|
||||
public void onComplete(Bundle values) {
|
||||
SessionEvents.onLoginSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFacebookError(FacebookError error) {
|
||||
SessionEvents.onLoginError(error.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(DialogError error) {
|
||||
SessionEvents.onLoginError(error.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
SessionEvents.onLoginError("Action Canceled");
|
||||
}
|
||||
}
|
||||
|
||||
private class LogoutRequestListener extends BaseRequestListener {
|
||||
@Override
|
||||
public void onComplete(String response, final Object state) {
|
||||
/*
|
||||
* callback should be run in the original thread, not the background
|
||||
* thread
|
||||
*/
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
SessionEvents.onLogoutFinish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private class SessionListener implements AuthListener, LogoutListener {
|
||||
|
||||
@Override
|
||||
public void onAuthSucceed() {
|
||||
setImageResource(R.drawable.logout_button);
|
||||
SessionStore.save(mFb, getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAuthFail(String error) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutBegin() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLogoutFinish() {
|
||||
SessionStore.clear(getContext());
|
||||
setImageResource(R.drawable.login_button);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,251 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
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;
|
||||
|
||||
import com.facebook.android.Facebook.DialogListener;
|
||||
|
||||
public class PermissionsDialog extends Dialog {
|
||||
|
||||
private final static int TAB_HEIGHT = 50;
|
||||
|
||||
private Button mGetPermissions;
|
||||
private TextView mPermissionDetails;
|
||||
|
||||
private Activity activity;
|
||||
|
||||
private ListView userPermissionsList, friendPermissionsList, extendedPermissionsList;
|
||||
|
||||
private BaseAdapter userPermissionsAdapter, friendPermissionsAdapter,
|
||||
extendedPermissionAdapter;
|
||||
|
||||
protected Vector<String> reqPermVector;
|
||||
|
||||
String[] user_permissions = { "user_about_me", "user_activities", "user_birthday",
|
||||
"user_checkins", "user_education_history", "user_events", "user_groups",
|
||||
"user_hometown", "user_interests", "user_likes", "user_location", "user_notes",
|
||||
"user_online_presence", "user_photos", "user_photo_video_tags", "user_relationships",
|
||||
"user_relationship_details", "user_religion_politics", "user_status", "user_videos",
|
||||
"user_website", "user_work_history" };
|
||||
|
||||
String[] friend_permissions = { "friends_about_me", "friends_activities", "friends_birthday",
|
||||
"friends_checkins", "friends_education_history", "friends_events", "friends_groups",
|
||||
"friends_hometown", "friends_interests", "friends_likes", "friends_location",
|
||||
"friends_notes", "friends_online_presence", "friends_photos",
|
||||
"friends_photo_video_tags", "friends_relationships", "friends_relationship_details",
|
||||
"friends_religion_politics", "friends_status", "friends_videos", "friends_website",
|
||||
"friends_work_history" };
|
||||
|
||||
String[] extended_permissions = { "ads_management", "create_event", "create_note", "email",
|
||||
"export_stream", "manage_friendlists", "manage_groups", "manage_pages",
|
||||
"offline_access", "publish_actions", "photo_upload", "publish_checkins",
|
||||
"publish_stream", "read_friendlists", "read_insights", "read_mailbox", "read_requests",
|
||||
"read_stream", "rsvp_event", "share_item", "status_update", "sms", "video_upload",
|
||||
"xmpp_login" };
|
||||
|
||||
public PermissionsDialog(Activity activity) {
|
||||
super(activity);
|
||||
this.activity = activity;
|
||||
setTitle(activity.getString(R.string.permissions_request));
|
||||
reqPermVector = new Vector<String>();
|
||||
}
|
||||
|
||||
/*
|
||||
* Layout the permission dialog
|
||||
*/
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.permissions_list);
|
||||
LayoutParams params = getWindow().getAttributes();
|
||||
params.width = LayoutParams.FILL_PARENT;
|
||||
params.height = LayoutParams.FILL_PARENT;
|
||||
getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
|
||||
|
||||
mPermissionDetails = (TextView) findViewById(R.id.permission_detail);
|
||||
mPermissionDetails.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
|
||||
userPermissionsList = (ListView) findViewById(R.id.user_permissions_list);
|
||||
friendPermissionsList = (ListView) findViewById(R.id.friend_permissions_list);
|
||||
extendedPermissionsList = (ListView) findViewById(R.id.extended_permissions_list);
|
||||
|
||||
userPermissionsAdapter = new PermissionsListAdapter(user_permissions);
|
||||
userPermissionsList.setAdapter(userPermissionsAdapter);
|
||||
|
||||
friendPermissionsAdapter = new PermissionsListAdapter(friend_permissions);
|
||||
friendPermissionsList.setAdapter(friendPermissionsAdapter);
|
||||
|
||||
extendedPermissionAdapter = new PermissionsListAdapter(extended_permissions);
|
||||
extendedPermissionsList.setAdapter(extendedPermissionAdapter);
|
||||
|
||||
TabHost tabHost = (TabHost) findViewById(R.id.tabHost);
|
||||
tabHost.setup();
|
||||
|
||||
TabSpec spec1 = tabHost.newTabSpec("Tab 1");
|
||||
spec1.setIndicator(activity.getString(R.string.user));
|
||||
spec1.setContent(R.id.user_permissions_list);
|
||||
|
||||
TabSpec spec2 = tabHost.newTabSpec("Tab 2");
|
||||
spec2.setIndicator(activity.getString(R.string.friend));
|
||||
spec2.setContent(R.id.friend_permissions_list);
|
||||
|
||||
TabSpec spec3 = tabHost.newTabSpec("Tab 3");
|
||||
spec3.setIndicator(activity.getString(R.string.extended));
|
||||
spec3.setContent(R.id.extended_permissions_list);
|
||||
|
||||
tabHost.addTab(spec1);
|
||||
tabHost.addTab(spec2);
|
||||
tabHost.addTab(spec3);
|
||||
tabHost.setCurrentTab(0);
|
||||
tabHost.getTabWidget().getChildAt(0).getLayoutParams().height = TAB_HEIGHT;
|
||||
tabHost.getTabWidget().getChildAt(1).getLayoutParams().height = TAB_HEIGHT;
|
||||
tabHost.getTabWidget().getChildAt(2).getLayoutParams().height = TAB_HEIGHT;
|
||||
|
||||
mGetPermissions = (Button) findViewById(R.id.get_permissions_button);
|
||||
|
||||
mGetPermissions.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
/*
|
||||
* Source Tag: perms_tag Call authorize to get the new
|
||||
* permissions
|
||||
*/
|
||||
if (reqPermVector.isEmpty() && Utility.mFacebook.isSessionValid()) {
|
||||
Toast.makeText(activity.getBaseContext(), "No Permissions selected.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
PermissionsDialog.this.dismiss();
|
||||
} else {
|
||||
String[] permissions = reqPermVector.toArray(new String[0]);
|
||||
Utility.mFacebook.authorize(activity, permissions, new LoginDialogListener());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback when user has authorized the app with the new permissions
|
||||
*/
|
||||
private final class LoginDialogListener implements DialogListener {
|
||||
@Override
|
||||
public void onComplete(Bundle values) {
|
||||
// Inform the parent loginlistener so it can update the user's
|
||||
// profile pic and name on the home screen.
|
||||
SessionEvents.onLoginSuccess();
|
||||
|
||||
Toast.makeText(activity.getBaseContext(), "New Permissions granted.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
PermissionsDialog.this.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFacebookError(FacebookError error) {
|
||||
Toast.makeText(activity.getBaseContext(),
|
||||
"Facebook Error! No new permissions granted.", Toast.LENGTH_SHORT).show();
|
||||
PermissionsDialog.this.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(DialogError error) {
|
||||
Toast.makeText(activity.getBaseContext(), "Error! No new permissions granted.",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
PermissionsDialog.this.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Toast.makeText(activity.getBaseContext(),
|
||||
"Action cancelled, No new permissions granted.", Toast.LENGTH_SHORT).show();
|
||||
PermissionsDialog.this.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition of the list adapter
|
||||
*/
|
||||
public class PermissionsListAdapter extends BaseAdapter {
|
||||
private LayoutInflater mInflater;
|
||||
String[] permissions;
|
||||
boolean[] isChecked;
|
||||
|
||||
public PermissionsListAdapter(String[] permissions) {
|
||||
this.permissions = permissions;
|
||||
this.isChecked = new boolean[permissions.length];
|
||||
mInflater = LayoutInflater.from(activity.getBaseContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return permissions.length;
|
||||
}
|
||||
|
||||
@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;
|
||||
CheckBox checkbox;
|
||||
|
||||
if (hView == null) {
|
||||
hView = mInflater.inflate(R.layout.permission_item, null);
|
||||
checkbox = (CheckBox) hView.findViewById(R.id.permission_checkbox);
|
||||
hView.setTag(checkbox);
|
||||
} else {
|
||||
checkbox = (CheckBox) hView.getTag();
|
||||
}
|
||||
checkbox.setText(this.permissions[position]);
|
||||
checkbox.setId(position);
|
||||
if (Utility.currentPermissions.containsKey(this.permissions[position])
|
||||
&& Utility.currentPermissions.get(this.permissions[position]).equals("1")) {
|
||||
checkbox.setTextColor(Color.GREEN);
|
||||
checkbox.setChecked(true);
|
||||
checkbox.setEnabled(false);
|
||||
checkbox.setOnCheckedChangeListener(null);
|
||||
} else {
|
||||
checkbox.setTextColor(Color.WHITE);
|
||||
checkbox.setChecked(this.isChecked[position]);
|
||||
checkbox.setEnabled(true);
|
||||
checkbox.setOnCheckedChangeListener(new OnCheckedChangeListener() {
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton button, boolean checked) {
|
||||
isChecked[button.getId()] = checked;
|
||||
if (checked) {
|
||||
reqPermVector.add(button.getText().toString());
|
||||
} else if (reqPermVector.contains(button.getText())) {
|
||||
reqPermVector.remove(button.getText());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
return hView;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,363 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.location.Criteria;
|
||||
import android.location.Location;
|
||||
import android.location.LocationListener;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class Places extends Activity implements OnItemClickListener {
|
||||
private Handler mHandler;
|
||||
private JSONObject location;
|
||||
|
||||
protected ListView placesList;
|
||||
protected LocationManager lm;
|
||||
protected MyLocationListener locationListener;
|
||||
|
||||
protected static JSONArray jsonArray;
|
||||
final static double TIMES_SQUARE_LAT = 40.756;
|
||||
final static double TIMES_SQUARE_LON = -73.987;
|
||||
|
||||
protected ProgressDialog dialog;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mHandler = new Handler();
|
||||
location = new JSONObject();
|
||||
|
||||
setContentView(R.layout.places_list);
|
||||
|
||||
Bundle extras = getIntent().getExtras();
|
||||
String default_or_new = extras.getString("LOCATION");
|
||||
if (default_or_new.equals("times_square")) {
|
||||
try {
|
||||
location.put("latitude", new Double(TIMES_SQUARE_LAT));
|
||||
location.put("longitude", new Double(TIMES_SQUARE_LON));
|
||||
} catch (JSONException e) {
|
||||
}
|
||||
fetchPlaces();
|
||||
} else {
|
||||
getLocation();
|
||||
}
|
||||
}
|
||||
|
||||
public void getLocation() {
|
||||
/*
|
||||
* launch a new Thread to get new location
|
||||
*/
|
||||
new Thread() {
|
||||
@Override
|
||||
public void run() {
|
||||
Looper.prepare();
|
||||
dialog = ProgressDialog.show(Places.this, "",
|
||||
getString(R.string.fetching_location), false, true,
|
||||
new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
showToast("No location fetched.");
|
||||
}
|
||||
});
|
||||
|
||||
if (lm == null) {
|
||||
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
|
||||
if (locationListener == null) {
|
||||
locationListener = new MyLocationListener();
|
||||
}
|
||||
|
||||
Criteria criteria = new Criteria();
|
||||
criteria.setAccuracy(Criteria.ACCURACY_COARSE);
|
||||
String provider = lm.getBestProvider(criteria, true);
|
||||
if (provider != null && lm.isProviderEnabled(provider)) {
|
||||
lm.requestLocationUpdates(provider, 1, 0, locationListener,
|
||||
Looper.getMainLooper());
|
||||
} else {
|
||||
/*
|
||||
* GPS not enabled, prompt user to enable GPS in the
|
||||
* Location menu
|
||||
*/
|
||||
new AlertDialog.Builder(Places.this)
|
||||
.setTitle(R.string.enable_gps_title)
|
||||
.setMessage(getString(R.string.enable_gps))
|
||||
.setPositiveButton(R.string.gps_settings,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
startActivityForResult(
|
||||
new Intent(
|
||||
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS),
|
||||
0);
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.cancel,
|
||||
new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
dialog.dismiss();
|
||||
Places.this.finish();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
Looper.loop();
|
||||
}
|
||||
}.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
/*
|
||||
* User returning from the Location settings menu. try to fetch location
|
||||
* again.
|
||||
*/
|
||||
dialog.dismiss();
|
||||
getLocation();
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch nearby places by providing the search type as 'place' within 1000
|
||||
* mtrs of the provided lat & lon
|
||||
*/
|
||||
private void fetchPlaces() {
|
||||
if (!isFinishing()) {
|
||||
dialog = ProgressDialog.show(Places.this, "", getString(R.string.nearby_places), true,
|
||||
true, new DialogInterface.OnCancelListener() {
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
showToast("No places fetched.");
|
||||
}
|
||||
});
|
||||
}
|
||||
/*
|
||||
* Source tag: fetch_places_tag
|
||||
*/
|
||||
Bundle params = new Bundle();
|
||||
params.putString("type", "place");
|
||||
try {
|
||||
params.putString("center",
|
||||
location.getString("latitude") + "," + location.getString("longitude"));
|
||||
} catch (JSONException e) {
|
||||
showToast("No places fetched.");
|
||||
return;
|
||||
}
|
||||
params.putString("distance", "1000");
|
||||
Utility.mAsyncRunner.request("search", params, new placesRequestListener());
|
||||
}
|
||||
|
||||
/*
|
||||
* Callback after places are fetched.
|
||||
*/
|
||||
public class placesRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
Log.d("Facebook-FbAPIs", "Got response: " + response);
|
||||
dialog.dismiss();
|
||||
|
||||
try {
|
||||
jsonArray = new JSONObject(response).getJSONArray("data");
|
||||
if (jsonArray == null) {
|
||||
showToast("Error: nearby places could not be fetched");
|
||||
return;
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
showToast("Error: " + e.getMessage());
|
||||
return;
|
||||
}
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
placesList = (ListView) findViewById(R.id.places_list);
|
||||
placesList.setOnItemClickListener(Places.this);
|
||||
placesList.setAdapter(new PlacesListAdapter(Places.this));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
showToast("Fetch Places Error: " + error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> arg0, View v, int position, long arg3) {
|
||||
if (!Utility.mFacebook.isSessionValid()) {
|
||||
Util.showAlert(this, "Warning", "You must first log in.");
|
||||
} else {
|
||||
try {
|
||||
final String message = "Check-in from the " + getString(R.string.app_name);
|
||||
final String name = jsonArray.getJSONObject(position).getString("name");
|
||||
final String placeID = jsonArray.getJSONObject(position).getString("id");
|
||||
new AlertDialog.Builder(this).setTitle(R.string.check_in_title)
|
||||
.setMessage(String.format(getString(R.string.check_in_at), name))
|
||||
.setPositiveButton(R.string.checkin, new DialogInterface.OnClickListener() {
|
||||
/*
|
||||
* Source tag: check_in_tag Check-in user at the
|
||||
* selected location posting to the me/checkins
|
||||
* endpoint. More info here:
|
||||
* https://developers.facebook
|
||||
* .com/docs/reference/api/user/ - checkins
|
||||
*/
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
Bundle params = new Bundle();
|
||||
params.putString("place", placeID);
|
||||
params.putString("message", message);
|
||||
params.putString("coordinates", location.toString());
|
||||
Utility.mAsyncRunner.request("me/checkins", params, "POST",
|
||||
new placesCheckInListener(), null);
|
||||
}
|
||||
}).setNegativeButton(R.string.cancel, null).show();
|
||||
} catch (JSONException e) {
|
||||
showToast("Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class placesCheckInListener extends BaseRequestListener {
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
showToast("API Response: " + response);
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
showToast("Check-in Error: " + error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void showToast(final String msg) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Toast toast = Toast.makeText(Places.this, msg, Toast.LENGTH_LONG);
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Definition of the list adapter
|
||||
*/
|
||||
public class PlacesListAdapter extends BaseAdapter {
|
||||
private LayoutInflater mInflater;
|
||||
Places placesList;
|
||||
|
||||
public PlacesListAdapter(Context context) {
|
||||
mInflater = LayoutInflater.from(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return jsonArray.length();
|
||||
}
|
||||
|
||||
@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) {
|
||||
JSONObject jsonObject = null;
|
||||
try {
|
||||
jsonObject = jsonArray.getJSONObject(position);
|
||||
} catch (JSONException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
View hView = convertView;
|
||||
if (convertView == null) {
|
||||
hView = mInflater.inflate(R.layout.place_item, null);
|
||||
ViewHolder holder = new ViewHolder();
|
||||
holder.name = (TextView) hView.findViewById(R.id.place_name);
|
||||
holder.location = (TextView) hView.findViewById(R.id.place_location);
|
||||
hView.setTag(holder);
|
||||
}
|
||||
|
||||
ViewHolder holder = (ViewHolder) hView.getTag();
|
||||
try {
|
||||
holder.name.setText(jsonObject.getString("name"));
|
||||
} catch (JSONException e) {
|
||||
holder.name.setText("");
|
||||
}
|
||||
try {
|
||||
String location = jsonObject.getJSONObject("location").getString("street") + ", "
|
||||
+ jsonObject.getJSONObject("location").getString("city") + ", "
|
||||
+ jsonObject.getJSONObject("location").getString("state");
|
||||
holder.location.setText(location);
|
||||
} catch (JSONException e) {
|
||||
holder.location.setText("");
|
||||
}
|
||||
return hView;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
TextView name;
|
||||
TextView location;
|
||||
}
|
||||
|
||||
class MyLocationListener implements LocationListener {
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location loc) {
|
||||
dialog.dismiss();
|
||||
if (loc != null) {
|
||||
try {
|
||||
location.put("latitude", new Double(loc.getLatitude()));
|
||||
location.put("longitude", new Double(loc.getLongitude()));
|
||||
} catch (JSONException e) {
|
||||
}
|
||||
showToast("Location acquired: " + String.valueOf(loc.getLatitude()) + " "
|
||||
+ String.valueOf(loc.getLongitude()));
|
||||
lm.removeUpdates(this);
|
||||
fetchPlaces();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright 2010 Facebook, Inc.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
public class SessionEvents {
|
||||
|
||||
private static LinkedList<AuthListener> mAuthListeners = new LinkedList<AuthListener>();
|
||||
private static LinkedList<LogoutListener> mLogoutListeners = new LinkedList<LogoutListener>();
|
||||
|
||||
/**
|
||||
* Associate the given listener with this Facebook object. The listener's
|
||||
* callback interface will be invoked when authentication events occur.
|
||||
*
|
||||
* @param listener
|
||||
* The callback object for notifying the application when auth
|
||||
* events happen.
|
||||
*/
|
||||
public static void addAuthListener(AuthListener listener) {
|
||||
mAuthListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given listener from the list of those that will be notified
|
||||
* when authentication events occur.
|
||||
*
|
||||
* @param listener
|
||||
* The callback object for notifying the application when auth
|
||||
* events happen.
|
||||
*/
|
||||
public static void removeAuthListener(AuthListener listener) {
|
||||
mAuthListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate the given listener with this Facebook object. The listener's
|
||||
* callback interface will be invoked when logout occurs.
|
||||
*
|
||||
* @param listener
|
||||
* The callback object for notifying the application when log out
|
||||
* starts and finishes.
|
||||
*/
|
||||
public static void addLogoutListener(LogoutListener listener) {
|
||||
mLogoutListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given listener from the list of those that will be notified
|
||||
* when logout occurs.
|
||||
*
|
||||
* @param listener
|
||||
* The callback object for notifying the application when log out
|
||||
* starts and finishes.
|
||||
*/
|
||||
public static void removeLogoutListener(LogoutListener listener) {
|
||||
mLogoutListeners.remove(listener);
|
||||
}
|
||||
|
||||
public static void onLoginSuccess() {
|
||||
for (AuthListener listener : mAuthListeners) {
|
||||
listener.onAuthSucceed();
|
||||
}
|
||||
}
|
||||
|
||||
public static void onLoginError(String error) {
|
||||
for (AuthListener listener : mAuthListeners) {
|
||||
listener.onAuthFail(error);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onLogoutBegin() {
|
||||
for (LogoutListener l : mLogoutListeners) {
|
||||
l.onLogoutBegin();
|
||||
}
|
||||
}
|
||||
|
||||
public static void onLogoutFinish() {
|
||||
for (LogoutListener l : mLogoutListeners) {
|
||||
l.onLogoutFinish();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for authorization events.
|
||||
*/
|
||||
public static interface AuthListener {
|
||||
|
||||
/**
|
||||
* Called when a auth flow completes successfully and a valid OAuth
|
||||
* Token was received. Executed by the thread that initiated the
|
||||
* authentication. API requests can now be made.
|
||||
*/
|
||||
public void onAuthSucceed();
|
||||
|
||||
/**
|
||||
* Called when a login completes unsuccessfully with an error.
|
||||
*
|
||||
* Executed by the thread that initiated the authentication.
|
||||
*/
|
||||
public void onAuthFail(String error);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for logout events.
|
||||
*/
|
||||
public static interface LogoutListener {
|
||||
/**
|
||||
* Called when logout begins, before session is invalidated. Last chance
|
||||
* to make an API call. Executed by the thread that initiated the
|
||||
* logout.
|
||||
*/
|
||||
public void onLogoutBegin();
|
||||
|
||||
/**
|
||||
* Called when the session information has been cleared. UI should be
|
||||
* updated to reflect logged-out state.
|
||||
*
|
||||
* Executed by the thread that initiated the logout.
|
||||
*/
|
||||
public void onLogoutFinish();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright 2010 Facebook, Inc.
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
|
||||
public class SessionStore {
|
||||
|
||||
private static final String TOKEN = "access_token";
|
||||
private static final String EXPIRES = "expires_in";
|
||||
private static final String KEY = "facebook-session";
|
||||
|
||||
/*
|
||||
* Save the access token and expiry date so you don't have to fetch it each
|
||||
* time
|
||||
*/
|
||||
|
||||
public static boolean save(Facebook session, Context context) {
|
||||
Editor editor = context.getSharedPreferences(KEY, Context.MODE_PRIVATE).edit();
|
||||
editor.putString(TOKEN, session.getAccessToken());
|
||||
editor.putLong(EXPIRES, session.getAccessExpires());
|
||||
return editor.commit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the access token and the expiry date from the shared preferences.
|
||||
*/
|
||||
public static boolean restore(Facebook session, Context context) {
|
||||
SharedPreferences savedSession = context.getSharedPreferences(KEY, Context.MODE_PRIVATE);
|
||||
session.setAccessToken(savedSession.getString(TOKEN, null));
|
||||
session.setAccessExpires(savedSession.getLong(EXPIRES, 0));
|
||||
return session.isSessionValid();
|
||||
}
|
||||
|
||||
public static void clear(Context context) {
|
||||
Editor editor = context.getSharedPreferences(KEY, Context.MODE_PRIVATE).edit();
|
||||
editor.clear();
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class SplashActivity extends Activity {
|
||||
private long splashDelay = 1500;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.splash);
|
||||
TimerTask task = new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
finish();
|
||||
Intent hackbookIntent = new Intent().setClass(SplashActivity.this, Hackbook.class);
|
||||
startActivity(hackbookIntent);
|
||||
}
|
||||
};
|
||||
|
||||
Timer timer = new Timer();
|
||||
timer.schedule(task, splashDelay);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class TokenRefreshDialog extends Dialog {
|
||||
|
||||
private EditText tokenEdit, tokenExpiresEdit;
|
||||
private TextView mUsefulTip;
|
||||
private Button mRefreshButton;
|
||||
private Activity activity;
|
||||
|
||||
public TokenRefreshDialog(Activity activity) {
|
||||
super(activity);
|
||||
this.activity = activity;
|
||||
setTitle(R.string.refresh_token_title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.token_refresh);
|
||||
|
||||
tokenEdit = (EditText) findViewById(R.id.tokenEdit);
|
||||
tokenEdit.setText(Utility.mFacebook.getAccessToken());
|
||||
|
||||
tokenExpiresEdit = (EditText) findViewById(R.id.tokenExpiresEdit);
|
||||
setExpiresAt(Utility.mFacebook.getAccessExpires());
|
||||
|
||||
mUsefulTip = (TextView) findViewById(R.id.usefulTip);
|
||||
mUsefulTip.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
mRefreshButton = (Button) findViewById(R.id.refresh_button);
|
||||
|
||||
mRefreshButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
changeButtonState(false);
|
||||
RefreshTokenListener listener = new RefreshTokenListener();
|
||||
if (!Utility.mFacebook.extendAccessToken(activity, listener)) {
|
||||
listener.onError(new Error(
|
||||
activity.getString(R.string.refresh_token_binding_error)));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class RefreshTokenListener implements Facebook.ServiceListener {
|
||||
|
||||
@Override
|
||||
public void onFacebookError(FacebookError e) {
|
||||
changeButtonState(true);
|
||||
String title = String.format(activity.getString(R.string.facebook_error) + "%d",
|
||||
e.getErrorCode());
|
||||
Util.showAlert(activity, title, e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Error e) {
|
||||
changeButtonState(true);
|
||||
Util.showAlert(activity, activity.getString(R.string.error), e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Bundle values) {
|
||||
changeButtonState(true);
|
||||
|
||||
// The access_token and expires_at values are automatically updated,
|
||||
// so they can be obtained by using:
|
||||
// - Facebook.getAccessToken()
|
||||
// - Facebook.getAccessExpires()
|
||||
// methods, but we can also get them from the 'values' bundle.
|
||||
tokenEdit.setText(values.getString(Facebook.TOKEN));
|
||||
setExpiresAt(values.getLong(Facebook.EXPIRES));
|
||||
}
|
||||
}
|
||||
|
||||
private void changeButtonState(boolean enabled) {
|
||||
mRefreshButton.setEnabled(enabled);
|
||||
mRefreshButton.setText(enabled ? R.string.refresh_button : R.string.refresh_button_pending);
|
||||
}
|
||||
|
||||
private void setExpiresAt(long time) {
|
||||
DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
tokenExpiresEdit.setText(dateFormat.format(new Date(time)));
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class UpdateStatusResultDialog extends Dialog {
|
||||
|
||||
private Bundle values;
|
||||
private TextView mOutput, mUsefulTip;
|
||||
private Button mViewPostButton, mDeletePostButton;
|
||||
private Activity activity;
|
||||
private Handler mHandler;
|
||||
|
||||
public UpdateStatusResultDialog(Activity activity, String title, Bundle values) {
|
||||
super(activity);
|
||||
this.activity = activity;
|
||||
this.values = values;
|
||||
setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
mHandler = new Handler();
|
||||
|
||||
setContentView(R.layout.update_post_response);
|
||||
LayoutParams params = getWindow().getAttributes();
|
||||
params.width = LayoutParams.FILL_PARENT;
|
||||
params.height = LayoutParams.FILL_PARENT;
|
||||
getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
|
||||
|
||||
mOutput = (TextView) findViewById(R.id.apiOutput);
|
||||
mOutput.setText(values.toString());
|
||||
|
||||
mUsefulTip = (TextView) findViewById(R.id.usefulTip);
|
||||
mUsefulTip.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
mViewPostButton = (Button) findViewById(R.id.view_post_button);
|
||||
mDeletePostButton = (Button) findViewById(R.id.delete_post_button);
|
||||
final String postId = values.getString("post_id");
|
||||
|
||||
mViewPostButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
/*
|
||||
* Source tag: view_post_tag
|
||||
*/
|
||||
Utility.mAsyncRunner.request(postId, new WallPostRequestListener());
|
||||
}
|
||||
});
|
||||
mDeletePostButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
/*
|
||||
* Source tag: delete_post_tag
|
||||
*/
|
||||
Utility.mAsyncRunner.request(postId, new Bundle(), "DELETE",
|
||||
new WallPostDeleteListener(), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public class WallPostRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
try {
|
||||
JSONObject json = new JSONObject(response);
|
||||
setText(json.toString(2));
|
||||
} catch (JSONException e) {
|
||||
setText(activity.getString(R.string.exception) + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
setText(activity.getString(R.string.facebook_error) + error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public class WallPostDeleteListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
if (response.equals("true")) {
|
||||
String message = "Wall Post deleted" + "\n";
|
||||
message += "Api Response: " + response;
|
||||
setText(message);
|
||||
} else {
|
||||
setText("wall post could not be deleted");
|
||||
}
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
setText(activity.getString(R.string.facebook_error) + error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(final String txt) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mOutput.setText(txt);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.graphics.Bitmap;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.text.util.Linkify;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.widget.Button;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class UploadPhotoResultDialog extends Dialog {
|
||||
|
||||
private String response, photo_id;
|
||||
private TextView mOutput, mUsefulTip;
|
||||
private Button mViewPhotoButton, mTagPhotoButton;
|
||||
private ImageView mUploadedPhoto;
|
||||
private Activity activity;
|
||||
private ProgressDialog dialog;
|
||||
private boolean hidePhoto = false;
|
||||
private Handler mHandler;
|
||||
|
||||
public UploadPhotoResultDialog(Activity activity, String title, String response) {
|
||||
super(activity);
|
||||
this.activity = activity;
|
||||
this.response = response;
|
||||
setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
mHandler = new Handler();
|
||||
|
||||
setContentView(R.layout.upload_photo_response);
|
||||
LayoutParams params = getWindow().getAttributes();
|
||||
params.width = LayoutParams.FILL_PARENT;
|
||||
params.height = LayoutParams.FILL_PARENT;
|
||||
getWindow().setAttributes((android.view.WindowManager.LayoutParams) params);
|
||||
|
||||
mOutput = (TextView) findViewById(R.id.apiOutput);
|
||||
mUsefulTip = (TextView) findViewById(R.id.usefulTip);
|
||||
mViewPhotoButton = (Button) findViewById(R.id.view_photo_button);
|
||||
mTagPhotoButton = (Button) findViewById(R.id.tag_photo_button);
|
||||
mUploadedPhoto = (ImageView) findViewById(R.id.uploadedPhoto);
|
||||
|
||||
JSONObject json;
|
||||
try {
|
||||
json = Util.parseJson(response);
|
||||
final String photo_id = json.getString("id");
|
||||
this.photo_id = photo_id;
|
||||
|
||||
mOutput.setText(json.toString(2));
|
||||
mUsefulTip.setText(activity.getString(R.string.photo_tip));
|
||||
Linkify.addLinks(mUsefulTip, Linkify.WEB_URLS);
|
||||
|
||||
mViewPhotoButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (hidePhoto) {
|
||||
mViewPhotoButton.setText(R.string.view_photo);
|
||||
hidePhoto = false;
|
||||
mUploadedPhoto.setImageBitmap(null);
|
||||
} else {
|
||||
hidePhoto = true;
|
||||
mViewPhotoButton.setText(R.string.hide_photo);
|
||||
/*
|
||||
* Source tag: view_photo_tag
|
||||
*/
|
||||
Bundle params = new Bundle();
|
||||
params.putString("fields", "picture");
|
||||
dialog = ProgressDialog.show(activity, "",
|
||||
activity.getString(R.string.please_wait), true, true);
|
||||
dialog.show();
|
||||
Utility.mAsyncRunner.request(photo_id, params,
|
||||
new ViewPhotoRequestListener());
|
||||
}
|
||||
}
|
||||
});
|
||||
mTagPhotoButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
/*
|
||||
* Source tag: tag_photo_tag
|
||||
*/
|
||||
setTag();
|
||||
}
|
||||
});
|
||||
} catch (JSONException e) {
|
||||
setText(activity.getString(R.string.exception) + e.getMessage());
|
||||
} catch (FacebookError e) {
|
||||
setText(activity.getString(R.string.facebook_error) + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void setTag() {
|
||||
String relativePath = photo_id + "/tags/" + Utility.userUID;
|
||||
Bundle params = new Bundle();
|
||||
params.putString("x", "5");
|
||||
params.putString("y", "5");
|
||||
Utility.mAsyncRunner.request(relativePath, params, "POST", new TagPhotoRequestListener(),
|
||||
null);
|
||||
}
|
||||
|
||||
public class ViewPhotoRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
try {
|
||||
JSONObject json = Util.parseJson(response);
|
||||
final String pictureURL = json.getString("picture");
|
||||
if (TextUtils.isEmpty(pictureURL)) {
|
||||
setText("Error getting \'picture\' field of the photo");
|
||||
} else {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new FetchImage().execute(pictureURL);
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
dialog.dismiss();
|
||||
setText(activity.getString(R.string.exception) + e.getMessage());
|
||||
} catch (FacebookError e) {
|
||||
dialog.dismiss();
|
||||
setText(activity.getString(R.string.facebook_error) + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
dialog.dismiss();
|
||||
setText(activity.getString(R.string.facebook_error) + error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public class TagPhotoRequestListener extends BaseRequestListener {
|
||||
|
||||
@Override
|
||||
public void onComplete(final String response, final Object state) {
|
||||
if (response.equals("true")) {
|
||||
String message = "User tagged in photo at (5, 5)" + "\n";
|
||||
message += "Api Response: " + response;
|
||||
setText(message);
|
||||
} else {
|
||||
setText("User could not be tagged.");
|
||||
}
|
||||
}
|
||||
|
||||
public void onFacebookError(FacebookError error) {
|
||||
setText(activity.getString(R.string.facebook_error) + error.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void setText(final String txt) {
|
||||
mHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mOutput.setText(txt);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private class FetchImage extends AsyncTask<String, Void, Bitmap> {
|
||||
@Override
|
||||
protected Bitmap doInBackground(String... urls) {
|
||||
return Utility.getBitmap(urls[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Bitmap result) {
|
||||
dialog.dismiss();
|
||||
mUploadedPhoto.setImageBitmap(result);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
package com.facebook.android;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Hashtable;
|
||||
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Matrix;
|
||||
import android.net.Uri;
|
||||
import android.net.http.AndroidHttpClient;
|
||||
import android.provider.MediaStore;
|
||||
|
||||
public class Utility extends Application {
|
||||
|
||||
public static Facebook mFacebook;
|
||||
public static AsyncFacebookRunner mAsyncRunner;
|
||||
public static JSONObject mFriendsList;
|
||||
public static String userUID = null;
|
||||
public static String objectID = null;
|
||||
public static FriendsGetProfilePics model;
|
||||
public static AndroidHttpClient httpclient = null;
|
||||
public static Hashtable<String, String> currentPermissions = new Hashtable<String, String>();
|
||||
|
||||
private static int MAX_IMAGE_DIMENSION = 720;
|
||||
public static final String HACK_ICON_URL = "http://www.facebookmobileweb.com/hackbook/img/facebook_icon_large.png";
|
||||
|
||||
public static Bitmap getBitmap(String url) {
|
||||
Bitmap bm = null;
|
||||
try {
|
||||
URL aURL = new URL(url);
|
||||
URLConnection conn = aURL.openConnection();
|
||||
conn.connect();
|
||||
InputStream is = conn.getInputStream();
|
||||
BufferedInputStream bis = new BufferedInputStream(is);
|
||||
bm = BitmapFactory.decodeStream(new FlushedInputStream(is));
|
||||
bis.close();
|
||||
is.close();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (httpclient != null) {
|
||||
httpclient.close();
|
||||
}
|
||||
}
|
||||
return bm;
|
||||
}
|
||||
|
||||
static class FlushedInputStream extends FilterInputStream {
|
||||
public FlushedInputStream(InputStream inputStream) {
|
||||
super(inputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long totalBytesSkipped = 0L;
|
||||
while (totalBytesSkipped < n) {
|
||||
long bytesSkipped = in.skip(n - totalBytesSkipped);
|
||||
if (bytesSkipped == 0L) {
|
||||
int b = read();
|
||||
if (b < 0) {
|
||||
break; // we reached EOF
|
||||
} else {
|
||||
bytesSkipped = 1; // we read one byte
|
||||
}
|
||||
}
|
||||
totalBytesSkipped += bytesSkipped;
|
||||
}
|
||||
return totalBytesSkipped;
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] scaleImage(Context context, Uri photoUri) throws IOException {
|
||||
InputStream is = context.getContentResolver().openInputStream(photoUri);
|
||||
BitmapFactory.Options dbo = new BitmapFactory.Options();
|
||||
dbo.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeStream(is, null, dbo);
|
||||
is.close();
|
||||
|
||||
int rotatedWidth, rotatedHeight;
|
||||
int orientation = getOrientation(context, photoUri);
|
||||
|
||||
if (orientation == 90 || orientation == 270) {
|
||||
rotatedWidth = dbo.outHeight;
|
||||
rotatedHeight = dbo.outWidth;
|
||||
} else {
|
||||
rotatedWidth = dbo.outWidth;
|
||||
rotatedHeight = dbo.outHeight;
|
||||
}
|
||||
|
||||
Bitmap srcBitmap;
|
||||
is = context.getContentResolver().openInputStream(photoUri);
|
||||
if (rotatedWidth > MAX_IMAGE_DIMENSION || rotatedHeight > MAX_IMAGE_DIMENSION) {
|
||||
float widthRatio = ((float) rotatedWidth) / ((float) MAX_IMAGE_DIMENSION);
|
||||
float heightRatio = ((float) rotatedHeight) / ((float) MAX_IMAGE_DIMENSION);
|
||||
float maxRatio = Math.max(widthRatio, heightRatio);
|
||||
|
||||
// Create the bitmap from file
|
||||
BitmapFactory.Options options = new BitmapFactory.Options();
|
||||
options.inSampleSize = (int) maxRatio;
|
||||
srcBitmap = BitmapFactory.decodeStream(is, null, options);
|
||||
} else {
|
||||
srcBitmap = BitmapFactory.decodeStream(is);
|
||||
}
|
||||
is.close();
|
||||
|
||||
/*
|
||||
* if the orientation is not 0 (or -1, which means we don't know), we
|
||||
* have to do a rotation.
|
||||
*/
|
||||
if (orientation > 0) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(orientation);
|
||||
|
||||
srcBitmap = Bitmap.createBitmap(srcBitmap, 0, 0, srcBitmap.getWidth(),
|
||||
srcBitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
String type = context.getContentResolver().getType(photoUri);
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
if (type.equals("image/png")) {
|
||||
srcBitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
|
||||
} else if (type.equals("image/jpg") || type.equals("image/jpeg")) {
|
||||
srcBitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
|
||||
}
|
||||
byte[] bMapArray = baos.toByteArray();
|
||||
baos.close();
|
||||
return bMapArray;
|
||||
}
|
||||
|
||||
public static int getOrientation(Context context, Uri photoUri) {
|
||||
/* it's on the external media. */
|
||||
Cursor cursor = context.getContentResolver().query(photoUri,
|
||||
new String[] { MediaStore.Images.ImageColumns.ORIENTATION }, null, null, null);
|
||||
|
||||
if (cursor.getCount() != 1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
cursor.moveToFirst();
|
||||
return cursor.getInt(0);
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
# 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.
|
||||
|
||||
android.library=true
|
||||
# Project target.
|
||||
target=android-3
|
@ -0,0 +1,20 @@
|
||||
# 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 *;
|
||||
#}
|
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 3.7 KiB |
After Width: | Height: | Size: 5.4 KiB |
After Width: | Height: | Size: 4.2 KiB |