/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ztspeech.weibo.sdk.kaixin;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.security.GeneralSecurityException;
import java.security.cert.X509Certificate;
import java.util.Map;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.X509TrustManager;
import org.json.JSONObject;
import android.Manifest;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.text.TextUtils;
import android.webkit.CookieSyncManager;
public class Kaixin {
/**
* �������ʱ��õ�api key���ڵ��ýӿ�ʱ������������Ψһ��ݡ�
*/
public static final String API_KEY = "846977132847356f74f09ddd08925e42";
// �滻Ϊ����ʱ��õ�api
// key
/**
* �������ʱ��õ�secret key
*/
public static final String SECRET_KEY = "186660258ac3bbd70a9738ab1e90a332"; // �滻Ϊ����ʱ��õ�secretkey
// /**
// * �������ʱ��õ�api key���ڵ��ýӿ�ʱ������������Ψһ��ݡ�
// */
// public static final String API_KEY = "391539743237928ea711a484a5d4c513";
// // �滻Ϊ����ʱ��õ�api
// // key
//
// /**
// * �������ʱ��õ�secret key
// */
// public static final String SECRET_KEY =
// "cdabd96b3c9684befb85a02cd02bf8a5"; // �滻Ϊ����ʱ��õ�secret
// // key
/**
* �������ʱ��д����վ��ַ
*/
private static String KX_AUTHORIZE_CALLBACK_URL = "http://localhost/"; // �滻Ϊ�������ʱ��д����վ��ַ
/**
* Kaixin��Ȩ��ַ
*/
private static final String KX_AUTHORIZE_URL = "http://api.kaixin001.com/oauth2/authorize";
/**
* ˢ�����Ƶ�ַ
*/
private static String KX_REFRESHTOKEN_URL = "http://api.kaixin001.com/oauth2/access_token";
/**
* ˢ�����Ƶ�ַ
*/
private static String KX_REFRESHTOKEN_URL_S = "https://api.kaixin001.com/oauth2/access_token";
/**
* Kaixin��¼��ַ
*/
@SuppressWarnings("unused")
private static String KX_LOGIN_URL = "http://www.kaixin001.com/login/connect.php";
/**
* oauth �汾
*/
@SuppressWarnings("unused")
private static final String OAUTH_VERSION = "2.0";
/**
* rest api�ӿڵ�ַ
*/
private static String KX_REST_URL = "https://api.kaixin001.com";
/**
* �����ַ���
*/
@SuppressWarnings("unused")
private static final String SESSION_KEY = "session_key";
private static final String ACCESS_TOKEN = "access_token";
private static final String REFRESH_TOKEN = "refresh_token";
private static final String EXPIRES_IN = "expires_in";
private static final String ACCESS_DENIED = "access_denied";
private static final String LOGIN_DENIED = "login_denied";
/**
* ��Ȩ���������صIJ���ֵ
*/
private String mAccessToken = null;
private String mRefreshToken = null;
private long mAccessExpires = 0;
/**
* ���ػ����ֶ�
*/
private static final String KAIXIN_SDK_STORAGE = "kaixin_sdk_storage";
private static final String KAIXIN_SDK_STORAGE_ACCESS_TOKEN = "kaixin_sdk_storage_access_token";
private static final String KAIXIN_SDK_STORAGE_REFRESH_TOKEN = "kaixin_sdk_storage_refresh_token";
private static final String KAIXIN_SDK_STORAGE_EXPIRES = "kaixin_sdk_storage_expires";
private static final long ONE_HOUR = 1000 * 60 * 60;
/**
* Kaixin��ʵ��
*/
private static Kaixin instance = null;
public static synchronized Kaixin getInstance() {
if (null == instance)
instance = new Kaixin();
return instance;
}
private X509TrustManager xtm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
private HostnameVerifier hnv = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
private Kaixin() {
System.setProperty("http.keepAlive", "false");
SSLContext sslContext = null;
try {
sslContext = SSLContext.getInstance("TLS");
X509TrustManager[] xtmArray = new X509TrustManager[] { xtm };
sslContext.init(null, xtmArray, new java.security.SecureRandom());
} catch (GeneralSecurityException gse) {
}
if (sslContext != null) {
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
}
HttpsURLConnection.setDefaultHostnameVerifier(hnv);
}
/**
* ��ɵ�¼����ȡaccess_token(User-Agent Flow��ʽ)
*
* @param context
* @param listener
*/
public void authorize(final Context context, final KaixinAuthListener listener) {
this.authorize(context, null, listener);
}
/**
* ��ɵ�¼����ȡaccess_token(User-Agent Flow��ʽ)
*
* @param context
* @param permissions
* @param listener
*/
public void authorize(final Context context, String[] permissions, final KaixinAuthListener listener) {
if (this.isSessionValid()) {
listener.onAuthComplete(new Bundle());
return;
}
this.authorize(context, permissions, listener, KX_AUTHORIZE_CALLBACK_URL, "token");
}
/**
* ��ɵ�¼����ȡaccess_token(User-Agent Flow��ʽ)
*
* @param context
* @param permissions
* Ȩ���б��μ�http://wiki.open.kaixin001.com/index.php?id=OAuth%E6%96
* % 87%E6%A1%A3#REST%E6%
* 8E%A5%E5%8F%A3%E5%92%8COAuth%E6%9D%83%E9%99%90%E5%AF%B9%E7%85%
* A 7%E8%A1%A8
* @param listener
* @param redirectUrl
* @param responseType
*/
private void authorize(final Context context, String[] permissions, final KaixinAuthListener listener,
final String redirectUrl, String responseType) {
CookieSyncManager.createInstance(context);
Bundle params = new Bundle();
params.putString("client_id", API_KEY);
params.putString("response_type", responseType);
params.putString("redirect_uri", redirectUrl);
params.putString("state", "");
params.putString("display", "page");
params.putString("oauth_client", "1");
if (permissions != null && permissions.length > 0) {
String scope = TextUtils.join(" ", permissions);
params.putString("scope", scope);
}
String url = KX_AUTHORIZE_URL + "?" + Util.encodeUrl(params);
if (context.checkCallingOrSelfPermission(Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED) {
Util.showAlert(context, "û��Ȩ��", "Ӧ����Ҫ���ʻ�������Ȩ��");
} else {
new KaixinDialog(context, url, new KaixinDialogListener() {
@Override
public int onPageBegin(String url) {
return KaixinDialogListener.DIALOG_PROCCESS;
}
@Override
public void onPageFinished(String url) {
}
@Override
public boolean onPageStart(String url) {
return (KaixinDialogListener.PROCCESSED == parseUrl(url));
}
@Override
public void onReceivedError(int errorCode, String description, String failingUrl) {
listener.onAuthError(new KaixinAuthError(String.valueOf(errorCode), description, failingUrl));
}
private int parseUrl(String url) {
if (url.startsWith(KX_AUTHORIZE_CALLBACK_URL)) {
Bundle values = Util.parseUrl(url);
String error = values.getString("error");// ��Ȩ���������صĴ������
if (error != null) {
if (ACCESS_DENIED.equalsIgnoreCase(error)) {
listener.onAuthCancel(values);
} else if (LOGIN_DENIED.equalsIgnoreCase(error)) {
listener.onAuthCancelLogin();
} else {
listener.onAuthError(new KaixinAuthError(error, error, url));
}
Util.clearCookies(context);
setAccessToken(null);
setRefreshToken(null);
setAccessExpires(0L);
} else {
this.authComplete(values, url);
}
return KaixinDialogListener.PROCCESSED;
}
return KaixinDialogListener.UNPROCCESS;
}
private void authComplete(Bundle values, String url) {
CookieSyncManager.getInstance().sync();
String accessToken = values.getString(ACCESS_TOKEN);
String refreshToken = values.getString(REFRESH_TOKEN);
String expiresIn = values.getString(EXPIRES_IN);
if (accessToken != null && refreshToken != null && expiresIn != null) {
try {
setAccessToken(accessToken);
setRefreshToken(refreshToken);
setAccessExpiresIn(expiresIn);
updateStorage(context);
listener.onAuthComplete(values);
} catch (Exception e) {
listener.onAuthError(new KaixinAuthError(e.getClass().getName(), e.getMessage(), e
.toString()));
}
} else {
listener.onAuthError(new KaixinAuthError("����", "��Ȩ���������ص���Ϣ������", url));
}
}
}).show();
}
}
/**
* �жϻỰ�Ƿ���Ч
*
* @return �Ự�Ƿ���Ч
*/
public boolean isSessionValid() {
return (getAccessToken() != null)
&& ((getAccessExpires() == 0) || (System.currentTimeMillis() < getAccessExpires()));
}
public void setAccessToken(String token) {
mAccessToken = token;
}
public String getAccessToken() {
return mAccessToken;
}
public void setRefreshToken(String token) {
mRefreshToken = token;
}
public String getRefreshToken() {
return mRefreshToken;
}
public void setAccessExpires(long time) {
mAccessExpires = time;
}
public long getAccessExpires() {
return mAccessExpires;
}
public void setAccessExpiresIn(String expiresIn) {
if (expiresIn != null && !expiresIn.equals("0")) {
setAccessExpires(System.currentTimeMillis() + Long.parseLong(expiresIn) * 1000);
}
}
/**
* ��accessToken����ʱ����ˢ�����ƻ�ȡ�µ�accessToken
*
* @param context
*
* @param permissions
* Ȩ���б��μ�http://wiki.open.kaixin001.com/index.php?id=OAuth%E6%96
* % 87%E6%A1%A3#REST%E6%
* 8E%A5%E5%8F%A3%E5%92%8COAuth%E6%9D%83%E9%99%90%E5%AF%B9%E7%85%
* A 7%E8%A1%A8
*
* @return ���������ص�JSON��
* @throws FileNotFoundException
* @throws MalformedURLException
* @throws IOException
*/
public String refreshAccessToken(Context context, String[] permissions) throws FileNotFoundException,
MalformedURLException, IOException {
mAccessToken = null;
if (mRefreshToken == null) {
return null;
}
Bundle params = new Bundle();
params.putString("grant_type", REFRESH_TOKEN);
params.putString("refresh_token", mRefreshToken);
params.putString("client_id", API_KEY);
params.putString("client_secret", SECRET_KEY);
if (permissions != null && permissions.length > 0) {
String scope = TextUtils.join(" ", permissions);
params.putString("scope", scope);
}
return Util.openUrl(context, KX_REFRESHTOKEN_URL, "GET", params, null);
}
/**
* �ϴ����ݽӿڣ�����multi-part post��ʽ�ϴ�����
*
* @param params
* �����б�
* @param photos
* key-value��ʽ��ͼ�����ݼ��� keyΪfilename��
* valueΪͼ�����ݣ��������Ϳ�����InputStream��byte[]
* �����������ΪInputStream������openUrl�����н������ر�
* @return ���������ص�JSON��
* @throws FileNotFoundException
* @throws MalformedURLException
* @throws IOException
*/
public String uploadContent(Context context, String restInterface, Bundle params, Map<String, Object> photos)
throws FileNotFoundException, MalformedURLException, IOException {
if (params == null) {
params = new Bundle();
}
params.putString("access_token", getAccessToken());
return Util.openUrl(context, KX_REST_URL + restInterface, "POST", params, photos);
}
/**
* ����kaixin rest apis
*
* @param context
* Ӧ�û���
* @param restInterface
* rest api�ӿ�
* @param params
* key-value��ʽ�IJ�������keyΪ��������valueΪ����ֵ���������Ϳ�����String��byte[]
* @param httpMethod
* GET �� POST
* @return ���������ص�JSON��
* @throws FileNotFoundException
* @throws MalformedURLException
* @throws IOException
*/
public String request(Context context, String restInterface, Bundle params, String httpMethod)
throws FileNotFoundException, MalformedURLException, IOException {
if (params == null) {
params = new Bundle();
}
params.putString("access_token", getAccessToken());
return Util.openUrl(context, KX_REST_URL + restInterface, httpMethod, params, null);
}
public String login(Bundle params, Context ctx) {
String url = KX_REFRESHTOKEN_URL_S;
String method = "POST";
String sError = null;
try {
String response = Util.openUrl(ctx, url, method, params, null);
if (response != null) {
sError = setOauth(response, ctx);
if (sError != null) {
return sError;
} else {
return null;
}
} else {
return null;
}
} catch (Exception e) {
e.printStackTrace();
return "��Ȩ���������쳣, ��������";
}
}
public String setOauth(String response, Context ctx) {
try {
JSONObject obj = new JSONObject(response);
String error = obj.optString("error");
if (error != null && error.length() > 0) {
return error;
} else {
String accessToken = obj.optString(ACCESS_TOKEN);
String refreshToken = obj.optString(REFRESH_TOKEN);
String expiresIn = obj.optString(EXPIRES_IN);
if (accessToken != null && refreshToken != null && expiresIn != null) {
try {
setAccessToken(accessToken);
setRefreshToken(refreshToken);
setAccessExpiresIn(expiresIn);
updateStorage(ctx);
return null;
} catch (Exception e) {
return "��Ȩ���������صĴ���";
}
} else {
return "��Ȩ���������صĴ���";
}
}
} catch (Exception e) {
e.printStackTrace();
return "��Ȩ���������صĴ���";
}
}
/**
* ��ȡ���ػ���
*
* @param context
* @return ��ȡ���ػ����Ƿ�ɹ�
*/
public boolean loadStorage(Context context) {
SharedPreferences sp = context.getSharedPreferences(KAIXIN_SDK_STORAGE, Context.MODE_PRIVATE);
String accessToken = sp.getString(KAIXIN_SDK_STORAGE_ACCESS_TOKEN, null);
if (accessToken == null) {
return false;
}
String refreshToken = sp.getString(KAIXIN_SDK_STORAGE_REFRESH_TOKEN, null);
if (refreshToken == null) {
return false;
}
long expires = sp.getLong(KAIXIN_SDK_STORAGE_EXPIRES, 0);
long currenct = System.currentTimeMillis();
if (expires < (currenct - ONE_HOUR)) {
clearStorage(context);
return false;
}
mAccessToken = accessToken;
mRefreshToken = refreshToken;
mAccessExpires = expires;
return true;
}
public boolean isBinder(Context context) {
SharedPreferences sp = context.getSharedPreferences(KAIXIN_SDK_STORAGE, Context.MODE_PRIVATE);
String accessToken = sp.getString(KAIXIN_SDK_STORAGE_ACCESS_TOKEN, null);
if (accessToken == null) {
return false;
}
String refreshToken = sp.getString(KAIXIN_SDK_STORAGE_REFRESH_TOKEN, null);
if (refreshToken == null) {
return false;
}
return true;
}
/**
* ���±��ػ���
*
* @param context
* @return ���±��ػ����Ƿ�ɹ�
*/
public boolean updateStorage(Context context) {
boolean bUpdate = false;
Editor editor = context.getSharedPreferences(KAIXIN_SDK_STORAGE, Context.MODE_PRIVATE).edit();
if (mAccessToken != null && mRefreshToken != null && mAccessExpires > 0) {
editor.putString(KAIXIN_SDK_STORAGE_ACCESS_TOKEN, mAccessToken);
editor.putString(KAIXIN_SDK_STORAGE_REFRESH_TOKEN, mRefreshToken);
editor.putLong(KAIXIN_SDK_STORAGE_EXPIRES, mAccessExpires);
bUpdate = true;
} else {
clearStorage(context);
bUpdate = false;
}
editor.commit();
return bUpdate;
}
/**
* ������ػ���
*
* @param context
*/
public void clearStorage(Context context) {
Editor editor = context.getSharedPreferences(KAIXIN_SDK_STORAGE, Context.MODE_PRIVATE).edit();
editor.remove(KAIXIN_SDK_STORAGE_ACCESS_TOKEN);
editor.remove(KAIXIN_SDK_STORAGE_REFRESH_TOKEN);
editor.remove(KAIXIN_SDK_STORAGE_EXPIRES);
editor.commit();
}
}