(context);
81 |
82 | FacebookEvents.addAuthListener(authListener);
83 | FacebookEvents.addPostListener(postListener);
84 | FacebookEvents.addLogoutListener(logoutListener);
85 | }
86 |
87 | /** Should be call at {@link Activity#onStop()} */
88 | public void unregisterListeners() {
89 | context.clear();
90 |
91 | FacebookEvents.removeAuthListener(authListener);
92 | FacebookEvents.removePostListener(postListener);
93 | FacebookEvents.removeLogoutListener(logoutListener);
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/Twitter_Geo.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Map;
6 |
7 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONArray;
8 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONException;
9 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONObject;
10 |
11 |
12 | /**
13 | * Twitter's geolocation support. Use {@link Twitter#geo()} to get one of these
14 | * objects.
15 | *
16 | * Conceptually, this is an extension of {@link Twitter}. The methods are here
17 | * because Twitter was getting crowded.
18 | *
19 | * @see Twitter#setMyLocation(double[])
20 | * @see Twitter#setSearchLocation(double, double, String)
21 | * @see Status#getLocation()
22 | *
23 | * @author Daniel Winterstein
24 | * @testedby {@link Twitter_GeoTest}
25 | */
26 | public class Twitter_Geo {
27 |
28 | private double accuracy;
29 |
30 | private final Twitter jtwit;
31 |
32 | /**
33 | * Use {@link Twitter#geo()} to get one.
34 | *
35 | * @param jtwit
36 | */
37 | Twitter_Geo(Twitter jtwit) {
38 | assert jtwit != null;
39 | assert jtwit.getHttpClient().canAuthenticate();
40 | this.jtwit = jtwit;
41 | }
42 |
43 | public List geoSearch(double latitude, double longitude) {
44 | throw new RuntimeException();
45 | }
46 |
47 | public List geoSearch(String query) {
48 | String url = jtwit.TWITTER_URL + "/geo/search.json";
49 | Map vars = InternalUtils.asMap("query", query);
50 | if (accuracy != 0) {
51 | vars.put("accuracy", String.valueOf(accuracy));
52 | }
53 | String json = jtwit.getHttpClient().getPage(url, vars,
54 | jtwit.getHttpClient().canAuthenticate());
55 | try {
56 | JSONObject jo = new JSONObject(json);
57 | JSONObject jo2 = jo.getJSONObject("result");
58 | JSONArray arr = jo2.getJSONArray("places");
59 | List places = new ArrayList(arr.length());
60 | for (int i = 0; i < arr.length(); i++) {
61 | JSONObject _place = arr.getJSONObject(i);
62 | // interpret it - maybe pinch code from jGeoPlanet?
63 | // https://dev.twitter.com/docs/api/1/get/geo/id/%3Aplace_id
64 | Place place = new Place(_place);
65 | places.add(place);
66 | }
67 | return places;
68 | } catch (JSONException e) {
69 | throw new TwitterException.Parsing(json, e);
70 | }
71 | }
72 |
73 | public List geoSearchByIP(String ipAddress) {
74 | throw new RuntimeException();
75 | }
76 |
77 | /**
78 | * @param woeid
79 | * @return regions from which you can get trending info
80 | * @see Twitter#getTrends(Number)
81 | */
82 | public List getTrendRegions() {
83 | String json = jtwit.getHttpClient().getPage(
84 | jtwit.TWITTER_URL + "/trends/available.json", null, false);
85 | try {
86 | JSONArray json2 = new JSONArray(json);
87 | List trends = new ArrayList();
88 | for (int i = 0; i < json2.length(); i++) {
89 | JSONObject ti = json2.getJSONObject(i);
90 | Place place = new Place(ti);
91 | trends.add(place);
92 | }
93 | return trends;
94 | } catch (JSONException e) {
95 | throw new TwitterException.Parsing(json, e);
96 | }
97 | }
98 |
99 | public void setAccuracy(double metres) {
100 | this.accuracy = metres;
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/json/JSONStringer.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.json;
2 |
3 | /*
4 | Copyright (c) 2006 JSON.org
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | The Software shall be used for Good, not Evil.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | SOFTWARE.
25 | */
26 |
27 | import java.io.StringWriter;
28 |
29 | /**
30 | * JSONStringer provides a quick and convenient way of producing JSON text.
31 | * The texts produced strictly conform to JSON syntax rules. No whitespace is
32 | * added, so the results are ready for transmission or storage. Each instance of
33 | * JSONStringer can produce one JSON text.
34 | *
35 | * A JSONStringer instance provides a value method for appending
36 | * values to the
37 | * text, and a key
38 | * method for adding keys before values in objects. There are array
39 | * and endArray methods that make and bound array values, and
40 | * object and endObject methods which make and bound
41 | * object values. All of these methods return the JSONWriter instance,
42 | * permitting cascade style. For example,
43 | * myString = new JSONStringer()
44 | * .object()
45 | * .key("JSON")
46 | * .value("Hello, World!")
47 | * .endObject()
48 | * .toString(); which produces the string
49 | * {"JSON":"Hello, World!"}
50 | *
51 | * The first method called must be array or object.
52 | * There are no methods for adding commas or colons. JSONStringer adds them for
53 | * you. Objects and arrays can be nested up to 20 levels deep.
54 | *
55 | * This can sometimes be easier than using a JSONObject to build a string.
56 | * @author JSON.org
57 | * @version 2
58 | */
59 | public class JSONStringer extends JSONWriter {
60 | /**
61 | * Make a fresh JSONStringer. It can be used to build one JSON text.
62 | */
63 | public JSONStringer() {
64 | super(new StringWriter());
65 | }
66 |
67 | /**
68 | * Return the JSON text. This method is used to obtain the product of the
69 | * JSONStringer instance. It will return null if there was a
70 | * problem in the construction of the JSON text (such as the calls to
71 | * array were not properly balanced with calls to
72 | * endArray).
73 | * @return The JSON text.
74 | */
75 | @Override
76 | public String toString() {
77 | return this.mode == 'd' ? this.writer.toString() : null;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/TwitterEvent.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
2 |
3 | import java.util.Date;
4 |
5 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONException;
6 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONObject;
7 |
8 |
9 | public class TwitterEvent {
10 |
11 | public static interface Type {
12 | public static final String ADDED_TO_LIST = "list_member_added";
13 | public static final String FAVORITE = "favorite";
14 | public static final String FOLLOW = "follow";
15 | public static final String LIST_CREATED = "list_created";
16 | public static final String REMOVED_FROM_LIST = "list_member_removed";
17 | public static final String UNFAVORITE = "unfavorite";
18 | /**
19 | * Indicates changes to the user's profile -- eg. their picture or
20 | * location.
21 | */
22 | public static final String USER_UPDATE = "user_update";
23 | }
24 |
25 | public final Date createdAt;
26 | /**
27 | * The user who initiated the event
28 | */
29 | public final User source;
30 | /**
31 | * The user who was affected, or who owns the affected object.
32 | */
33 | public final User target;
34 | private Object targetObject;
35 | /**
36 | * What type of event this is. Known values:
37 | *
38 | * - follow
39 | *
- favorite, unfavorite
40 | *
- user_update: Changes to the user's profile
41 | *
- list_created
42 | *
- list_member_added, list_member_removed
43 | *
44 | * See the {@link Type} constants for known definitions.
45 | */
46 | public final String type;
47 |
48 | TwitterEvent(Date createdAt, User source, String type, User target,
49 | Object targetObject) {
50 | this.createdAt = createdAt;
51 | this.source = source;
52 | this.type = type;
53 | this.target = target;
54 | this.targetObject = targetObject;
55 | }
56 |
57 | public TwitterEvent(JSONObject jo, Twitter jtwit) throws JSONException {
58 | type = jo.getString("event");
59 | target = new User(jo.getJSONObject("target"), null);
60 | source = new User(jo.getJSONObject("source"), null);
61 | createdAt = InternalUtils.parseDate(jo.getString("created_at"));
62 | // TODO how can we tell what this is??
63 | JSONObject to = jo.optJSONObject("target_object");
64 | if (to == null)
65 | return;
66 | if (to.has("member_count")) {
67 | targetObject = new TwitterList(to, jtwit);
68 | } else {
69 | targetObject = to;
70 | }
71 | }
72 |
73 | public Date getCreatedAt() {
74 | return createdAt;
75 | }
76 |
77 | /**
78 | * The user who initiated the event
79 | */
80 | public User getSource() {
81 | return source;
82 | }
83 |
84 | /**
85 | * The user who was affected, or who owns the affected object.
86 | */
87 | public User getTarget() {
88 | return target;
89 | }
90 |
91 | /**
92 | * The affected object, if not a user. E.g. For a favorite event, target=the
93 | * owner of the favorited tweet, target object=the actual favorited tweet.
94 | * Can be null.
95 | */
96 | public Object getTargetObject() {
97 | return targetObject;
98 | }
99 |
100 | public String getType() {
101 | return type;
102 | }
103 |
104 | /**
105 | * Convenience method for filtering events. E.g. given a
106 | * TwitterEvent event use
107 | * event.is(TwitterEvent.Type.FOLLOW) to pick out follow
108 | * events.
109 | *
110 | * @param type
111 | * @return true if this is an event of the given type.
112 | */
113 | public boolean is(String type) {
114 | return this.type.equals(type);
115 | }
116 |
117 | @Override
118 | public String toString() {
119 | return source + " " + type + " " + target + " " + getTargetObject();
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/oauth/signpost/commonshttp/CommonsHttpOAuthProvider.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2009 Matthias Kaeppler Licensed under the Apache License,
3 | * Version 2.0 (the "License"); you may not use this file except in compliance
4 | * with the License. You may obtain a copy of the License at
5 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 | * or agreed to in writing, software distributed under the License is
7 | * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 | * KIND, either express or implied. See the License for the specific language
9 | * governing permissions and limitations under the License.
10 | */
11 | package com.nostra13.socialsharing.twitter.extpack.oauth.signpost.commonshttp;
12 |
13 | import java.io.IOException;
14 |
15 |
16 | import org.apache.http.HttpEntity;
17 | import org.apache.http.HttpResponse;
18 | import org.apache.http.client.HttpClient;
19 | import org.apache.http.client.methods.HttpPost;
20 | import org.apache.http.client.methods.HttpUriRequest;
21 | import org.apache.http.impl.client.DefaultHttpClient;
22 |
23 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.AbstractOAuthProvider;
24 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpRequest;
25 |
26 | /**
27 | * This implementation uses the Apache Commons {@link HttpClient} 4.x HTTP
28 | * implementation to fetch OAuth tokens from a service provider. Android users
29 | * should use this provider implementation in favor of the default one, since
30 | * the latter is known to cause problems with Android's Apache Harmony
31 | * underpinnings.
32 | *
33 | * @author Matthias Kaeppler
34 | */
35 | public class CommonsHttpOAuthProvider extends AbstractOAuthProvider {
36 |
37 | private static final long serialVersionUID = 1L;
38 |
39 | private transient HttpClient httpClient;
40 |
41 | public CommonsHttpOAuthProvider(String requestTokenEndpointUrl, String accessTokenEndpointUrl,
42 | String authorizationWebsiteUrl) {
43 | super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl);
44 | this.httpClient = new DefaultHttpClient();
45 | }
46 |
47 | public CommonsHttpOAuthProvider(String requestTokenEndpointUrl, String accessTokenEndpointUrl,
48 | String authorizationWebsiteUrl, HttpClient httpClient) {
49 | super(requestTokenEndpointUrl, accessTokenEndpointUrl, authorizationWebsiteUrl);
50 | this.httpClient = httpClient;
51 | }
52 |
53 | public void setHttpClient(HttpClient httpClient) {
54 | this.httpClient = httpClient;
55 | }
56 |
57 | @Override
58 | protected HttpRequest createRequest(String endpointUrl) throws Exception {
59 | HttpPost request = new HttpPost(endpointUrl);
60 | return new HttpRequestAdapter(request);
61 | }
62 |
63 | @Override
64 | protected com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpResponse sendRequest(HttpRequest request) throws Exception {
65 | HttpResponse response = httpClient.execute((HttpUriRequest) request.unwrap());
66 | return new HttpResponseAdapter(response);
67 | }
68 |
69 | @Override
70 | protected void closeConnection(HttpRequest request, com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpResponse response)
71 | throws Exception {
72 | if (response != null) {
73 | HttpEntity entity = ((HttpResponse) response.unwrap()).getEntity();
74 | if (entity != null) {
75 | try {
76 | // free the connection
77 | entity.consumeContent();
78 | } catch (IOException e) {
79 | // this means HTTP keep-alive is not possible
80 | e.printStackTrace();
81 | }
82 | }
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/UserStream.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
5 |
6 | import java.io.IOException;
7 | import java.net.HttpURLConnection;
8 | import java.util.Collection;
9 | import java.util.List;
10 | import java.util.Map;
11 |
12 | /**
13 | * @deprecated There are bugs on Twitter's end -- the messages returned by this
14 | * stream may not include all the messages to a user. The results
15 | * vary from user to user!
16 | *
17 | * Connect to the streaming API.
18 | *
19 | * This class picks up the following tweets:
20 | *
21 | * - Tweets by you
22 | * - Tweets that mention you
23 | * - Tweets by people you follow IF
24 | * {@link #setWithFollowings(boolean)} is true.
25 | * - Retweets of your messages.
26 | * - Retweets made by you.
27 | *
28 | *
29 | * Duplicate messages may be delivered when reconnecting to the
30 | * Streaming API.
31 | *
32 | * TODO test out url-signing over header-signing -- c.f.
33 | * http://groups
34 | * .google.com/group/twitter-development-talk/browse_thread
35 | * /thread/420c4b555198aa6c/f85e2507b7f65e39?pli=1
36 | *
37 | * "figured it out on my own. must use HTTP GET with OAuth params
38 | * passed in URI string. Not mentioned in the documentation. Wasted
39 | * many hours figuring out this stuff would be clarified if someone
40 | * updated the docs and made some examples."
41 | *
42 | *
43 | * @author Daniel
44 | * @testedby {@link UserStreamTest}
45 | */
46 | @Deprecated
47 | public class UserStream extends AStream {
48 |
49 | boolean withFollowings;
50 |
51 | public UserStream(Twitter jtwit) {
52 | super(jtwit);
53 | }
54 |
55 | @Override
56 | HttpURLConnection connect2() throws IOException {
57 | String url = "https://userstream.twitter.com/2/user.json?delimited=length";
58 | Map vars = InternalUtils.asMap("with",
59 | (withFollowings ? "followings" : "user"));
60 | HttpURLConnection con = client.connect(url, vars, true);
61 | return con;
62 | }
63 |
64 | /**
65 | * Use the REST API to fill in: mentions of you. Missed you-follow-them
66 | * events are automatically generated on reconnect.
67 | */
68 | @Override
69 | void fillInOutages2(Twitter jtwit2, Outage outage)
70 | throws UnsupportedOperationException, TwitterException {
71 | // fetch
72 | if (withFollowings)
73 | // TODO pull in network activity
74 | throw new UnsupportedOperationException("TODO");
75 | // get mentions of you
76 | List mentions = jtwit2.getMentions();
77 | for (Status status : mentions) {
78 | if (tweets.contains(status)) {
79 | continue;
80 | }
81 | tweets.add(status);
82 | }
83 | // get your traffic
84 | List updates = jtwit2.getUserTimeline(jtwit2.getScreenName());
85 | for (Status status : updates) {
86 | if (tweets.contains(status)) {
87 | continue;
88 | }
89 | tweets.add(status);
90 | }
91 | // Missed follow events are sort of OK: the reconnect will update
92 | // friends
93 | }
94 |
95 | /**
96 | * @return people who the user follows -- at the point when the stream last
97 | * connected.
98 | */
99 | public Collection getFriends() {
100 | // TODO update the friends list from follow events??
101 | return friends;
102 | }
103 |
104 | /**
105 | * @param withFollowings
106 | * if true, pick up all tweets by the people the user follows.
107 | */
108 | public void setWithFollowings(boolean withFollowings) {
109 | assert !isConnected();
110 | this.withFollowings = withFollowings;
111 | }
112 |
113 | }
114 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/com/google/gdata/util/common/base/Escaper.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2008 Google Inc.
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 |
16 |
17 | package com.nostra13.socialsharing.twitter.extpack.com.google.gdata.util.common.base;
18 |
19 | /**
20 | * An object that converts literal text into a format safe for inclusion in a
21 | * particular context (such as an XML document). Typically (but not always), the
22 | * inverse process of "unescaping" the text is performed automatically by the
23 | * relevant parser.
24 | *
25 | * For example, an XML escaper would convert the literal string {@code
26 | * "Foo"} into {@code "Foo<Bar>"} to prevent {@code ""} from
27 | * being confused with an XML tag. When the resulting XML document is parsed,
28 | * the parser API will return this text as the original literal string {@code
29 | * "Foo"}.
30 | *
31 | * An {@code Escaper} instance is required to be stateless, and safe when
32 | * used concurrently by multiple threads.
33 | *
34 | *
Several popular escapers are defined as constants in the class {@link
35 | * CharEscapers}. To create your own escapers, use {@link
36 | * CharEscaperBuilder}, or extend {@link CharEscaper} or {@code UnicodeEscaper}.
37 | *
38 | *
39 | */
40 | public interface Escaper {
41 | /**
42 | * Returns the escaped form of a given literal string.
43 | *
44 | *
Note that this method may treat input characters differently depending on
45 | * the specific escaper implementation.
46 | *
47 | * - {@link UnicodeEscaper} handles
48 | * UTF-16 correctly,
49 | * including surrogate character pairs. If the input is badly formed the
50 | * escaper should throw {@link IllegalArgumentException}.
51 | *
- {@link CharEscaper} handles Java characters independently and does not
52 | * verify the input for well formed characters. A CharEscaper should not be
53 | * used in situations where input is not guaranteed to be restricted to the
54 | * Basic Multilingual Plane (BMP).
55 | *
56 | *
57 | * @param string the literal string to be escaped
58 | * @return the escaped form of {@code string}
59 | * @throws NullPointerException if {@code string} is null
60 | * @throws IllegalArgumentException if {@code string} contains badly formed
61 | * UTF-16 or cannot be escaped for any other reason
62 | */
63 | public String escape(String string);
64 |
65 | /**
66 | * Returns an {@code Appendable} instance which automatically escapes all
67 | * text appended to it before passing the resulting text to an underlying
68 | * {@code Appendable}.
69 | *
70 | * Note that this method may treat input characters differently depending on
71 | * the specific escaper implementation.
72 | *
73 | * - {@link UnicodeEscaper} handles
74 | * UTF-16 correctly,
75 | * including surrogate character pairs. If the input is badly formed the
76 | * escaper should throw {@link IllegalArgumentException}.
77 | *
- {@link CharEscaper} handles Java characters independently and does not
78 | * verify the input for well formed characters. A CharEscaper should not be
79 | * used in situations where input is not guaranteed to be restricted to the
80 | * Basic Multilingual Plane (BMP).
81 | *
82 | *
83 | * @param out the underlying {@code Appendable} to append escaped output to
84 | * @return an {@code Appendable} which passes text to {@code out} after
85 | * escaping it.
86 | */
87 | public Appendable escape(Appendable out);
88 | }
89 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/TwitterEvents.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter;
2 |
3 | import java.util.LinkedList;
4 |
5 | import com.nostra13.socialsharing.common.AuthListener;
6 | import com.nostra13.socialsharing.common.LogoutListener;
7 | import com.nostra13.socialsharing.common.PostListener;
8 |
9 | /**
10 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
11 | */
12 | public final class TwitterEvents {
13 |
14 | private TwitterEvents() {
15 | }
16 |
17 | private static LinkedList authListeners = new LinkedList();
18 | private static LinkedList logoutListeners = new LinkedList();
19 | private static LinkedList postListeners = new LinkedList();
20 |
21 | /**
22 | * Associate the given listener with this Twitter object. The listener's callback interface will be invoked when
23 | * authentication events occur.
24 | *
25 | * @param listener
26 | * The callback object for notifying the application when auth events happen.
27 | */
28 | public static void addAuthListener(AuthListener listener) {
29 | synchronized (authListeners) {
30 | authListeners.add(listener);
31 | }
32 | }
33 |
34 | /**
35 | * Remove the given listener from the list of those that will be notified when authentication events occur.
36 | *
37 | * @param listener
38 | * The callback object for notifying the application when auth events happen.
39 | */
40 | public static void removeAuthListener(AuthListener listener) {
41 | synchronized (authListeners) {
42 | authListeners.remove(listener);
43 | }
44 | }
45 |
46 | /**
47 | * Associate the given listener with this Twitter object. The listener's callback interface will be invoked when
48 | * logout occurs.
49 | *
50 | * @param listener
51 | * The callback object for notifying the application when log out starts and finishes.
52 | */
53 | public static void addLogoutListener(LogoutListener listener) {
54 | synchronized (logoutListeners) {
55 | logoutListeners.add(listener);
56 | }
57 | }
58 |
59 | /**
60 | * Remove the given listener from the list of those that will be notified when logout occurs.
61 | *
62 | * @param listener
63 | * The callback object for notifying the application when log out starts and finishes.
64 | */
65 | public static void removeLogoutListener(LogoutListener listener) {
66 | synchronized (logoutListeners) {
67 | logoutListeners.remove(listener);
68 | }
69 | }
70 |
71 | /**
72 | * Associate the given listener with this Twitter object. The listener's callback interface will be invoked when
73 | * post publishing occurs.
74 | *
75 | * @param listener
76 | * The callback object for notifying the application when post was published (or publishing was failed).
77 | */
78 | public static void addPostListener(PostListener listener) {
79 | synchronized (postListeners) {
80 | postListeners.add(listener);
81 | }
82 | }
83 |
84 | /**
85 | * Remove the given listener from the list of those that will be notified when post publishing occurs.
86 | *
87 | * @param listener
88 | * The callback object for notifying the application when post was published (or publishing was failed).
89 | */
90 | public static void removePostListener(PostListener listener) {
91 | synchronized (postListeners) {
92 | postListeners.remove(listener);
93 | }
94 | }
95 |
96 | static void onLoginSuccess() {
97 | synchronized (authListeners) {
98 | for (AuthListener listener : authListeners) {
99 | listener.onAuthSucceed();
100 | }
101 | }
102 | }
103 |
104 | static void onLoginError(String error) {
105 | synchronized (authListeners) {
106 | for (AuthListener listener : authListeners) {
107 | listener.onAuthFail(error);
108 | }
109 | }
110 | }
111 |
112 | static void onLogoutComplete() {
113 | synchronized (logoutListeners) {
114 | for (LogoutListener l : logoutListeners) {
115 | l.onLogoutComplete();
116 | }
117 | }
118 | }
119 |
120 | static void onPostPublished() {
121 | synchronized (postListeners) {
122 | for (PostListener l : postListeners) {
123 | l.onPostPublished();
124 | }
125 | }
126 | }
127 |
128 | static void onPostPublishingFailed() {
129 | synchronized (postListeners) {
130 | for (PostListener l : postListeners) {
131 | l.onPostPublishingFailed();
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/facebook/FacebookEvents.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.facebook;
2 |
3 | import java.util.LinkedList;
4 |
5 | import com.nostra13.socialsharing.common.AuthListener;
6 | import com.nostra13.socialsharing.common.LogoutListener;
7 | import com.nostra13.socialsharing.common.PostListener;
8 |
9 | /**
10 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
11 | */
12 | public final class FacebookEvents {
13 |
14 | private FacebookEvents() {
15 | }
16 |
17 | private static LinkedList authListeners = new LinkedList();
18 | private static LinkedList logoutListeners = new LinkedList();
19 | private static LinkedList postListeners = new LinkedList();
20 |
21 | /**
22 | * Associate the given listener with this Facebook object. The listener's callback interface will be invoked when
23 | * authentication events occur.
24 | *
25 | * @param listener
26 | * The callback object for notifying the application when auth events happen.
27 | */
28 | public static void addAuthListener(AuthListener listener) {
29 | synchronized (authListeners) {
30 | authListeners.add(listener);
31 | }
32 | }
33 |
34 | /**
35 | * Remove the given listener from the list of those that will be notified when authentication events occur.
36 | *
37 | * @param listener
38 | * The callback object for notifying the application when auth events happen.
39 | */
40 | public static void removeAuthListener(AuthListener listener) {
41 | synchronized (authListeners) {
42 | authListeners.remove(listener);
43 | }
44 | }
45 |
46 | /**
47 | * Associate the given listener with this Facebook object. The listener's callback interface will be invoked when
48 | * logout occurs.
49 | *
50 | * @param listener
51 | * The callback object for notifying the application when log out starts and finishes.
52 | */
53 | public static void addLogoutListener(LogoutListener listener) {
54 | synchronized (logoutListeners) {
55 | logoutListeners.add(listener);
56 | }
57 | }
58 |
59 | /**
60 | * Remove the given listener from the list of those that will be notified when logout occurs.
61 | *
62 | * @param listener
63 | * The callback object for notifying the application when log out starts and finishes.
64 | */
65 | public static void removeLogoutListener(LogoutListener listener) {
66 | synchronized (logoutListeners) {
67 | logoutListeners.remove(listener);
68 | }
69 | }
70 |
71 | /**
72 | * Associate the given listener with this Facebook object. The listener's callback interface will be invoked when
73 | * post publishing occurs.
74 | *
75 | * @param listener
76 | * The callback object for notifying the application when post was published (or publishing was failed).
77 | */
78 | public static void addPostListener(PostListener listener) {
79 | synchronized (postListeners) {
80 | postListeners.add(listener);
81 | }
82 | }
83 |
84 | /**
85 | * Remove the given listener from the list of those that will be notified when post publishing occurs.
86 | *
87 | * @param listener
88 | * The callback object for notifying the application when post was published (or publishing was failed).
89 | */
90 | public static void removePostListener(PostListener listener) {
91 | synchronized (postListeners) {
92 | postListeners.remove(listener);
93 | }
94 | }
95 |
96 | static void onLoginSuccess() {
97 | synchronized (authListeners) {
98 | for (AuthListener listener : authListeners) {
99 | listener.onAuthSucceed();
100 | }
101 | }
102 | }
103 |
104 | static void onLoginError(String error) {
105 | synchronized (authListeners) {
106 | for (AuthListener listener : authListeners) {
107 | listener.onAuthFail(error);
108 | }
109 | }
110 | }
111 |
112 | static void onLogoutComplete() {
113 | synchronized (logoutListeners) {
114 | for (LogoutListener l : logoutListeners) {
115 | l.onLogoutComplete();
116 | }
117 | }
118 | }
119 |
120 | static void onPostPublished() {
121 | synchronized (postListeners) {
122 | for (PostListener l : postListeners) {
123 | l.onPostPublished();
124 | }
125 | }
126 | }
127 |
128 | static void onPostPublishingFailed() {
129 | synchronized (postListeners) {
130 | for (PostListener l : postListeners) {
131 | l.onPostPublishingFailed();
132 | }
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## ! THIS PROJECT IS NO LONGER BEING MAINTAINED !
2 |
3 | # Simple Social Sharing for Android
4 |
5 | This project aims to provide a reusable instrument for simple sharing with popular social networks (Facebook, Twiiter).
6 | Project uses other open source projects' code (actual on 25.02.2012):
7 |
8 | * [Facebook SDK for Android](https://github.com/facebook/facebook-android-sdk)
9 | * [OAuth Signpost](https://github.com/kaeppler/signpost)
10 | * [JTwitter](https://github.com/winterstein/JTwitter)
11 |
12 |
13 | ## Features
14 | * Simple API for Facebook and Twitter sharing (fast indroduction)
15 | * Simple API for event listening (authentication, posting, logging out)
16 | * Support only simple sharing (post message or image to Facebook, post status to Twitter)
17 |
18 | **Important:** In your Twitter Developer Application Settings (https://dev.twitter.com/) you must fill "Callback URL" field with any URL (i.e. http://abc.de).
19 | It's behaviour by default.
20 |
21 | There are two classes in SSS:
22 |
23 | * TwitterDialog
24 | * CallbackTwitterDialog
25 |
26 | ```CallbackTwitterDialog``` is used by default and it works only when "Callback URL" is filled in your Twitter Application settings.
27 | You may not use callback URL. Then you should clear "Callback URL" field in app settings and replace all using ```CallbackTwitterDialog``` with ```TwitterDilaog``` (in ```TwitterFacade``` class).
28 |
29 | ## Usage
30 |
31 | ### Sharing API
32 |
33 | #### Facebook
34 |
35 | ``` java
36 | FacebookFacade facebook = new FacebookFacade(activity, FACEBOOK_APP_ID);
37 | if (!facebook.isAuthorized()) {
38 | facebook.authorize();
39 | }
40 | facebook.publishMessage("This is great App!");
41 | facebook.logout();
42 | ```
43 |
44 | **More powerful posting:**
45 |
46 | ``` java
47 | Map actions = new HashMap();
48 | actions.put("Android Simple Social Sharing", "https://github.com/nostra13");
49 | facebook.publishMessage("Look at this great App!",
50 | "Use Android Simple Social Sharing in your project!",
51 | "https://github.com/nostra13/Android-Simple-Social-Sharing",
52 | "Also see other projects of nostra13 on GitHub!",
53 | "http://.......facebook-android-logo-1.jpg",
54 | actions);
55 | ```
56 | 
57 |
58 | #### Twitter
59 |
60 | ``` java
61 | TwitterFacade twitter = new TwitterFacade(context, TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET);
62 | if (!twitter.isAuthorized()) {
63 | twitter.authorize();
64 | }
65 | twitter.publishMessage("This is great app!");
66 | twitter.logout();
67 | ```
68 |
69 | ### Event listening API
70 |
71 | #### Facebook
72 |
73 | ``` java
74 | ...
75 | @Override
76 | protected void onStart() {
77 | super.onStart();
78 | FacebookEvents.addAuthListener(authListener);
79 | FacebookEvents.addPostListener(postListener);
80 | FacebookEvents.addLogoutListener(logoutListener);
81 | }
82 |
83 | @Override
84 | protected void onStop() {
85 | super.onStop();
86 | FacebookEvents.removeAuthListener(authListener);
87 | FacebookEvents.removePostListener(postListener);
88 | FacebookEvents.removeLogoutListener(logoutListener);
89 | }
90 |
91 | private AuthListener authListener = new AuthListener() {
92 | @Override
93 | public void onAuthSucceed() {
94 | showToastOnUIThread("Facebook authentication is successful");
95 | }
96 |
97 | @Override
98 | public void onAuthFail(String error) {
99 | showToastOnUIThread("Error was occurred during Facebook authentication");
100 | }
101 | };
102 |
103 | private PostListener postListener = new PostListener() {
104 | @Override
105 | public void onPostPublishingFailed() {
106 | showToastOnUIThread("Post publishing was failed");
107 | }
108 |
109 | @Override
110 | public void onPostPublished() {
111 | showToastOnUIThread("Posted to Facebook successfully");
112 | }
113 | };
114 |
115 | private LogoutListener logoutListener = new LogoutListener() {
116 | @Override
117 | public void onLogoutComplete() {
118 | showToastOnUIThread("You are logged out");
119 | }
120 | };
121 |
122 | private void showToastOnUIThread(final String text) {
123 | runOnUiThread(new Runnable() {
124 | @Override
125 | public void run() {
126 | Toast.makeText(YourActivity.this, text, Toast.LENGTH_SHORT).show();
127 | }
128 | });
129 | }
130 | ...
131 | ```
132 |
133 | #### Twitter
134 |
135 | Like Facebook listening example but use TwitterEvents instead of FacebookEvents.
136 |
137 | ## License
138 |
139 | Licensed under the [BSD 3-clause](http://www.opensource.org/licenses/BSD-3-Clause)
140 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/oauth/signpost/signature/SignatureBaseString.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2009 Matthias Kaeppler Licensed under the Apache License,
3 | * Version 2.0 (the "License"); you may not use this file except in compliance
4 | * with the License. You may obtain a copy of the License at
5 | * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law
6 | * or agreed to in writing, software distributed under the License is
7 | * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
8 | * KIND, either express or implied. See the License for the specific language
9 | * governing permissions and limitations under the License.
10 | */
11 | package com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature;
12 |
13 | import java.io.IOException;
14 | import java.net.URI;
15 | import java.net.URISyntaxException;
16 | import java.util.Iterator;
17 |
18 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.OAuth;
19 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.exception.OAuthMessageSignerException;
20 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpParameters;
21 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpRequest;
22 |
23 |
24 | public class SignatureBaseString {
25 |
26 | private HttpRequest request;
27 |
28 | private HttpParameters requestParameters;
29 |
30 | /**
31 | * Constructs a new SBS instance that will operate on the given request
32 | * object and parameter set.
33 | *
34 | * @param request
35 | * the HTTP request
36 | * @param requestParameters
37 | * the set of request parameters from the Authorization header, query
38 | * string and form body
39 | */
40 | public SignatureBaseString(HttpRequest request, HttpParameters requestParameters) {
41 | this.request = request;
42 | this.requestParameters = requestParameters;
43 | }
44 |
45 | /**
46 | * Builds the signature base string from the data this instance was
47 | * configured with.
48 | *
49 | * @return the signature base string
50 | * @throws OAuthMessageSignerException
51 | */
52 | public String generate() throws OAuthMessageSignerException {
53 |
54 | try {
55 | String normalizedUrl = normalizeRequestUrl();
56 | String normalizedParams = normalizeRequestParameters();
57 |
58 | return request.getMethod() + '&' + OAuth.percentEncode(normalizedUrl) + '&'
59 | + OAuth.percentEncode(normalizedParams);
60 | } catch (Exception e) {
61 | throw new OAuthMessageSignerException(e);
62 | }
63 | }
64 |
65 | public String normalizeRequestUrl() throws URISyntaxException {
66 | URI uri = new URI(request.getRequestUrl());
67 | String scheme = uri.getScheme().toLowerCase();
68 | String authority = uri.getAuthority().toLowerCase();
69 | boolean dropPort = (scheme.equals("http") && uri.getPort() == 80)
70 | || (scheme.equals("https") && uri.getPort() == 443);
71 | if (dropPort) {
72 | // find the last : in the authority
73 | int index = authority.lastIndexOf(":");
74 | if (index >= 0) {
75 | authority = authority.substring(0, index);
76 | }
77 | }
78 | String path = uri.getRawPath();
79 | if (path == null || path.length() <= 0) {
80 | path = "/"; // conforms to RFC 2616 section 3.2.2
81 | }
82 | // we know that there is no query and no fragment here.
83 | return scheme + "://" + authority + path;
84 | }
85 |
86 | /**
87 | * Normalizes the set of request parameters this instance was configured
88 | * with, as per OAuth spec section 9.1.1.
89 | *
90 | * @param parameters
91 | * the set of request parameters
92 | * @return the normalized params string
93 | * @throws IOException
94 | */
95 | public String normalizeRequestParameters() throws IOException {
96 | if (requestParameters == null) {
97 | return "";
98 | }
99 |
100 | StringBuilder sb = new StringBuilder();
101 | Iterator iter = requestParameters.keySet().iterator();
102 |
103 | for (int i = 0; iter.hasNext(); i++) {
104 | String param = iter.next();
105 |
106 | if (OAuth.OAUTH_SIGNATURE.equals(param) || "realm".equals(param)) {
107 | continue;
108 | }
109 |
110 | if (i > 0) {
111 | sb.append("&");
112 | }
113 |
114 | sb.append(requestParameters.getAsQueryString(param));
115 | }
116 | return sb.toString();
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/Place.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
2 |
3 | import java.io.Serializable;
4 | import java.util.AbstractList;
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONArray;
9 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONException;
10 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONObject;
11 |
12 |
13 | /**
14 | * Support for Twitter's geo location features.
15 | *
16 | * Status: experimental & subject to change!
17 | *
18 | * @author Daniel Winterstein
19 | *
20 | */
21 | public class Place implements Serializable {
22 | /**
23 | * A latitude-longitude coordinate.
24 | */
25 | public static final class LatLong extends AbstractList {
26 |
27 | public final double latitude;
28 | public final double longitude;
29 |
30 | public LatLong(double latitude, double longitude) {
31 | this.latitude = latitude;
32 | this.longitude = longitude;
33 | }
34 |
35 | @Override
36 | public Double get(int index) {
37 | return index == 0 ? latitude : longitude;
38 | }
39 |
40 | @Override
41 | public int size() {
42 | return 2;
43 | }
44 | }
45 |
46 | private static final long serialVersionUID = 1L;
47 | private List boundingBox;
48 | private String country;
49 | private String countryCode;
50 | private List geometry;
51 | private String id;
52 | private String name;
53 |
54 | private String type;
55 |
56 | public Place(JSONObject _place) throws JSONException {
57 | // e.g. {"id":"0a3e119020705b64","place_type":"city",
58 | // "bounding_box":{"type":"Polygon",
59 | // "coordinates":[[[-95.519568,37.303542],[-95.227853,37.303542],[-95.227853,37.383978],[-95.519568,37.383978]]]},
60 | // "name":"Parsons","attributes":{},
61 | // "country_code":"US",
62 | // "url":"http://api.twitter.com/1/geo/id/0a3e119020705b64.json",
63 | // "full_name":"Parsons, KS","country":"United States"}
64 | id = InternalUtils.jsonGet("id", _place);
65 | if (id == null) { // a Yahoo ID?
66 | id = InternalUtils.jsonGet("woeid", _place);
67 | // TODO Test Me!
68 | // TODO should we have a separate id field for Yahoo?
69 | }
70 | type = InternalUtils.jsonGet("place_type", _place);
71 | // name and full_name seem to be much the same, e.g.
72 | // "City of Edinburgh"?
73 | name = InternalUtils.jsonGet("full_name", _place);
74 | if (name == null) {
75 | name = InternalUtils.jsonGet("name", _place);
76 | }
77 | countryCode = InternalUtils.jsonGet("country_code", _place);
78 | country = InternalUtils.jsonGet("country", _place);
79 | // bounding box
80 | Object bbox = _place.opt("bounding_box");
81 | if (bbox instanceof JSONObject) {
82 | this.boundingBox = parseCoords((JSONObject) bbox);
83 | }
84 | Object geo = _place.opt("geometry");
85 | if (geo instanceof JSONObject) {
86 | this.geometry = parseCoords((JSONObject) geo);
87 | }
88 | }
89 |
90 | /**
91 | * @return list of lat/long pairs. Can be null
92 | */
93 | public List getBoundingBox() {
94 | return boundingBox;
95 | }
96 |
97 | public String getCountryCode() {
98 | return countryCode;
99 | }
100 |
101 | public String getCountryName() {
102 | return country;
103 | }
104 |
105 | /**
106 | * @return list of lat/long pairs. Usually null
107 | */
108 | public List getGeometry() {
109 | return geometry;
110 | }
111 |
112 | /**
113 | * Note: this is not a number.
114 | */
115 | public String getId() {
116 | return id;
117 | }
118 |
119 | /**
120 | * Call this to get a JSON object with a lot of details.
121 | *
122 | * TODO wrap this in TwitterPlace
123 | */
124 | public String getInfoUrl() {
125 | return "http://api.twitter.com/1/geo/id/" + id + ".json";
126 | }
127 |
128 | public String getName() {
129 | return name;
130 | }
131 |
132 | /**
133 | * @return e.g. "city", "admin" Often "admin" (which covers anything), so
134 | * it's not clear how useful this is!
135 | */
136 | public String getType() {
137 | return type;
138 | }
139 |
140 | private List parseCoords(JSONObject bbox) throws JSONException {
141 | JSONArray coords = bbox.getJSONArray("coordinates");
142 | // pointless nesting?
143 | coords = coords.getJSONArray(0);
144 | List coordinates = new ArrayList();
145 | for (int i = 0, n = coords.length(); i < n; i++) {
146 | // these are longitude, latitude pairs
147 | JSONArray pt = coords.getJSONArray(i);
148 | LatLong x = new LatLong(pt.getDouble(1), pt.getDouble(0));
149 | coordinates.add(x);
150 | }
151 | return coordinates;
152 | }
153 |
154 | @Override
155 | public String toString() {
156 | return getName();
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/SimpleSocialSharingExample/src/com/nostra13/example/socialsharing/FacebookActivity.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.example.socialsharing;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | import android.app.Activity;
8 | import android.graphics.Bitmap;
9 | import android.graphics.drawable.BitmapDrawable;
10 | import android.os.Bundle;
11 | import android.view.Menu;
12 | import android.view.MenuInflater;
13 | import android.view.MenuItem;
14 | import android.view.View;
15 | import android.view.View.OnClickListener;
16 | import android.widget.Button;
17 | import android.widget.TextView;
18 |
19 | import com.nostra13.example.socialsharing.Constants.Extra;
20 | import com.nostra13.example.socialsharing.assist.FacebookEventObserver;
21 | import com.nostra13.socialsharing.common.AuthListener;
22 | import com.nostra13.socialsharing.facebook.FacebookFacade;
23 |
24 | /**
25 | * Activity for sharing information with Facebook
26 | *
27 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
28 | */
29 | public class FacebookActivity extends Activity {
30 |
31 | private FacebookFacade facebook;
32 | private FacebookEventObserver facebookEventObserver;
33 |
34 | private TextView messageView;
35 |
36 | private String link;
37 | private String linkName;
38 | private String linkDescription;
39 | private String picture;
40 | private Map actionsMap;
41 |
42 | @Override
43 | protected void onCreate(Bundle savedInstanceState) {
44 | super.onCreate(savedInstanceState);
45 |
46 | setContentView(R.layout.ac_facebook);
47 |
48 | facebook = new FacebookFacade(this, Constants.FACEBOOK_APP_ID);
49 | facebookEventObserver = FacebookEventObserver.newInstance();
50 |
51 | messageView = (TextView) findViewById(R.id.message);
52 | TextView linkNameView = (TextView) findViewById(R.id.link_name);
53 | TextView linkDescriptionView = (TextView) findViewById(R.id.link_description);
54 | Button postButton = (Button) findViewById(R.id.button_post);
55 | Button postImageButton = (Button) findViewById(R.id.button_post_image);
56 |
57 | Bundle bundle = getIntent().getExtras();
58 | if (bundle != null) {
59 | String message = bundle.getString(Extra.POST_MESSAGE);
60 | link = bundle.getString(Extra.POST_LINK);
61 | linkName = bundle.getString(Extra.POST_LINK_NAME);
62 | linkDescription = bundle.getString(Extra.POST_LINK_DESCRIPTION);
63 | picture = bundle.getString(Extra.POST_PICTURE);
64 | actionsMap = new HashMap();
65 | actionsMap.put(Constants.FACEBOOK_SHARE_ACTION_NAME, Constants.FACEBOOK_SHARE_ACTION_LINK);
66 |
67 | messageView.setText(message);
68 | linkNameView.setText(linkName);
69 | linkDescriptionView.setText(linkDescription);
70 | }
71 |
72 | postButton.setOnClickListener(new OnClickListener() {
73 | @Override
74 | public void onClick(View v) {
75 | if (facebook.isAuthorized()) {
76 | publishMessage();
77 | finish();
78 | } else {
79 | // Start authentication dialog and publish message after successful authentication
80 | facebook.authorize(new AuthListener() {
81 | @Override
82 | public void onAuthSucceed() {
83 | publishMessage();
84 | finish();
85 | }
86 |
87 | @Override
88 | public void onAuthFail(String error) { // Do noting
89 | }
90 | });
91 | }
92 | }
93 | });
94 | postImageButton.setOnClickListener(new OnClickListener() {
95 | @Override
96 | public void onClick(View v) {
97 | if (facebook.isAuthorized()) {
98 | publishImage();
99 | finish();
100 | } else {
101 | // Start authentication dialog and publish image after successful authentication
102 | facebook.authorize(new AuthListener() {
103 | @Override
104 | public void onAuthSucceed() {
105 | publishImage();
106 | finish();
107 | }
108 |
109 | @Override
110 | public void onAuthFail(String error) { // Do noting
111 | }
112 | });
113 | }
114 | }
115 | });
116 | }
117 |
118 | private void publishMessage() {
119 | facebook.publishMessage(messageView.getText().toString(), link, linkName, linkDescription, picture, actionsMap);
120 | }
121 |
122 | private void publishImage() {
123 | Bitmap bmp = ((BitmapDrawable) getResources().getDrawable(R.drawable.ic_app)).getBitmap();
124 | ByteArrayOutputStream stream = new ByteArrayOutputStream();
125 | bmp.compress(Bitmap.CompressFormat.JPEG, 100, stream);
126 | byte[] bitmapdata = stream.toByteArray();
127 | facebook.publishImage(bitmapdata, Constants.FACEBOOK_SHARE_IMAGE_CAPTION);
128 | }
129 |
130 | @Override
131 | public void onStart() {
132 | super.onStart();
133 | facebookEventObserver.registerListeners(this);
134 | if (!facebook.isAuthorized()) {
135 | facebook.authorize();
136 | }
137 | }
138 |
139 | @Override
140 | public void onStop() {
141 | facebookEventObserver.unregisterListeners();
142 | super.onStop();
143 | }
144 |
145 | @Override
146 | public boolean onCreateOptionsMenu(Menu menu) {
147 | MenuInflater inflater = getMenuInflater();
148 | inflater.inflate(R.menu.menu_facebook_twitter, menu);
149 | return true;
150 | }
151 |
152 | public boolean onOptionsItemSelected(MenuItem item) {
153 | switch (item.getItemId()) {
154 | case R.id.item_logout:
155 | facebook.logout();
156 | return true;
157 | default:
158 | return false;
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/lgpl/haustein/Base64Encoder.java:
--------------------------------------------------------------------------------
1 |
2 | package com.nostra13.socialsharing.twitter.extpack.lgpl.haustein;
3 |
4 | import java.io.ByteArrayOutputStream;
5 |
6 | /**
7 | * Routines to encode and decode using base 64 encoding.
8 | *
9 | //kObjects
10 | //
11 | // Copyright (C) 2001 Stefan Haustein, Oberhausen (Rhld.), Germany
12 | //
13 | // Contributors:
14 | //
15 | // License: LGPL
16 | //
17 | // This library is free software; you can redistribute it and/or
18 | // modify it under the terms of the GNU Lesser General Public License
19 | // as published by the Free Software Foundation; either version 2.1 of
20 | // the License, or (at your option) any later version.
21 | //
22 | // This library is distributed in the hope that it will be useful, but
23 | // WITHOUT ANY WARRANTY; without even the implied warranty of
24 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 | // Lesser General Public License for more details.
26 | //
27 | // You should have received a copy of the GNU Lesser General Public
28 | // License along with this library; if not, write to the Free Software
29 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30 | // USA
31 |
32 | * You can now use also javax.mail.internet.MimeUtility
33 | * and sun.misc.BASE64Encoder.encode.
34 | * There is a non-public class in Java 1.4+ called java.util.prefs.Base64
35 | */
36 | public final class Base64Encoder {
37 |
38 | static final char[] charTab =
39 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".toCharArray ();
40 |
41 | /**
42 | * @param string
43 | * @return the input string encoded using Base 64 encoding.
44 | */
45 | public static String encode (String string) {
46 | return encode(string.getBytes()).toString ();
47 | }
48 |
49 | public static String encode (byte [] data) {
50 | return encode (data, 0, data.length, null).toString ();
51 | }
52 |
53 |
54 | /** Encodes the part of the given byte array denoted by start and
55 | len to the Base64 format. The encoded data is appended to the
56 | given StringBuffer. If no StringBuffer is given, a new one is
57 | created automatically. The StringBuffer is the return value of
58 | this method. */
59 |
60 |
61 | public static StringBuffer encode (byte [] data, int start, int len, StringBuffer buf) {
62 |
63 | if (buf == null)
64 | buf = new StringBuffer (data.length * 3 / 2);
65 |
66 | int end = len - 3;
67 | int i = start;
68 | int n = 0;
69 |
70 | while (i <= end) {
71 | int d = (((data [i]) & 0x0ff) << 16)
72 | | (((data [i+1]) & 0x0ff) << 8)
73 | | ((data [i+2]) & 0x0ff);
74 |
75 | buf.append (charTab [(d >> 18) & 63]);
76 | buf.append (charTab [(d >> 12) & 63]);
77 | buf.append (charTab [(d >> 6) & 63]);
78 | buf.append (charTab [d & 63]);
79 |
80 | i += 3;
81 |
82 | if (n++ >= 14) {
83 | n = 0;
84 | buf.append ("\r\n");
85 | }
86 | }
87 |
88 |
89 | if (i == start + len - 2) {
90 | int d = (((data [i]) & 0x0ff) << 16)
91 | | (((data [i+1]) & 255) << 8);
92 |
93 | buf.append (charTab [(d >> 18) & 63]);
94 | buf.append (charTab [(d >> 12) & 63]);
95 | buf.append (charTab [(d >> 6) & 63]);
96 | buf.append ("=");
97 | }
98 | else if (i == start + len - 1) {
99 | int d = ((data [i]) & 0x0ff) << 16;
100 |
101 | buf.append (charTab [(d >> 18) & 63]);
102 | buf.append (charTab [(d >> 12) & 63]);
103 | buf.append ("==");
104 | }
105 |
106 | return buf;
107 | }
108 |
109 |
110 | static int decode (char c) {
111 | if (c >= 'A' && c <= 'Z')
112 | return c - 65;
113 | else if (c >= 'a' && c <= 'z')
114 | return c - 97 + 26;
115 | else if (c >= '0' && c <= '9')
116 | return c - 48 + 26 + 26;
117 | else switch (c) {
118 | case '+': return 62;
119 | case '/': return 63;
120 | case '=': return 0;
121 | default:
122 | throw new RuntimeException (new StringBuffer("unexpected code: ").append(c).toString());
123 | }
124 | }
125 |
126 |
127 | /** Decodes the given Base64 encoded String to a new byte array.
128 | The byte array holding the decoded data is returned. */
129 |
130 |
131 | public static byte [] decode (String s) {
132 | int i = 0;
133 | ByteArrayOutputStream bos = new ByteArrayOutputStream ();
134 | int len = s.length ();
135 |
136 | while (true) {
137 | while (i < len && s.charAt (i) <= ' ') i++;
138 |
139 | if (i == len) break;
140 |
141 | int tri = (decode (s.charAt (i)) << 18)
142 | + (decode (s.charAt (i+1)) << 12)
143 | + (decode (s.charAt (i+2)) << 6)
144 | + (decode (s.charAt (i+3)));
145 |
146 | bos.write ((tri >> 16) & 255);
147 | if (s.charAt (i+2) == '=') break;
148 | bos.write ((tri >> 8) & 255);
149 | if (s.charAt (i+3) == '=') break;
150 | bos.write (tri & 255);
151 |
152 | i += 4;
153 | }
154 | return bos.toByteArray ();
155 | }
156 |
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/facebook/FacebookFacade.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.facebook;
2 |
3 | import java.util.Map;
4 | import java.util.Map.Entry;
5 | import java.util.Set;
6 |
7 | import org.json.JSONException;
8 | import org.json.JSONObject;
9 |
10 | import android.app.Activity;
11 | import android.os.Bundle;
12 | import android.util.Log;
13 |
14 | import com.nostra13.socialsharing.Constants;
15 | import com.nostra13.socialsharing.common.AuthListener;
16 | import com.nostra13.socialsharing.facebook.extpack.com.facebook.android.AsyncFacebookRunner;
17 | import com.nostra13.socialsharing.facebook.extpack.com.facebook.android.DialogError;
18 | import com.nostra13.socialsharing.facebook.extpack.com.facebook.android.Facebook;
19 | import com.nostra13.socialsharing.facebook.extpack.com.facebook.android.FacebookError;
20 |
21 | /**
22 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
23 | */
24 | public class FacebookFacade {
25 |
26 | private static final String TAG = FacebookFacade.class.getSimpleName();
27 |
28 | private Activity context;
29 | private Facebook facebook;
30 | private AsyncFacebookRunner asyncFacebook;
31 |
32 | public FacebookFacade(Activity context, String facebookAppId) {
33 | this.context = context;
34 | facebook = new Facebook(facebookAppId);
35 | FacebookSessionStore.restore(facebook, context);
36 | asyncFacebook = new AsyncFacebookRunner(facebook);
37 | }
38 |
39 | public boolean isAuthorized() {
40 | return facebook.isSessionValid();
41 | }
42 |
43 | public void authorize() {
44 | authorize(null);
45 | }
46 |
47 | public void authorize(final AuthListener authListener) {
48 | facebook.authorize(context, Constants.FACEBOOK_PERMISSIONS, Facebook.FORCE_DIALOG_AUTH, new FacebookAuthListener() {
49 | @Override
50 | public void onFacebookError(FacebookError e) {
51 | if (authListener != null) authListener.onAuthFail(e.getMessage());
52 | super.onFacebookError(e);
53 | }
54 |
55 | @Override
56 | public void onError(DialogError e) {
57 | if (authListener != null) authListener.onAuthFail(e.getMessage());
58 | super.onError(e);
59 | }
60 |
61 | @Override
62 | public void onComplete(Bundle values) {
63 | FacebookSessionStore.save(facebook, context);
64 | if (authListener != null) authListener.onAuthSucceed();
65 | super.onComplete(values);
66 | }
67 | });
68 | }
69 |
70 | public void logout() {
71 | asyncFacebook.logout(context, new FacebookLogoutListener() {
72 | @Override
73 | public void onComplete(final String response, final Object state) {
74 | super.onComplete(response, state);
75 | FacebookSessionStore.clear(context);
76 | }
77 | });
78 | }
79 |
80 | public void publishMessage(String message) {
81 | publishMessage(message, null, null, null);
82 | }
83 |
84 | public void publishMessage(String message, String link, String linkName, String linkDescription) {
85 | publishMessage(message, link, linkName, linkDescription, null);
86 | }
87 |
88 | public void publishMessage(String message, String link, String linkName, String linkDescription, String pictureUrl) {
89 | publishMessage(message, link, linkName, linkDescription, pictureUrl, null);
90 | }
91 |
92 | public void publishMessage(String message, String link, String linkName, String linkDescription, String pictureUrl, Map actions) {
93 | Bundle params = new Bundle();
94 | params.putString(RequestParameter.MESSAGE, message);
95 | if (link != null) {
96 | params.putString(RequestParameter.LINK, link);
97 | }
98 | if (linkName != null) {
99 | params.putString(RequestParameter.NAME, linkName);
100 | }
101 | if (linkDescription != null) {
102 | params.putString(RequestParameter.DESCRIPTION, linkDescription);
103 | }
104 | if (pictureUrl != null) {
105 | params.putString(RequestParameter.PICTURE, pictureUrl);
106 | }
107 | if (actions != null) {
108 | params.putString(RequestParameter.ACTIONS, buildActionsString(actions));
109 | }
110 |
111 | asyncFacebook.request("me/feed", params, "POST", new FacebookPostListener(), null);
112 | }
113 |
114 | private String buildActionsString(Map actionsMap) {
115 | JSONObject actionsObject = new JSONObject();
116 | Set> actionEntries = actionsMap.entrySet();
117 | for (Entry actionEntry : actionEntries) {
118 | try {
119 | actionsObject.put(RequestParameter.NAME, actionEntry.getKey());
120 | actionsObject.put(RequestParameter.LINK, actionEntry.getValue());
121 | } catch (JSONException e) {
122 | Log.e(TAG, e.getMessage(), e);
123 | }
124 | }
125 | return actionsObject.toString();
126 | }
127 |
128 | public void publishImage(byte[] imageData, String caption) {
129 | Bundle params = new Bundle();
130 | params.putString("method", "photos.upload");
131 | params.putString(RequestParameter.CAPTION, caption);
132 | params.putByteArray(RequestParameter.PICTURE, imageData);
133 | asyncFacebook.request(null, params, "POST", new FacebookPostListener(), null);
134 | }
135 |
136 | protected static class RequestParameter {
137 | public static final String MESSAGE = "message";
138 | public static final String PICTURE = "picture";
139 | public static final String CAPTION = "caption";
140 | public static final String LINK = "link";
141 | public static final String NAME = "name";
142 | public static final String DESCRIPTION = "description";
143 | public static final String ACTIONS = "actions";
144 | }
145 | }
146 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/facebook/extpack/com/facebook/android/FbDialog.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2010 Facebook, Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package com.nostra13.socialsharing.facebook.extpack.com.facebook.android;
18 |
19 | import android.annotation.SuppressLint;
20 | import android.app.Dialog;
21 | import android.app.ProgressDialog;
22 | import android.content.Context;
23 | import android.content.Intent;
24 | import android.graphics.Bitmap;
25 | import android.graphics.Color;
26 | import android.net.Uri;
27 | import android.os.Bundle;
28 | import android.util.Log;
29 | import android.view.View;
30 | import android.view.ViewGroup;
31 | import android.view.ViewGroup.LayoutParams;
32 | import android.view.Window;
33 | import android.webkit.WebView;
34 | import android.webkit.WebViewClient;
35 | import android.widget.FrameLayout;
36 | import android.widget.LinearLayout;
37 |
38 | import com.nostra13.socialsharing.facebook.extpack.com.facebook.android.Facebook.DialogListener;
39 |
40 | public class FbDialog extends Dialog {
41 |
42 | static final int FB_BLUE = 0xFF6D84B4;
43 | static final float[] DIMENSIONS_DIFF_LANDSCAPE = {20, 60};
44 | static final float[] DIMENSIONS_DIFF_PORTRAIT = {40, 60};
45 | static final FrameLayout.LayoutParams FILL = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
46 | static final int MARGIN = 4;
47 | static final int PADDING = 2;
48 | static final String DISPLAY_STRING = "touch";
49 | static final String FB_ICON = "icon.png";
50 |
51 | private String mUrl;
52 | private DialogListener mListener;
53 | private ProgressDialog mSpinner;
54 | private WebView mWebView;
55 | private FrameLayout mContent;
56 |
57 | public FbDialog(Context context, String url, DialogListener listener) {
58 | super(context, android.R.style.Theme_Translucent_NoTitleBar);
59 | mUrl = url;
60 | mListener = listener;
61 | }
62 |
63 | @Override
64 | protected void onCreate(Bundle savedInstanceState) {
65 | super.onCreate(savedInstanceState);
66 | mSpinner = new ProgressDialog(getContext());
67 | mSpinner.requestWindowFeature(Window.FEATURE_NO_TITLE);
68 | mSpinner.setMessage("Loading...");
69 | mSpinner.setCancelable(false);
70 |
71 | requestWindowFeature(Window.FEATURE_NO_TITLE);
72 | mContent = new FrameLayout(getContext());
73 |
74 | setUpWebView(10);
75 |
76 | /* Finally add the 'x' image to the mContent layout and
77 | * add mContent to the Dialog view
78 | */
79 | addContentView(mContent, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
80 | }
81 |
82 | @SuppressLint("SetJavaScriptEnabled")
83 | private void setUpWebView(int margin) {
84 | LinearLayout webViewContainer = new LinearLayout(getContext());
85 | mWebView = new WebView(getContext());
86 | mWebView.setVerticalScrollBarEnabled(false);
87 | mWebView.setHorizontalScrollBarEnabled(false);
88 | mWebView.setWebViewClient(new FbDialog.FbWebViewClient());
89 | mWebView.getSettings().setJavaScriptEnabled(true);
90 | mWebView.loadUrl(mUrl);
91 | mWebView.setLayoutParams(FILL);
92 | mWebView.setVisibility(View.INVISIBLE);
93 |
94 | webViewContainer.setPadding(margin, margin, margin, margin);
95 | webViewContainer.addView(mWebView);
96 | mContent.addView(webViewContainer);
97 | }
98 |
99 | private class FbWebViewClient extends WebViewClient {
100 |
101 | @Override
102 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
103 | Log.d("Facebook-WebView", "Redirect URL: " + url);
104 | if (url.startsWith(Facebook.REDIRECT_URI)) {
105 | Bundle values = Util.parseUrl(url);
106 |
107 | String error = values.getString("error");
108 | if (error == null) {
109 | error = values.getString("error_type");
110 | }
111 |
112 | if (error == null) {
113 | mListener.onComplete(values);
114 | } else if (error.equals("access_denied") || error.equals("OAuthAccessDeniedException")) {
115 | mListener.onCancel();
116 | } else {
117 | mListener.onFacebookError(new FacebookError(error));
118 | }
119 |
120 | FbDialog.this.dismiss();
121 | return true;
122 | } else if (url.startsWith(Facebook.CANCEL_URI)) {
123 | mListener.onCancel();
124 | FbDialog.this.dismiss();
125 | return true;
126 | } else if (url.contains(DISPLAY_STRING)) {
127 | return false;
128 | }
129 | // launch non-dialog URLs in a full browser
130 | getContext().startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
131 | return true;
132 | }
133 |
134 | @Override
135 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
136 | super.onReceivedError(view, errorCode, description, failingUrl);
137 | mListener.onError(new DialogError(description, errorCode, failingUrl));
138 | FbDialog.this.dismiss();
139 | }
140 |
141 | @Override
142 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
143 | Log.d("Facebook-WebView", "Webview loading URL: " + url);
144 | super.onPageStarted(view, url, favicon);
145 | mSpinner.show();
146 | }
147 |
148 | @Override
149 | public void onPageFinished(WebView view, String url) {
150 | super.onPageFinished(view, url);
151 | mSpinner.dismiss();
152 | /*
153 | * Once webview is fully loaded, set the mContent background to be transparent
154 | * and make visible the 'x' image.
155 | */
156 | mContent.setBackgroundColor(Color.TRANSPARENT);
157 | mWebView.setVisibility(View.VISIBLE);
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/Message.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.Date;
6 | import java.util.EnumMap;
7 | import java.util.List;
8 |
9 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONArray;
10 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONException;
11 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONObject;
12 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.Twitter.ITweet;
13 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.Twitter.KEntityType;
14 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.Twitter.TweetEntity;
15 |
16 |
17 |
18 | /**
19 | * A Twitter direct message. Fields are null if unset.
20 | *
21 | * TODO are there more fields now? check the raw json
22 | */
23 | public final class Message implements ITweet {
24 |
25 | private static final long serialVersionUID = 1L;
26 |
27 |
28 | @Override
29 | public String getDisplayText() {
30 | return Status.getDisplayText2(this);
31 | }
32 |
33 | /**
34 | *
35 | * @param json
36 | * @return
37 | * @throws TwitterException
38 | */
39 | static List getMessages(String json) throws TwitterException {
40 | if (json.trim().equals(""))
41 | return Collections.emptyList();
42 | try {
43 | List msgs = new ArrayList();
44 | JSONArray arr = new JSONArray(json);
45 | for (int i = 0; i < arr.length(); i++) {
46 | JSONObject obj = arr.getJSONObject(i);
47 | Message u = new Message(obj);
48 | msgs.add(u);
49 | }
50 | return msgs;
51 | } catch (JSONException e) {
52 | throw new TwitterException.Parsing(json, e);
53 | }
54 | }
55 |
56 | private final Date createdAt;
57 | private EnumMap> entities;
58 |
59 | final Long id;
60 |
61 | /**
62 | * Equivalent to {@link Status#inReplyToStatusId} *but null by default*. If
63 | * you want to use this, you must set it yourself. The field is just a
64 | * convenient storage place. Strangely Twitter don't report the previous ID
65 | * for messages.
66 | */
67 | public Number inReplyToMessageId;
68 |
69 | private String location;
70 |
71 | private Place place;
72 | private final User recipient;
73 | private final User sender;
74 | public final String text;
75 |
76 | /**
77 | * @param obj
78 | * @throws JSONException
79 | * @throws TwitterException
80 | */
81 | Message(JSONObject obj) throws JSONException, TwitterException {
82 | // No need for BigInteger - yet
83 | // String _id = obj.getString("id_str");
84 | // id = new BigInteger(_id==null? ""+obj.get("id") : _id);
85 | id = obj.getLong("id");
86 | String _text = obj.getString("text");
87 | text = InternalUtils.unencode(_text);
88 | String c = InternalUtils.jsonGet("created_at", obj);
89 | createdAt = InternalUtils.parseDate(c);
90 | sender = new User(obj.getJSONObject("sender"), null);
91 | // recipient - for messages you sent
92 | Object recip = obj.opt("recipient");
93 | if (recip instanceof JSONObject) { // Note JSONObject.has is dangerously
94 | // misleading
95 | recipient = new User((JSONObject) recip, null);
96 | } else {
97 | recipient = null;
98 | }
99 | JSONObject jsonEntities = obj.optJSONObject("entities");
100 | if (jsonEntities != null) {
101 | // Note: Twitter filters out dud @names
102 | entities = new EnumMap>(
103 | KEntityType.class);
104 | for (KEntityType type : KEntityType.values()) {
105 | List es = TweetEntity.parse(this, _text, type,
106 | jsonEntities);
107 | entities.put(type, es);
108 | }
109 | }
110 | // geo-location?
111 | Object _locn = Status.jsonGetLocn(obj);
112 | location = _locn == null ? null : _locn.toString();
113 | if (_locn instanceof Place) {
114 | place = (Place) _locn;
115 | }
116 | }
117 |
118 | /**
119 | * Tests by class=Message and tweet id number
120 | */
121 | @Override
122 | public boolean equals(Object obj) {
123 | if (this == obj)
124 | return true;
125 | if (obj == null)
126 | return false;
127 | if (getClass() != obj.getClass())
128 | return false;
129 | Message other = (Message) obj;
130 | return id.equals(other.id);
131 | }
132 |
133 | @Override
134 | public Date getCreatedAt() {
135 | return createdAt;
136 | }
137 |
138 | /**
139 | * @return The Twitter id for this post. This is used by some API methods.
140 | *
141 | * Note: this may switch to BigInteger in the future, if Twitter
142 | * change their id numbering scheme. Use Number (which is a
143 | * super-class for both Long and BigInteger) if you wish to
144 | * future-proof your code.
145 | */
146 | @Override
147 | public Long getId() {
148 | return id;
149 | }
150 |
151 | @Override
152 | public String getLocation() {
153 | return location;
154 | }
155 |
156 | @Override
157 | public List getMentions() {
158 | return Collections.singletonList(recipient.screenName);
159 | }
160 |
161 | @Override
162 | public Place getPlace() {
163 | return place;
164 | }
165 |
166 | /**
167 | * @return the recipient (for messages sent by the authenticating user)
168 | */
169 | public User getRecipient() {
170 | return recipient;
171 | }
172 |
173 | public User getSender() {
174 | return sender;
175 | }
176 |
177 | @Override
178 | public String getText() {
179 | return text;
180 | }
181 |
182 | @Override
183 | public List getTweetEntities(KEntityType type) {
184 | return entities == null ? null : entities.get(type);
185 | }
186 |
187 | /**
188 | * This is equivalent to {@link #getSender()}
189 | */
190 | @Override
191 | public User getUser() {
192 | return getSender();
193 | }
194 |
195 | @Override
196 | public int hashCode() {
197 | return id.hashCode();
198 | }
199 |
200 | @Override
201 | public String toString() {
202 | return text;
203 | }
204 |
205 | }
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/TwitterDialog.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter;
2 |
3 | import java.util.regex.Matcher;
4 | import java.util.regex.Pattern;
5 |
6 | import android.annotation.SuppressLint;
7 | import android.app.Dialog;
8 | import android.app.ProgressDialog;
9 | import android.content.Context;
10 | import android.graphics.Bitmap;
11 | import android.graphics.Color;
12 | import android.os.Bundle;
13 | import android.util.Log;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.view.ViewGroup.LayoutParams;
17 | import android.view.Window;
18 | import android.webkit.JavascriptInterface;
19 | import android.webkit.WebView;
20 | import android.webkit.WebViewClient;
21 | import android.widget.FrameLayout;
22 | import android.widget.LinearLayout;
23 |
24 | import com.nostra13.socialsharing.common.AuthListener;
25 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.TwitterException;
26 |
27 | /**
28 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
29 | */
30 | class TwitterDialog extends Dialog {
31 |
32 | public static final String TAG = "twitter";
33 |
34 | static final FrameLayout.LayoutParams FILL = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
35 |
36 | static final String JS_HTML_EXTRACTOR = "javascript:window.HTMLOUT.processHTML(''+document.getElementsByTagName('html')[0].innerHTML+'');";
37 | static final String OAUTH_PIN_BLOCK_REGEXP = "id=\\\"oauth_pin((.|\\n)*)(\\d{7})";
38 | static final String OAUTH_PIN_REGEXP = "\\d{7}";
39 |
40 | private ProgressDialog spinner;
41 | private WebView browser;
42 | private FrameLayout content;
43 |
44 | private AsyncTwitter twitter;
45 | private String requestUrl;
46 |
47 | private AuthListener authListener;
48 |
49 | public TwitterDialog(Context context, AsyncTwitter twitter) {
50 | super(context, android.R.style.Theme_Translucent_NoTitleBar);
51 | this.twitter = twitter;
52 | }
53 |
54 | @Override
55 | protected void onCreate(Bundle savedInstanceState) {
56 | super.onCreate(savedInstanceState);
57 | spinner = new ProgressDialog(getContext());
58 | spinner.requestWindowFeature(Window.FEATURE_NO_TITLE);
59 | spinner.setMessage("Loading...");
60 |
61 | requestWindowFeature(Window.FEATURE_NO_TITLE);
62 | content = new FrameLayout(getContext());
63 | setUpWebView(10);
64 | addContentView(content, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
65 | }
66 |
67 | @Override
68 | public void show() {
69 | super.show();
70 | browser.setVisibility(View.INVISIBLE);
71 | spinner.show();
72 | if (requestUrl == null) {
73 | retrieveRequestToken();
74 | } else {
75 | browser.loadUrl(requestUrl);
76 | }
77 | }
78 |
79 | private void retrieveRequestToken() {
80 | twitter.getOAuthRequestToken(new AuthRequestListener() {
81 | @Override
82 | public void onAuthRequestFailed(Exception e) {
83 | Log.e(TAG, e.getMessage(), e);
84 | String errorMessage = e.getMessage();
85 | if (errorMessage == null) {
86 | errorMessage = e.getMessage();
87 | }
88 | TwitterEvents.onLoginError(errorMessage);
89 | spinner.dismiss();
90 | dismiss();
91 | }
92 |
93 | @Override
94 | public void onAuthRequestComplete(String requestUrl) {
95 | TwitterDialog.this.requestUrl = requestUrl;
96 | browser.loadUrl(requestUrl);
97 | }
98 | });
99 | }
100 |
101 | @SuppressLint("SetJavaScriptEnabled")
102 | private void setUpWebView(int margin) {
103 | LinearLayout webViewContainer = new LinearLayout(getContext());
104 | browser = new WebView(getContext());
105 | browser.setVerticalScrollBarEnabled(false);
106 | browser.setHorizontalScrollBarEnabled(false);
107 | browser.setWebViewClient(new TwitterDialog.TwWebViewClient());
108 | browser.getSettings().setJavaScriptEnabled(true);
109 | browser.addJavascriptInterface(new MyJavaScriptInterface(), "HTMLOUT");
110 | browser.setLayoutParams(FILL);
111 |
112 | webViewContainer.setPadding(margin, margin, margin, margin);
113 | webViewContainer.addView(browser);
114 | content.addView(webViewContainer);
115 | }
116 |
117 | public void setAuthListener(AuthListener authListener) {
118 | this.authListener = authListener;
119 | }
120 |
121 | private class TwWebViewClient extends WebViewClient {
122 |
123 | @Override
124 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
125 | view.loadUrl(url);
126 | return true;
127 | }
128 |
129 | @Override
130 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
131 | super.onReceivedError(view, errorCode, description, failingUrl);
132 | if (authListener != null) authListener.onAuthFail(description);
133 | TwitterEvents.onLoginError(description);
134 | TwitterDialog.this.dismiss();
135 | }
136 |
137 | @Override
138 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
139 | Log.d(TAG, "WebView loading URL: " + url);
140 | super.onPageStarted(view, url, favicon);
141 | spinner.show();
142 | }
143 |
144 | @Override
145 | public void onPageFinished(WebView view, String url) {
146 | super.onPageFinished(view, url);
147 | browser.loadUrl(JS_HTML_EXTRACTOR);
148 |
149 | content.setBackgroundColor(Color.TRANSPARENT);
150 | browser.setVisibility(View.VISIBLE);
151 | }
152 | }
153 |
154 | class MyJavaScriptInterface {
155 | @JavascriptInterface
156 | public void processHTML(String html) {
157 | String blockWithPin = findExpression(html, OAUTH_PIN_BLOCK_REGEXP);
158 | if (blockWithPin != null) {
159 | String pin = findExpression(blockWithPin, OAUTH_PIN_REGEXP);
160 | if (pin != null) {
161 | autorizeApp(pin);
162 | spinner.dismiss();
163 | dismiss();
164 | }
165 | }
166 | spinner.dismiss();
167 | }
168 |
169 | private String findExpression(String text, String regExp) {
170 | Pattern p = Pattern.compile(regExp);
171 | Matcher m = p.matcher(text);
172 | if (m.find()) {
173 | return m.group(0);
174 | } else {
175 | return null;
176 | }
177 | }
178 |
179 | private void autorizeApp(String pin) {
180 | try {
181 | AccessToken accessToken = twitter.getOAuthAccessToken(pin);
182 | TwitterSessionStore.save(accessToken, getContext());
183 | if (authListener != null) authListener.onAuthSucceed();
184 | TwitterEvents.onLoginSuccess();
185 | } catch (TwitterException e) {
186 | Log.e(TAG, e.getMessage(), e);
187 | if (authListener != null) authListener.onAuthFail(e.getMessage());
188 | TwitterEvents.onLoginError(e.getMessage());
189 | }
190 | }
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/CallbackTwitterDialog.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.app.Dialog;
5 | import android.app.ProgressDialog;
6 | import android.content.Context;
7 | import android.graphics.Bitmap;
8 | import android.graphics.Color;
9 | import android.os.AsyncTask;
10 | import android.os.Bundle;
11 | import android.os.Handler;
12 | import android.util.Log;
13 | import android.view.View;
14 | import android.view.ViewGroup;
15 | import android.view.ViewGroup.LayoutParams;
16 | import android.view.Window;
17 | import android.webkit.WebView;
18 | import android.webkit.WebViewClient;
19 | import android.widget.FrameLayout;
20 | import android.widget.LinearLayout;
21 |
22 | import com.nostra13.socialsharing.common.AuthListener;
23 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.TwitterException;
24 |
25 | /**
26 | * @author Sergey Tarasevich (nostra13[at]gmail[dot]com)
27 | */
28 | class CallbackTwitterDialog extends Dialog {
29 |
30 | private static final String TAG = CallbackTwitterDialog.class.getSimpleName();
31 |
32 | private static final FrameLayout.LayoutParams FILL = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
33 |
34 | private static final String OAUTH_VERIFIER_KEY = "oauth_verifier";
35 |
36 | private static final String PARAMS_START = "?";
37 | private static final String PARAMS_SEPARATOR = "&";
38 | private static final String KEY_VALUE_SEPARATOR = "=";
39 |
40 | private ProgressDialog spinner;
41 | private WebView browser;
42 | private FrameLayout content;
43 |
44 | private AsyncTwitter twitter;
45 | private String requestUrl;
46 |
47 | private AuthListener authListener;
48 | private Handler handler;
49 |
50 | public CallbackTwitterDialog(Context context, AsyncTwitter twitter) {
51 | super(context, android.R.style.Theme_Translucent_NoTitleBar);
52 | this.twitter = twitter;
53 | this.handler = new Handler();
54 | }
55 |
56 | @Override
57 | protected void onCreate(Bundle savedInstanceState) {
58 | super.onCreate(savedInstanceState);
59 | spinner = new ProgressDialog(getContext());
60 | spinner.requestWindowFeature(Window.FEATURE_NO_TITLE);
61 | spinner.setMessage("Loading...");
62 | spinner.setCancelable(false);
63 |
64 | requestWindowFeature(Window.FEATURE_NO_TITLE);
65 | content = new FrameLayout(getContext());
66 | setUpWebView(10);
67 | addContentView(content, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
68 | }
69 |
70 | @Override
71 | public void show() {
72 | super.show();
73 | browser.setVisibility(View.INVISIBLE);
74 | spinner.show();
75 | if (requestUrl == null) {
76 | retrieveRequestToken();
77 | } else {
78 | browser.loadUrl(requestUrl);
79 | }
80 | }
81 |
82 | private void retrieveRequestToken() {
83 | twitter.getOAuthRequestToken(new AuthRequestListener() {
84 | @Override
85 | public void onAuthRequestFailed(Exception e) {
86 | Log.e(TAG, e.getMessage(), e);
87 | String errorMessage = e.getMessage();
88 | if (errorMessage == null) {
89 | errorMessage = e.getMessage();
90 | }
91 | TwitterEvents.onLoginError(errorMessage);
92 | spinner.dismiss();
93 | dismiss();
94 | }
95 |
96 | @Override
97 | public void onAuthRequestComplete(final String requestUrl) {
98 | CallbackTwitterDialog.this.requestUrl = requestUrl;
99 | handler.post(new Runnable() {
100 | @Override
101 | public void run() {
102 | browser.loadUrl(requestUrl);
103 | }
104 | });
105 | }
106 | });
107 | }
108 |
109 | @SuppressLint("SetJavaScriptEnabled")
110 | private void setUpWebView(int margin) {
111 | LinearLayout webViewContainer = new LinearLayout(getContext());
112 | browser = new WebView(getContext());
113 | browser.setVerticalScrollBarEnabled(false);
114 | browser.setHorizontalScrollBarEnabled(false);
115 | browser.setWebViewClient(new TwWebViewClient());
116 | browser.getSettings().setJavaScriptEnabled(true);
117 | browser.setLayoutParams(FILL);
118 |
119 | webViewContainer.setPadding(margin, margin, margin, margin);
120 | webViewContainer.addView(browser);
121 | content.addView(webViewContainer);
122 | }
123 |
124 | private class TwWebViewClient extends WebViewClient {
125 |
126 | @Override
127 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
128 | view.loadUrl(url);
129 | return true;
130 | }
131 |
132 | @Override
133 | public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
134 | super.onReceivedError(view, errorCode, description, failingUrl);
135 | String pin = extractAuthVerifier(failingUrl);
136 | if (pin != null) {
137 | new AuthorizationTask().execute(pin);
138 | } else {
139 | if (authListener != null) authListener.onAuthFail(description);
140 | TwitterEvents.onLoginError(description);
141 | dismiss();
142 | }
143 | }
144 |
145 | @Override
146 | public void onPageStarted(WebView view, String url, Bitmap favicon) {
147 | Log.d(TAG, "WebView loading URL: " + url);
148 | super.onPageStarted(view, url, favicon);
149 | spinner.show();
150 | }
151 |
152 | @Override
153 | public void onPageFinished(WebView view, String url) {
154 | super.onPageFinished(view, url);
155 |
156 | content.setBackgroundColor(Color.TRANSPARENT);
157 | browser.setVisibility(View.VISIBLE);
158 | spinner.dismiss();
159 | }
160 | }
161 |
162 | private String extractAuthVerifier(String url) {
163 | String verifier = null;
164 | if (url.contains(PARAMS_START)) {
165 | url = url.substring(url.indexOf(PARAMS_START));
166 | String[] params = url.split(PARAMS_SEPARATOR);
167 | for (String param : params) {
168 | String[] keyValue = param.split(KEY_VALUE_SEPARATOR);
169 | if (OAUTH_VERIFIER_KEY.equals(keyValue[0])) {
170 | verifier = keyValue[1];
171 | }
172 | }
173 | }
174 | return verifier;
175 | }
176 |
177 | public void setAuthListener(AuthListener authListener) {
178 | this.authListener = authListener;
179 | }
180 |
181 | private class AuthorizationTask extends AsyncTask {
182 |
183 | private Exception occuredException;
184 |
185 | @Override
186 | protected Boolean doInBackground(String... params) {
187 | String pin = params[0];
188 | try {
189 | AccessToken accessToken = twitter.getOAuthAccessToken(pin);
190 | TwitterSessionStore.save(accessToken, getContext());
191 | return true;
192 | } catch (TwitterException e) {
193 | Log.e(TAG, e.getMessage(), e);
194 | occuredException = e;
195 | return false;
196 | }
197 | }
198 |
199 | @Override
200 | protected void onPostExecute(Boolean success) {
201 | if (success) {
202 | if (authListener != null) authListener.onAuthSucceed();
203 | TwitterEvents.onLoginSuccess();
204 | } else {
205 | if (authListener != null) authListener.onAuthFail(occuredException.getMessage());
206 | TwitterEvents.onLoginError(occuredException.getMessage());
207 | }
208 | spinner.dismiss();
209 | dismiss();
210 | }
211 | }
212 | }
213 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/TwitterStream.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
2 |
3 | import java.net.HttpURLConnection;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 | import java.util.concurrent.ConcurrentHashMap;
8 |
9 |
10 | /**
11 | * Connect to the streaming API.
12 | *
13 | * Duplicate messages may be delivered when reconnecting to the Streaming API.
14 | *
15 | * @author Daniel
16 | */
17 | public class TwitterStream extends AStream {
18 |
19 | public static enum KMethod {
20 | /**
21 | * Follow hashtags, users or regions
22 | */
23 | filter,
24 |
25 | /** Everything! Requires special access privileges! */
26 | firehose,
27 |
28 | /** Requires special access privileges! */
29 | links,
30 |
31 | /**
32 | * New-style retweets. Requires special access privileges! From
33 | * dev.twitter.com: Few applications require this level of access.
34 | * Creative use of a combination of other resources and various access
35 | * levels can satisfy nearly every application use case.
36 | * */
37 | retweet,
38 |
39 | /**
40 | * Spritzer or Garden-hose: A sample of tweets, suitable for trend
41 | * analysis.
42 | * The default level (spritzer) is roughly 1% of all public tweets.
43 | * The upgraded level (garden-hose - apply to Twitter for this) is 10%.
44 | * In both cases the algorithm is based on the tweet-id modulo 100.
45 | */
46 | sample
47 | }
48 |
49 | /**
50 | * Used to help avoid breaking api limits.
51 | */
52 | private static Map user2stream = new ConcurrentHashMap();
53 |
54 | private List follow;
55 |
56 | private List locns;
57 |
58 | KMethod method = KMethod.sample;
59 |
60 | private List track;
61 |
62 | /**
63 | *
64 | * @param client
65 | * This will have it's timeout set to 90 seconds. So you probably
66 | * don't want to reuse the object with the REST api.
67 | */
68 | public TwitterStream(Twitter jtwit) {
69 | super(jtwit);
70 | }
71 |
72 | @Override
73 | HttpURLConnection connect2() throws Exception {
74 | connect3_rateLimit();
75 |
76 | String url = "https://stream.twitter.com/1/statuses/" + method
77 | + ".json";
78 | Map vars = new HashMap();
79 | vars.put("delimited", "length");
80 | if (follow != null && follow.size() != 0) {
81 | vars.put("follow", InternalUtils.join(follow, 0, Integer.MAX_VALUE));
82 | }
83 | if (track != null && track.size() != 0) {
84 | vars.put("track", InternalUtils.join(track, 0, Integer.MAX_VALUE));
85 | }
86 | // use post in case it's a long set of vars
87 | HttpURLConnection con = client.post2_connect(url, vars);
88 | return con;
89 | }
90 |
91 | /**
92 | * Protect the rate limits & _help_ you avoid annoying Twitter (only
93 | * locally! And forgetful! Do NOT rely on this)
94 | */
95 | private void connect3_rateLimit() {
96 | if (jtwit.getScreenName() == null)
97 | return; // dunno
98 | AStream s = user2stream.get(jtwit.getScreenName());
99 | if (s != null && s.isConnected())
100 | throw new TwitterException.TooManyLogins(
101 | "One account, one stream (running: "
102 | + s
103 | + "; trying to run"
104 | + this
105 | + ").\n But streams OR their filter parameters, so one stream can do a lot.");
106 | // memory paranoia
107 | if (user2stream.size() > 1000) {
108 | user2stream = new ConcurrentHashMap();
109 | }
110 | user2stream.put(jtwit.getScreenName(), this);
111 | }
112 |
113 | @Override
114 | void fillInOutages2(Twitter jtwit2, Outage outage) {
115 | if (method != KMethod.filter)
116 | throw new UnsupportedOperationException();
117 | // keywords?
118 | if (track != null) {
119 | for (String keyword : track) {
120 | List msgs = jtwit.search(keyword);
121 | for (Status status : msgs) {
122 | if (tweets.contains(status)) {
123 | continue;
124 | }
125 | tweets.add(status);
126 | }
127 | }
128 | }
129 |
130 | // users?
131 | if (follow != null) {
132 | for (Long user : follow) {
133 | List msgs = jtwit.getUserTimeline(user);
134 | for (Status status : msgs) {
135 | if (tweets.contains(status)) {
136 | continue;
137 | }
138 | tweets.add(status);
139 | }
140 | }
141 | }
142 | // regions?
143 | if (locns != null && ! locns.isEmpty())
144 | throw new UnsupportedOperationException("TODO"); // TODO
145 | }
146 |
147 | public List getTrackKeywords() {
148 | return track;
149 | }
150 |
151 | /**
152 | * @param userIds Upto 5,000 userids to follow
153 | */
154 | public void setFollowUsers(List userIds) {
155 | method = KMethod.filter;
156 | // if (userIds!=null&&! userIds.isEmpty()){
157 | follow = userIds;
158 | // }
159 | // If not, really don't! it screws stuff up.
160 | }
161 |
162 | /**
163 | * TODO This is not implemented yet!
164 | * 25 0.1-360 degree location boxes.
165 | *
166 | * Only tweets that are both created using the Geotagging API and are placed
167 | * from within a tracked bounding box will be included in the stream – the
168 | * user’s location field is not used to filter tweets
169 | *
170 | * @param boundingBoxes
171 | * Each element consists of longitude/latitude south-west,
172 | * north-east.
173 | */
174 | @Deprecated // TODO
175 | public void setLocation(List boundingBoxes) {
176 | method = KMethod.filter;
177 | this.locns = boundingBoxes;
178 | throw new RuntimeException("TODO! Not implemented yet (sorry)");
179 | }
180 |
181 | /**
182 | * Set the method. The default is "sample", as this is the only one which
183 | * works with no extra settings.
184 | *
185 | * @param method
186 | */
187 | void setMethod(KMethod method) {
188 | this.method = method;
189 | }
190 |
191 | /**
192 | * See https://dev.twitter.com/docs/streaming-api/methods#track
193 | *
194 | * Terms are exact-matched, and also exact-matched ignoring punctuation.
195 | * Each term may be up to 60 characters long.
196 | *
197 | * Exact matching on phrases, that is, keywords with spaces,
198 | * is not supported. Keywords containing punctuation will only exact match
199 | * tokens and, other than keywords prefixed by # and @, will tend to
200 | * never match. Non-space separated languages, such as CJK and
201 | * Arabic, are currently unsupported as tokenization only occurs on
202 | * whitespace and punctuation. Other UTF-8 phrases should exact match
203 | * correctly, but will not substitute similar characters to their
204 | * least-common-denominator. For all these cases, consider falling back
205 | * to the Search REST API.
206 | *
207 | * @param keywords
208 | * The default access level allows up to 400 track keywords.
209 | * You can also do phrases, separating words with a space.
210 | *
211 | */
212 | public void setTrackKeywords(List keywords) {
213 | // check them for length
214 | for (String kw : keywords) {
215 | if (kw.length() > 60) {
216 | throw new IllegalArgumentException("Track term too long: "+kw+" (60 char limit)");
217 | }
218 | }
219 | // we don't check >400 'cos you might have special access
220 | this.track = keywords;
221 | method = KMethod.filter;
222 | }
223 |
224 | @Override
225 | public String toString() {
226 | StringBuilder sb = new StringBuilder("TwitterStream");
227 | sb.append("[" + method);
228 | if (track != null) {
229 | sb.append(" track:" + InternalUtils.join(track, 0, 5));
230 | }
231 | if (follow != null) {
232 | sb.append(" follow:" + InternalUtils.join(follow, 0, 5));
233 | }
234 | if (locns != null) {
235 | sb.append(" in:" + InternalUtils.join(locns, 0, 5));
236 | }
237 | sb.append("]");
238 | return sb.toString();
239 | }
240 |
241 | /**
242 | * default: false
243 | * If true, json is only sent to listeners, and polling based access
244 | * via {@link #getTweets()} will return no results.
245 | * @see #addListener(IListen)
246 | */
247 | public void setListenersOnly(boolean listenersOnly) {
248 | this.listenersOnly = listenersOnly;
249 | }
250 |
251 | }
252 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/oauth/signpost/OAuthConsumer.java:
--------------------------------------------------------------------------------
1 | /* Copyright (c) 2009 Matthias Kaeppler
2 | *
3 | * Licensed under the Apache License, Version 2.0 (the "License");
4 | * you may not use this file except in compliance with the License.
5 | * You may obtain a copy of the License at
6 | *
7 | * http://www.apache.org/licenses/LICENSE-2.0
8 | *
9 | * Unless required by applicable law or agreed to in writing, software
10 | * distributed under the License is distributed on an "AS IS" BASIS,
11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | * See the License for the specific language governing permissions and
13 | * limitations under the License.
14 | */
15 | package com.nostra13.socialsharing.twitter.extpack.oauth.signpost;
16 |
17 | import java.io.Serializable;
18 |
19 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.exception.OAuthCommunicationException;
20 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.exception.OAuthExpectationFailedException;
21 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.exception.OAuthMessageSignerException;
22 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpParameters;
23 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.http.HttpRequest;
24 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature.AuthorizationHeaderSigningStrategy;
25 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature.HmacSha1MessageSigner;
26 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature.OAuthMessageSigner;
27 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature.PlainTextMessageSigner;
28 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature.QueryStringSigningStrategy;
29 | import com.nostra13.socialsharing.twitter.extpack.oauth.signpost.signature.SigningStrategy;
30 |
31 |
32 | /**
33 | *
34 | * Exposes a simple interface to sign HTTP requests using a given OAuth token
35 | * and secret. Refer to {@link OAuthProvider} how to retrieve a valid token and
36 | * token secret.
37 | *
38 | *
39 | * HTTP messages are signed as follows:
40 | *
41 | *
42 | *
43 | * // exchange the arguments with the actual token/secret pair
44 | * OAuthConsumer consumer = new DefaultOAuthConsumer("1234", "5678");
45 | *
46 | * URL url = new URL("http://example.com/protected.xml");
47 | * HttpURLConnection request = (HttpURLConnection) url.openConnection();
48 | *
49 | * consumer.sign(request);
50 | *
51 | * request.connect();
52 | *
53 | *
54 | *
55 | *
56 | *
57 | * @author Matthias Kaeppler
58 | */
59 | public interface OAuthConsumer extends Serializable {
60 |
61 | /**
62 | * Sets the message signer that should be used to generate the OAuth
63 | * signature.
64 | *
65 | * @param messageSigner
66 | * the signer
67 | * @see HmacSha1MessageSigner
68 | * @see PlainTextMessageSigner
69 | */
70 | public void setMessageSigner(OAuthMessageSigner messageSigner);
71 |
72 | /**
73 | * Allows you to add parameters (typically OAuth parameters such as
74 | * oauth_callback or oauth_verifier) which will go directly into the signer,
75 | * i.e. you don't have to put them into the request first. The consumer's
76 | * {@link SigningStrategy} will then take care of writing them to the
77 | * correct part of the request before it is sent. Note that these parameters
78 | * are expected to already be percent encoded -- they will be simply merged
79 | * as-is.
80 | *
81 | * @param additionalParameters
82 | * the parameters
83 | */
84 | public void setAdditionalParameters(HttpParameters additionalParameters);
85 |
86 | /**
87 | * Defines which strategy should be used to write a signature to an HTTP
88 | * request.
89 | *
90 | * @param signingStrategy
91 | * the strategy
92 | * @see AuthorizationHeaderSigningStrategy
93 | * @see QueryStringSigningStrategy
94 | */
95 | public void setSigningStrategy(SigningStrategy signingStrategy);
96 |
97 | /**
98 | *
99 | * Causes the consumer to always include the oauth_token parameter to be
100 | * sent, even if blank. If you're seeing 401s during calls to
101 | * {@link OAuthProvider#retrieveRequestToken}, try setting this to true.
102 | *
103 | *
104 | * @param enable
105 | * true or false
106 | */
107 | public void setSendEmptyTokens(boolean enable);
108 |
109 | /**
110 | * Signs the given HTTP request by writing an OAuth signature (and other
111 | * required OAuth parameters) to it. Where these parameters are written
112 | * depends on the current {@link SigningStrategy}.
113 | *
114 | * @param request
115 | * the request to sign
116 | * @return the request object passed as an argument
117 | * @throws OAuthMessageSignerException
118 | * @throws OAuthExpectationFailedException
119 | * @throws OAuthCommunicationException
120 | */
121 | public HttpRequest sign(HttpRequest request) throws OAuthMessageSignerException,
122 | OAuthExpectationFailedException, OAuthCommunicationException;
123 |
124 | /**
125 | *
126 | * Signs the given HTTP request by writing an OAuth signature (and other
127 | * required OAuth parameters) to it. Where these parameters are written
128 | * depends on the current {@link SigningStrategy}.
129 | *
130 | * This method accepts HTTP library specific request objects; the consumer
131 | * implementation must ensure that only those request types are passed which
132 | * it supports.
133 | *
134 | * @param request
135 | * the request to sign
136 | * @return the request object passed as an argument
137 | * @throws OAuthMessageSignerException
138 | * @throws OAuthExpectationFailedException
139 | * @throws OAuthCommunicationException
140 | */
141 | public HttpRequest sign(Object request) throws OAuthMessageSignerException,
142 | OAuthExpectationFailedException, OAuthCommunicationException;
143 |
144 | /**
145 | *
146 | * "Signs" the given URL by appending all OAuth parameters to it which are
147 | * required for message signing. The assumed HTTP method is GET.
148 | * Essentially, this is equivalent to signing an HTTP GET request, but it
149 | * can be useful if your application requires clickable links to protected
150 | * resources, i.e. when your application does not have access to the actual
151 | * request that is being sent.
152 | *
153 | *
154 | * @param url
155 | * the input URL. May have query parameters.
156 | * @return the input URL, with all necessary OAuth parameters attached as a
157 | * query string. Existing query parameters are preserved.
158 | * @throws OAuthMessageSignerException
159 | * @throws OAuthExpectationFailedException
160 | * @throws OAuthCommunicationException
161 | */
162 | public String sign(String url) throws OAuthMessageSignerException,
163 | OAuthExpectationFailedException, OAuthCommunicationException;
164 |
165 | /**
166 | * Sets the OAuth token and token secret used for message signing.
167 | *
168 | * @param token
169 | * the token
170 | * @param tokenSecret
171 | * the token secret
172 | */
173 | public void setTokenWithSecret(String token, String tokenSecret);
174 |
175 | public String getToken();
176 |
177 | public String getTokenSecret();
178 |
179 | public String getConsumerKey();
180 |
181 | public String getConsumerSecret();
182 |
183 | /**
184 | * Returns all parameters collected from the HTTP request during message
185 | * signing (this means the return value may be NULL before a call to
186 | * {@link #sign}), plus all required OAuth parameters that were added
187 | * because the request didn't contain them beforehand. In other words, this
188 | * is the exact set of parameters that were used for creating the message
189 | * signature.
190 | *
191 | * @return the request parameters used for message signing
192 | */
193 | public HttpParameters getRequestParameters();
194 | }
195 |
--------------------------------------------------------------------------------
/SimpleSocialSharing/src/com/nostra13/socialsharing/twitter/extpack/winterwell/jtwitter/Twitter_Account.java:
--------------------------------------------------------------------------------
1 | package com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Date;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONArray;
9 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONException;
10 | import com.nostra13.socialsharing.twitter.extpack.winterwell.json.JSONObject;
11 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.Twitter.IHttpClient;
12 | import com.nostra13.socialsharing.twitter.extpack.winterwell.jtwitter.Twitter.ITweet;
13 |
14 |
15 |
16 | /**
17 | * Access the account methods: e.g. change your profile colours.
18 | *
19 | * Note that user blocking/unblocking methods are in
20 | * {@link Twitter_Users} -- see {@link Twitter#users()}
21 | *
22 | * @author Daniel Winterstein
23 | */
24 | public class Twitter_Account {
25 |
26 | public static enum KAccessLevel {
27 | /** no login or invalid login */
28 | NONE,
29 | /** Read public messages */
30 | READ_ONLY,
31 | /** Read, write of public messages (but not DMs) */
32 | READ_WRITE,
33 | /** Read, write of public and private messages */
34 | READ_WRITE_DM
35 | }
36 |
37 | public static class Search {
38 | private Date createdAt;
39 | private Long id;
40 | private String query;
41 |
42 | public Search(Long id, Date createdAt, String query) {
43 | this.id = id;
44 | this.createdAt = createdAt;
45 | this.query = query;
46 | }
47 |
48 | public Date getCreatedAt() {
49 | return createdAt;
50 | }
51 |
52 | public Long getId() {
53 | return id;
54 | }
55 |
56 | public String getText() {
57 | return query;
58 | }
59 |
60 | }
61 |
62 | public static String COLOR_BG = "profile_background_color";
63 |
64 | public static String COLOR_LINK = "profile_link_color";
65 |
66 | public static String COLOR_SIDEBAR_BORDER = "profile_sidebar_border_color";
67 | public static String COLOR_SIDEBAR_FILL = "profile_sidebar_fill_color";
68 | public static String COLOR_TEXT = "profile_text_color";
69 | private KAccessLevel accessLevel;
70 | final Twitter jtwit;
71 |
72 | public Twitter_Account(Twitter jtwit) {
73 | assert jtwit.getHttpClient().canAuthenticate() : jtwit;
74 | this.jtwit = jtwit;
75 | }
76 |
77 | /**
78 | * Create a new saved search.
79 | *
80 | * @param query
81 | * The search query
82 | * @return the new search
83 | */
84 | public Search createSavedSearch(String query) {
85 | String url = jtwit.TWITTER_URL + "saved_searches/create.json";
86 | Map vars = InternalUtils.asMap("query", query);
87 | String json = jtwit.getHttpClient().post(url, vars, true);
88 | try {
89 | return makeSearch(new JSONObject(json));
90 | } catch (JSONException e) {
91 | throw new TwitterException.Parsing(json, e);
92 | }
93 | }
94 |
95 | /**
96 | * Delete one of the user's saved searches!
97 | *
98 | * @param id
99 | * The id for this search
100 | * @return the deleted search
101 | */
102 | public Search destroySavedSearch(Long id) {
103 | String url = jtwit.TWITTER_URL + "saved_searches/destroy/" + id
104 | + ".json";
105 | String json = jtwit.getHttpClient().post(url, null, true);
106 | try {
107 | return makeSearch(new JSONObject(json));
108 | } catch (JSONException e) {
109 | throw new TwitterException.Parsing(json, e);
110 | }
111 | }
112 |
113 | /**
114 | * @return What access level does this login have? If the login is bogus,
115 | * this will return {@link KAccessLevel#NONE}.
116 | */
117 | public KAccessLevel getAccessLevel() {
118 | if (accessLevel != null)
119 | return accessLevel;
120 | try {
121 | verifyCredentials();
122 | return accessLevel;
123 | } catch (TwitterException.E401 e) {
124 | return KAccessLevel.NONE;
125 | }
126 | }
127 |
128 | /**
129 | * @return The current user's saved searches on Twitter. Use
130 | * {@link ITweet#getText()} to retrieve the search query.
131 | */
132 | public List getSavedSearches() {
133 | String url = jtwit.TWITTER_URL + "saved_searches.json";
134 | String json = jtwit.getHttpClient().getPage(url, null, true);
135 | try {
136 | JSONArray ja = new JSONArray(json);
137 | List searches = new ArrayList();
138 | for (int i = 0; i < ja.length(); i++) {
139 | final JSONObject jo = ja.getJSONObject(i);
140 | Search search = makeSearch(jo);
141 | searches.add(search);
142 | }
143 | return searches;
144 | } catch (JSONException e) {
145 | throw new TwitterException.Parsing(json, e);
146 | }
147 | }
148 |
149 | /**
150 | * Reuse the ITweet interface. This is a bit dodgy (it's not a message), but
151 | * it has exactly the methods we want.
152 | *
153 | * @param jo
154 | * @return a search in ITweet format.
155 | * @throws JSONException
156 | */
157 | private Search makeSearch(JSONObject jo) throws JSONException {
158 | final Date createdAt = InternalUtils.parseDate(jo
159 | .getString("created_at"));
160 | final Long id = jo.getLong("id");
161 | final String query = jo.getString("query");
162 | Search search = new Search(id, createdAt, query);
163 | return search;
164 | }
165 |
166 | /**
167 | * Update profile.
168 | *
169 | * @param name
170 | * Can be null for no change. Full name associated with the
171 | * profile. Maximum of 20 characters.
172 | * @param url
173 | * Can be null for no change. URL associated with the profile.
174 | * Will be prepended with "http://" if not present. Maximum of
175 | * 100 characters.
176 | * @param location
177 | * Can be null for no change. The city or country describing
178 | * where the user of the account is located. The contents are not
179 | * normalized or geocoded in any way. Maximum of 30 characters.
180 | * @param description
181 | * Can be null for no change. A description of the user. Maximum
182 | * of 160 characters.
183 | * @return updated User object
184 | */
185 | public User setProfile(String name, String url, String location,
186 | String description) {
187 | Map vars = InternalUtils.asMap("name", name, "url",
188 | url, "location", location, "description", description);
189 | String apiUrl = jtwit.TWITTER_URL + "/account/update_profile.json";
190 | String json = jtwit.getHttpClient().post(apiUrl, vars, true);
191 | return InternalUtils.user(json);
192 | }
193 |
194 | /**
195 | * Set the authenticating user's colors.
196 | *
197 | * @param colorName2hexCode
198 | * Use the COLOR_XXX constants as keys, and 3 or 6 letter
199 | * hex-codes as values (e.g. 0f0 or 00ff00 both code for green).
200 | * You can set as many colors as you like (but at least one).
201 | * @return updated User object
202 | */
203 | public User setProfileColors(Map colorName2hexCode) {
204 | assert colorName2hexCode.size() != 0;
205 | String url = jtwit.TWITTER_URL + "/account/update_profile_colors.json";
206 | String json = jtwit.getHttpClient().post(url, colorName2hexCode, true);
207 | return InternalUtils.user(json);
208 | }
209 |
210 | @Override
211 | public String toString() {
212 | return "TwitterAccount[" + jtwit.getScreenName() + "]";
213 | }
214 |
215 | /**
216 | * Test the login credentials -- and get some user info (which gets cached
217 | * at {@link Twitter#getSelf()}).
218 | *
219 | * @return a representation of the requesting user if authentication was
220 | * successful
221 | * @throws TwitterException.E401
222 | * thrown if the authorisation credentials fail.
223 | *
224 | * @see Twitter#isValidLogin()
225 | */
226 | public User verifyCredentials() throws TwitterException.E401 {
227 | String url = jtwit.TWITTER_URL + "/account/verify_credentials.json";
228 | String json = jtwit.getHttpClient().getPage(url, null, true);
229 | // store the access level info
230 | IHttpClient client = jtwit.getHttpClient();
231 | String al = client.getHeader("X-Access-Level");
232 | if (al != null) {
233 | if ("read".equals(al)) {
234 | accessLevel = KAccessLevel.READ_ONLY;
235 | }
236 | if ("read-write".equals(al)) {
237 | accessLevel = KAccessLevel.READ_WRITE;
238 | }
239 | if ("read-write-directmessages".equals(al)) {
240 | accessLevel = KAccessLevel.READ_WRITE_DM;
241 | }
242 | }
243 | User self = InternalUtils.user(json);
244 | // update the self object
245 | jtwit.self = self;
246 | return self;
247 | }
248 |
249 | }
250 |
--------------------------------------------------------------------------------