package net.oschina.app.ui;
import java.lang.ref.WeakReference;
import net.oschina.app.R;
import net.oschina.app.base.BaseActivity;
import net.oschina.app.base.BaseFragment;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.emoji.OnSendClickListener;
import net.oschina.app.fragment.MessageDetailFragment;
import net.oschina.app.fragment.TweetPubFragment;
import net.oschina.app.fragment.TweetsFragment;
import net.oschina.app.util.UIHelper;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
public class SimpleBackActivity extends BaseActivity implements
OnSendClickListener {
public final static String BUNDLE_KEY_PAGE = "BUNDLE_KEY_PAGE";
public final static String BUNDLE_KEY_ARGS = "BUNDLE_KEY_ARGS";
private static final String TAG = "FLAG_TAG";
protected WeakReference mFragment;
protected int mPageValue = -1;
@Override
protected int getLayoutId() {
return R.layout.activity_simple_fragment;
}
@Override
protected boolean hasBackButton() {
return true;
}
@Override
protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
if (mPageValue == -1) {
mPageValue = getIntent().getIntExtra(BUNDLE_KEY_PAGE, 0);
}
initFromIntent(mPageValue, getIntent());
}
protected void initFromIntent(int pageValue, Intent data) {
if (data == null) {
throw new RuntimeException(
"you must provide a page info to display");
}
SimpleBackPage page = SimpleBackPage.getPageByValue(pageValue);
if (page == null) {
throw new IllegalArgumentException("can not find page by value:"
+ pageValue);
}
setActionBarTitle(page.getTitle());
try {
Fragment fragment = (Fragment) page.getClz().newInstance();
Bundle args = data.getBundleExtra(BUNDLE_KEY_ARGS);
if (args != null) {
fragment.setArguments(args);
}
FragmentTransaction trans = getSupportFragmentManager()
.beginTransaction();
trans.replace(R.id.container, fragment, TAG);
trans.commitAllowingStateLoss();
mFragment = new WeakReference(fragment);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException(
"generate fragment error. by value:" + pageValue);
}
}
@Override
protected void onResume() {
super.onResume();
if (mFragment.get() instanceof TweetsFragment) {
setActionBarTitle("话题");
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.public_menu_send:
if (mFragment.get() instanceof TweetsFragment) {
sendTopic();
} else {
return super.onOptionsItemSelected(item);
}
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
if (mFragment.get() instanceof TweetsFragment) {
getMenuInflater().inflate(R.menu.pub_topic_menu, menu);
}
return super.onCreateOptionsMenu(menu);
}
/**
* 发送话题
*/
private void sendTopic() {
Bundle bundle = new Bundle();
bundle.putInt(TweetPubFragment.ACTION_TYPE,
TweetPubFragment.ACTION_TYPE_TOPIC);
bundle.putString("tweet_topic", "#"
+ ((TweetsFragment) mFragment.get()).getTopic() + "# ");
UIHelper.showTweetActivity(this, SimpleBackPage.TWEET_PUB, bundle);
}
@Override
public void onBackPressed() {
if (mFragment != null && mFragment.get() != null
&& mFragment.get() instanceof BaseFragment) {
BaseFragment bf = (BaseFragment) mFragment.get();
if (!bf.onBackPressed()) {
super.onBackPressed();
}
} else {
super.onBackPressed();
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.ACTION_DOWN
&& mFragment.get() instanceof BaseFragment) {
((BaseFragment) mFragment.get()).onBackPressed();
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onActivityResult(int arg0, int arg1, Intent arg2) {
super.onActivityResult(arg0, arg1, arg2);
}
@Override
public void onClick(View v) {}
@Override
public void initView() {}
@Override
public void initData() {}
@Override
public void onClickSendButton(Editable str) {
if (mFragment.get() instanceof MessageDetailFragment) {
((OnSendClickListener) mFragment.get()).onClickSendButton(str);
((MessageDetailFragment) mFragment.get()).emojiFragment.clean();
}
}
@Override
public void onClickFlagButton() {}
}
AndroidManifest.xml 文件
proguard-project.txt 文件
# To enable ProGuard in your project, edit project.properties
# to define the proguard.config property as described in that file.
#
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in ${sdk.dir}/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the ProGuard
# include property in project.properties.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
-libraryjars /libs/android-async-http-1.4.6.jar
-libraryjars /libs/android-support-v4.jar
-libraryjars /libs/baidumapapi_v3_2_0.jar
-libraryjars /libs/butterknife-5.1.2.jar
-libraryjars /libs/core-2.3.0.jar
-libraryjars /libs/KJFrameForAndroid_V2.03.jar
-libraryjars /libs/locSDK_3.1.jar
-libraryjars /libs/universal-image-loader-1.9.3.jar
-libraryjars /libs/xstream-1.4.7.jar
-dontwarn butterknife.**
-dontwarn com.tencent.**
-dontwarn com.thoughtworks.xstream.**
-dontwarn com.baidu.**
-keep class com.baidu.** { *; }
-keep class vi.com.gdi.bgl.android.**{*;}
-keep class android.support.v4.** {*; }
-keep class com.tencent.connect.** {*;}
#友盟
-dontshrink
-dontoptimize
-dontwarn com.google.android.maps.**
-dontwarn android.webkit.WebView
-dontwarn com.umeng.**
-dontwarn com.tencent.weibo.sdk.**
-dontwarn com.facebook.**
-keep enum com.facebook.**
-keepattributes Exceptions,InnerClasses,Signature
-keepattributes *Annotation*
-keepattributes SourceFile,LineNumberTable
-keep public interface com.facebook.**
-keep public interface com.tencent.**
-keep public interface com.umeng.socialize.**
-keep public interface com.umeng.socialize.sensor.**
-keep public interface com.umeng.scrshot.**
-keep public class com.umeng.socialize.* {*;}
-keep public class javax.**
-keep public class android.webkit.**
-keep class com.facebook.**
-keep class com.umeng.scrshot.**
-keep public class com.tencent.** {*;}
-keep class com.umeng.socialize.sensor.**
-keep class com.tencent.mm.sdk.modelmsg.WXMediaMessage {*;}
-keep class com.tencent.mm.sdk.modelmsg.** implements com.tencent.mm.sdk.modelmsg.WXMediaMessage$IMediaObject {*;}
-keep class im.yixin.sdk.api.YXMessage {*;}
-keep class im.yixin.sdk.api.** implements im.yixin.sdk.api.YXMessage$YXMessageData{*;}
-keep public class [your_pkg].R$*{
public static final int *;
}
project.properties
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-20
android.library.reference.1=../osc-android-app-appcompat-v7
android.library.reference.2=../libraries/UmengShareLib
android.library.reference.3=../libraries/PhotoView-library
lint.xml
BaseApplication.java
package net.oschina.app.base;
import net.oschina.app.R;
import net.oschina.app.util.StringUtils;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.res.Resources;
import android.os.Build;
import android.util.DisplayMetrics;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
@SuppressLint("InflateParams")
public class BaseApplication extends Application {
private static String PREF_NAME = "creativelocker.pref";
private static String LAST_REFRESH_TIME = "last_refresh_time.pref";
static Context _context;
static Resources _resource;
private static String lastToast = "";
private static long lastToastTime;
private static boolean sIsAtLeastGB;
static {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
sIsAtLeastGB = true;
}
}
@Override
public void onCreate() {
super.onCreate();
_context = getApplicationContext();
_resource = _context.getResources();
}
public static synchronized BaseApplication context() {
return (BaseApplication) _context;
}
public static Resources resources() {
return _resource;
}
/**
* 放入已读文章列表中
*
* @param id
*/
public static void putReadedPostList(String prefFileName, String key,
String value) {
SharedPreferences preferences = getPreferences(prefFileName);
int size = preferences.getAll().size();
Editor editor = preferences.edit();
if (size >= 100) {
editor.clear();
}
editor.putString(key, value);
apply(editor);
}
/**
* 读取是否是已读的文章列表
*
* @param id
* @return
*/
public static boolean isOnReadedPostList(String prefFileName, String key) {
return getPreferences(prefFileName).contains(key);
}
/***
* 记录列表上次刷新时间
* @author 火蚁
* 2015-2-9 下午2:21:37
*
* @return void
* @param key
* @param value
*/
public static void putToLastRefreshTime(String key, String value) {
SharedPreferences preferences = getPreferences(LAST_REFRESH_TIME);
Editor editor = preferences.edit();
editor.putString(key, value);
apply(editor);
}
/***
* 获取列表的上次刷新时间
* @author 火蚁
* 2015-2-9 下午2:22:04
*
* @return String
* @param key
* @return
*/
public static String getLastRefreshTime(String key) {
return getPreferences(LAST_REFRESH_TIME).getString(key, StringUtils.getCurTimeStr());
}
@TargetApi(Build.VERSION_CODES.GINGERBREAD)
public static void apply(SharedPreferences.Editor editor) {
if (sIsAtLeastGB) {
editor.apply();
} else {
editor.commit();
}
}
public static void set(String key, boolean value) {
Editor editor = getPreferences().edit();
editor.putBoolean(key, value);
apply(editor);
}
public static void set(String key, String value) {
Editor editor = getPreferences().edit();
editor.putString(key, value);
apply(editor);
}
public static boolean get(String key, boolean defValue) {
return getPreferences().getBoolean(key, defValue);
}
public static String get(String key, String defValue) {
return getPreferences().getString(key, defValue);
}
public static int get(String key, int defValue) {
return getPreferences().getInt(key, defValue);
}
public static long get(String key, long defValue) {
return getPreferences().getLong(key, defValue);
}
public static float get(String key, float defValue) {
return getPreferences().getFloat(key, defValue);
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static SharedPreferences getPreferences() {
SharedPreferences pre = context().getSharedPreferences(PREF_NAME,
Context.MODE_MULTI_PROCESS);
return pre;
}
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static SharedPreferences getPreferences(String prefName) {
return context().getSharedPreferences(prefName,
Context.MODE_MULTI_PROCESS);
}
public static int[] getDisplaySize() {
return new int[] { getPreferences().getInt("screen_width", 480),
getPreferences().getInt("screen_height", 854) };
}
public static void saveDisplaySize(Activity activity) {
DisplayMetrics displaymetrics = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay()
.getMetrics(displaymetrics);
SharedPreferences.Editor editor = getPreferences().edit();
editor.putInt("screen_width", displaymetrics.widthPixels);
editor.putInt("screen_height", displaymetrics.heightPixels);
editor.putFloat("density", displaymetrics.density);
editor.commit();
}
public static String string(int id) {
return _resource.getString(id);
}
public static String string(int id, Object... args) {
return _resource.getString(id, args);
}
public static void showToast(int message) {
showToast(message, Toast.LENGTH_LONG, 0);
}
public static void showToast(String message) {
showToast(message, Toast.LENGTH_LONG, 0, Gravity.BOTTOM);
}
public static void showToast(int message, int icon) {
showToast(message, Toast.LENGTH_LONG, icon);
}
public static void showToast(String message, int icon) {
showToast(message, Toast.LENGTH_LONG, icon, Gravity.BOTTOM);
}
public static void showToastShort(int message) {
showToast(message, Toast.LENGTH_SHORT, 0);
}
public static void showToastShort(String message) {
showToast(message, Toast.LENGTH_SHORT, 0, Gravity.BOTTOM);
}
public static void showToastShort(int message, Object... args) {
showToast(message, Toast.LENGTH_SHORT, 0, Gravity.BOTTOM, args);
}
public static void showToast(int message, int duration, int icon) {
showToast(message, duration, icon, Gravity.BOTTOM);
}
public static void showToast(int message, int duration, int icon,
int gravity) {
showToast(context().getString(message), duration, icon, gravity);
}
public static void showToast(int message, int duration, int icon,
int gravity, Object... args) {
showToast(context().getString(message, args), duration, icon, gravity);
}
public static void showToast(String message, int duration, int icon,
int gravity) {
if (message != null && !message.equalsIgnoreCase("")) {
long time = System.currentTimeMillis();
if (!message.equalsIgnoreCase(lastToast)
|| Math.abs(time - lastToastTime) > 2000) {
View view = LayoutInflater.from(context()).inflate(
R.layout.view_toast, null);
((TextView) view.findViewById(R.id.title_tv)).setText(message);
if (icon != 0) {
((ImageView) view.findViewById(R.id.icon_iv))
.setImageResource(icon);
((ImageView) view.findViewById(R.id.icon_iv))
.setVisibility(View.VISIBLE);
}
Toast toast = new Toast(context());
toast.setView(view);
if (gravity == Gravity.CENTER) {
toast.setGravity(gravity, 0, 0);
} else {
toast.setGravity(gravity, 0, 35);
}
toast.setDuration(duration);
toast.show();
lastToast = message;
lastToastTime = System.currentTimeMillis();
}
}
}
}
BaseActivity.java
package net.oschina.app.base;
import net.oschina.app.AppManager;
import net.oschina.app.R;
import net.oschina.app.interf.BaseViewInterface;
import net.oschina.app.ui.dialog.CommonToast;
import net.oschina.app.ui.dialog.DialogControl;
import net.oschina.app.ui.dialog.DialogHelper;
import net.oschina.app.ui.dialog.WaitDialog;
import net.oschina.app.util.TDevice;
import org.kymjs.kjframe.utils.StringUtils;
import android.os.Bundle;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.LayoutParams;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Spinner;
import android.widget.TextView;
import butterknife.ButterKnife;
/**
* baseActionBar Activity
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年9月25日 上午11:30:15 引用自:tonlin
*/
public abstract class BaseActivity extends ActionBarActivity implements
DialogControl, View.OnClickListener, BaseViewInterface {
public static final String INTENT_ACTION_EXIT_APP = "INTENT_ACTION_EXIT_APP";
private boolean _isVisible;
private WaitDialog _waitDialog;
protected LayoutInflater mInflater;
protected ActionBar mActionBar;
private TextView mTvActionTitle;
@Override
protected void onDestroy() {
super.onDestroy();
TDevice.hideSoftKeyboard(getCurrentFocus());
ButterKnife.reset(this);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppManager.getAppManager().addActivity(this);
if (!hasActionBar()) {
// supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
}
onBeforeSetContentLayout();
if (getLayoutId() != 0) {
setContentView(getLayoutId());
}
mActionBar = getSupportActionBar();
mInflater = getLayoutInflater();
if (hasActionBar()) {
initActionBar(mActionBar);
}
// 通过注解绑定控件
ButterKnife.inject(this);
init(savedInstanceState);
initView();
initData();
_isVisible = true;
}
protected void onBeforeSetContentLayout() {}
protected boolean hasActionBar() {
return true;
}
protected int getLayoutId() {
return 0;
}
protected View inflateView(int resId) {
return mInflater.inflate(resId, null);
}
protected int getActionBarTitle() {
return R.string.app_name;
}
protected boolean hasBackButton() {
return false;
}
protected int getActionBarCustomView() {
return 0;
}
protected boolean haveSpinner() {
return false;
}
protected void init(Bundle savedInstanceState) {}
protected void initActionBar(ActionBar actionBar) {
if (actionBar == null)
return;
if (hasBackButton()) {
mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
int layoutRes = getActionBarCustomView();
View view = inflateView(layoutRes == 0 ? R.layout.actionbar_custom_backtitle
: layoutRes);
View back = view.findViewById(R.id.btn_back);
if (back == null) {
throw new IllegalArgumentException(
"can not find R.id.btn_back in customView");
}
back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TDevice.hideSoftKeyboard(getCurrentFocus());
onBackPressed();
}
});
mTvActionTitle = (TextView) view
.findViewById(R.id.tv_actionbar_title);
if (mTvActionTitle == null) {
throw new IllegalArgumentException(
"can not find R.id.tv_actionbar_title in customView");
}
int titleRes = getActionBarTitle();
if (titleRes != 0) {
mTvActionTitle.setText(titleRes);
}
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
actionBar.setCustomView(view, params);
View spinner = actionBar.getCustomView().findViewById(R.id.spinner);
if (haveSpinner()) {
spinner.setVisibility(View.VISIBLE);
} else {
spinner.setVisibility(View.GONE);
}
} else {
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_TITLE);
actionBar.setDisplayUseLogoEnabled(false);
int titleRes = getActionBarTitle();
if (titleRes != 0) {
actionBar.setTitle(titleRes);
}
}
}
protected Spinner getSpinner() {
return (Spinner) mActionBar.getCustomView().findViewById(R.id.spinner);
}
public void setActionBarTitle(int resId) {
if (resId != 0) {
setActionBarTitle(getString(resId));
}
}
public void setActionBarTitle(String title) {
if (StringUtils.isEmpty(title)) {
title = getString(R.string.app_name);
}
if (hasActionBar() && mActionBar != null) {
if (mTvActionTitle != null) {
mTvActionTitle.setText(title);
}
mActionBar.setTitle(title);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onResume() {
super.onResume();
}
public void showToast(int msgResid, int icon, int gravity) {
showToast(getString(msgResid), icon, gravity);
}
public void showToast(String message, int icon, int gravity) {
CommonToast toast = new CommonToast(this);
toast.setMessage(message);
toast.setMessageIc(icon);
toast.setLayoutGravity(gravity);
toast.show();
}
@Override
public WaitDialog showWaitDialog() {
return showWaitDialog(R.string.loading);
}
@Override
public WaitDialog showWaitDialog(int resid) {
return showWaitDialog(getString(resid));
}
@Override
public WaitDialog showWaitDialog(String message) {
if (_isVisible) {
if (_waitDialog == null) {
_waitDialog = DialogHelper.getWaitDialog(this, message);
}
if (_waitDialog != null) {
_waitDialog.setMessage(message);
_waitDialog.show();
}
return _waitDialog;
}
return null;
}
@Override
public void hideWaitDialog() {
if (_isVisible && _waitDialog != null) {
try {
_waitDialog.dismiss();
_waitDialog = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
@Override
public boolean onMenuOpened(int featureId, Menu menu) {
// setOverflowIconVisible(featureId, menu);
return super.onMenuOpened(featureId, menu);
}
}
BaseFragment.java
package net.oschina.app.base;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.interf.BaseFragmentInterface;
import net.oschina.app.ui.dialog.DialogControl;
import net.oschina.app.ui.dialog.WaitDialog;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* 碎片基类
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年9月25日 上午11:18:46
*
*/
public class BaseFragment extends Fragment implements
android.view.View.OnClickListener, BaseFragmentInterface {
public static final int STATE_NONE = 0;
public static final int STATE_REFRESH = 1;
public static final int STATE_LOADMORE = 2;
public static final int STATE_NOMORE = 3;
public static final int STATE_PRESSNONE = 4;// 正在下拉但还没有到刷新的状态
public static int mState = STATE_NONE;
protected LayoutInflater mInflater;
public AppContext getApplication() {
return (AppContext) getActivity().getApplication();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
this.mInflater = inflater;
View view = super.onCreateView(inflater, container, savedInstanceState);
return view;
}
@Override
public void onResume() {
super.onResume();
}
@Override
public void onPause() {
super.onPause();
}
@Override
public void onDestroy() {
super.onDestroy();
}
protected int getLayoutId() {
return 0;
}
protected View inflateView(int resId) {
return this.mInflater.inflate(resId, null);
}
public boolean onBackPressed() {
return false;
}
protected void hideWaitDialog() {
FragmentActivity activity = getActivity();
if (activity instanceof DialogControl) {
((DialogControl) activity).hideWaitDialog();
}
}
protected WaitDialog showWaitDialog() {
return showWaitDialog(R.string.loading);
}
protected WaitDialog showWaitDialog(int resid) {
FragmentActivity activity = getActivity();
if (activity instanceof DialogControl) {
return ((DialogControl) activity).showWaitDialog(resid);
}
return null;
}
protected WaitDialog showWaitDialog(String resid) {
FragmentActivity activity = getActivity();
if (activity instanceof DialogControl) {
return ((DialogControl) activity).showWaitDialog(resid);
}
return null;
}
@Override
public void initView(View view) {
}
@Override
public void initData() {
}
@Override
public void onClick(View v) {
}
}
BaseDetailFragment.java
package net.oschina.app.base;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.bean.Comment;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.Entity;
import net.oschina.app.bean.Report;
import net.oschina.app.bean.Result;
import net.oschina.app.bean.ResultBean;
import net.oschina.app.cache.CacheManager;
import net.oschina.app.ui.DetailActivity;
import net.oschina.app.ui.ReportDialog;
import net.oschina.app.ui.ShareDialog;
import net.oschina.app.ui.ShareDialog.OnSharePlatformClick;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.util.HTMLUtil;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.XmlUtils;
import org.apache.http.Header;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v7.internal.widget.ListPopupWindow;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.TextHttpResponseHandler;
import com.umeng.socialize.bean.SHARE_MEDIA;
import com.umeng.socialize.controller.UMServiceFactory;
import com.umeng.socialize.controller.UMSocialService;
import com.umeng.socialize.controller.listener.SocializeListeners.UMAuthListener;
import com.umeng.socialize.exception.SocializeException;
import com.umeng.socialize.media.UMImage;
import com.umeng.socialize.sso.SinaSsoHandler;
import com.umeng.socialize.sso.UMQQSsoHandler;
import com.umeng.socialize.utils.OauthHelper;
import com.umeng.socialize.weixin.controller.UMWXHandler;
import com.umeng.socialize.weixin.media.CircleShareContent;
import com.umeng.socialize.weixin.media.WeiXinShareContent;
public abstract class BaseDetailFragment extends BaseFragment implements
OnItemClickListener {
public static final String INTENT_ACTION_COMMENT_CHANGED = "INTENT_ACTION_COMMENT_CHAGED";
final UMSocialService mController = UMServiceFactory
.getUMSocialService("com.umeng.share");
private ListPopupWindow mMenuWindow;
private MenuAdapter mMenuAdapter;
protected EmptyLayout mEmptyLayout;
public int mCommentCount = 0;
protected WebView mWebView;
protected AsyncHttpResponseHandler mCommentHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
ResultBean rsb = XmlUtils.toBean(ResultBean.class,
new ByteArrayInputStream(arg2));
Result res = rsb.getResult();
if (res.OK()) {
hideWaitDialog();
AppContext.showToastShort(R.string.comment_publish_success);
commentPubSuccess(rsb.getComment());
} else {
hideWaitDialog();
AppContext.showToastShort(res.getErrorMessage());
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
((DetailActivity) getActivity()).emojiFragment.clean();
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
hideWaitDialog();
AppContext.showToastShort(R.string.comment_publish_faile);
}
@Override
public void onFinish() {
((DetailActivity) getActivity()).emojiFragment.hideAllKeyBoard();
};
};
protected void recycleWebView() {
if (mWebView != null) {
mWebView.setVisibility(View.GONE);
mWebView.removeAllViews();
mWebView.destroy();
mWebView = null;
}
}
protected void onCommentChanged(int opt, int id, int catalog,
boolean isBlog, Comment comment) {}
private AsyncTask mCacheTask;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mMenuAdapter = new MenuAdapter();
setHasOptionsMenu(true);
mController.getConfig().closeToast();
}
protected boolean hasReportMenu() {
return false;
}
@Override
public void onDestroyView() {
recycleWebView();
super.onDestroyView();
}
@Override
public void onDestroy() {
cancelReadCache();
recycleWebView();
super.onDestroy();
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
requestData(false);
}
protected String getCacheKey() {
return null;
}
protected Entity parseData(InputStream is) throws Exception {
return null;
}
protected Entity readData(Serializable seri) {
return null;
}
protected void sendRequestData() {}
protected void requestData(boolean refresh) {
String key = getCacheKey();
if (TDevice.hasInternet()
&& (!CacheManager.isExistDataCache(getActivity(), key) || refresh)) {
sendRequestData();
} else {
readCacheData(key);
}
}
// 刷新数据
protected void sendRefresh() {
sendRequestData();
}
private void readCacheData(String cacheKey) {
cancelReadCache();
mCacheTask = new CacheTask(getActivity()).execute(cacheKey);
}
private void cancelReadCache() {
if (mCacheTask != null) {
mCacheTask.cancel(true);
mCacheTask = null;
}
}
private class CacheTask extends AsyncTask {
private final WeakReference mContext;
private CacheTask(Context context) {
mContext = new WeakReference(context);
}
@Override
protected Entity doInBackground(String... params) {
if (mContext.get() != null) {
Serializable seri = CacheManager.readObject(mContext.get(),
params[0]);
if (seri == null) {
return null;
} else {
return readData(seri);
}
}
return null;
}
@Override
protected void onPostExecute(Entity entity) {
super.onPostExecute(entity);
if (entity != null) {
executeOnLoadDataSuccess(entity);
} else {
executeOnLoadDataError(null);
}
executeOnLoadFinish();
}
}
private class SaveCacheTask extends AsyncTask {
private final WeakReference mContext;
private final Serializable seri;
private final String key;
private SaveCacheTask(Context context, Serializable seri, String key) {
mContext = new WeakReference(context);
this.seri = seri;
this.key = key;
}
@Override
protected Void doInBackground(Void... params) {
CacheManager.saveObject(mContext.get(), seri, key);
return null;
}
}
protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
Entity entity = parseData(new ByteArrayInputStream(arg2));
if (entity != null) {
mEmptyLayout.setErrorType(EmptyLayout.HIDE_LAYOUT);
executeOnLoadDataSuccess(entity);
saveCache(entity);
} else {
throw new RuntimeException("load detail error");
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
// executeOnLoadDataError(arg3.getMessage());
readCacheData(getCacheKey());
}
};
private boolean mIsFavorited;
protected void saveCache(Entity entity) {
new SaveCacheTask(getActivity(), entity, getCacheKey()).execute();
}
protected void executeOnLoadDataSuccess(Entity entity) {}
protected void executeOnLoadDataError(String object) {
mEmptyLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
mEmptyLayout.setOnLayoutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mState = STATE_REFRESH;
mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
requestData(true);
}
});
}
protected void executeOnLoadFinish() {}
protected void onFavoriteChanged(boolean flag) {
((DetailActivity) getActivity()).toolFragment.setFavorite(flag);
}
protected int getFavoriteTargetId() {
return -1;
}
protected int getFavoriteTargetType() {
return -1;
}
protected String getShareUrl() {
return "";
}
protected String getShareTitle() {
return getString(R.string.share_title);
}
protected String getShareContent() {
return "";
}
/***
* 获取去除html标签的body
*
* @param body
* @return
*/
protected String getFilterHtmlBody(String body) {
if (body == null)
return "";
return HTMLUtil.delHTMLTag(body.trim());
}
protected UMImage getShareImg() {
UMImage img = new UMImage(getActivity(), R.drawable.ic_share);
return img;
}
protected void commentPubSuccess(Comment comment) {}
@Override
public void onItemClick(AdapterView> parent, View view, int position,
long id) {
if (position == 0) {
handleFavoriteOrNot();
handleShare();
} else if (position == 1) {
onReportMenuClick();
} else if (position == 2) {
}
if (mMenuWindow != null) {
mMenuWindow.dismiss();
mMenuWindow = null;
}
}
private final AsyncHttpResponseHandler mReportHandler = new TextHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, String arg2) {
if (TextUtils.isEmpty(arg2)) {
AppContext.showToastShort(R.string.tip_report_success);
} else {
AppContext.showToastShort(new String(arg2));
}
}
@Override
public void onFailure(int arg0, Header[] arg1, String arg2,
Throwable arg3) {
AppContext.showToastShort(R.string.tip_report_faile);
}
@Override
public void onFinish() {
hideWaitDialog();
}
};
public void onReportMenuClick() {
if (getRepotrId() == 0) {
AppContext.showToast("正在加载,请稍等...");
}
if (!AppContext.getInstance().isLogin()) {
UIHelper.showLoginActivity(getActivity());
return;
}
int reportId = getRepotrId();
final ReportDialog dialog = new ReportDialog(getActivity(),
getRepotrUrl(), reportId);
dialog.setCancelable(true);
dialog.setTitle(R.string.report);
dialog.setCanceledOnTouchOutside(true);
dialog.setNegativeButton(R.string.cancle, null);
dialog.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int which) {
Report report = null;
if ((report = dialog.getReport()) != null) {
showWaitDialog(R.string.progress_submit);
OSChinaApi.report(report, mReportHandler);
}
d.dismiss();
}
});
dialog.show();
}
protected String getRepotrUrl() {
return "";
}
protected int getRepotrId() {
return 0;
}
/**
* 收藏
*/
public void handleFavoriteOrNot() {
if (!TDevice.hasInternet()) {
AppContext.showToastShort(R.string.tip_no_internet);
return;
}
if (!AppContext.getInstance().isLogin()) {
UIHelper.showLoginActivity(getActivity());
return;
}
if (getFavoriteTargetId() == -1 || getFavoriteTargetType() == -1) {
return;
}
int uid = AppContext.getInstance().getLoginUid();
if (mIsFavorited) {
OSChinaApi.delFavorite(uid, getFavoriteTargetId(),
getFavoriteTargetType(), mDelFavoriteHandler);
} else {
OSChinaApi.addFavorite(uid, getFavoriteTargetId(),
getFavoriteTargetType(), mAddFavoriteHandler);
}
}
/**
* 分享
*/
public void handleShare() {
if (TextUtils.isEmpty(getShareContent())
|| TextUtils.isEmpty(getShareUrl())) {
AppContext.showToast("内容加载失败...");
return;
}
final ShareDialog dialog = new ShareDialog(getActivity());
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
dialog.setTitle(R.string.share_to);
dialog.setOnPlatformClickListener(new OnSharePlatformClick() {
@Override
public void onPlatformClick(int id) {
switch (id) {
case R.id.ly_share_weichat_circle:
shareToWeiChatCircle();
break;
case R.id.ly_share_weichat:
shareToWeiChat();
break;
case R.id.ly_share_sina_weibo:
shareToSinaWeibo();
break;
case R.id.ly_share_qq:
shareToQQ(SHARE_MEDIA.QQ);
break;
case R.id.ly_share_copy_link:
TDevice.copyTextToBoard(getShareUrl());
break;
case R.id.ly_share_more_option:
TDevice.showSystemShareOption(getActivity(),
getShareTitle(), getShareUrl());
break;
default:
break;
}
dialog.dismiss();
}
});
dialog.show();
}
@SuppressWarnings("deprecation")
private void shareToWeiChatCircle() {
// 支持微信朋友圈
UMWXHandler wxCircleHandler = new UMWXHandler(getActivity(),
Constants.WEICHAT_APPID);
wxCircleHandler.setToCircle(true);
wxCircleHandler.addToSocialSDK();
// 设置微信朋友圈分享内容
CircleShareContent circleMedia = new CircleShareContent();
circleMedia.setShareContent(getShareContent());
// 设置朋友圈title
circleMedia.setTitle(getShareTitle());
circleMedia.setShareImage(getShareImg());
circleMedia.setTargetUrl(getShareUrl());
mController.setShareMedia(circleMedia);
mController.postShare(getActivity(), SHARE_MEDIA.WEIXIN_CIRCLE, null);
}
@SuppressWarnings("deprecation")
private void shareToWeiChat() {
// 添加微信平台
UMWXHandler wxHandler = new UMWXHandler(getActivity(),
Constants.WEICHAT_APPID);
wxHandler.addToSocialSDK();
// 设置微信好友分享内容
WeiXinShareContent weixinContent = new WeiXinShareContent();
// 设置分享文字
weixinContent.setShareContent(getShareContent());
// 设置title
weixinContent.setTitle(getShareTitle());
// 设置分享内容跳转URL
weixinContent.setTargetUrl(getShareUrl());
// 设置分享图片
weixinContent.setShareImage(getShareImg());
mController.setShareMedia(weixinContent);
mController.postShare(getActivity(), SHARE_MEDIA.WEIXIN, null);
}
private void shareToSinaWeibo() {
// 设置新浪微博SSO handler
mController.getConfig().setSsoHandler(new SinaSsoHandler());
if (OauthHelper.isAuthenticated(getActivity(), SHARE_MEDIA.SINA)) {
shareContent(SHARE_MEDIA.SINA);
} else {
mController.doOauthVerify(getActivity(), SHARE_MEDIA.SINA,
new UMAuthListener() {
@Override
public void onStart(SHARE_MEDIA arg0) {}
@Override
public void onError(SocializeException arg0,
SHARE_MEDIA arg1) {}
@Override
public void onComplete(Bundle arg0, SHARE_MEDIA arg1) {
shareContent(SHARE_MEDIA.SINA);
}
@Override
public void onCancel(SHARE_MEDIA arg0) {}
});
}
}
private void shareContent(SHARE_MEDIA media) {
mController.setShareContent(getShareContent() + getShareUrl());
mController.directShare(getActivity(), media, null);
}
protected void shareToQQ(SHARE_MEDIA media) {
UMQQSsoHandler qqSsoHandler = new UMQQSsoHandler(getActivity(),
Constants.QQ_APPID, Constants.QQ_APPKEY);
qqSsoHandler.setTargetUrl(getShareUrl());
qqSsoHandler.setTitle(getShareTitle());
qqSsoHandler.addToSocialSDK();
mController.setShareContent(getShareContent());
mController.setShareImage(getShareImg());
mController.postShare(getActivity(), media, null);
}
protected void notifyFavorite(boolean favorite) {
mIsFavorited = favorite;
FragmentActivity aty = getActivity();
if (aty != null) {
aty.supportInvalidateOptionsMenu();
}
if (mMenuAdapter != null) {
mMenuAdapter.setFavorite(favorite);
}
onFavoriteChanged(favorite);
}
public boolean isFavorited() {
return mIsFavorited;
}
@SuppressLint("ViewHolder")
private static class MenuAdapter extends BaseAdapter {
public void setFavorite(boolean favorite) {
notifyDataSetChanged();
}
@Override
public int getCount() {
return 2;
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@SuppressLint("InflateParams")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = LayoutInflater.from(parent.getContext()).inflate(
R.layout.list_cell_popup_menu, null);
TextView name = (TextView) convertView.findViewById(R.id.tv_name);
int iconResId = 0;
// if (position == 0) {
// name.setText(isFavorite ? R.string.detail_menu_unfavorite
// : R.string.detail_menu_favorite);
// iconResId = isFavorite ?
// R.drawable.actionbar_menu_icn_unfavoirite
// : R.drawable.actionbar_menu_icn_favoirite;
// } else
if (position == 0) {
name.setText(parent.getResources().getString(
R.string.detail_menu_for_share));
iconResId = R.drawable.abc_ic_menu_moreoverflow_normal_holo_dark;
} else if (position == 1) {
name.setText(parent.getResources().getString(
R.string.detail_menu_for_report));
iconResId = R.drawable.abc_ic_menu_moreoverflow_normal_holo_dark;
}
Drawable drawable = AppContext.resources().getDrawable(iconResId);
drawable.setBounds(0, 0, drawable.getMinimumWidth(),
drawable.getMinimumHeight());
name.setCompoundDrawables(drawable, null, null, null);
return convertView;
}
}
private final AsyncHttpResponseHandler mAddFavoriteHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
Result res = XmlUtils.toBean(ResultBean.class,
new ByteArrayInputStream(arg2)).getResult();
if (res.OK()) {
AppContext.showToastShort(R.string.add_favorite_success);
mMenuAdapter.setFavorite(true);
mMenuAdapter.notifyDataSetChanged();
mIsFavorited = true;
getActivity().supportInvalidateOptionsMenu();
onFavoriteChanged(true);
ImageView view = (ImageView) getActivity().findViewById(
R.id.action_favor);
view.setImageResource(R.drawable.ic_action_favor_on_normal);
} else {
AppContext.showToastShort(res.getErrorMessage());
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
AppContext.showToastShort(R.string.add_favorite_faile);
}
};
private final AsyncHttpResponseHandler mDelFavoriteHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
Result res = XmlUtils.toBean(ResultBean.class,
new ByteArrayInputStream(arg2)).getResult();
if (res.OK()) {
AppContext.showToastShort(R.string.del_favorite_success);
mMenuAdapter.setFavorite(false);
mMenuAdapter.notifyDataSetChanged();
mIsFavorited = false;
getActivity().supportInvalidateOptionsMenu();
onFavoriteChanged(false);
ImageView view = (ImageView) getActivity().findViewById(
R.id.action_favor);
view.setImageResource(R.drawable.ic_action_favor);
} else {
AppContext.showToastShort(res.getErrorMessage());
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
AppContext.showToastShort(R.string.del_favorite_faile);
}
};
public abstract int getCommentCount();
@Override
public void onClick(View v) {}
@Override
public void initView(View view) {}
public void onclickWriteComment() {}
@Override
public void initData() {}
}
BaseListFragment.java
package net.oschina.app.base;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.bean.Entity;
import net.oschina.app.bean.ListEntity;
import net.oschina.app.bean.Result;
import net.oschina.app.bean.ResultBean;
import net.oschina.app.cache.CacheManager;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.XmlUtils;
import org.apache.http.Header;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
import com.loopj.android.http.AsyncHttpResponseHandler;
@SuppressLint("NewApi")
public abstract class BaseListFragment extends BaseFragment
implements SwipeRefreshLayout.OnRefreshListener, OnItemClickListener,
OnScrollListener {
public static final String BUNDLE_KEY_CATALOG = "BUNDLE_KEY_CATALOG";
@InjectView(R.id.swiperefreshlayout)
protected SwipeRefreshLayout mSwipeRefreshLayout;
@InjectView(R.id.listview)
protected ListView mListView;
protected ListBaseAdapter mAdapter;
@InjectView(R.id.error_layout)
protected EmptyLayout mErrorLayout;
protected int mStoreEmptyState = -1;
protected int mCurrentPage = 0;
protected int mCatalog = 1;
// 错误信息
protected Result mResult;
private AsyncTask> mCacheTask;
private ParserTask mParserTask;
@Override
protected int getLayoutId() {
return R.layout.fragment_pull_refresh_listview;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(getLayoutId(), container, false);
return view;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ButterKnife.inject(this, view);
initView(view);
}
@Override
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mCatalog = args.getInt(BUNDLE_KEY_CATALOG, 0);
}
}
@Override
public void initView(View view) {
mSwipeRefreshLayout.setOnRefreshListener(this);
mSwipeRefreshLayout.setColorSchemeResources(
R.color.swiperefresh_color1, R.color.swiperefresh_color2,
R.color.swiperefresh_color3, R.color.swiperefresh_color4);
mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mCurrentPage = 0;
mState = STATE_REFRESH;
mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
requestData(true);
}
});
mListView.setOnItemClickListener(this);
mListView.setOnScrollListener(this);
if (mAdapter != null) {
mListView.setAdapter(mAdapter);
mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT);
} else {
mAdapter = getListAdapter();
mListView.setAdapter(mAdapter);
if (requestDataIfViewCreated()) {
mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
mState = STATE_NONE;
requestData(false);
} else {
mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT);
}
}
if (mStoreEmptyState != -1) {
mErrorLayout.setErrorType(mStoreEmptyState);
}
}
@Override
public void onDestroyView() {
mStoreEmptyState = mErrorLayout.getErrorState();
super.onDestroyView();
}
@Override
public void onDestroy() {
cancelReadCacheTask();
cancelParserTask();
super.onDestroy();
}
protected abstract ListBaseAdapter getListAdapter();
// 下拉刷新数据
@Override
public void onRefresh() {
if (mState == STATE_REFRESH) {
return;
}
// 设置顶部正在刷新
mListView.setSelection(0);
setSwipeRefreshLoadingState();
mCurrentPage = 0;
mState = STATE_REFRESH;
requestData(true);
}
protected boolean requestDataIfViewCreated() {
return true;
}
protected String getCacheKeyPrefix() {
return null;
}
protected ListEntity parseList(InputStream is) throws Exception {
return null;
}
protected ListEntity readList(Serializable seri) {
return null;
}
@Override
public void onItemClick(AdapterView> parent, View view, int position,
long id) {}
private String getCacheKey() {
return new StringBuilder(getCacheKeyPrefix()).append("_")
.append(mCurrentPage).toString();
}
// 是否需要自动刷新
protected boolean needAutoRefresh() {
return true;
}
/***
* 获取列表数据
*
*
* @author 火蚁 2015-2-9 下午3:16:12
*
* @return void
* @param refresh
*/
protected void requestData(boolean refresh) {
String key = getCacheKey();
if (isReadCacheData(refresh)) {
readCacheData(key);
} else {
// 取新的数据
sendRequestData();
}
}
/***
* 判断是否需要读取缓存的数据
*
* @author 火蚁 2015-2-10 下午2:41:02
*
* @return boolean
* @param refresh
* @return
*/
protected boolean isReadCacheData(boolean refresh) {
String key = getCacheKey();
if (!TDevice.hasInternet()) {
return true;
}
// 第一页若不是主动刷新,缓存存在,优先取缓存的
if (CacheManager.isExistDataCache(getActivity(), key) && !refresh
&& mCurrentPage == 0) {
return true;
}
// 其他页数的,缓存存在以及还没有失效,优先取缓存的
if (CacheManager.isExistDataCache(getActivity(), key)
&& !CacheManager.isCacheDataFailure(getActivity(), key)
&& mCurrentPage != 0) {
return true;
}
return false;
}
// 是否到时间去刷新数据了
private boolean onTimeRefresh() {
String lastRefreshTime = AppContext.getLastRefreshTime(getCacheKey());
String currTime = StringUtils.getCurTimeStr();
long diff = StringUtils.calDateDifferent(lastRefreshTime, currTime);
return needAutoRefresh() && diff > getAutoRefreshTime();
}
/***
* 自动刷新的时间
*
* 默认:自动刷新的时间为半天时间
*
* @author 火蚁 2015-2-9 下午5:55:11
*
* @return long
* @return
*/
protected long getAutoRefreshTime() {
return 12 * 60 * 60;
}
@Override
public void onResume() {
super.onResume();
if (onTimeRefresh()) {
onRefresh();
}
}
protected void sendRequestData() {}
private void readCacheData(String cacheKey) {
cancelReadCacheTask();
mCacheTask = new CacheTask(getActivity()).execute(cacheKey);
}
private void cancelReadCacheTask() {
if (mCacheTask != null) {
mCacheTask.cancel(true);
mCacheTask = null;
}
}
private class CacheTask extends AsyncTask> {
private final WeakReference mContext;
private CacheTask(Context context) {
mContext = new WeakReference(context);
}
@Override
protected ListEntity doInBackground(String... params) {
Serializable seri = CacheManager.readObject(mContext.get(),
params[0]);
if (seri == null) {
return null;
} else {
return readList(seri);
}
}
@Override
protected void onPostExecute(ListEntity list) {
super.onPostExecute(list);
if (list != null) {
executeOnLoadDataSuccess(list.getList());
} else {
executeOnLoadDataError(null);
}
executeOnLoadFinish();
}
}
private class SaveCacheTask extends AsyncTask {
private final WeakReference mContext;
private final Serializable seri;
private final String key;
private SaveCacheTask(Context context, Serializable seri, String key) {
mContext = new WeakReference(context);
this.seri = seri;
this.key = key;
}
@Override
protected Void doInBackground(Void... params) {
CacheManager.saveObject(mContext.get(), seri, key);
return null;
}
}
protected AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int statusCode, Header[] headers,
byte[] responseBytes) {
if (mCurrentPage == 0 && needAutoRefresh()) {
AppContext.putToLastRefreshTime(getCacheKey(),
StringUtils.getCurTimeStr());
}
if (isAdded()) {
if (mState == STATE_REFRESH) {
onRefreshNetworkSuccess();
}
executeParserTask(responseBytes);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
if (isAdded()) {
readCacheData(getCacheKey());
}
}
};
protected void executeOnLoadDataSuccess(List data) {
if (data == null) {
data = new ArrayList();
}
if (mResult != null && !mResult.OK()) {
AppContext.showToast(mResult.getErrorMessage());
// 注销登陆,密码已经修改,cookie,失效了
AppContext.getInstance().Logout();
}
mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT);
if (mCurrentPage == 0) {
mAdapter.clear();
}
for (int i = 0; i < data.size(); i++) {
if (compareTo(mAdapter.getData(), data.get(i))) {
data.remove(i);
i--;
}
}
int adapterState = ListBaseAdapter.STATE_EMPTY_ITEM;
if ((mAdapter.getCount() + data.size()) == 0) {
adapterState = ListBaseAdapter.STATE_EMPTY_ITEM;
} else if (data.size() == 0
|| (data.size() < getPageSize() && mCurrentPage == 0)) {
adapterState = ListBaseAdapter.STATE_NO_MORE;
mAdapter.notifyDataSetChanged();
} else {
adapterState = ListBaseAdapter.STATE_LOAD_MORE;
}
mAdapter.setState(adapterState);
mAdapter.addData(data);
// 判断等于是因为最后有一项是listview的状态
if (mAdapter.getCount() == 1) {
if (needShowEmptyNoData()) {
mErrorLayout.setErrorType(EmptyLayout.NODATA);
} else {
mAdapter.setState(ListBaseAdapter.STATE_EMPTY_ITEM);
mAdapter.notifyDataSetChanged();
}
}
}
/**
* 是否需要隐藏listview,显示无数据状态
*
* @author 火蚁 2015-1-27 下午6:18:59
*
*/
protected boolean needShowEmptyNoData() {
return true;
}
protected boolean compareTo(List extends Entity> data, Entity enity) {
int s = data.size();
if (enity != null) {
for (int i = 0; i < s; i++) {
if (enity.getId() == data.get(i).getId()) {
return true;
}
}
}
return false;
}
protected int getPageSize() {
return AppContext.PAGE_SIZE;
}
protected void onRefreshNetworkSuccess() {}
protected void executeOnLoadDataError(String error) {
if (mCurrentPage == 0
&& !CacheManager.isExistDataCache(getActivity(), getCacheKey())) {
mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
} else {
mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT);
mAdapter.setState(ListBaseAdapter.STATE_NETWORK_ERROR);
mAdapter.notifyDataSetChanged();
}
}
// 完成刷新
protected void executeOnLoadFinish() {
setSwipeRefreshLoadedState();
mState = STATE_NONE;
}
/** 设置顶部正在加载的状态 */
private void setSwipeRefreshLoadingState() {
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(true);
// 防止多次重复刷新
mSwipeRefreshLayout.setEnabled(false);
}
}
/** 设置顶部加载完毕的状态 */
private void setSwipeRefreshLoadedState() {
if (mSwipeRefreshLayout != null) {
mSwipeRefreshLayout.setRefreshing(false);
mSwipeRefreshLayout.setEnabled(true);
}
}
private void executeParserTask(byte[] data) {
cancelParserTask();
mParserTask = new ParserTask(data);
mParserTask.execute();
}
private void cancelParserTask() {
if (mParserTask != null) {
mParserTask.cancel(true);
mParserTask = null;
}
}
class ParserTask extends AsyncTask {
private final byte[] reponseData;
private boolean parserError;
private List list;
public ParserTask(byte[] data) {
this.reponseData = data;
}
@Override
protected String doInBackground(Void... params) {
try {
ListEntity data = parseList(new ByteArrayInputStream(
reponseData));
new SaveCacheTask(getActivity(), data, getCacheKey()).execute();
list = data.getList();
if (list == null) {
ResultBean resultBean = XmlUtils.toBean(ResultBean.class,
reponseData);
if (resultBean != null) {
mResult = resultBean.getResult();
}
}
} catch (Exception e) {
e.printStackTrace();
parserError = true;
}
return null;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if (parserError) {
readCacheData(getCacheKey());
} else {
executeOnLoadDataSuccess(list);
executeOnLoadFinish();
}
}
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
if (mAdapter == null || mAdapter.getCount() == 0) {
return;
}
// 数据已经全部加载,或数据为空时,或正在加载,不处理滚动事件
if (mState == STATE_LOADMORE || mState == STATE_REFRESH) {
return;
}
// 判断是否滚动到底部
boolean scrollEnd = false;
try {
if (view.getPositionForView(mAdapter.getFooterView()) == view
.getLastVisiblePosition())
scrollEnd = true;
} catch (Exception e) {
scrollEnd = false;
}
if (mState == STATE_NONE && scrollEnd) {
if (mAdapter.getState() == ListBaseAdapter.STATE_LOAD_MORE
|| mAdapter.getState() == ListBaseAdapter.STATE_NETWORK_ERROR) {
mCurrentPage++;
mState = STATE_LOADMORE;
requestData(false);
mAdapter.setFooterViewLoading();
}
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// 数据已经全部加载,或数据为空时,或正在加载,不处理滚动事件
// if (mState == STATE_NOMORE || mState == STATE_LOADMORE
// || mState == STATE_REFRESH) {
// return;
// }
// if (mAdapter != null
// && mAdapter.getDataSize() > 0
// && mListView.getLastVisiblePosition() == (mListView.getCount() - 1))
// {
// if (mState == STATE_NONE
// && mAdapter.getState() == ListBaseAdapter.STATE_LOAD_MORE) {
// mState = STATE_LOADMORE;
// mCurrentPage++;
// requestData(true);
// }
// }
}
/**
* 保存已读的文章列表
*
* @param view
* @param prefFileName
* @param key
*/
protected void saveToReadedList(final View view, final String prefFileName,
final String key) {
// 放入已读列表
AppContext.putReadedPostList(prefFileName, key, "true");
TextView tvTitle = (TextView) view.findViewById(R.id.tv_title);
if (tvTitle != null) {
tvTitle.setTextColor(0xff9a9a9a);
}
}
}
BaseViewPagerFragment.java
package net.oschina.app.base;
import net.oschina.app.R;
import net.oschina.app.adapter.ViewPageFragmentAdapter;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.widget.PagerSlidingTabStrip;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
/**
* 带有导航条的基类
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年11月6日 下午4:59:50
*
*/
public abstract class BaseViewPagerFragment extends BaseFragment {
protected PagerSlidingTabStrip mTabStrip;
protected ViewPager mViewPager;
protected ViewPageFragmentAdapter mTabsAdapter;
protected EmptyLayout mErrorLayout;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.base_viewpage_fragment, null);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
mTabStrip = (PagerSlidingTabStrip) view
.findViewById(R.id.pager_tabstrip);
mViewPager = (ViewPager) view.findViewById(R.id.pager);
mErrorLayout = (EmptyLayout) view.findViewById(R.id.error_layout);
mTabsAdapter = new ViewPageFragmentAdapter(getChildFragmentManager(),
mTabStrip, mViewPager);
setScreenPageLimit();
onSetupTabAdapter(mTabsAdapter);
// if (savedInstanceState != null) {
// int pos = savedInstanceState.getInt("position");
// mViewPager.setCurrentItem(pos, true);
// }
}
protected void setScreenPageLimit() {
}
// @Override
// public void onSaveInstanceState(Bundle outState) {
// //No call for super(). Bug on API Level > 11.
// if (outState != null && mViewPager != null) {
// outState.putInt("position", mViewPager.getCurrentItem());
// }
// //super.onSaveInstanceState(outState);
// }
protected abstract void onSetupTabAdapter(ViewPageFragmentAdapter adapter);
}
BeseHaveHeaderListFragment.java
package net.oschina.app.base;
import java.io.ByteArrayInputStream;
import java.io.Serializable;
import java.lang.ref.WeakReference;
import net.oschina.app.bean.Entity;
import net.oschina.app.cache.CacheManager;
import net.oschina.app.ui.empty.EmptyLayout;
import org.apache.http.Header;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import butterknife.ButterKnife;
import com.loopj.android.http.AsyncHttpResponseHandler;
/**
* 需要加入header的BaseListFragment
*
* @desc 应用场景:如动弹详情、团队任务详情这些, 即是头部显示详情,然后下面显示评论列表的
*
* BeseHaveHeaderListFragment.java
*
* @author 火蚁(http://my.oschina.net/u/253900)
*
* @data 2015-1-27 下午3:02:42
*/
public abstract class BeseHaveHeaderListFragment
extends BaseListFragment {
protected T2 detailBean;// list 头部的详情实体类
protected Activity aty;
protected final AsyncHttpResponseHandler mDetailHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
if (arg2 != null) {
T2 detail = getDetailBean(new ByteArrayInputStream(arg2));
if (detail != null) {
requstListData();
executeOnLoadDetailSuccess(detail);
new SaveCacheTask(getActivity(), detail,
getDetailCacheKey()).execute();
} else {
onFailure(arg0, arg1, arg2, null);
}
} else {
throw new RuntimeException("load detail error");
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
readDetailCacheData(getDetailCacheKey());
}
};
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// 通过注解绑定控件
ButterKnife.inject(this, view);
mListView.addHeaderView(initHeaderView());
aty = getActivity();
super.initView(view);
requestDetailData(isRefresh());
}
protected boolean isRefresh() {
return false;
}
protected abstract void requestDetailData(boolean isRefresh);
protected abstract View initHeaderView();
protected abstract String getDetailCacheKey();
protected abstract void executeOnLoadDetailSuccess(T2 detailBean);
protected abstract T2 getDetailBean(ByteArrayInputStream is);
@Override
protected boolean requestDataIfViewCreated() {
return false;
}
private void requstListData() {
mState = STATE_REFRESH;
mAdapter.setState(ListBaseAdapter.STATE_LOAD_MORE);
sendRequestData();
}
/***
* 带有header view的listfragment不需要显示是否数据为空
*/
@Override
protected boolean needShowEmptyNoData() {
return false;
}
protected void readDetailCacheData(String cacheKey) {
new ReadCacheTask(getActivity()).execute(cacheKey);
}
private class SaveCacheTask extends AsyncTask {
private final WeakReference mContext;
private final Serializable seri;
private final String key;
private SaveCacheTask(Context context, Serializable seri, String key) {
mContext = new WeakReference(context);
this.seri = seri;
this.key = key;
}
@Override
protected Void doInBackground(Void... params) {
CacheManager.saveObject(mContext.get(), seri, key);
return null;
}
}
private class ReadCacheTask extends AsyncTask {
private final WeakReference mContext;
private ReadCacheTask(Context context) {
mContext = new WeakReference(context);
}
@Override
protected T2 doInBackground(String... params) {
if (mContext.get() != null) {
Serializable seri = CacheManager.readObject(mContext.get(),
params[0]);
if (seri == null) {
return null;
} else {
return (T2) seri;
}
}
return null;
}
@Override
protected void onPostExecute(T2 t) {
super.onPostExecute(t);
if (t != null) {
requstListData();
executeOnLoadDetailSuccess(t);
}
}
}
@Override
protected void executeOnLoadDataError(String error) {
mErrorLayout.setErrorType(EmptyLayout.HIDE_LAYOUT);
mAdapter.setState(ListBaseAdapter.STATE_NETWORK_ERROR);
mAdapter.notifyDataSetChanged();
}
@SuppressWarnings("unchecked")
protected T findHeaderView(View headerView, int viewId) {
return (T) headerView.findViewById(viewId);
}
}
ListBaseAdapter.java
package net.oschina.app.base;
import java.util.ArrayList;
import java.util.List;
import net.oschina.app.R;
import net.oschina.app.bean.Entity;
import net.oschina.app.emoji.InputHelper;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TDevice;
import net.oschina.app.widget.MyLinkMovementMethod;
import net.oschina.app.widget.MyURLSpan;
import net.oschina.app.widget.TweetTextView;
import android.annotation.SuppressLint;
import android.content.Context;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
public class ListBaseAdapter extends BaseAdapter {
public static final int STATE_EMPTY_ITEM = 0;
public static final int STATE_LOAD_MORE = 1;
public static final int STATE_NO_MORE = 2;
public static final int STATE_NO_DATA = 3;
public static final int STATE_LESS_ONE_PAGE = 4;
public static final int STATE_NETWORK_ERROR = 5;
public static final int STATE_OTHER = 6;
protected int state = STATE_LESS_ONE_PAGE;
protected int _loadmoreText;
protected int _loadFinishText;
protected int _noDateText;
protected int mScreenWidth;
private LayoutInflater mInflater;
protected LayoutInflater getLayoutInflater(Context context) {
if (mInflater == null) {
mInflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
return mInflater;
}
public void setScreenWidth(int width) {
mScreenWidth = width;
}
public void setState(int state) {
this.state = state;
}
public int getState() {
return this.state;
}
protected ArrayList mDatas = new ArrayList();
public ListBaseAdapter() {
_loadmoreText = R.string.loading;
_loadFinishText = R.string.loading_no_more;
_noDateText = R.string.error_view_no_data;
}
@Override
public int getCount() {
switch (getState()) {
case STATE_EMPTY_ITEM:
return getDataSize() + 1;
case STATE_NETWORK_ERROR:
case STATE_LOAD_MORE:
return getDataSize() + 1;
case STATE_NO_DATA:
return 1;
case STATE_NO_MORE:
return getDataSize() + 1;
case STATE_LESS_ONE_PAGE:
return getDataSize();
default:
break;
}
return getDataSize();
}
public int getDataSize() {
return mDatas.size();
}
@Override
public T getItem(int arg0) {
if (mDatas.size() > arg0) {
return mDatas.get(arg0);
}
return null;
}
@Override
public long getItemId(int arg0) {
return arg0;
}
public void setData(ArrayList data) {
mDatas = data;
notifyDataSetChanged();
}
public ArrayList getData() {
return mDatas == null ? (mDatas = new ArrayList()) : mDatas;
}
public void addData(List data) {
if (mDatas != null && data != null && !data.isEmpty()) {
mDatas.addAll(data);
}
notifyDataSetChanged();
}
public void addItem(T obj) {
if (mDatas != null) {
mDatas.add(obj);
}
notifyDataSetChanged();
}
public void addItem(int pos, T obj) {
if (mDatas != null) {
mDatas.add(pos, obj);
}
notifyDataSetChanged();
}
public void removeItem(Object obj) {
mDatas.remove(obj);
notifyDataSetChanged();
}
public void clear() {
mDatas.clear();
notifyDataSetChanged();
}
public void setLoadmoreText(int loadmoreText) {
_loadmoreText = loadmoreText;
}
public void setLoadFinishText(int loadFinishText) {
_loadFinishText = loadFinishText;
}
public void setNoDataText(int noDataText) {
_noDateText = noDataText;
}
protected boolean loadMoreHasBg() {
return true;
}
@SuppressWarnings("deprecation")
@SuppressLint("InflateParams")
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (position == getCount() - 1) {// 最后一条
// if (position < _data.size()) {
// position = getCount() - 2; // footview
// }
if (getState() == STATE_LOAD_MORE || getState() == STATE_NO_MORE
|| state == STATE_EMPTY_ITEM
|| getState() == STATE_NETWORK_ERROR) {
this.mFooterView = (LinearLayout) LayoutInflater.from(
parent.getContext()).inflate(R.layout.list_cell_footer,
null);
if (!loadMoreHasBg()) {
mFooterView.setBackgroundDrawable(null);
}
ProgressBar progress = (ProgressBar) mFooterView
.findViewById(R.id.progressbar);
TextView text = (TextView) mFooterView.findViewById(R.id.text);
switch (getState()) {
case STATE_LOAD_MORE:
setFooterViewLoading();
break;
case STATE_NO_MORE:
mFooterView.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
text.setVisibility(View.VISIBLE);
text.setText(_loadFinishText);
break;
case STATE_EMPTY_ITEM:
progress.setVisibility(View.GONE);
mFooterView.setVisibility(View.VISIBLE);
text.setText(_noDateText);
break;
case STATE_NETWORK_ERROR:
mFooterView.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
text.setVisibility(View.VISIBLE);
if (TDevice.hasInternet()) {
text.setText("加载出错了");
} else {
text.setText("没有可用的网络");
}
break;
default:
progress.setVisibility(View.GONE);
mFooterView.setVisibility(View.GONE);
text.setVisibility(View.GONE);
break;
}
return mFooterView;
}
}
if (position < 0) {
position = 0; // 若列表没有数据,是没有footview/headview的
}
return getRealView(position, convertView, parent);
}
protected View getRealView(int position, View convertView, ViewGroup parent) {
return null;
}
private LinearLayout mFooterView;
public View getFooterView() {
return this.mFooterView;
}
public void setFooterViewLoading(String loadMsg) {
ProgressBar progress = (ProgressBar) mFooterView
.findViewById(R.id.progressbar);
TextView text = (TextView) mFooterView.findViewById(R.id.text);
mFooterView.setVisibility(View.VISIBLE);
progress.setVisibility(View.VISIBLE);
text.setVisibility(View.VISIBLE);
if (StringUtils.isEmpty(loadMsg)) {
text.setText(_loadmoreText);
} else {
text.setText(loadMsg);
}
}
public void setFooterViewLoading() {
setFooterViewLoading("");
}
public void setFooterViewText(String msg) {
ProgressBar progress = (ProgressBar) mFooterView
.findViewById(R.id.progressbar);
TextView text = (TextView) mFooterView.findViewById(R.id.text);
mFooterView.setVisibility(View.VISIBLE);
progress.setVisibility(View.GONE);
text.setVisibility(View.VISIBLE);
text.setText(msg);
}
protected void setContent(TweetTextView contentView, String content) {
contentView.setMovementMethod(MyLinkMovementMethod.a());
contentView.setFocusable(false);
contentView.setDispatchToParent(true);
contentView.setLongClickable(false);
Spanned span = Html.fromHtml(TweetTextView.modifyPath(content));
span = InputHelper.displayEmoji(contentView.getResources(),
span.toString());
contentView.setText(span);
MyURLSpan.parseLinkText(contentView, span);
}
protected void setText(TextView textView, String text, boolean needGone) {
if (text == null || TextUtils.isEmpty(text)) {
if (needGone) {
textView.setVisibility(View.GONE);
}
} else {
textView.setText(text);
}
}
protected void setText(TextView textView, String text) {
setText(textView, text, false);
}
}
AppConfig.java
package net.oschina.app;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Properties;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Environment;
import android.preference.PreferenceManager;
/**
* 应用程序配置类:用于保存用户相关信息及设置
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年9月25日 下午5:29:00
*
*/
public class AppConfig {
private final static String APP_CONFIG = "config";
public final static String CONF_COOKIE = "cookie";
public final static String CONF_APP_UNIQUEID = "APP_UNIQUEID";
public static final String KEY_LOAD_IMAGE = "KEY_LOAD_IMAGE";
public static final String KEY_NOTIFICATION_ACCEPT = "KEY_NOTIFICATION_ACCEPT";
public static final String KEY_NOTIFICATION_SOUND = "KEY_NOTIFICATION_SOUND";
public static final String KEY_NOTIFICATION_VIBRATION = "KEY_NOTIFICATION_VIBRATION";
public static final String KEY_NOTIFICATION_DISABLE_WHEN_EXIT = "KEY_NOTIFICATION_DISABLE_WHEN_EXIT";
public static final String KEY_CHECK_UPDATE = "KEY_CHECK_UPDATE";
public static final String KEY_DOUBLE_CLICK_EXIT = "KEY_DOUBLE_CLICK_EXIT";
public static final String LAST_QUESTION_CATEGORY_IDX = "LAST_QUESTION_CATEGORY_IDX";
public static final String KEY_DAILY_ENGLISH = "KEY_DAILY_ENGLISH";
public static final String KEY_GET_LAST_DAILY_ENG = "KEY_GET_LAST_DAILY_ENG";
public static final String KEY_TWEET_DRAFT = "KEY_TWEET_DRAFT";
public static final String KEY_NOTE_DRAFT = "KEY_NOTE_DRAFT";
public static final String KEY_QUESTION_TITLE_DRAFT = "KEY_QUESTION_TITLE_DRAFT";
public static final String KEY_QUESTION_CONTENT_DRAFT = "KEY_QUESTION_CONTENT_DRAFT";
public static final String KEY_QUESTION_TYPE_DRAFT = "KEY_QUESTION_TYPE_DRAFT";
public static final String KEY_QUESTION_LMK_DRAFT = "KEY_QUESTION_LMK_DRAFT";
public static final String KEY_FRITST_START = "KEY_FRIST_START";
public static final String APP_QQ_KEY = "100942993";
// 默认存放图片的路径
public final static String DEFAULT_SAVE_IMAGE_PATH = Environment
.getExternalStorageDirectory()
+ File.separator
+ "OSChina"
+ File.separator + "osc_img" + File.separator;
// 默认存放文件下载的路径
public final static String DEFAULT_SAVE_FILE_PATH = Environment
.getExternalStorageDirectory()
+ File.separator
+ "OSChina"
+ File.separator + "download" + File.separator;
private Context mContext;
private static AppConfig appConfig;
public static AppConfig getAppConfig(Context context) {
if (appConfig == null) {
appConfig = new AppConfig();
appConfig.mContext = context;
}
return appConfig;
}
/**
* 获取Preference设置
*/
public static SharedPreferences getSharedPreferences(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context);
}
public String get(String key) {
Properties props = get();
return (props != null) ? props.getProperty(key) : null;
}
public Properties get() {
FileInputStream fis = null;
Properties props = new Properties();
try {
// 读取files目录下的config
// fis = activity.openFileInput(APP_CONFIG);
// 读取app_config目录下的config
File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_PRIVATE);
fis = new FileInputStream(dirConf.getPath() + File.separator
+ APP_CONFIG);
props.load(fis);
} catch (Exception e) {
} finally {
try {
fis.close();
} catch (Exception e) {
}
}
return props;
}
private void setProps(Properties p) {
FileOutputStream fos = null;
try {
// 把config建在files目录下
// fos = activity.openFileOutput(APP_CONFIG, Context.MODE_PRIVATE);
// 把config建在(自定义)app_config的目录下
File dirConf = mContext.getDir(APP_CONFIG, Context.MODE_PRIVATE);
File conf = new File(dirConf, APP_CONFIG);
fos = new FileOutputStream(conf);
p.store(fos, null);
fos.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
fos.close();
} catch (Exception e) {
}
}
}
public void set(Properties ps) {
Properties props = get();
props.putAll(ps);
setProps(props);
}
public void set(String key, String value) {
Properties props = get();
props.setProperty(key, value);
setProps(props);
}
public void remove(String... key) {
Properties props = get();
for (String k : key)
props.remove(k);
setProps(props);
}
}
AppContext .java
package net.oschina.app;
import static net.oschina.app.AppConfig.KEY_FRITST_START;
import static net.oschina.app.AppConfig.KEY_LOAD_IMAGE;
import static net.oschina.app.AppConfig.KEY_TWEET_DRAFT;
import java.util.Properties;
import java.util.UUID;
import net.oschina.app.api.ApiHttpClient;
import net.oschina.app.base.BaseApplication;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.User;
import net.oschina.app.cache.DataCleanManager;
import net.oschina.app.util.CyptoUtils;
import net.oschina.app.util.MethodsCompat;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TLog;
import net.oschina.app.util.UIHelper;
import org.kymjs.kjframe.KJBitmap;
import org.kymjs.kjframe.bitmap.BitmapConfig;
import org.kymjs.kjframe.utils.KJLoger;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager.NameNotFoundException;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.PersistentCookieStore;
/**
* 全局应用程序类:用于保存和调用全局应用配置及访问网络数据
*
* @author 火蚁 (http://my.oschina.net/LittleDY)
* @version 1.0
* @created 2014-04-22
*/
public class AppContext extends BaseApplication {
public static final int PAGE_SIZE = 20;// 默认分页大小
private static AppContext instance;
private int loginUid;
private boolean login;
@Override
public void onCreate() {
super.onCreate();
instance = this;
init();
initLogin();
// Thread.setDefaultUncaughtExceptionHandler(AppException
// .getAppExceptionHandler(this));
UIHelper.sendBroadcastForNotice(this);
}
private void init() {
// 初始化网络请求
AsyncHttpClient client = new AsyncHttpClient();
PersistentCookieStore myCookieStore = new PersistentCookieStore(this);
client.setCookieStore(myCookieStore);
ApiHttpClient.setHttpClient(client);
ApiHttpClient.setCookie(ApiHttpClient.getCookie(this));
// Log控制器
KJLoger.openDebutLog(true);
TLog.DEBUG = BuildConfig.DEBUG;
// Bitmap缓存地址
BitmapConfig.CACHEPATH = "OSChina/imagecache";
}
private void initLogin() {
User user = getLoginUser();
if (null != user && user.getId() > 0) {
login = true;
loginUid = user.getId();
} else {
this.cleanLoginInfo();
}
}
/**
* 获得当前app运行的AppContext
*
* @return
*/
public static AppContext getInstance() {
return instance;
}
public boolean containsProperty(String key) {
Properties props = getProperties();
return props.containsKey(key);
}
public void setProperties(Properties ps) {
AppConfig.getAppConfig(this).set(ps);
}
public Properties getProperties() {
return AppConfig.getAppConfig(this).get();
}
public void setProperty(String key, String value) {
AppConfig.getAppConfig(this).set(key, value);
}
/**
* 获取cookie时传AppConfig.CONF_COOKIE
*
* @param key
* @return
*/
public String getProperty(String key) {
String res = AppConfig.getAppConfig(this).get(key);
return res;
}
public void removeProperty(String... key) {
AppConfig.getAppConfig(this).remove(key);
}
/**
* 获取App唯一标识
*
* @return
*/
public String getAppId() {
String uniqueID = getProperty(AppConfig.CONF_APP_UNIQUEID);
if (StringUtils.isEmpty(uniqueID)) {
uniqueID = UUID.randomUUID().toString();
setProperty(AppConfig.CONF_APP_UNIQUEID, uniqueID);
}
return uniqueID;
}
/**
* 获取App安装包信息
*
* @return
*/
public PackageInfo getPackageInfo() {
PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (NameNotFoundException e) {
e.printStackTrace(System.err);
}
if (info == null)
info = new PackageInfo();
return info;
}
/**
* 保存登录信息
*
* @param username
* @param pwd
*/
@SuppressWarnings("serial")
public void saveUserInfo(final User user) {
this.loginUid = user.getId();
this.login = true;
setProperties(new Properties() {
{
setProperty("user.uid", String.valueOf(user.getId()));
setProperty("user.name", user.getName());
setProperty("user.face", user.getPortrait());// 用户头像-文件名
setProperty("user.account", user.getAccount());
setProperty("user.pwd",
CyptoUtils.encode("oschinaApp", user.getPwd()));
setProperty("user.location", user.getLocation());
setProperty("user.followers",
String.valueOf(user.getFollowers()));
setProperty("user.fans", String.valueOf(user.getFans()));
setProperty("user.score", String.valueOf(user.getScore()));
setProperty("user.favoritecount",
String.valueOf(user.getFavoritecount()));
setProperty("user.gender", String.valueOf(user.getGender()));
setProperty("user.isRememberMe",
String.valueOf(user.isRememberMe()));// 是否记住我的信息
}
});
}
/**
* 更新用户信息
*
* @param user
*/
@SuppressWarnings("serial")
public void updateUserInfo(final User user) {
setProperties(new Properties() {
{
setProperty("user.name", user.getName());
setProperty("user.face", user.getPortrait());// 用户头像-文件名
setProperty("user.followers",
String.valueOf(user.getFollowers()));
setProperty("user.fans", String.valueOf(user.getFans()));
setProperty("user.score", String.valueOf(user.getScore()));
setProperty("user.favoritecount",
String.valueOf(user.getFavoritecount()));
setProperty("user.gender", String.valueOf(user.getGender()));
}
});
}
/**
* 获得登录用户的信息
*
* @return
*/
public User getLoginUser() {
User user = new User();
user.setId(StringUtils.toInt(getProperty("user.uid"), 0));
user.setName(getProperty("user.name"));
user.setPortrait(getProperty("user.face"));
user.setAccount(getProperty("user.account"));
user.setLocation(getProperty("user.location"));
user.setFollowers(StringUtils.toInt(getProperty("user.followers"), 0));
user.setFans(StringUtils.toInt(getProperty("user.fans"), 0));
user.setScore(StringUtils.toInt(getProperty("user.score"), 0));
user.setFavoritecount(StringUtils.toInt(
getProperty("user.favoritecount"), 0));
user.setRememberMe(StringUtils.toBool(getProperty("user.isRememberMe")));
user.setGender(getProperty("user.gender"));
return user;
}
/**
* 清除登录信息
*/
public void cleanLoginInfo() {
this.loginUid = 0;
this.login = false;
removeProperty("user.uid", "user.name", "user.face", "user.location",
"user.followers", "user.fans", "user.score",
"user.isRememberMe", "user.gender", "user.favoritecount");
}
public int getLoginUid() {
return loginUid;
}
public boolean isLogin() {
return login;
}
/**
* 用户注销
*/
public void Logout() {
cleanLoginInfo();
ApiHttpClient.cleanCookie();
this.cleanCookie();
this.login = false;
this.loginUid = 0;
Intent intent = new Intent(Constants.INTENT_ACTION_LOGOUT);
sendBroadcast(intent);
}
/**
* 清除保存的缓存
*/
public void cleanCookie() {
removeProperty(AppConfig.CONF_COOKIE);
}
/**
* 清除app缓存
*/
public void clearAppCache() {
DataCleanManager.cleanDatabases(this);
// 清除数据缓存
DataCleanManager.cleanInternalCache(this);
// 2.2版本才有将应用缓存转移到sd卡的功能
if (isMethodsCompat(android.os.Build.VERSION_CODES.FROYO)) {
DataCleanManager.cleanCustomCache(MethodsCompat
.getExternalCacheDir(this));
}
// 清除编辑器保存的临时内容
Properties props = getProperties();
for (Object key : props.keySet()) {
String _key = key.toString();
if (_key.startsWith("temp"))
removeProperty(_key);
}
new KJBitmap().cleanCache();
}
public static void setLoadImage(boolean flag) {
set(KEY_LOAD_IMAGE, flag);
}
/**
* 判断当前版本是否兼容目标版本的方法
*
* @param VersionCode
* @return
*/
public static boolean isMethodsCompat(int VersionCode) {
int currentVersion = android.os.Build.VERSION.SDK_INT;
return currentVersion >= VersionCode;
}
public static String getTweetDraft() {
return getPreferences().getString(
KEY_TWEET_DRAFT + getInstance().getLoginUid(), "");
}
public static void setTweetDraft(String draft) {
set(KEY_TWEET_DRAFT + getInstance().getLoginUid(), draft);
}
public static String getNoteDraft() {
return getPreferences().getString(
AppConfig.KEY_NOTE_DRAFT + getInstance().getLoginUid(), "");
}
public static void setNoteDraft(String draft) {
set(AppConfig.KEY_NOTE_DRAFT + getInstance().getLoginUid(), draft);
}
public static boolean isFristStart() {
return getPreferences().getBoolean(KEY_FRITST_START, true);
}
public static void setFristStart(boolean frist) {
set(KEY_FRITST_START, frist);
}
}
AppException.java
package net.oschina.app;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.Thread.UncaughtExceptionHandler;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.UnknownHostException;
import net.oschina.app.util.UIHelper;
import org.apache.http.HttpException;
import org.kymjs.kjframe.utils.FileUtils;
import org.kymjs.kjframe.utils.SystemTool;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
/**
* 应用程序异常:用于捕获异常和提示错误信息
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @author kymjs ([email protected])
* @created 2014年9月25日 下午5:34:05
*
*/
@SuppressWarnings("serial")
public class AppException extends Exception implements UncaughtExceptionHandler {
/** 定义异常类型 */
public final static byte TYPE_NETWORK = 0x01;
public final static byte TYPE_SOCKET = 0x02;
public final static byte TYPE_HTTP_CODE = 0x03;
public final static byte TYPE_HTTP_ERROR = 0x04;
public final static byte TYPE_XML = 0x05;
public final static byte TYPE_IO = 0x06;
public final static byte TYPE_RUN = 0x07;
public final static byte TYPE_JSON = 0x08;
public final static byte TYPE_FILENOTFOUND = 0x09;
private byte type;// 异常的类型
// 异常的状态码,这里一般是网络请求的状态码
private int code;
/** 系统默认的UncaughtException处理类 */
private AppContext mContext;
private AppException(Context context) {
this.mContext = (AppContext) context;
}
private AppException(byte type, int code, Exception excp) {
super(excp);
this.type = type;
this.code = code;
}
public int getCode() {
return this.code;
}
public int getType() {
return this.type;
}
public static AppException http(int code) {
return new AppException(TYPE_HTTP_CODE, code, null);
}
public static AppException http(Exception e) {
return new AppException(TYPE_HTTP_ERROR, 0, e);
}
public static AppException socket(Exception e) {
return new AppException(TYPE_SOCKET, 0, e);
}
public static AppException file(Exception e) {
return new AppException(TYPE_FILENOTFOUND, 0, e);
}
// io异常
public static AppException io(Exception e) {
return io(e, 0);
}
// io异常
public static AppException io(Exception e, int code) {
if (e instanceof UnknownHostException || e instanceof ConnectException) {
return new AppException(TYPE_NETWORK, code, e);
} else if (e instanceof IOException) {
return new AppException(TYPE_IO, code, e);
}
return run(e);
}
public static AppException xml(Exception e) {
return new AppException(TYPE_XML, 0, e);
}
public static AppException json(Exception e) {
return new AppException(TYPE_JSON, 0, e);
}
// 网络请求异常
public static AppException network(Exception e) {
if (e instanceof UnknownHostException || e instanceof ConnectException) {
return new AppException(TYPE_NETWORK, 0, e);
} else if (e instanceof HttpException) {
return http(e);
} else if (e instanceof SocketException) {
return socket(e);
}
return http(e);
}
public static AppException run(Exception e) {
return new AppException(TYPE_RUN, 0, e);
}
/**
* 获取APP异常崩溃处理对象
*
* @param context
* @return
*/
public static AppException getAppExceptionHandler(Context context) {
return new AppException(context.getApplicationContext());
}
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex)) {
System.exit(0);
}
}
/**
* 自定义异常处理:收集错误信息&发送错误报告
*
* @param ex
* @return true:处理了该异常信息;否则返回false
*/
private boolean handleException(final Throwable ex) {
if (ex == null || mContext == null) {
return false;
}
boolean success = true;
try {
success = saveToSDCard(ex);
} catch (Exception e) {
} finally {
if (!success) {
return false;
} else {
final Context context = AppManager.getAppManager()
.currentActivity();
// 显示异常信息&发送报告
new Thread() {
@Override
public void run() {
Looper.prepare();
// 拿到未捕获的异常,
UIHelper.sendAppCrashReport(context);
Looper.loop();
}
}.start();
}
}
return true;
}
private boolean saveToSDCard(Throwable ex) throws Exception {
boolean append = false;
File file = FileUtils.getSaveFile("OSChina", "OSCLog.log");
if (System.currentTimeMillis() - file.lastModified() > 5000) {
append = true;
}
PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(
file, append)));
// 导出发生异常的时间
pw.println(SystemTool.getDataTime("yyyy-MM-dd-HH-mm-ss"));
// 导出手机信息
dumpPhoneInfo(pw);
pw.println();
// 导出异常的调用栈信息
ex.printStackTrace(pw);
pw.println();
pw.close();
return append;
}
private void dumpPhoneInfo(PrintWriter pw) throws NameNotFoundException {
// 应用的版本名称和版本号
PackageManager pm = mContext.getPackageManager();
PackageInfo pi = pm.getPackageInfo(mContext.getPackageName(),
PackageManager.GET_ACTIVITIES);
pw.print("App Version: ");
pw.print(pi.versionName);
pw.print('_');
pw.println(pi.versionCode);
pw.println();
// android版本号
pw.print("OS Version: ");
pw.print(Build.VERSION.RELEASE);
pw.print("_");
pw.println(Build.VERSION.SDK_INT);
pw.println();
// 手机制造商
pw.print("Vendor: ");
pw.println(Build.MANUFACTURER);
pw.println();
// 手机型号
pw.print("Model: ");
pw.println(Build.MODEL);
pw.println();
// cpu架构
pw.print("CPU ABI: ");
pw.println(Build.CPU_ABI);
pw.println();
}
}
AppManager.java
package net.oschina.app;
import java.util.Stack;
import android.app.Activity;
import android.content.Context;
/**
* activity堆栈式管理
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年10月30日 下午6:22:05
*
*/
public class AppManager {
private static Stack activityStack;
private static AppManager instance;
private AppManager() {}
/**
* 单一实例
*/
public static AppManager getAppManager() {
if (instance == null) {
instance = new AppManager();
}
return instance;
}
/**
* 添加Activity到堆栈
*/
public void addActivity(Activity activity) {
if (activityStack == null) {
activityStack = new Stack();
}
activityStack.add(activity);
}
/**
* 获取当前Activity(堆栈中最后一个压入的)
*/
public Activity currentActivity() {
Activity activity = activityStack.lastElement();
return activity;
}
/**
* 结束当前Activity(堆栈中最后一个压入的)
*/
public void finishActivity() {
Activity activity = activityStack.lastElement();
finishActivity(activity);
}
/**
* 结束指定的Activity
*/
public void finishActivity(Activity activity) {
if (activity != null && !activity.isFinishing()) {
activityStack.remove(activity);
activity.finish();
activity = null;
}
}
/**
* 结束指定类名的Activity
*/
public void finishActivity(Class> cls) {
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
finishActivity(activity);
break;
}
}
}
/**
* 结束所有Activity
*/
public void finishAllActivity() {
for (int i = 0, size = activityStack.size(); i < size; i++) {
if (null != activityStack.get(i)) {
finishActivity(activityStack.get(i));
break;
}
}
activityStack.clear();
}
/**
* 获取指定的Activity
*
* @author kymjs
*/
public static Activity getActivity(Class> cls) {
if (activityStack != null)
for (Activity activity : activityStack) {
if (activity.getClass().equals(cls)) {
return activity;
}
}
return null;
}
/**
* 退出应用程序
*/
public void AppExit(Context context) {
try {
finishAllActivity();
// 杀死该应用进程
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
} catch (Exception e) {
}
}
}
AppStart.java
package net.oschina.app;
import java.io.File;
import net.oschina.app.ui.MainActivity;
import net.oschina.app.util.TDevice;
import org.kymjs.kjframe.http.KJAsyncTask;
import org.kymjs.kjframe.utils.FileUtils;
import org.kymjs.kjframe.utils.PreferenceHelper;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.Animation.AnimationListener;
/**
* 应用启动界面
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年12月22日 上午11:51:56
*
*/
public class AppStart extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 防止第三方跳转时出现双实例
Activity aty = AppManager.getActivity(MainActivity.class);
if (aty != null && !aty.isFinishing()) {
finish();
}
// SystemTool.gc(this); //针对性能好的手机使用,加快应用相应速度
final View view = View.inflate(this, R.layout.app_start, null);
setContentView(view);
// 渐变展示启动屏
AlphaAnimation aa = new AlphaAnimation(0.5f, 1.0f);
aa.setDuration(800);
view.startAnimation(aa);
aa.setAnimationListener(new AnimationListener() {
@Override
public void onAnimationEnd(Animation arg0) {
redirectTo();
}
@Override
public void onAnimationRepeat(Animation animation) {}
@Override
public void onAnimationStart(Animation animation) {}
});
}
@Override
protected void onResume() {
super.onResume();
int cacheVersion = PreferenceHelper.readInt(this, "first_install",
"first_install", -1);
int currentVersion = TDevice.getVersionCode();
if (cacheVersion < currentVersion) {
PreferenceHelper.write(this, "first_install", "first_install",
currentVersion);
cleanImageCache();
}
}
private void cleanImageCache() {
final File folder = FileUtils.getSaveFolder("OSChina/imagecache");
KJAsyncTask.execute(new Runnable() {
@Override
public void run() {
for (File file : folder.listFiles()) {
file.delete();
}
}
});
}
/**
* 跳转到...
*/
private void redirectTo() {
Intent uploadLog = new Intent(this, LogUploadService.class);
startService(uploadLog);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}
LogUploadService.java
package net.oschina.app;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.util.StringUtils;
import org.apache.http.Header;
import org.kymjs.kjframe.utils.FileUtils;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import com.loopj.android.http.AsyncHttpResponseHandler;
public class LogUploadService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
final File log = FileUtils.getSaveFile("OSChina", "OSCLog.log");
String data = null;
try {
FileInputStream inputStream = new FileInputStream(log);
data = StringUtils.toConvertString(inputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
if (!StringUtils.isEmpty(data)) {
OSChinaApi.uploadLog(data, new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
log.delete();
LogUploadService.this.stopSelf();
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
LogUploadService.this.stopSelf();
}
});
} else {
LogUploadService.this.stopSelf();
}
return super.onStartCommand(intent, flags, startId);
}
}
ActiveAdapter.java
package net.oschina.app.adapter;
import net.oschina.app.R;
import net.oschina.app.base.ListBaseAdapter;
import net.oschina.app.bean.Active;
import net.oschina.app.bean.Active.ObjectReply;
import net.oschina.app.bean.Tweet;
import net.oschina.app.emoji.InputHelper;
import net.oschina.app.ui.ImagePreviewActivity;
import net.oschina.app.util.ImageUtils;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.UIHelper;
import net.oschina.app.widget.AvatarView;
import net.oschina.app.widget.MyLinkMovementMethod;
import net.oschina.app.widget.MyURLSpan;
import net.oschina.app.widget.TweetTextView;
import org.kymjs.kjframe.KJBitmap;
import org.kymjs.kjframe.bitmap.BitmapCallBack;
import org.kymjs.kjframe.bitmap.BitmapHelper;
import org.kymjs.kjframe.utils.DensityUtils;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.text.Html;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.ImageSpan;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
public class ActiveAdapter extends ListBaseAdapter {
private final static String AT_HOST_PRE = "http://my.oschina.net";
private final static String MAIN_HOST = "http://www.oschina.net";
public ActiveAdapter() {}
private Bitmap recordBitmap;
private final KJBitmap kjb = new KJBitmap();
private int rectSize;
private void initRecordImg(Context cxt) {
recordBitmap = BitmapFactory.decodeResource(cxt.getResources(),
R.drawable.audio3);
recordBitmap = ImageUtils.zoomBitmap(recordBitmap,
DensityUtils.dip2px(cxt, 20f), DensityUtils.dip2px(cxt, 20f));
}
private void initImageSize(Context cxt) {
if (cxt != null && rectSize == 0) {
rectSize = (int) cxt.getResources().getDimension(R.dimen.space_100);
} else {
rectSize = 300;
}
}
@Override
@SuppressLint("InflateParams")
protected View getRealView(int position, View convertView,
final ViewGroup parent) {
ViewHolder vh = null;
initImageSize(parent.getContext());
if (convertView == null || convertView.getTag() == null) {
convertView = getLayoutInflater(parent.getContext()).inflate(
R.layout.list_cell_active, null);
vh = new ViewHolder(convertView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
final Active item = (Active) mDatas.get(position);
vh.name.setText(item.getAuthor());
vh.action.setText(UIHelper.parseActiveAction(item.getObjectType(),
item.getObjectCatalog(), item.getObjectTitle()));
if (TextUtils.isEmpty(item.getMessage())) {
vh.body.setVisibility(View.GONE);
} else {
vh.body.setMovementMethod(MyLinkMovementMethod.a());
vh.body.setFocusable(false);
vh.body.setDispatchToParent(true);
vh.body.setLongClickable(false);
Spanned span = Html.fromHtml(modifyPath(item.getMessage()));
if (!StringUtils.isEmpty(item.getTweetattach())) {
if (recordBitmap == null) {
initRecordImg(parent.getContext());
}
ImageSpan recordImg = new ImageSpan(parent.getContext(),
recordBitmap);
SpannableString str = new SpannableString("c");
str.setSpan(recordImg, 0, 1, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);
vh.body.setText(str);
span = InputHelper.displayEmoji(parent.getContext()
.getResources(), span);
vh.body.append(span);
} else {
span = InputHelper.displayEmoji(parent.getContext()
.getResources(), span);
vh.body.setText(span);
}
MyURLSpan.parseLinkText(vh.body, span);
}
ObjectReply reply = item.getObjectReply();
if (reply != null) {
vh.reply.setMovementMethod(MyLinkMovementMethod.a());
vh.reply.setFocusable(false);
vh.reply.setDispatchToParent(true);
vh.reply.setLongClickable(false);
Spanned span = UIHelper.parseActiveReply(reply.objectName,
reply.objectBody);
vh.reply.setText(span);//
MyURLSpan.parseLinkText(vh.reply, span);
vh.lyReply.setVisibility(TextView.VISIBLE);
} else {
vh.reply.setText("");
vh.lyReply.setVisibility(TextView.GONE);
}
vh.time.setText(StringUtils.friendly_time(item.getPubDate()));
vh.from.setVisibility(View.VISIBLE);
switch (item.getAppClient()) {
default:
vh.from.setText(R.string.from_web); // 不显示
vh.from.setVisibility(View.GONE);
break;
case Tweet.CLIENT_MOBILE:
vh.from.setText(R.string.from_mobile);
break;
case Tweet.CLIENT_ANDROID:
vh.from.setText(R.string.from_android);
break;
case Tweet.CLIENT_IPHONE:
vh.from.setText(R.string.from_iphone);
break;
case Tweet.CLIENT_WINDOWS_PHONE:
vh.from.setText(R.string.from_windows_phone);
break;
case Tweet.CLIENT_WECHAT:
vh.from.setText(R.string.from_wechat);
break;
}
if (item.getCommentCount() > 0) {
vh.commentCount.setText(String.valueOf(item.getCommentCount()));
vh.commentCount.setVisibility(View.VISIBLE);
} else {
vh.commentCount.setVisibility(View.GONE);
}
vh.avatar.setUserInfo(item.getAuthorId(), item.getAuthor());
vh.avatar.setAvatarUrl(item.getPortrait());
if (!TextUtils.isEmpty(item.getTweetimage())) {
setTweetImage(parent, vh, item);
} else {
vh.pic.setVisibility(View.GONE);
vh.pic.setImageBitmap(null);
}
return convertView;
}
/**
* 动态设置图片显示样式
*
* @author kymjs
*/
private void setTweetImage(final ViewGroup parent, final ViewHolder vh,
final Active item) {
vh.pic.setVisibility(View.VISIBLE);
kjb.display(vh.pic, item.getTweetimage(), R.drawable.pic_bg, rectSize,
rectSize, new BitmapCallBack() {
@Override
public void onSuccess(Bitmap bitmap) {
super.onSuccess(bitmap);
if (bitmap != null) {
bitmap = BitmapHelper.scaleWithXY(bitmap, rectSize
/ bitmap.getHeight());
vh.pic.setImageBitmap(bitmap);
}
}
});
vh.pic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImagePreviewActivity.showImagePrivew(parent.getContext(), 0,
new String[] { getOriginalUrl(item.getTweetimage()) });
}
});
}
private String modifyPath(String message) {
message = message.replaceAll("(]+href=\")/([\\S]+)\"", "$1"
+ AT_HOST_PRE + "/$2\"");
message = message.replaceAll(
"(]+href=\")http://m.oschina.net([\\S]+)\"", "$1"
+ MAIN_HOST + "$2\"");
return message;
}
private String getOriginalUrl(String url) {
return url.replaceAll("_thumb", "");
}
static class ViewHolder {
@InjectView(R.id.tv_name)
TextView name;
@InjectView(R.id.tv_from)
TextView from;
@InjectView(R.id.tv_time)
TextView time;
@InjectView(R.id.tv_action)
TextView action;
@InjectView(R.id.tv_action_name)
TextView actionName;
@InjectView(R.id.tv_comment_count)
TextView commentCount;
// @InjectView(R.id.tv_reply_content)
// TextView retweetCount;
@InjectView(R.id.tv_body)
TweetTextView body;
@InjectView(R.id.tv_reply)
TweetTextView reply;
@InjectView(R.id.iv_pic)
ImageView pic;
@InjectView(R.id.ly_reply)
View lyReply;
@InjectView(R.id.iv_avatar)
AvatarView avatar;
public ViewHolder(View view) {
ButterKnife.inject(this, view);
}
}
}
BlogAdapter.java
package net.oschina.app.adapter;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.base.ListBaseAdapter;
import net.oschina.app.bean.Blog;
import net.oschina.app.bean.BlogList;
import net.oschina.app.util.StringUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* @author HuangWenwei
*
* @date 2014年9月29日
*/
public class BlogAdapter extends ListBaseAdapter {
static class ViewHolder {
@InjectView(R.id.tv_title)
TextView title;
@InjectView(R.id.tv_description)
TextView description;
@InjectView(R.id.tv_source)
TextView source;
@InjectView(R.id.tv_time)
TextView time;
@InjectView(R.id.tv_comment_count)
TextView comment_count;
@InjectView(R.id.iv_tip)
ImageView tip;
public ViewHolder(View view) {
ButterKnife.inject(this, view);
}
}
@Override
protected View getRealView(int position, View convertView, ViewGroup parent) {
ViewHolder vh = null;
if (convertView == null || convertView.getTag() == null) {
convertView = getLayoutInflater(parent.getContext()).inflate(
R.layout.list_cell_news, null);
vh = new ViewHolder(convertView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
Blog blog = mDatas.get(position);
vh.tip.setVisibility(View.VISIBLE);
if (blog.getDocumenttype() == Blog.DOC_TYPE_ORIGINAL) {
vh.tip.setImageResource(R.drawable.widget_original_icon);
} else {
vh.tip.setImageResource(R.drawable.widget_repaste_icon);
}
vh.title.setText(blog.getTitle());
if (AppContext.isOnReadedPostList(BlogList.PREF_READED_BLOG_LIST,
blog.getId() + "")) {
vh.title.setTextColor(parent.getContext().getResources()
.getColor(R.color.main_gray));
} else {
vh.title.setTextColor(parent.getContext().getResources()
.getColor(R.color.main_black));
}
vh.description.setVisibility(View.GONE);
String description = blog.getBody();
if (null != description && !StringUtils.isEmpty(description)) {
vh.description.setVisibility(View.VISIBLE);
vh.description.setText(description.trim());
}
vh.source.setText(blog.getAuthor());
vh.time.setText(StringUtils.friendly_time(blog.getPubDate()));
vh.comment_count.setText(blog.getCommentCount() + "");
return convertView;
}
}
RecycleBin.java
package net.oschina.app.adapter;
import android.annotation.SuppressLint;
import android.os.Build;
import android.util.SparseArray;
import android.view.View;
/**
* The RecycleBin facilitates reuse of views across layouts. The RecycleBin has two levels of
* storage: ActiveViews and ScrapViews. ActiveViews are those views which were onscreen at the
* start of a layout. By construction, they are displaying current information. At the end of
* layout, all views in ActiveViews are demoted to ScrapViews. ScrapViews are old views that
* could potentially be used by the adapter to avoid allocating views unnecessarily.
*
* This class was taken from Android's implementation of {@link android.widget.AbsListView} which
* is copyrighted 2006 The Android Open Source Project.
*/
public class RecycleBin {
/**
* Views that were on screen at the start of layout. This array is populated at the start of
* layout, and at the end of layout all view in activeViews are moved to scrapViews.
* Views in activeViews represent a contiguous range of Views, with position of the first
* view store in mFirstActivePosition.
*/
private View[] activeViews = new View[0];
private int[] activeViewTypes = new int[0];
/** Unsorted views that can be used by the adapter as a convert view. */
private SparseArray[] scrapViews;
private int viewTypeCount;
private SparseArray currentScrapViews;
public void setViewTypeCount(int viewTypeCount) {
if (viewTypeCount < 1) {
throw new IllegalArgumentException("Can't have a viewTypeCount < 1");
}
//noinspection unchecked
SparseArray[] scrapViews = new SparseArray[viewTypeCount];
for (int i = 0; i < viewTypeCount; i++) {
scrapViews[i] = new SparseArray();
}
this.viewTypeCount = viewTypeCount;
currentScrapViews = scrapViews[0];
this.scrapViews = scrapViews;
}
protected boolean shouldRecycleViewType(int viewType) {
return viewType >= 0;
}
/** @return A view from the ScrapViews collection. These are unordered. */
View getScrapView(int position, int viewType) {
if (viewTypeCount == 1) {
return retrieveFromScrap(currentScrapViews, position);
} else if (viewType >= 0 && viewType < scrapViews.length) {
return retrieveFromScrap(scrapViews[viewType], position);
}
return null;
}
/**
* Put a view into the ScrapViews list. These views are unordered.
*
* @param scrap The view to add
*/
@SuppressLint("NewApi")
void addScrapView(View scrap, int position, int viewType) {
if (viewTypeCount == 1) {
currentScrapViews.put(position, scrap);
} else {
scrapViews[viewType].put(position, scrap);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
scrap.setAccessibilityDelegate(null);
}
}
/** Move all views remaining in activeViews to scrapViews. */
@SuppressLint("NewApi")
void scrapActiveViews() {
final View[] activeViews = this.activeViews;
final int[] activeViewTypes = this.activeViewTypes;
final boolean multipleScraps = viewTypeCount > 1;
SparseArray scrapViews = currentScrapViews;
final int count = activeViews.length;
for (int i = count - 1; i >= 0; i--) {
final View victim = activeViews[i];
if (victim != null) {
int whichScrap = activeViewTypes[i];
activeViews[i] = null;
activeViewTypes[i] = -1;
if (!shouldRecycleViewType(whichScrap)) {
continue;
}
if (multipleScraps) {
scrapViews = this.scrapViews[whichScrap];
}
scrapViews.put(i, victim);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
victim.setAccessibilityDelegate(null);
}
}
}
pruneScrapViews();
}
/**
* Makes sure that the size of scrapViews does not exceed the size of activeViews.
* (This can happen if an adapter does not recycle its views).
*/
private void pruneScrapViews() {
final int maxViews = activeViews.length;
final int viewTypeCount = this.viewTypeCount;
final SparseArray[] scrapViews = this.scrapViews;
for (int i = 0; i < viewTypeCount; ++i) {
final SparseArray scrapPile = scrapViews[i];
int size = scrapPile.size();
final int extras = size - maxViews;
size--;
for (int j = 0; j < extras; j++) {
scrapPile.remove(scrapPile.keyAt(size--));
}
}
}
static View retrieveFromScrap(SparseArray scrapViews, int position) {
int size = scrapViews.size();
if (size > 0) {
// See if we still have a view for this position.
for (int i = 0; i < size; i++) {
int fromPosition = scrapViews.keyAt(i);
View view = scrapViews.get(fromPosition);
if (fromPosition == position) {
scrapViews.remove(fromPosition);
return view;
}
}
int index = size - 1;
View r = scrapViews.valueAt(index);
scrapViews.remove(scrapViews.keyAt(index));
return r;
} else {
return null;
}
}
}
ViewPageFragmentAdapter.java
package net.oschina.app.adapter;
import java.util.ArrayList;
import net.oschina.app.R;
import net.oschina.app.widget.PagerSlidingTabStrip;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
@SuppressLint("Recycle")
public class ViewPageFragmentAdapter extends FragmentStatePagerAdapter {
private final Context mContext;
protected PagerSlidingTabStrip mPagerStrip;
private final ViewPager mViewPager;
private final ArrayList mTabs = new ArrayList();
public ViewPageFragmentAdapter(FragmentManager fm,
PagerSlidingTabStrip pageStrip, ViewPager pager) {
super(fm);
mContext = pager.getContext();
mPagerStrip = pageStrip;
mViewPager = pager;
mViewPager.setAdapter(this);
mPagerStrip.setViewPager(mViewPager);
}
public void addTab(String title, String tag, Class> clss, Bundle args) {
ViewPageInfo viewPageInfo = new ViewPageInfo(title, tag, clss, args);
addFragment(viewPageInfo);
}
public void addAllTab(ArrayList mTabs) {
for (ViewPageInfo viewPageInfo : mTabs) {
addFragment(viewPageInfo);
}
}
private void addFragment(ViewPageInfo info) {
if (info == null) {
return;
}
// 加入tab title
View v = LayoutInflater.from(mContext).inflate(
R.layout.base_viewpage_fragment_tab_item, null, false);
TextView title = (TextView) v.findViewById(R.id.tab_title);
title.setText(info.title);
mPagerStrip.addTab(v);
mTabs.add(info);
notifyDataSetChanged();
}
/**
* 移除第一次
*/
public void remove() {
remove(0);
}
/**
* 移除一个tab
*
* @param index
* 备注:如果index小于0,则从第一个开始删 如果大于tab的数量值则从最后一个开始删除
*/
public void remove(int index) {
if (mTabs.isEmpty()) {
return;
}
if (index < 0) {
index = 0;
}
if (index >= mTabs.size()) {
index = mTabs.size() - 1;
}
mTabs.remove(index);
mPagerStrip.removeTab(index, 1);
notifyDataSetChanged();
}
/**
* 移除所有的tab
*/
public void removeAll() {
if (mTabs.isEmpty()) {
return;
}
mPagerStrip.removeAllTab();
mTabs.clear();
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public int getItemPosition(Object object) {
return PagerAdapter.POSITION_NONE;
}
@Override
public Fragment getItem(int position) {
ViewPageInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public CharSequence getPageTitle(int position) {
return mTabs.get(position).title;
}
}
ApiClientHelper.java
package net.oschina.app.api;
import net.oschina.app.AppContext;
public class ApiClientHelper {
/**
* 获得请求的服务端数据的userAgent
* @param appContext
* @return
*/
public static String getUserAgent(AppContext appContext) {
StringBuilder ua = new StringBuilder("OSChina.NET");
ua.append('/' + appContext.getPackageInfo().versionName + '_'
+ appContext.getPackageInfo().versionCode);// app版本信息
ua.append("/Android");// 手机系统平台
ua.append("/" + android.os.Build.VERSION.RELEASE);// 手机系统版本
ua.append("/" + android.os.Build.MODEL); // 手机型号
ua.append("/" + appContext.getAppId());// 客户端唯一标识
return ua.toString();
}
}
ApiHttpClient.java
package net.oschina.app.api;
import java.util.Locale;
import net.oschina.app.AppContext;
import net.oschina.app.util.TLog;
import org.apache.http.client.params.ClientPNames;
import android.content.Context;
import android.util.Log;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
public class ApiHttpClient {
public final static String HOST = "www.oschina.net";
private static String API_URL = "http://www.oschina.net/%s";
// public final static String HOST = "192.168.1.46";
// private static String API_URL = "http://192.168.1.46/%s";
public static final String DELETE = "DELETE";
public static final String GET = "GET";
public static final String POST = "POST";
public static final String PUT = "PUT";
public static AsyncHttpClient client;
public ApiHttpClient() {}
public static AsyncHttpClient getHttpClient() {
return client;
}
public static void cancelAll(Context context) {
client.cancelRequests(context, true);
}
public static void clearUserCookies(Context context) {
// (new HttpClientCookieStore(context)).a();
}
public static void delete(String partUrl, AsyncHttpResponseHandler handler) {
client.delete(getAbsoluteApiUrl(partUrl), handler);
log(new StringBuilder("DELETE ").append(partUrl).toString());
}
public static void get(String partUrl, AsyncHttpResponseHandler handler) {
client.get(getAbsoluteApiUrl(partUrl), handler);
log(new StringBuilder("GET ").append(partUrl).toString());
}
public static void get(String partUrl, RequestParams params,
AsyncHttpResponseHandler handler) {
client.get(getAbsoluteApiUrl(partUrl), params, handler);
log(new StringBuilder("GET ").append(partUrl).append("&")
.append(params).toString());
}
public static String getAbsoluteApiUrl(String partUrl) {
String url = String.format(API_URL, partUrl);
Log.d("BASE_CLIENT", "request:" + url);
return url;
}
public static String getApiUrl() {
return API_URL;
}
public static void getDirect(String url, AsyncHttpResponseHandler handler) {
client.get(url, handler);
log(new StringBuilder("GET ").append(url).toString());
}
public static void log(String log) {
Log.d("BaseApi", log);
TLog.log("Test", log);
}
public static void post(String partUrl, AsyncHttpResponseHandler handler) {
client.post(getAbsoluteApiUrl(partUrl), handler);
log(new StringBuilder("POST ").append(partUrl).toString());
}
public static void post(String partUrl, RequestParams params,
AsyncHttpResponseHandler handler) {
client.post(getAbsoluteApiUrl(partUrl), params, handler);
log(new StringBuilder("POST ").append(partUrl).append("&")
.append(params).toString());
}
public static void postDirect(String url, RequestParams params,
AsyncHttpResponseHandler handler) {
client.post(url, params, handler);
log(new StringBuilder("POST ").append(url).append("&").append(params)
.toString());
}
public static void put(String partUrl, AsyncHttpResponseHandler handler) {
client.put(getAbsoluteApiUrl(partUrl), handler);
log(new StringBuilder("PUT ").append(partUrl).toString());
}
public static void put(String partUrl, RequestParams params,
AsyncHttpResponseHandler handler) {
client.put(getAbsoluteApiUrl(partUrl), params, handler);
log(new StringBuilder("PUT ").append(partUrl).append("&")
.append(params).toString());
}
public static void setApiUrl(String apiUrl) {
API_URL = apiUrl;
}
public static void setHttpClient(AsyncHttpClient c) {
client = c;
client.addHeader("Accept-Language", Locale.getDefault().toString());
client.addHeader("Host", HOST);
client.addHeader("Connection", "Keep-Alive");
client.getHttpClient().getParams()
.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);
setUserAgent(ApiClientHelper.getUserAgent(AppContext.getInstance()));
}
public static void setUserAgent(String userAgent) {
client.setUserAgent(userAgent);
}
public static void setCookie(String cookie) {
client.addHeader("Cookie", cookie);
}
private static String appCookie;
public static void cleanCookie() {
appCookie = "";
}
public static String getCookie(AppContext appContext) {
if (appCookie == null || appCookie == "") {
appCookie = appContext.getProperty("cookie");
}
return appCookie;
}
}
ApiResponse.java
package net.oschina.app.api;
import org.json.JSONObject;
public class ApiResponse {
protected Object _data;
protected String _message;
protected int _errorCode;
protected boolean _isOk;
private long _total;
private String _serverTime;
private boolean isCanceled;
public ApiResponse(JSONObject json) {
if (json != null) {
setData(json.optJSONObject("data") == null ? json
.optJSONArray("data") : json.optJSONObject("data"));
setMessage(json.optString("result_desc"));
setErrorCode(json.optInt("result_code"));
setOk(getErrorCode() == 0);
setServerTime(json.optString("timestamp"));
}
}
public Object getData() {
return _data;
}
public void setData(Object _data) {
this._data = _data;
}
public boolean isOk() {
return _isOk;
}
public void setOk(boolean _isOk) {
this._isOk = _isOk;
}
public String getMessage() {
return _message;
}
public void setMessage(String _message) {
this._message = _message;
}
public int getErrorCode() {
return _errorCode;
}
public void setErrorCode(int _errorCode) {
this._errorCode = _errorCode;
}
@Override
public String toString() {
return "data:" + getData() + " message:" + getMessage() + " errocode:"
+ _errorCode;
}
public void update(ApiResponse response) {
_message = response.getMessage();
}
public void setTotal(long total) {
_total = total;
}
public long getTotal() {
return _total;
}
public String getServerTime() {
return _serverTime;
}
public void setServerTime(String _serverTime) {
this._serverTime = _serverTime;
}
public boolean isCanceled() {
return isCanceled;
}
public void setCanceled(boolean isCanceled) {
this.isCanceled = isCanceled;
}
}
OperationResponseHandler.java
package net.oschina.app.api;
import java.io.ByteArrayInputStream;
import org.apache.http.Header;
import android.os.Looper;
import com.loopj.android.http.AsyncHttpResponseHandler;
public class OperationResponseHandler extends AsyncHttpResponseHandler {
private Object[] args;
public OperationResponseHandler(Looper looper, Object... args) {
super(looper);
this.args = args;
}
public OperationResponseHandler(Object... args) {
this.args = args;
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2, Throwable arg3) {
onFailure(arg0, arg3.getMessage(), args);
}
public void onFailure(int code, String errorMessage, Object[] args) {
}
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
onSuccess(arg0, new ByteArrayInputStream(arg2), args);
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, e.getMessage(), args);
}
}
public void onSuccess(int code, ByteArrayInputStream is, Object[] args)
throws Exception {
}
}
OSChinaApi.java
package net.oschina.app.api.remote;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.URLEncoder;
import net.oschina.app.AppContext;
import net.oschina.app.AppException;
import net.oschina.app.api.ApiHttpClient;
import net.oschina.app.bean.EventApplyData;
import net.oschina.app.bean.NewsList;
import net.oschina.app.bean.Report;
import net.oschina.app.bean.Tweet;
import net.oschina.app.team.bean.Team;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TLog;
import org.kymjs.kjframe.utils.KJLoger;
import android.text.TextUtils;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
public class OSChinaApi {
/**
* 登陆
*
* @param username
* @param password
* @param handler
*/
public static void login(String username, String password,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("username", username);
params.put("pwd", password);
params.put("keep_login", 1);
String loginurl = "action/api/login_validate";
ApiHttpClient.post(loginurl, params, handler);
}
/**
* 获取新闻列表
*
* @param catalog
* 类别 (1,2,3)
* @param page
* 第几页
* @param handler
*/
public static void getNewsList(int catalog, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
if (catalog == NewsList.CATALOG_WEEK) {
params.put("show", "week");
} else if (catalog == NewsList.CATALOG_MONTH) {
params.put("show", "month");
}
ApiHttpClient.get("action/api/news_list", params, handler);
}
public static void getBlogList(String type, int pageIndex,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("type", type);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/blog_list", params, handler);
}
public static void getPostList(int catalog, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/post_list", params, handler);
}
public static void getPostListByTag(String tag, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("tag", tag);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/post_list", params, handler);
}
public static void getTweetList(int uid, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/tweet_list", params, handler);
}
public static void getTweetTopicList(int page, String topic,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("pageIndex", page);
params.put("title", topic);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/tweet_topic_list", params, handler);
}
public static void getTweetLikeList(AsyncHttpResponseHandler handler) {
ApiHttpClient.get("action/api/my_tweet_like_list", handler);
}
public static void pubLikeTweet(int tweetId, int authorId,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("tweetid", tweetId);
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("ownerOfTweet", authorId);
ApiHttpClient.post("action/api/tweet_like", params, handler);
}
public static void pubUnLikeTweet(int tweetId, int authorId,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("tweetid", tweetId);
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("ownerOfTweet", authorId);
ApiHttpClient.post("action/api/tweet_unlike", params, handler);
}
public static void getTweetLikeList(int tweetId, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("tweetid", tweetId);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/tweet_like_list", params, handler);
}
public static void getActiveList(int uid, int catalog, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("catalog", catalog);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/active_list", params, handler);
}
public static void getFriendList(int uid, int relation, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("relation", relation);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/friends_list", params, handler);
}
/**
* 获取用户收藏
*
* @param uid
* 指定用户UID
* @param type
* 收藏类型: 0:全部收藏 1:软件 2:话题 3:博客 4:新闻 5:代码
* @param page
* @param handler
*/
public static void getFavoriteList(int uid, int type, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("type", type);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/favorite_list", params, handler);
}
/**
* 分类列表
*
* @param tag
* 第一级:0
* @param handler
*/
public static void getSoftwareCatalogList(int tag,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams("tag", tag);
ApiHttpClient.get("action/api/softwarecatalog_list", params, handler);
}
public static void getSoftwareTagList(int searchTag, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("searchTag", searchTag);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/softwaretag_list", params, handler);
}
/**
* @param searchTag
* 软件分类 推荐:recommend 最新:time 热门:view 国产:list_cn
* @param page
* @param handler
*/
public static void getSoftwareList(String searchTag, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("searchTag", searchTag);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/software_list", params, handler);
}
/**
* 获取评论列表
*
* @param id
* @param catalog
* 1新闻 2帖子 3动弹 4动态
* @param page
* @param handler
*/
public static void getCommentList(int id, int catalog, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("id", id);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/comment_list", params, handler);
}
public static void getBlogCommentList(int id, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("id", id);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/blogcomment_list", params, handler);
}
public static void getUserInformation(int uid, int hisuid, String hisname,
int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("hisuid", hisuid);
params.put("hisname", hisname);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/user_information", params, handler);
}
@SuppressWarnings("deprecation")
public static void getUserBlogList(int authoruid, final String authorname,
final int uid, final int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("authoruid", authoruid);
params.put("authorname", URLEncoder.encode(authorname));
params.put("uid", uid);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/userblog_list", params, handler);
}
public static void updateRelation(int uid, int hisuid, int newrelation,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("hisuid", hisuid);
params.put("newrelation", newrelation);
ApiHttpClient.post("action/api/user_updaterelation", params, handler);
}
public static void getMyInformation(int uid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
ApiHttpClient.get("action/api/my_information", params, handler);
}
/**
* 获取新闻明细
*
* @param newsId
* @param handler
*/
public static void getNewsDetail(int id, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams("id", id);
ApiHttpClient.get("action/api/news_detail", params, handler);
}
public static void getBlogDetail(int id, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams("id", id);
ApiHttpClient.get("action/api/blog_detail", params, handler);
}
/**
* 获取软件详情
*
* @param ident
* @param handler
*/
public static void getSoftwareDetail(String ident,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams("ident",
ident.replace(" ", ""));
ApiHttpClient.get("action/api/software_detail", params, handler);
}
public static void getPostDetail(int id, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams("id", id);
ApiHttpClient.get("action/api/post_detail", params, handler);
}
public static void getTweetDetail(int id, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams("id", id);
ApiHttpClient.get("action/api/tweet_detail", params, handler);
}
/**
* 用户针对某个新闻,帖子,动弹,消息发表评论的接口,参数使用POST方式提交
*
* @param catalog
* 1新闻 2 帖子 3 动弹 4消息中心
* @param id
* 被评论的某条新闻,帖子,动弹或者某条消息的id
* @param uid
* 当天登陆用户的UID
* @param content
* 发表的评论内容
* @param isPostToMyZone
* 是否转发到我的空间,0不转发 1转发到我的空间(注意该功能之对某条动弹进行评论是有效,其他情况下服务器借口可以忽略该参数)
* @param handler
*/
public static void publicComment(int catalog, int id, int uid,
String content, int isPostToMyZone, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("id", id);
params.put("uid", uid);
params.put("content", content);
params.put("isPostToMyZone", isPostToMyZone);
ApiHttpClient.post("action/api/comment_pub", params, handler);
}
public static void replyComment(int id, int catalog, int replyid,
int authorid, int uid, String content,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("id", id);
params.put("uid", uid);
params.put("content", content);
params.put("replyid", replyid);
params.put("authorid", authorid);
ApiHttpClient.post("action/api/comment_reply", params, handler);
}
public static void publicBlogComment(int blog, int uid, String content,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("blog", blog);
params.put("uid", uid);
params.put("content", content);
ApiHttpClient.post("action/api/blogcomment_pub", params, handler);
}
public static void replyBlogComment(int blog, int uid, String content,
int reply_id, int objuid, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("blog", blog);
params.put("uid", uid);
params.put("content", content);
params.put("reply_id", reply_id);
params.put("objuid", objuid);
ApiHttpClient.post("action/api/blogcomment_pub", params, handler);
}
public static void pubTweet(Tweet tweet, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", tweet.getAuthorid());
params.put("msg", tweet.getBody());
// Map files = new HashMap();
if (!TextUtils.isEmpty(tweet.getImageFilePath())) {
try {
params.put("img", new File(tweet.getImageFilePath()));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
if (!TextUtils.isEmpty(tweet.getAudioPath())) {
try {
params.put("amr", new File(tweet.getAudioPath()));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
ApiHttpClient.post("action/api/tweet_pub", params, handler);
}
public static void pubSoftWareTweet(Tweet tweet, int softid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", tweet.getAuthorid());
params.put("msg", tweet.getBody());
params.put("project", softid);
ApiHttpClient.post("action/api/software_tweet_pub", params, handler);
}
public static void deleteTweet(int uid, int tweetid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("tweetid", tweetid);
ApiHttpClient.post("action/api/tweet_delete", params, handler);
}
public static void deleteComment(int id, int catalog, int replyid,
int authorid, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("id", id);
params.put("catalog", catalog);
params.put("replyid", replyid);
params.put("authorid", authorid);
ApiHttpClient.post("action/api/comment_delete", params, handler);
}
public static void deleteBlog(int uid, int authoruid, int id,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("authoruid", authoruid);
params.put("id", id);
ApiHttpClient.post("action/api/userblog_delete", params, handler);
}
public static void deleteBlogComment(int uid, int blogid, int replyid,
int authorid, int owneruid, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("blogid", blogid);
params.put("replyid", replyid);
params.put("authorid", authorid);
params.put("owneruid", owneruid);
ApiHttpClient.post("action/api/blogcomment_delete", params, handler);
}
/**
* 用户添加收藏
*
* @param uid
* 用户UID
* @param objid
* 比如是新闻ID 或者问答ID 或者动弹ID
* @param type
* 1:软件 2:话题 3:博客 4:新闻 5:代码
*/
public static void addFavorite(int uid, int objid, int type,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("objid", objid);
params.put("type", type);
ApiHttpClient.post("action/api/favorite_add", params, handler);
}
public static void delFavorite(int uid, int objid, int type,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("objid", objid);
params.put("type", type);
ApiHttpClient.post("action/api/favorite_delete", params, handler);
}
public static void getSearchList(String catalog, String content,
int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("catalog", catalog);
params.put("content", content);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/search_list", params, handler);
}
public static void publicMessage(int uid, int receiver, String content,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("receiver", receiver);
params.put("content", content);
ApiHttpClient.post("action/api/message_pub", params, handler);
}
public static void deleteMessage(int uid, int friendid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("friendid", friendid);
ApiHttpClient.post("action/api/message_delete", params, handler);
}
public static void forwardMessage(int uid, String receiverName,
String content, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("receiverName", receiverName);
params.put("content", content);
ApiHttpClient.post("action/api/message_pub", params, handler);
}
public static void getMessageList(int uid, int pageIndex,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/message_list", params, handler);
}
public static void updatePortrait(int uid, File portrait,
AsyncHttpResponseHandler handler) throws FileNotFoundException {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("portrait", portrait);
ApiHttpClient.post("action/api/portrait_update", params, handler);
}
public static void getNotices(AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
ApiHttpClient.get("action/api/user_notice", params, handler);
}
/**
* 清空通知消息
*
* @param uid
* @param type
* 1:@我的信息 2:未读消息 3:评论个数 4:新粉丝个数
* @return
* @throws AppException
*/
public static void clearNotice(int uid, int type,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("type", type);
ApiHttpClient.post("action/api/notice_clear", params, handler);
}
public static void singnIn(String url, AsyncHttpResponseHandler handler) {
ApiHttpClient.getDirect(url, handler);
}
/**
* 获取软件的动态列表
*
* @param softid
* @param handler
*/
public static void getSoftTweetList(int softid, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("project", softid);
params.put("pageIndex", page);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/software_tweet_list", params, handler);
}
public static void checkUpdate(AsyncHttpResponseHandler handler) {
ApiHttpClient.get("MobileAppVersion.xml", handler);
}
/**
* 查找用户
*
* @param username
* @param handler
*/
public static void findUser(String username,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("name", username);
ApiHttpClient.get("action/api/find_user", params, handler);
}
/**
* 获取活动列表
*
* @param pageIndex
* @param uid
* <= 0 近期活动 实际的用户ID 则获取用户参与的活动列表,需要已登陆的用户
* @param handler
*/
public static void getEventList(int pageIndex, int uid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("pageIndex", pageIndex);
params.put("uid", uid);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/event_list", params, handler);
}
/**
* 获取某活动已出席的人员列表
*
* @param eventId
* @param pageIndex
* @param handler
*/
public static void getEventApplies(int eventId, int pageIndex,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("pageIndex", pageIndex);
params.put("event_id", eventId);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/event_attend_user", params, handler);
}
/**
* 举报
*
* @param report
* @param handler
*/
public static void report(Report report, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("obj_id", report.getReportId());
params.put("url", report.getLinkAddress());
params.put("obj_type", report.getReason());
if (report.getOtherReason() != null
&& !StringUtils.isEmpty(report.getOtherReason())) {
params.put("memo", report.getOtherReason());
} else {
params.put("memo", "其他原因");
}
TLog.log("Test", report.getReportId() + "" + report.getLinkAddress()
+ report.getReason() + report.getOtherReason());
ApiHttpClient.post("action/communityManage/report", params, handler);
}
/**
* 摇一摇,随机数据
*
* @param handler
*/
public static void shake(AsyncHttpResponseHandler handler) {
shake(-1, handler);
}
/**
* 摇一摇指定请求类型
*/
public static void shake(int type, AsyncHttpResponseHandler handler) {
String inter = "action/api/rock_rock";
if (type > 0) {
inter = (inter + "/?type=" + type);
}
ApiHttpClient.get(inter, handler);
}
/**
* 活动报名
*
* @param data
* @param handler
*/
public static void eventApply(EventApplyData data,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("event", data.getEvent());
params.put("user", data.getUser());
params.put("name", data.getName());
params.put("gender", data.getGender());
params.put("mobile", data.getPhone());
params.put("company", data.getCompany());
params.put("job", data.getJob());
ApiHttpClient.post("action/api/event_apply", params, handler);
}
private static void uploadLog(String data, String report,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("app", "1");
params.put("report", report);
params.put("msg", data);
ApiHttpClient.post("action/api/user_report_to_admin", params, handler);
}
/**
* BUG上报
*
* @param data
* @param handler
*/
public static void uploadLog(String data, AsyncHttpResponseHandler handler) {
uploadLog(data, "1", handler);
}
/**
* 反馈意见
*
* @param data
* @param handler
*/
public static void feedback(String data, AsyncHttpResponseHandler handler) {
uploadLog(data, "2", handler);
}
/**
* team动态
*
* @param team
* @param page
* @param handler
*/
public static void teamDynamic(Team team, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
// int uid = AppContext.getInstance().getLoginUid();
// params.put("uid", uid);
params.put("teamid", team.getId());
params.put("pageIndex", page);
params.put("pageSize", 20);
params.put("type", "all");
ApiHttpClient.get("action/api/team_active_list", params, handler);
}
/**
* 获取team列表
*
* @param handler
*/
public static void teamList(AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
ApiHttpClient.get("action/api/team_list", params, handler);
}
/**
* 获取team成员列表
*
* @param handler
*/
public static void getTeamMemberList(int teamid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
ApiHttpClient.get("action/api/team_member_list", params, handler);
}
/**
* 获取team成员个人信息
*
* @param handler
*/
public static void getTeamUserInfo(String teamid, String uid,
int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("uid", uid);
params.put("pageIndex", pageIndex);
params.put("pageSize", 20);
ApiHttpClient.get("action/api/team_user_information", params, handler);
}
/**
* 获取我的任务中进行中、未完成、已完成等状态的数量
*/
public static void getMyIssueState(String teamid, String uid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("uid", uid);
ApiHttpClient.get("action/api/team_user_issue_information", params,
handler);
}
/**
* 获取指定用户的动态
*/
public static void getUserDynamic(int teamid, String uid, int pageIndex,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("pageIndex", pageIndex);
params.put("pageSize", 20);
params.put("type", "git");
params.put("uid", uid);
ApiHttpClient.get("action/api/team_active_list", params, handler);
}
/**
* 动态详情
*
* @param activeid
* @param teamid
* @param uid
* @param handler
*/
public static void getDynamicDetail(int activeid, int teamid, int uid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("uid", uid);
params.put("activeid", activeid);
ApiHttpClient.get("action/api/team_active_detail", params, handler);
}
/**
* 获取指定用户的任务
*/
public static void getMyIssue(String teamid, String uid, int pageIndex,
String type, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("uid", uid);
params.put("pageIndex", pageIndex);
params.put("pageSize", 20);
params.put("state", type);
params.put("projectid", "-1");
ApiHttpClient.get("action/api/team_issue_list", params, handler);
}
/**
* 获取指定周周报
*
* @param teamid
* @param year
* @param week
* @param handler
*/
public static void getDiaryFromWhichWeek(int teamid, int year, int week,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("year", year);
params.put("week", week);
ApiHttpClient.get("action/api/team_diary_list", params, handler);
}
/**
* 删除一个便签
*
* @param id
* 便签id
* @param uid
* 用户id
*/
public static void deleteNoteBook(int id, int uid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("id", id); // 便签id
ApiHttpClient
.get("action/api/team_stickynote_recycle", params, handler);
}
public static void getNoteBook(int uid, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
ApiHttpClient.get("action/api/team_sticky_list", params, handler);
}
/**
* 获取指定周报的详细信息
*
* @param teamid
* @param diaryid
* @param handler
*/
public static void getDiaryDetail(int teamid, int diaryid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("diaryid", diaryid);
ApiHttpClient.get("action/api/team_diary_detail", params, handler);
}
/**
* diary评论列表
*
* @param teamid
* @param diaryid
* @param handler
*/
public static void getDiaryComment(int teamid, int diaryid,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamid);
params.put("id", diaryid);
params.put("type", "diary");
params.put("pageIndex", 0);
params.put("pageSize", "20");
KJLoger.debug(teamid + "==getDiaryComment接口=" + diaryid);
ApiHttpClient
.get("action/api/team_reply_list_by_type", params, handler);
}
/**
* 周报评论(以后可改为全局评论)
*
* @param uid
* @param teamid
* @param diaryId
* @param content
* @param handler
*/
public static void sendComment(int uid, int teamid, int diaryId,
String content, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("teamid", teamid);
params.put("type", "118");
params.put("tweetid", diaryId);
params.put("content", content);
ApiHttpClient.post("action/api/team_tweet_reply", params, handler);
}
/***
* 客户端扫描二维码登陆
*
* @author 火蚁 2015-3-13 上午11:45:47
*
* @return void
* @param url
* @param handler
*/
public static void scanQrCodeLogin(String url,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
String uuid = url.substring(url.lastIndexOf("=") + 1);
params.put("uuid", uuid);
ApiHttpClient.getDirect(url, handler);
}
}
OSChinaTeamApi.java
package net.oschina.app.api.remote;
import java.io.File;
import java.io.FileNotFoundException;
import net.oschina.app.AppContext;
import net.oschina.app.api.ApiHttpClient;
import net.oschina.app.team.bean.TeamIssue;
import net.oschina.app.team.bean.TeamProject;
import android.text.TextUtils;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;
/**
* osc team api集合类
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2015年1月14日 下午3:32:18
*
*/
public class OSChinaTeamApi {
/**
* 获取团队项目列表
*
* @param teamId
* @param handler
*/
public static void getTeamProjectList(int teamId,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
ApiHttpClient.get("action/api/team_project_list", params, handler);
}
/**
* 获取team动态列表
*
* @param teamId
* @param activeId
* @param pageIndex
* @param handler
*/
public static void getTeamCommentList(int teamId, int activeId,
int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("id", activeId);
params.put("pageIndex", pageIndex);
params.put("pageSize", 20);
ApiHttpClient.get("action/api/team_reply_list_by_activeid", params,
handler);
}
/***
* 获取团队绑定项目的成员列表(包括管理员以及开发者)
*
* @author 火蚁 2015-2-5 下午6:45:41
*
* @return void
* @param teamId
* @param teamProject
* @param handler
*/
public static void getTeamProjectMemberList(int teamId,
TeamProject teamProject, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("projectid", teamProject.getGit().getId());
String source = teamProject.getSource();
if (source != null && !TextUtils.isEmpty(source)) {
params.put("source", teamProject.getSource());
}
ApiHttpClient.get("action/api/team_project_member_list", params,
handler);
}
/***
* 获取项目的动态列表
*
* @author 火蚁 2015-3-2 下午5:18:54
*
* @return void
* @param teamId
* @param project
* @param type
* "all"(default),"issue","code","other"
* @param page
* @param handler
*/
public static void getTeamProjectActiveList(int teamId,
TeamProject project, String type, int page,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("projectid", project.getGit().getId());
if (!TextUtils.isEmpty(project.getSource())) {
params.put("source", project.getSource());
}
params.put("type", type);
params.put("pageIndex", page);
ApiHttpClient.get("action/api/team_project_active_list", params,
handler);
}
/**
* 获取某项目的任务列表
*
* @param uId
* 用户id
* @param teamId
* 团队id
* @param projectId
* 项目id(当<=0或不设置时,查询非项目的任务列表)
* @param source
* "Git@OSC","GitHub"(只有设置了projectid值,这里才需要设置该值)
*/
public static void getTeamCatalogIssueList(int uId, int teamId,
int projectId, String source, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uId);
params.put("teamid", teamId);
params.put("projectid", projectId);
params.put("source", source);
ApiHttpClient.get("action/api/team_project_catalog_list", params,
handler);
}
/**
* 获取指定任务列表的任务列表
*
* @param teamId
* @param projectId
* 项目id(-1获取非项目任务列表, 0获取所有任务列表)
* @param catalogId
* 任务列表的的目录id
* @param source
* "Team@OSC"(default),"Git@OSC","GitHub",如果指定了projectid的值,
* 这个值就是必须的
* @param uid
* 如果指定该值,则获取该id用户相关的任务
* @param state
* "all"(default),"opened","closed","outdate"
* @param scope
* "tome"(default,指派给我的任务),"meto"(我指派的任务)
* @param pageIndex
* @param pageSize
* @param handler
*/
public static void getTeamIssueList(int teamId, int projectId,
int catalogId, String source, int uid, String state, String scope,
int pageIndex, int pageSize, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("projectid", projectId);
params.put("catalogid", catalogId);
params.put("source", source);
params.put("uid", uid);
params.put("state", state);
params.put("scope", scope);
params.put("pageIndex", pageIndex);
params.put("pageSize", pageSize);
ApiHttpClient.get("action/api/team_issue_list", params, handler);
}
/***
* 改变一个任务的状态
*
* @author 火蚁 2015-3-6 上午11:44:01
*
* @return void
* @param teamId
* @param issue
* @param target
* 修改的属性("state" : 状态, "assignee" 指派人, "deadline" : 截止日期)
* @param handler
*/
public static void changeIssueState(int teamId, TeamIssue issue,
String target, AsyncHttpResponseHandler handler) {
if (issue == null)
return;
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("teamid", teamId);
params.put("target", target);
params.put("issueid", issue.getId());
if (target.equals("state")) {
params.put("state", issue.getState());
} else if (target.equals("assignee")) {
params.put("assignee", issue.getToUser().getId());
} else if (target.equals("deadline")) {
params.put("deadline", issue.getDeadlineTime());
}
ApiHttpClient.post("action/api/team_issue_update", params, handler);
}
public static void pubTeamNewIssue(RequestParams params,
AsyncHttpResponseHandler handler) {
ApiHttpClient.post("action/api/team_issue_pub", params, handler);
}
/***
* 获取团队的讨论区列表
*
* @param type
* @param teamId
* @param uid
* @param pageIndex
* @param handler
*/
public static void getTeamDiscussList(String type, int teamId, int uid,
int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("type", type);
params.put("teamid", teamId);
params.put("uid", uid);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/team_discuss_list", params, handler);
}
/***
* 获取讨论贴详情
*
* @author 火蚁 2015-2-2 下午6:19:54
*
* @return void
* @param teamId
* @param discussId
* @param handler
*/
public static void getTeamDiscussDetail(int teamId, int discussId,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("discussid", discussId);
ApiHttpClient.get("action/api/team_discuss_detail", params, handler);
}
/***
* 发表讨论贴评论
*
* @author 火蚁 2015-2-3 下午2:42:54
*
* @return void
* @param uid
* @param teamId
* @param dicussId
* @param content
* @param handler
*/
public static void pubTeamDiscussReply(int uid, int teamId, int discussId,
String content, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("teamid", teamId);
params.put("discussid", discussId);
params.put("content", content);
ApiHttpClient.post("action/api/team_discuss_reply", params, handler);
}
/***
* 发表一条综合评论 动态、分享内容、周报
*
* @author 火蚁 2015-3-6 下午3:31:07
*
* @return void
* @param teamId
* @param type
* 普通动态-110,分享内容-114, 周报-118
* @param tweetId
* @param content
* @param handler
*/
public static void pubTeamTweetReply(int teamId, int type, long tweetId,
String content, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("type", type);
params.put("teamid", teamId);
params.put("tweetid", tweetId);
params.put("content", content);
ApiHttpClient.post("action/api/team_tweet_reply", params, handler);
}
/***
* 获取团队任务详情
*
* @author 火蚁 2015-1-27 下午7:47:17
*
*/
public static void getTeamIssueDetail(int teamId, int issueId,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("issueid", issueId);
ApiHttpClient.get("action/api/team_issue_detail", params, handler);
}
/***
* 获取团队的周报列表
*
* @param uid
* @param teamId
* @param year
* @param week
* @param pageIndex
* @param handler
*/
public static void getTeamDiaryList(int uid, int teamId, int year,
int week, int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", uid);
params.put("teamid", teamId);
params.put("year", year);
params.put("week", week);
params.put("pageIndex", pageIndex);
params.put("pageSize", AppContext.PAGE_SIZE);
ApiHttpClient.get("action/api/team_diary_list", params, handler);
}
/***
* 任务、周报、讨论的回复列表
*
* @author 火蚁 2015-2-2 上午11:39:04
*
* @return void
* @param teamId
* @param id
* @param type
* 评论列表的类型(周报diary,讨论discuss,任务issue)
* @param pageIndex
* @param handler
*/
public static void getTeamReplyList(int teamId, int id, String type,
int pageIndex, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("id", id);
params.put("type", type);
params.put("pageIndex", pageIndex);
ApiHttpClient
.get("action/api/team_reply_list_by_type", params, handler);
}
/***
* 发表一个新的团队动态
*
* @author 火蚁 2015-3-9 下午2:46:13
*
* @return void
* @param teamId
* @param content
* @param img
* @param handler
*/
public static void pubTeamNewActive(int teamId, String content, File img,
AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("teamid", teamId);
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("msg", content);
params.put("appid", 3);
if (img != null) {
try {
params.put("img", img);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
ApiHttpClient.post("action/api/team_tweet_pub", params, handler);
}
/***
* 更新子任务属性
*
* @author 火蚁 2015-3-10 下午4:53:49
*
* @return void
* @param teamId
* @param target
* @param childIssue
* @param handler
*/
public static void updateChildIssue(int teamId, String target,
TeamIssue childIssue, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("teamid", teamId);
params.put("childissueid", childIssue.getId());
params.put("target", target);
if (target.equals("state")) {
params.put("state", childIssue.getState());
} else {
params.put("title", childIssue.getTitle());
}
ApiHttpClient.post("action/api/team_issue_update_child_issue", params,
handler);
}
/***
* 发表任务评论
*
* @author 火蚁 2015-3-13 下午6:22:41
*
* @return void
* @param teamId
* @param issueId
* @param content
* @param handler
*/
public static void pubTeamIssueReply(int teamId, int issueId,
String content, AsyncHttpResponseHandler handler) {
RequestParams params = new RequestParams();
params.put("uid", AppContext.getInstance().getLoginUid());
params.put("teamid", teamId);
params.put("content", content);
params.put("issueid", issueId);
ApiHttpClient.post("action/api/team_issue_reply", params, handler);
}
}
Base.java
package net.oschina.app.bean;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 实体基类:实现序列化
* @author liux (http://my.oschina.net/liux)
* @version 1.0
* @created 2012-3-21
*/
@SuppressWarnings("serial")
public abstract class Base implements Serializable {
@XStreamAlias("notice")
protected Notice notice;
public Notice getNotice() {
return notice;
}
public void setNotice(Notice notice) {
this.notice = notice;
}
}
ListEntity.java
package net.oschina.app.bean;
import java.io.Serializable;
import java.util.List;
public interface ListEntity extends Serializable {
public List getList();
}
Entity.java
package net.oschina.app.bean;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 实体类
*
* @author liux (http://my.oschina.net/liux)
* @version 1.0
* @created 2012-3-21
*/
@SuppressWarnings("serial")
public abstract class Entity extends Base {
@XStreamAlias("id")
protected int id;
protected String cacheKey;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCacheKey() {
return cacheKey;
}
public void setCacheKey(String cacheKey) {
this.cacheKey = cacheKey;
}
}
Active.java
package net.oschina.app.bean;
import java.io.Serializable;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 动态实体类
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年10月22日 下午3:22:09
*
*/
@SuppressWarnings("serial")
@XStreamAlias("active")
public class Active extends Entity {
public final static int CATALOG_OTHER = 0;// 其他
public final static int CATALOG_NEWS = 1;// 新闻
public final static int CATALOG_POST = 2;// 帖子
public final static int CATALOG_TWEET = 3;// 动弹
public final static int CATALOG_BLOG = 4;// 博客
public final static int CLIENT_MOBILE = 2;
public final static int CLIENT_ANDROID = 3;
public final static int CLIENT_IPHONE = 4;
public final static int CLIENT_WINDOWS_PHONE = 5;
@XStreamAlias("portrait")
private String portrait;
@XStreamAlias("message")
private String message;
@XStreamAlias("author")
private String author;
@XStreamAlias("authorid")
private int authorId;
@XStreamAlias("activetype")
private int activeType;
@XStreamAlias("objectID")
private int objectId;
@XStreamAlias("catalog")
private int catalog;
@XStreamAlias("objecttype")
private int objectType;
@XStreamAlias("objectcatalog")
private int objectCatalog;
@XStreamAlias("objecttitle")
private String objectTitle;
@XStreamAlias("objectreply")
private ObjectReply objectReply;
@XStreamAlias("commentCount")
private int commentCount;
@XStreamAlias("pubDate")
private String pubDate;
@XStreamAlias("tweetimage")
private String tweetimage;
@XStreamAlias("tweetattach")
private String tweetattach;
@XStreamAlias("appclient")
private int appClient;
@XStreamAlias("url")
private String url;
public String getPortrait() {
return portrait;
}
public void setPortrait(String portrait) {
this.portrait = portrait;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getAuthorId() {
return authorId;
}
public void setAuthorId(int authorId) {
this.authorId = authorId;
}
public int getActiveType() {
return activeType;
}
public void setActiveType(int activeType) {
this.activeType = activeType;
}
public int getObjectId() {
return objectId;
}
public void setObjectId(int objectId) {
this.objectId = objectId;
}
public int getCatalog() {
return catalog;
}
public void setCatalog(int catalog) {
this.catalog = catalog;
}
public int getObjectType() {
return objectType;
}
public void setObjectType(int objectType) {
this.objectType = objectType;
}
public int getObjectCatalog() {
return objectCatalog;
}
public void setObjectCatalog(int objectCatalog) {
this.objectCatalog = objectCatalog;
}
public String getObjectTitle() {
return objectTitle;
}
public void setObjectTitle(String objectTitle) {
this.objectTitle = objectTitle;
}
public ObjectReply getObjectReply() {
return objectReply;
}
public void setObjectReply(ObjectReply objectReply) {
this.objectReply = objectReply;
}
public int getCommentCount() {
return commentCount;
}
public void setCommentCount(int commentCount) {
this.commentCount = commentCount;
}
public String getPubDate() {
return pubDate;
}
public void setPubDate(String pubDate) {
this.pubDate = pubDate;
}
public String getTweetattach() {
return tweetattach;
}
public void setTweetattach(String tweetattach) {
this.tweetattach = tweetattach;
}
public String getTweetimage() {
return tweetimage;
}
public void setTweetimage(String tweetimage) {
this.tweetimage = tweetimage;
}
public int getAppClient() {
return appClient;
}
public void setAppClient(int appClient) {
this.appClient = appClient;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@XStreamAlias("objectreply")
public static class ObjectReply implements Serializable {
@XStreamAlias("objectname")
public String objectName;
@XStreamAlias("objectbody")
public String objectBody;
public String getObjectName() {
return objectName;
}
public void setObjectName(String objectName) {
this.objectName = objectName;
}
public String getObjectBody() {
return objectBody;
}
public void setObjectBody(String objectBody) {
this.objectBody = objectBody;
}
}
}
ActiveList.java
package net.oschina.app.bean;
import java.util.ArrayList;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 动态实体列表
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年10月22日 下午3:34:21
*
*/
@SuppressWarnings("serial")
@XStreamAlias("oschina")
public class ActiveList extends Entity implements ListEntity {
public final static int CATALOG_LASTEST = 1;// 最新
public final static int CATALOG_ATME = 2;// @我
public final static int CATALOG_COMMENT = 3;// 评论
public final static int CATALOG_MYSELF = 4;// 我自己
@XStreamAlias("pagesize")
private int pageSize;
@XStreamAlias("activeCount")
private int activeCount;
@XStreamAlias("activies")
private List activelist = new ArrayList();
@XStreamAlias("result")
private Result result;
public int getPageSize() {
return pageSize;
}
public int getActiveCount() {
return activeCount;
}
public List getActivelist() {
return activelist;
}
@Override
public List getList() {
return activelist;
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
}
Constants.java
package net.oschina.app.bean;
/**
* 常量类
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2014年10月27日 下午12:14:42
*
*/
public class Constants {
public static final String INTENT_ACTION_USER_CHANGE = "net.oschina.action.USER_CHANGE";
public static final String INTENT_ACTION_COMMENT_CHANGED = "net.oschina.action.COMMENT_CHANGED";
public static final String INTENT_ACTION_NOTICE = "net.oschina.action.APPWIDGET_UPDATE";
public static final String INTENT_ACTION_LOGOUT = "net.oschina.action.LOGOUT";
public static final String WEICHAT_APPID = "wx41be5fe48092e94c";
public static final String WEICHAT_SECRET = "0101b0595ffe2042c214420fac358abc";
public static final String QQ_APPID = "100942993";
public static final String QQ_APPKEY = "8edd3cc7ca8dcc15082d6fe75969601b";
}
AlarmReceiver.java
package net.oschina.app.broadcast;
import net.oschina.app.service.NoticeUtils;
import net.oschina.app.util.TLog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
TLog.log("onReceive ->net.oschina.app收到定时获取消息");
NoticeUtils.requestNotice(context);
}
}
CacheManager.java
package net.oschina.app.cache;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import net.oschina.app.util.TDevice;
import android.content.Context;
public class CacheManager {
// wifi缓存时间为5分钟
private static long wifi_cache_time = 5 * 60 * 1000;
// 其他网络环境为1小时
private static long other_cache_time = 60 * 60 * 1000;
/**
* 保存对象
*
* @param ser
* @param file
* @throws IOException
*/
public static boolean saveObject(Context context, Serializable ser,
String file) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = context.openFileOutput(file, Context.MODE_PRIVATE);
oos = new ObjectOutputStream(fos);
oos.writeObject(ser);
oos.flush();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
oos.close();
} catch (Exception e) {
}
try {
fos.close();
} catch (Exception e) {
}
}
}
/**
* 读取对象
*
* @param file
* @return
* @throws IOException
*/
public static Serializable readObject(Context context, String file) {
if (!isExistDataCache(context, file))
return null;
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = context.openFileInput(file);
ois = new ObjectInputStream(fis);
return (Serializable) ois.readObject();
} catch (FileNotFoundException e) {
} catch (Exception e) {
e.printStackTrace();
// 反序列化失败 - 删除缓存文件
if (e instanceof InvalidClassException) {
File data = context.getFileStreamPath(file);
data.delete();
}
} finally {
try {
ois.close();
} catch (Exception e) {
}
try {
fis.close();
} catch (Exception e) {
}
}
return null;
}
/**
* 判断缓存是否存在
*
* @param cachefile
* @return
*/
public static boolean isExistDataCache(Context context, String cachefile) {
if (context == null)
return false;
boolean exist = false;
File data = context.getFileStreamPath(cachefile);
if (data.exists())
exist = true;
return exist;
}
/**
* 判断缓存是否已经失效
*/
public static boolean isCacheDataFailure(Context context, String cachefile) {
File data = context.getFileStreamPath(cachefile);
if (!data.exists()) {
return false;
}
long existTime = System.currentTimeMillis() - data.lastModified();
boolean failure = false;
if (TDevice.getNetworkType() == TDevice.NETTYPE_WIFI) {
failure = existTime > wifi_cache_time ? true : false;
} else {
failure = existTime > other_cache_time ? true : false;
}
return failure;
}
}
DataCleanManager.java
package net.oschina.app.cache;
import java.io.File;
import android.content.Context;
import android.os.Environment;
/**
* 数据删除工具类
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2014年10月27日 上午10:18:22
*
*/
public class DataCleanManager {
/**
* 清除本应用内部缓存
* (/data/data/com.xxx.xxx/cache)
* @param context
*/
public static void cleanInternalCache(Context context) {
deleteFilesByDirectory(context.getCacheDir());
deleteFilesByDirectory(context.getFilesDir());
}
/**
* 清楚本应用所有数据库
* (/data/data/com.xxx.xxx/databases)
* @param context
*/
public static void cleanDatabases(Context context) {
deleteFilesByDirectory(new File("/data/data/"
+ context.getPackageName() + "/databases"));
}
/**
* 清除本应用SharedPreference
* (/data/data/com.xxx.xxx/shared_prefs)
* @param context
*/
public static void cleanSharedPreference(Context context) {
deleteFilesByDirectory(new File("/data/data/"
+ context.getPackageName() + "/shared_prefs"));
}
/**
* 按名字清除本应用数据库
* @param context
* @param dbName
*/
public static void cleanDatabaseByName(Context context, String dbName) {
context.deleteDatabase(dbName);
}
/**
* 清除/data/data/com.xxx.xxx/files下的内容
* @param context
*/
public static void cleanFiles(Context context) {
deleteFilesByDirectory(context.getFilesDir());
}
/**
* 清除外部cache下的内容(/mnt/sdcard/android/data/com.xxx.xxx/cache)
* @param context
*/
public static void cleanExternalCache(Context context) {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
deleteFilesByDirectory(context.getExternalCacheDir());
}
}
/**
* 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除
* @param filePath
*/
public static void cleanCustomCache(String filePath) {
deleteFilesByDirectory(new File(filePath));
}
/**
* 清除自定义路径下的文件,使用需小心,请不要误删。而且只支持目录下的文件删除
* @param filePath
*/
public static void cleanCustomCache(File file) {
deleteFilesByDirectory(file);
}
/**
* 清除本应用所有的数据
* @param context
* @param filepath
*/
public static void cleanApplicationData(Context context, String... filepath) {
cleanInternalCache(context);
cleanExternalCache(context);
cleanDatabases(context);
cleanSharedPreference(context);
cleanFiles(context);
for (String filePath : filepath) {
cleanCustomCache(filePath);
}
}
/**
* 删除方法 这里只会删除某个文件夹下的文件,如果传入的directory是个文件,将不做处理
* @param directory
*/
private static void deleteFilesByDirectory(File directory) {
if (directory != null && directory.exists() && directory.isDirectory()) {
for (File child : directory.listFiles()) {
if (child.isDirectory()) {
deleteFilesByDirectory(child);
}
child.delete();
}
}
}
}
DiskLruCache.java
/*
* Copyright (C) 2011 The Android Open Source Project
*
* 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 net.oschina.app.cache;
import java.io.BufferedInputStream;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
******************************************************************************
* Taken from the JB source code, can be found in:
* libcore/luni/src/main/java/libcore/io/DiskLruCache.java
* or direct link:
* https://android.googlesource.com/platform/libcore/+/android-4.1.1_r1/luni/src/main/java/libcore/io/DiskLruCache.java
******************************************************************************
*
* A cache that uses a bounded amount of space on a filesystem. Each cache
* entry has a string key and a fixed number of values. Values are byte
* sequences, accessible as streams or files. Each value must be between {@code
* 0} and {@code Integer.MAX_VALUE} bytes in length.
*
* The cache stores its data in a directory on the filesystem. This
* directory must be exclusive to the cache; the cache may delete or overwrite
* files from its directory. It is an error for multiple processes to use the
* same cache directory at the same time.
*
*
This cache limits the number of bytes that it will store on the
* filesystem. When the number of stored bytes exceeds the limit, the cache will
* remove entries in the background until the limit is satisfied. The limit is
* not strict: the cache may temporarily exceed it while waiting for files to be
* deleted. The limit does not include filesystem overhead or the cache
* journal so space-sensitive applications should set a conservative limit.
*
*
Clients call {@link #edit} to create or update the values of an entry. An
* entry may have only one editor at one time; if a value is not available to be
* edited then {@link #edit} will return null.
*
* - When an entry is being created it is necessary to
* supply a full set of values; the empty value should be used as a
* placeholder if necessary.
*
- When an entry is being edited, it is not necessary
* to supply data for every value; values default to their previous
* value.
*
* Every {@link #edit} call must be matched by a call to {@link Editor#commit}
* or {@link Editor#abort}. Committing is atomic: a read observes the full set
* of values as they were before or after the commit, but never a mix of values.
*
* Clients call {@link #get} to read a snapshot of an entry. The read will
* observe the value at the time that {@link #get} was called. Updates and
* removals after the call do not impact ongoing reads.
*
*
This class is tolerant of some I/O errors. If files are missing from the
* filesystem, the corresponding entries will be dropped from the cache. If
* an error occurs while writing a cache value, the edit will fail silently.
* Callers should handle other problems by catching {@code IOException} and
* responding appropriately.
*/
public final class DiskLruCache implements Closeable {
static final String JOURNAL_FILE = "journal";
static final String JOURNAL_FILE_TMP = "journal.tmp";
static final String MAGIC = "libcore.io.DiskLruCache";
static final String VERSION_1 = "1";
static final long ANY_SEQUENCE_NUMBER = -1;
private static final String CLEAN = "CLEAN";
private static final String DIRTY = "DIRTY";
private static final String REMOVE = "REMOVE";
private static final String READ = "READ";
private static final Charset UTF_8 = Charset.forName("UTF-8");
private static final int IO_BUFFER_SIZE = 8 * 1024;
/*
* This cache uses a journal file named "journal". A typical journal file
* looks like this:
* libcore.io.DiskLruCache
* 1
* 100
* 2
*
* CLEAN 3400330d1dfc7f3f7f4b8d4d803dfcf6 832 21054
* DIRTY 335c4c6028171cfddfbaae1a9c313c52
* CLEAN 335c4c6028171cfddfbaae1a9c313c52 3934 2342
* REMOVE 335c4c6028171cfddfbaae1a9c313c52
* DIRTY 1ab96a171faeeee38496d8b330771a7a
* CLEAN 1ab96a171faeeee38496d8b330771a7a 1600 234
* READ 335c4c6028171cfddfbaae1a9c313c52
* READ 3400330d1dfc7f3f7f4b8d4d803dfcf6
*
* The first five lines of the journal form its header. They are the
* constant string "libcore.io.DiskLruCache", the disk cache's version,
* the application's version, the value count, and a blank line.
*
* Each of the subsequent lines in the file is a record of the state of a
* cache entry. Each line contains space-separated values: a state, a key,
* and optional state-specific values.
* o DIRTY lines track that an entry is actively being created or updated.
* Every successful DIRTY action should be followed by a CLEAN or REMOVE
* action. DIRTY lines without a matching CLEAN or REMOVE indicate that
* temporary files may need to be deleted.
* o CLEAN lines track a cache entry that has been successfully published
* and may be read. A publish line is followed by the lengths of each of
* its values.
* o READ lines track accesses for LRU.
* o REMOVE lines track entries that have been deleted.
*
* The journal file is appended to as cache operations occur. The journal may
* occasionally be compacted by dropping redundant lines. A temporary file named
* "journal.tmp" will be used during compaction; that file should be deleted if
* it exists when the cache is opened.
*/
private final File directory;
private final File journalFile;
private final File journalFileTmp;
private final int appVersion;
private final long maxSize;
private final int valueCount;
private long size = 0;
private Writer journalWriter;
private final LinkedHashMap lruEntries
= new LinkedHashMap(0, 0.75f, true);
private int redundantOpCount;
/**
* To differentiate between old and current snapshots, each entry is given
* a sequence number each time an edit is committed. A snapshot is stale if
* its sequence number is not equal to its entry's sequence number.
*/
private long nextSequenceNumber = 0;
/* From java.util.Arrays */
@SuppressWarnings("unchecked")
private static T[] copyOfRange(T[] original, int start, int end) {
final int originalLength = original.length; // For exception priority compatibility.
if (start > end) {
throw new IllegalArgumentException();
}
if (start < 0 || start > originalLength) {
throw new ArrayIndexOutOfBoundsException();
}
final int resultLength = end - start;
final int copyLength = Math.min(resultLength, originalLength - start);
final T[] result = (T[]) Array
.newInstance(original.getClass().getComponentType(), resultLength);
System.arraycopy(original, start, result, 0, copyLength);
return result;
}
/**
* Returns the remainder of 'reader' as a string, closing it when done.
*/
public static String readFully(Reader reader) throws IOException {
try {
StringWriter writer = new StringWriter();
char[] buffer = new char[1024];
int count;
while ((count = reader.read(buffer)) != -1) {
writer.write(buffer, 0, count);
}
return writer.toString();
} finally {
reader.close();
}
}
/**
* Returns the ASCII characters up to but not including the next "\r\n", or
* "\n".
*
* @throws java.io.EOFException if the stream is exhausted before the next newline
* character.
*/
public static String readAsciiLine(InputStream in) throws IOException {
// TODO: support UTF-8 here instead
StringBuilder result = new StringBuilder(80);
while (true) {
int c = in.read();
if (c == -1) {
throw new EOFException();
} else if (c == '\n') {
break;
}
result.append((char) c);
}
int length = result.length();
if (length > 0 && result.charAt(length - 1) == '\r') {
result.setLength(length - 1);
}
return result.toString();
}
/**
* Closes 'closeable', ignoring any checked exceptions. Does nothing if 'closeable' is null.
*/
public static void closeQuietly(Closeable closeable) {
if (closeable != null) {
try {
closeable.close();
} catch (RuntimeException rethrown) {
throw rethrown;
} catch (Exception ignored) {
}
}
}
/**
* Recursively delete everything in {@code dir}.
*/
// TODO: this should specify paths as Strings rather than as Files
public static void deleteContents(File dir) throws IOException {
File[] files = dir.listFiles();
if (files == null) {
throw new IllegalArgumentException("not a directory: " + dir);
}
for (File file : files) {
if (file.isDirectory()) {
deleteContents(file);
}
if (!file.delete()) {
throw new IOException("failed to delete file: " + file);
}
}
}
/** This cache uses a single background thread to evict entries. */
private final ExecutorService executorService = new ThreadPoolExecutor(0, 1,
60L, TimeUnit.SECONDS, new LinkedBlockingQueue());
private final Callable cleanupCallable = new Callable() {
@Override public Void call() throws Exception {
synchronized (DiskLruCache.this) {
if (journalWriter == null) {
return null; // closed
}
trimToSize();
if (journalRebuildRequired()) {
rebuildJournal();
redundantOpCount = 0;
}
}
return null;
}
};
private DiskLruCache(File directory, int appVersion, int valueCount, long maxSize) {
this.directory = directory;
this.appVersion = appVersion;
this.journalFile = new File(directory, JOURNAL_FILE);
this.journalFileTmp = new File(directory, JOURNAL_FILE_TMP);
this.valueCount = valueCount;
this.maxSize = maxSize;
}
/**
* Opens the cache in {@code directory}, creating a cache if none exists
* there.
*
* @param directory a writable directory
* @param appVersion
* @param valueCount the number of values per cache entry. Must be positive.
* @param maxSize the maximum number of bytes this cache should use to store
* @throws java.io.IOException if reading or writing the cache directory fails
*/
public static DiskLruCache open(File directory, int appVersion, int valueCount, long maxSize)
throws IOException {
if (maxSize <= 0) {
throw new IllegalArgumentException("maxSize <= 0");
}
if (valueCount <= 0) {
throw new IllegalArgumentException("valueCount <= 0");
}
// prefer to pick up where we left off
DiskLruCache cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
if (cache.journalFile.exists()) {
try {
cache.readJournal();
cache.processJournal();
cache.journalWriter = new BufferedWriter(new FileWriter(cache.journalFile, true),
IO_BUFFER_SIZE);
return cache;
} catch (IOException journalIsCorrupt) {
// System.logW("DiskLruCache " + directory + " is corrupt: "
// + journalIsCorrupt.getMessage() + ", removing");
cache.delete();
}
}
// create a new empty cache
directory.mkdirs();
cache = new DiskLruCache(directory, appVersion, valueCount, maxSize);
cache.rebuildJournal();
return cache;
}
private void readJournal() throws IOException {
InputStream in = new BufferedInputStream(new FileInputStream(journalFile), IO_BUFFER_SIZE);
try {
String magic = readAsciiLine(in);
String version = readAsciiLine(in);
String appVersionString = readAsciiLine(in);
String valueCountString = readAsciiLine(in);
String blank = readAsciiLine(in);
if (!MAGIC.equals(magic)
|| !VERSION_1.equals(version)
|| !Integer.toString(appVersion).equals(appVersionString)
|| !Integer.toString(valueCount).equals(valueCountString)
|| !"".equals(blank)) {
throw new IOException("unexpected journal header: ["
+ magic + ", " + version + ", " + valueCountString + ", " + blank + "]");
}
while (true) {
try {
readJournalLine(readAsciiLine(in));
} catch (EOFException endOfJournal) {
break;
}
}
} finally {
closeQuietly(in);
}
}
private void readJournalLine(String line) throws IOException {
String[] parts = line.split(" ");
if (parts.length < 2) {
throw new IOException("unexpected journal line: " + line);
}
String key = parts[1];
if (parts[0].equals(REMOVE) && parts.length == 2) {
lruEntries.remove(key);
return;
}
Entry entry = lruEntries.get(key);
if (entry == null) {
entry = new Entry(key);
lruEntries.put(key, entry);
}
if (parts[0].equals(CLEAN) && parts.length == 2 + valueCount) {
entry.readable = true;
entry.currentEditor = null;
entry.setLengths(copyOfRange(parts, 2, parts.length));
} else if (parts[0].equals(DIRTY) && parts.length == 2) {
entry.currentEditor = new Editor(entry);
} else if (parts[0].equals(READ) && parts.length == 2) {
// this work was already done by calling lruEntries.get()
} else {
throw new IOException("unexpected journal line: " + line);
}
}
/**
* Computes the initial size and collects garbage as a part of opening the
* cache. Dirty entries are assumed to be inconsistent and will be deleted.
*/
private void processJournal() throws IOException {
deleteIfExists(journalFileTmp);
for (Iterator i = lruEntries.values().iterator(); i.hasNext(); ) {
Entry entry = i.next();
if (entry.currentEditor == null) {
for (int t = 0; t < valueCount; t++) {
size += entry.lengths[t];
}
} else {
entry.currentEditor = null;
for (int t = 0; t < valueCount; t++) {
deleteIfExists(entry.getCleanFile(t));
deleteIfExists(entry.getDirtyFile(t));
}
i.remove();
}
}
}
/**
* Creates a new journal that omits redundant information. This replaces the
* current journal if it exists.
*/
private synchronized void rebuildJournal() throws IOException {
if (journalWriter != null) {
journalWriter.close();
}
Writer writer = new BufferedWriter(new FileWriter(journalFileTmp), IO_BUFFER_SIZE);
writer.write(MAGIC);
writer.write("\n");
writer.write(VERSION_1);
writer.write("\n");
writer.write(Integer.toString(appVersion));
writer.write("\n");
writer.write(Integer.toString(valueCount));
writer.write("\n");
writer.write("\n");
for (Entry entry : lruEntries.values()) {
if (entry.currentEditor != null) {
writer.write(DIRTY + ' ' + entry.key + '\n');
} else {
writer.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
}
}
writer.close();
journalFileTmp.renameTo(journalFile);
journalWriter = new BufferedWriter(new FileWriter(journalFile, true), IO_BUFFER_SIZE);
}
private static void deleteIfExists(File file) throws IOException {
// try {
// Libcore.os.remove(file.getPath());
// } catch (ErrnoException errnoException) {
// if (errnoException.errno != OsConstants.ENOENT) {
// throw errnoException.rethrowAsIOException();
// }
// }
if (file.exists() && !file.delete()) {
throw new IOException();
}
}
/**
* Returns a snapshot of the entry named {@code key}, or null if it doesn't
* exist is not currently readable. If a value is returned, it is moved to
* the head of the LRU queue.
*/
public synchronized Snapshot get(String key) throws IOException {
checkNotClosed();
validateKey(key);
Entry entry = lruEntries.get(key);
if (entry == null) {
return null;
}
if (!entry.readable) {
return null;
}
/*
* Open all streams eagerly to guarantee that we see a single published
* snapshot. If we opened streams lazily then the streams could come
* from different edits.
*/
InputStream[] ins = new InputStream[valueCount];
try {
for (int i = 0; i < valueCount; i++) {
ins[i] = new FileInputStream(entry.getCleanFile(i));
}
} catch (FileNotFoundException e) {
// a file must have been deleted manually!
return null;
}
redundantOpCount++;
journalWriter.append(READ + ' ' + key + '\n');
if (journalRebuildRequired()) {
executorService.submit(cleanupCallable);
}
return new Snapshot(key, entry.sequenceNumber, ins);
}
/**
* Returns an editor for the entry named {@code key}, or null if another
* edit is in progress.
*/
public Editor edit(String key) throws IOException {
return edit(key, ANY_SEQUENCE_NUMBER);
}
private synchronized Editor edit(String key, long expectedSequenceNumber) throws IOException {
checkNotClosed();
validateKey(key);
Entry entry = lruEntries.get(key);
if (expectedSequenceNumber != ANY_SEQUENCE_NUMBER
&& (entry == null || entry.sequenceNumber != expectedSequenceNumber)) {
return null; // snapshot is stale
}
if (entry == null) {
entry = new Entry(key);
lruEntries.put(key, entry);
} else if (entry.currentEditor != null) {
return null; // another edit is in progress
}
Editor editor = new Editor(entry);
entry.currentEditor = editor;
// flush the journal before creating files to prevent file leaks
journalWriter.write(DIRTY + ' ' + key + '\n');
journalWriter.flush();
return editor;
}
/**
* Returns the directory where this cache stores its data.
*/
public File getDirectory() {
return directory;
}
/**
* Returns the maximum number of bytes that this cache should use to store
* its data.
*/
public long maxSize() {
return maxSize;
}
/**
* Returns the number of bytes currently being used to store the values in
* this cache. This may be greater than the max size if a background
* deletion is pending.
*/
public synchronized long size() {
return size;
}
private synchronized void completeEdit(Editor editor, boolean success) throws IOException {
Entry entry = editor.entry;
if (entry.currentEditor != editor) {
throw new IllegalStateException();
}
// if this edit is creating the entry for the first time, every index must have a value
if (success && !entry.readable) {
for (int i = 0; i < valueCount; i++) {
if (!entry.getDirtyFile(i).exists()) {
editor.abort();
throw new IllegalStateException("edit didn't create file " + i);
}
}
}
for (int i = 0; i < valueCount; i++) {
File dirty = entry.getDirtyFile(i);
if (success) {
if (dirty.exists()) {
File clean = entry.getCleanFile(i);
dirty.renameTo(clean);
long oldLength = entry.lengths[i];
long newLength = clean.length();
entry.lengths[i] = newLength;
size = size - oldLength + newLength;
}
} else {
deleteIfExists(dirty);
}
}
redundantOpCount++;
entry.currentEditor = null;
if (entry.readable | success) {
entry.readable = true;
journalWriter.write(CLEAN + ' ' + entry.key + entry.getLengths() + '\n');
if (success) {
entry.sequenceNumber = nextSequenceNumber++;
}
} else {
lruEntries.remove(entry.key);
journalWriter.write(REMOVE + ' ' + entry.key + '\n');
}
if (size > maxSize || journalRebuildRequired()) {
executorService.submit(cleanupCallable);
}
}
/**
* We only rebuild the journal when it will halve the size of the journal
* and eliminate at least 2000 ops.
*/
private boolean journalRebuildRequired() {
final int REDUNDANT_OP_COMPACT_THRESHOLD = 2000;
return redundantOpCount >= REDUNDANT_OP_COMPACT_THRESHOLD
&& redundantOpCount >= lruEntries.size();
}
/**
* Drops the entry for {@code key} if it exists and can be removed. Entries
* actively being edited cannot be removed.
*
* @return true if an entry was removed.
*/
public synchronized boolean remove(String key) throws IOException {
checkNotClosed();
validateKey(key);
Entry entry = lruEntries.get(key);
if (entry == null || entry.currentEditor != null) {
return false;
}
for (int i = 0; i < valueCount; i++) {
File file = entry.getCleanFile(i);
if (!file.delete()) {
throw new IOException("failed to delete " + file);
}
size -= entry.lengths[i];
entry.lengths[i] = 0;
}
redundantOpCount++;
journalWriter.append(REMOVE + ' ' + key + '\n');
lruEntries.remove(key);
if (journalRebuildRequired()) {
executorService.submit(cleanupCallable);
}
return true;
}
/**
* Returns true if this cache has been closed.
*/
public boolean isClosed() {
return journalWriter == null;
}
private void checkNotClosed() {
if (journalWriter == null) {
throw new IllegalStateException("cache is closed");
}
}
/**
* Force buffered operations to the filesystem.
*/
public synchronized void flush() throws IOException {
checkNotClosed();
trimToSize();
journalWriter.flush();
}
/**
* Closes this cache. Stored values will remain on the filesystem.
*/
public synchronized void close() throws IOException {
if (journalWriter == null) {
return; // already closed
}
for (Entry entry : new ArrayList(lruEntries.values())) {
if (entry.currentEditor != null) {
entry.currentEditor.abort();
}
}
trimToSize();
journalWriter.close();
journalWriter = null;
}
private void trimToSize() throws IOException {
while (size > maxSize) {
// Map.Entry toEvict = lruEntries.eldest();
final Map.Entry toEvict = lruEntries.entrySet().iterator().next();
remove(toEvict.getKey());
}
}
/**
* Closes the cache and deletes all of its stored values. This will delete
* all files in the cache directory including files that weren't created by
* the cache.
*/
public void delete() throws IOException {
close();
deleteContents(directory);
}
private void validateKey(String key) {
if (key.contains(" ") || key.contains("\n") || key.contains("\r")) {
throw new IllegalArgumentException(
"keys must not contain spaces or newlines: \"" + key + "\"");
}
}
private static String inputStreamToString(InputStream in) throws IOException {
return readFully(new InputStreamReader(in, UTF_8));
}
/**
* A snapshot of the values for an entry.
*/
public final class Snapshot implements Closeable {
private final String key;
private final long sequenceNumber;
private final InputStream[] ins;
private Snapshot(String key, long sequenceNumber, InputStream[] ins) {
this.key = key;
this.sequenceNumber = sequenceNumber;
this.ins = ins;
}
/**
* Returns an editor for this snapshot's entry, or null if either the
* entry has changed since this snapshot was created or if another edit
* is in progress.
*/
public Editor edit() throws IOException {
return DiskLruCache.this.edit(key, sequenceNumber);
}
/**
* Returns the unbuffered stream with the value for {@code index}.
*/
public InputStream getInputStream(int index) {
return ins[index];
}
/**
* Returns the string value for {@code index}.
*/
public String getString(int index) throws IOException {
return inputStreamToString(getInputStream(index));
}
@Override public void close() {
for (InputStream in : ins) {
closeQuietly(in);
}
}
}
/**
* Edits the values for an entry.
*/
public final class Editor {
private final Entry entry;
private boolean hasErrors;
private Editor(Entry entry) {
this.entry = entry;
}
/**
* Returns an unbuffered input stream to read the last committed value,
* or null if no value has been committed.
*/
public InputStream newInputStream(int index) throws IOException {
synchronized (DiskLruCache.this) {
if (entry.currentEditor != this) {
throw new IllegalStateException();
}
if (!entry.readable) {
return null;
}
return new FileInputStream(entry.getCleanFile(index));
}
}
/**
* Returns the last committed value as a string, or null if no value
* has been committed.
*/
public String getString(int index) throws IOException {
InputStream in = newInputStream(index);
return in != null ? inputStreamToString(in) : null;
}
/**
* Returns a new unbuffered output stream to write the value at
* {@code index}. If the underlying output stream encounters errors
* when writing to the filesystem, this edit will be aborted when
* {@link #commit} is called. The returned output stream does not throw
* IOExceptions.
*/
public OutputStream newOutputStream(int index) throws IOException {
synchronized (DiskLruCache.this) {
if (entry.currentEditor != this) {
throw new IllegalStateException();
}
return new FaultHidingOutputStream(new FileOutputStream(entry.getDirtyFile(index)));
}
}
/**
* Sets the value at {@code index} to {@code value}.
*/
public void set(int index, String value) throws IOException {
Writer writer = null;
try {
writer = new OutputStreamWriter(newOutputStream(index), UTF_8);
writer.write(value);
} finally {
closeQuietly(writer);
}
}
/**
* Commits this edit so it is visible to readers. This releases the
* edit lock so another edit may be started on the same key.
*/
public void commit() throws IOException {
if (hasErrors) {
completeEdit(this, false);
remove(entry.key); // the previous entry is stale
} else {
completeEdit(this, true);
}
}
/**
* Aborts this edit. This releases the edit lock so another edit may be
* started on the same key.
*/
public void abort() throws IOException {
completeEdit(this, false);
}
private class FaultHidingOutputStream extends FilterOutputStream {
private FaultHidingOutputStream(OutputStream out) {
super(out);
}
@Override public void write(int oneByte) {
try {
out.write(oneByte);
} catch (IOException e) {
hasErrors = true;
}
}
@Override public void write(byte[] buffer, int offset, int length) {
try {
out.write(buffer, offset, length);
} catch (IOException e) {
hasErrors = true;
}
}
@Override public void close() {
try {
out.close();
} catch (IOException e) {
hasErrors = true;
}
}
@Override public void flush() {
try {
out.flush();
} catch (IOException e) {
hasErrors = true;
}
}
}
}
private final class Entry {
private final String key;
/** Lengths of this entry's files. */
private final long[] lengths;
/** True if this entry has ever been published */
private boolean readable;
/** The ongoing edit or null if this entry is not being edited. */
private Editor currentEditor;
/** The sequence number of the most recently committed edit to this entry. */
private long sequenceNumber;
private Entry(String key) {
this.key = key;
this.lengths = new long[valueCount];
}
public String getLengths() throws IOException {
StringBuilder result = new StringBuilder();
for (long size : lengths) {
result.append(' ').append(size);
}
return result.toString();
}
/**
* Set lengths using decimal numbers like "10123".
*/
private void setLengths(String[] strings) throws IOException {
if (strings.length != valueCount) {
throw invalidLengths(strings);
}
try {
for (int i = 0; i < strings.length; i++) {
lengths[i] = Long.parseLong(strings[i]);
}
} catch (NumberFormatException e) {
throw invalidLengths(strings);
}
}
private IOException invalidLengths(String[] strings) throws IOException {
throw new IOException("unexpected journal line: " + Arrays.toString(strings));
}
public File getCleanFile(int i) {
return new File(directory, key + "." + i);
}
public File getDirtyFile(int i) {
return new File(directory, key + "." + i + ".tmp");
}
}
}
DiskLruCacheUtil.java
package net.oschina.app.cache;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import net.oschina.app.util.TDevice;
import org.kymjs.kjframe.utils.FileUtils;
import android.content.Context;
import android.os.Environment;
/**
* 缓存工具类
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2014年12月26日 下午4:53:13
*
*/
public class DiskLruCacheUtil {
private static int appVersion = TDevice.getVersionCode();
private static int valueCount = 1;// 同一个key可以对应多少个缓存文件
private static int maxSize = 10 * 1024 * 1024;// 一个缓存文件最大可以缓存10M
public static final String CACHE_OBJECT = "object";// 对象缓存目录
/**
* 保存对象缓存
*
* @param context
* @param ser
* @param key
*/
public static void saveObject(Context context, Serializable ser, String key) {
ObjectOutputStream oos = null;
try {
DiskLruCache.Editor editor = getDiskLruCacheOutputStream(context,
CACHE_OBJECT, key);
if (editor != null) {
oos = new ObjectOutputStream(editor.newOutputStream(0));
oos.writeObject(ser);
oos.flush();
editor.commit();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
FileUtils.closeIO(oos);
}
}
/**
* 读取对象缓存
*
* @param context
* @param key
* @return
*/
public static Serializable readObject(Context context, String key) {
ObjectInputStream ois = null;
try {
DiskLruCache.Editor editor = getDiskLruCacheOutputStream(context,
CACHE_OBJECT, key);
ois = new ObjectInputStream(editor.newInputStream(0));
return (Serializable) ois.readObject();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
FileUtils.closeIO(ois);
}
return null;
}
/**
* 获取DiskLruCache的editor
*
* @param context
* @param key
* @return
* @throws IOException
*/
public static DiskLruCache.Editor getDiskLruCacheOutputStream(
Context context, String uniqueName, String key) throws IOException {
DiskLruCache mDiskLruCache = DiskLruCache.open(
getDiskCacheDir(context, uniqueName), appVersion, valueCount,
maxSize);
DiskLruCache.Editor editor = mDiskLruCache.edit(hashKeyForDisk(key));
return editor;
}
/**
* 获取相应的缓存目录
*
* @param context
* @param uniqueName
* @return
*/
public static File getDiskCacheDir(Context context, String uniqueName) {
String cachePath;
if (Environment.MEDIA_MOUNTED.equals(Environment
.getExternalStorageState())
|| !Environment.isExternalStorageRemovable()) {
cachePath = context.getExternalCacheDir().getPath();
} else {
cachePath = context.getCacheDir().getPath();
}
return new File(cachePath + File.separator + uniqueName);
}
/**
* 传入缓存的key值,以得到相应的MD5值
*
* @param key
* @return
*/
public static String hashKeyForDisk(String key) {
String cacheKey;
try {
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
mDigest.update(key.getBytes());
cacheKey = bytesToHexString(mDigest.digest());
} catch (NoSuchAlgorithmException e) {
cacheKey = String.valueOf(key.hashCode());
}
return cacheKey;
}
private static String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(0xFF & bytes[i]);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString();
}
}
DatabaseHelper.java
package net.oschina.app.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* 创建便签的数据库
*
* @author kymjs
*
* update:2014-01-12 updateor: fireant 内容:修改为全应用数据库
*
*/
public class DatabaseHelper extends SQLiteOpenHelper {
public static final String OSC_DATABASE_NAME = "oschina";
public static final String NOTE_TABLE_NAME = "osc_Notebook";
public static final String CREATE_NOTE_TABLE = "create table "
+ NOTE_TABLE_NAME
+ " (_id integer primary key autoincrement, iid integer,"
+ " time varchar(10), date varchar(10), content text, color integer)";
public static final String NEWS_LIST = "osc_news_list";
public static final String CREATE_NEWS_LIST_TABLE = "create table "
+ NOTE_TABLE_NAME + "(" + "_id integer primary key autoincrement, "
+ "news_id interger, title varchar(10), " + ")";
public DatabaseHelper(Context context) {
super(context, OSC_DATABASE_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE);
// db.execSQL(CREATE_NEWS_LIST_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
NoteDatabase.java
package net.oschina.app.db;
import java.util.ArrayList;
import java.util.List;
import net.oschina.app.bean.NotebookData;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
public class NoteDatabase {
private final DatabaseHelper dbHelper;
public NoteDatabase(Context context) {
super();
dbHelper = new DatabaseHelper(context);
}
/**
* 增
*
* @param data
*/
public void insert(NotebookData data) {
String sql = "insert into " + DatabaseHelper.NOTE_TABLE_NAME;
sql += "(_id, iid, time, date, content, color) values(?, ?, ?, ?, ?, ?)";
SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
sqlite.execSQL(sql, new String[] { data.getId() + "",
data.getIid() + "", data.getUnixTime() + "", data.getDate(),
data.getContent(), data.getColor() + "" });
sqlite.close();
}
/**
* 删
*
* @param id
*/
public void delete(int id) {
SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
String sql = ("delete from " + DatabaseHelper.NOTE_TABLE_NAME + " where _id=?");
sqlite.execSQL(sql, new Integer[] { id });
sqlite.close();
}
/**
* 改
*
* @param data
*/
public void update(NotebookData data) {
SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
String sql = ("update " + DatabaseHelper.NOTE_TABLE_NAME + " set iid=?, time=?, date=?, content=?, color=? where _id=?");
sqlite.execSQL(sql,
new String[] { data.getIid() + "", data.getUnixTime() + "",
data.getDate(), data.getContent(),
data.getColor() + "", data.getId() + "" });
sqlite.close();
}
public List query() {
return query(" ");
}
/**
* 查
*
* @param where
* @return
*/
public List query(String where) {
SQLiteDatabase sqlite = dbHelper.getReadableDatabase();
ArrayList data = null;
data = new ArrayList();
Cursor cursor = sqlite.rawQuery("select * from "
+ DatabaseHelper.NOTE_TABLE_NAME + where, null);
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
NotebookData notebookData = new NotebookData();
notebookData.setId(cursor.getInt(0));
notebookData.setIid(cursor.getInt(1));
notebookData.setUnixTime(cursor.getString(2));
notebookData.setDate(cursor.getString(3));
notebookData.setContent(cursor.getString(4));
notebookData.setColor(cursor.getInt(5));
data.add(notebookData);
}
if (!cursor.isClosed()) {
cursor.close();
}
sqlite.close();
return data;
}
/**
* 重置
*
* @param datas
*/
public void reset(List datas) {
if (datas != null) {
SQLiteDatabase sqlite = dbHelper.getWritableDatabase();
// 删除全部
sqlite.execSQL("delete from " + DatabaseHelper.NOTE_TABLE_NAME);
// 重新添加
for (NotebookData data : datas) {
insert(data);
}
sqlite.close();
}
}
/**
* 保存一条数据到本地(若已存在则直接覆盖)
*
* @param data
*/
public void save(NotebookData data) {
List datas = query(" where _id=" + data.getId());
if (datas != null && !datas.isEmpty()) {
update(data);
} else {
insert(data);
}
}
//
// /**
// * 合并一条数据到本地(通过更新时间判断仅保留最新)
// *
// * @param data
// * @return 数据是否被合并了
// */
// public boolean merge(NotebookData data) {
// Cursor cursor = sqlite.rawQuery(
// "select * from " + DatabaseHelper.NOTE_TABLE_NAME
// + " where _id=" + data.getId(), null);
// NotebookData localData = new NotebookData();
// // 本循环其实只执行一次
// for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
// localData.setId(cursor.getInt(0));
// localData.setIid(cursor.getInt(1));
// localData.setUnixTime(cursor.getString(2));
// localData.setDate(cursor.getString(3));
// localData.setContent(cursor.getString(4));
// localData.setColor(cursor.getInt(5));
// }
// // 是否需要合这条数据
// boolean isMerge = localData.getUnixTime() < data.getUnixTime();
// if (isMerge) {
// save(data);
// }
// return isMerge;
// }
public void destroy() {
dbHelper.close();
}
}
ActiveFragment.java
package net.oschina.app.fragment;
import java.io.InputStream;
import java.io.Serializable;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.adapter.ActiveAdapter;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.BaseListFragment;
import net.oschina.app.bean.Active;
import net.oschina.app.bean.ActiveList;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.Notice;
import net.oschina.app.service.NoticeUtils;
import net.oschina.app.ui.MainActivity;
import net.oschina.app.ui.dialog.CommonDialog;
import net.oschina.app.ui.dialog.DialogHelper;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.util.HTMLUtil;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.XmlUtils;
import net.oschina.app.viewpagerfragment.NoticeViewPagerFragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AdapterView.OnItemLongClickListener;
/**
* 动态fragment
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @author kymjs (https://github.com/kymjs)
* @created 2014年10月22日 下午3:35:43
*
*/
public class ActiveFragment extends BaseListFragment implements
OnItemLongClickListener {
protected static final String TAG = ActiveFragment.class.getSimpleName();
private static final String CACHE_KEY_PREFIX = "active_list";
private boolean mIsWatingLogin; // 还没登陆
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (mErrorLayout != null) {
mIsWatingLogin = true;
mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip));
}
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_LOGOUT);
getActivity().registerReceiver(mReceiver, filter);
}
@Override
public void onDestroy() {
getActivity().unregisterReceiver(mReceiver);
super.onDestroy();
}
@Override
public void onResume() {
if (mIsWatingLogin) {
mCurrentPage = 0;
mState = STATE_REFRESH;
requestData(false);
}
refreshNotice();
super.onResume();
}
/**
* 开始刷新请求
*/
private void refreshNotice() {
Notice notice = MainActivity.mNotice;
if (notice == null) {
return;
}
if (notice.getAtmeCount() > 0 && mCatalog == ActiveList.CATALOG_ATME) {
onRefresh();
} else if (notice.getReviewCount() > 0
&& mCatalog == ActiveList.CATALOG_COMMENT) {
onRefresh();
}
}
@Override
protected ActiveAdapter getListAdapter() {
return new ActiveAdapter();
}
@Override
protected String getCacheKeyPrefix() {
return new StringBuffer(CACHE_KEY_PREFIX + mCatalog).append(
AppContext.getInstance().getLoginUid()).toString();
}
@Override
protected ActiveList parseList(InputStream is) {
ActiveList list = XmlUtils.toBean(ActiveList.class, is);
return list;
}
@Override
protected ActiveList readList(Serializable seri) {
return ((ActiveList) seri);
}
@Override
public void initView(View view) {
if (mCatalog == ActiveList.CATALOG_LASTEST) {
setHasOptionsMenu(true);
}
super.initView(view);
mListView.setOnItemLongClickListener(this);
mListView.setOnItemClickListener(this);
mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (AppContext.getInstance().isLogin()) {
mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
requestData(false);
} else {
UIHelper.showLoginActivity(getActivity());
}
}
});
if (AppContext.getInstance().isLogin()) {
UIHelper.sendBroadcastForNotice(getActivity());
}
}
@Override
protected void requestData(boolean refresh) {
if (AppContext.getInstance().isLogin()) {
mIsWatingLogin = false;
super.requestData(refresh);
} else {
mIsWatingLogin = true;
mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip));
}
}
@Override
protected void sendRequestData() {
OSChinaApi.getActiveList(AppContext.getInstance().getLoginUid(),
mCatalog, mCurrentPage, mHandler);
}
@Override
protected void onRefreshNetworkSuccess() {
if (AppContext.getInstance().isLogin()) {
if (0 == NoticeViewPagerFragment.sCurrentPage) {
NoticeUtils.clearNotice(Notice.TYPE_ATME);
} else if (1 == NoticeViewPagerFragment.sCurrentPage
|| NoticeViewPagerFragment.sShowCount[1] > 0) { // 如果当前显示的是评论页,则发送评论页已被查看的Http请求
NoticeUtils.clearNotice(Notice.TYPE_COMMENT);
} else {
NoticeUtils.clearNotice(Notice.TYPE_ATME);
}
UIHelper.sendBroadcastForNotice(getActivity());
}
}
@Override
public void onItemClick(AdapterView> parent, View view, int position,
long id) {
Active active = mAdapter.getItem(position);
if (active != null)
UIHelper.showActiveRedirect(view.getContext(), active);
}
@Override
public boolean onItemLongClick(AdapterView> parent, View view,
int position, long id) {
final Active active = mAdapter.getItem(position);
if (active == null)
return false;
String[] items = new String[] { getResources().getString(R.string.copy) };
final CommonDialog dialog = DialogHelper
.getPinterestDialogCancelable(getActivity());
dialog.setNegativeButton(R.string.cancle, null);
dialog.setItemsWithoutChk(items, new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
dialog.dismiss();
TDevice.copyTextToBoard(HTMLUtil.delHTMLTag(active.getMessage()));
}
});
dialog.show();
return true;
}
@Override
protected long getAutoRefreshTime() {
// 最新动态,即是好友圈
if (mCatalog == ActiveList.CATALOG_LASTEST) {
return 5 * 60;
}
return super.getAutoRefreshTime();
}
}
EventFragment.java
package net.oschina.app.fragment;
import java.io.InputStream;
import java.io.Serializable;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.adapter.EventAdapter;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.BaseListFragment;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.Event;
import net.oschina.app.bean.EventList;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.XmlUtils;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
/**
* 活动列表fragment
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2014年12月8日 下午5:17:32
*
*/
public class EventFragment extends BaseListFragment {
public static final String BUNDLE_KEY_EVENT_TYPE = "eventlist_type";
protected static final String TAG = EventFragment.class.getSimpleName();
private static final String CACHE_KEY_PREFIX = "eventlist_";
private int event_type;
@Override
protected EventAdapter getListAdapter() {
EventAdapter adapter = new EventAdapter();
adapter.setEventType(event_type);
return adapter;
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
requestData(true);
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
event_type = args.getInt(BUNDLE_KEY_EVENT_TYPE);
}
if (event_type == EventList.EVENT_LIST_TYPE_MY_EVENT) {
IntentFilter filter = new IntentFilter(
Constants.INTENT_ACTION_USER_CHANGE);
filter.addAction(Constants.INTENT_ACTION_LOGOUT);
getActivity().registerReceiver(mReceiver, filter);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (event_type == EventList.EVENT_LIST_TYPE_MY_EVENT) {
getActivity().unregisterReceiver(mReceiver);
}
}
@Override
public void initView(View view) {
super.initView(view);
mErrorLayout.setOnLayoutClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
clickErrorLayout();
}
});
}
private void clickErrorLayout() {
if (event_type == EventList.EVENT_LIST_TYPE_NEW_EVENT) {
mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
requestData(true);
} else {
if (AppContext.getInstance().isLogin()) {
mErrorLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
requestData(true);
} else {
UIHelper.showLoginActivity(getActivity());
}
}
}
@Override
protected void requestData(boolean refresh) {
if (event_type == EventList.EVENT_LIST_TYPE_NEW_EVENT) {
mCatalog = -1;
super.requestData(refresh);
return;
}
if (AppContext.getInstance().isLogin()) {
mCatalog = AppContext.getInstance().getLoginUid();
super.requestData(refresh);
} else {
mErrorLayout.setErrorType(EmptyLayout.NETWORK_ERROR);
mErrorLayout.setErrorMessage(getString(R.string.unlogin_tip));
}
}
@Override
protected String getCacheKeyPrefix() {
return CACHE_KEY_PREFIX + mCatalog;
}
@Override
protected EventList parseList(InputStream is) throws Exception {
EventList list = XmlUtils.toBean(EventList.class, is);
return list;
}
@Override
protected EventList readList(Serializable seri) {
return ((EventList) seri);
}
@Override
protected void sendRequestData() {
OSChinaApi.getEventList(mCurrentPage, mCatalog, mHandler);
}
@Override
public void onItemClick(AdapterView> parent, View view, int position,
long id) {
Event event = mAdapter.getItem(position);
if (event != null)
UIHelper.showEventDetail(view.getContext(), event.getId());
}
}
EventDetailFragment.java
package net.oschina.app.fragment;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URLEncoder;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.BaseDetailFragment;
import net.oschina.app.base.BaseListFragment;
import net.oschina.app.bean.CommentList;
import net.oschina.app.bean.Entity;
import net.oschina.app.bean.Event;
import net.oschina.app.bean.EventApplyData;
import net.oschina.app.bean.FavoriteList;
import net.oschina.app.bean.Post;
import net.oschina.app.bean.PostDetail;
import net.oschina.app.bean.Result;
import net.oschina.app.bean.ResultBean;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.emoji.OnSendClickListener;
import net.oschina.app.ui.DetailActivity;
import net.oschina.app.ui.EventApplyDialog;
import net.oschina.app.ui.empty.EmptyLayout;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.XmlUtils;
import org.apache.http.Header;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.text.Editable;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
import com.loopj.android.http.AsyncHttpResponseHandler;
/**
* 活动详情页面
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年12月12日 下午3:08:49
*
*/
public class EventDetailFragment extends BaseDetailFragment implements
OnSendClickListener {
protected static final String TAG = EventDetailFragment.class
.getSimpleName();
private static final String POST_CACHE_KEY = "post_";
@InjectView(R.id.tv_event_title)
TextView mTvTitle;
@InjectView(R.id.tv_event_start_time)
TextView mTvStartTime;
@InjectView(R.id.tv_event_end_time)
TextView mTvEndTime;
@InjectView(R.id.tv_event_spot)
TextView mTvSpot;
@InjectView(R.id.webview)
WebView mWebView;
@InjectView(R.id.rl_event_location)
View mLocation;
@InjectView(R.id.bt_event_attend)
Button mBtAttend;// 出席人员
@InjectView(R.id.bt_event_apply)
Button mBtEventApply;// 活动报名
@InjectView(R.id.tv_event_tip)
TextView mEventTip;
private int mPostId;
private Post mPost;
private EventApplyDialog mEventApplyDialog;
@Override
public View onCreateView(LayoutInflater inflater,
@Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View view = inflater.inflate(R.layout.fragment_event_detail, container,
false);
mPostId = getActivity().getIntent().getIntExtra("post_id", 0);
ButterKnife.inject(this, view);
initViews(view);
return view;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
requestData(true);
}
@Override
protected void onFavoriteChanged(boolean flag) {
super.onFavoriteChanged(flag);
mPost.setFavorite(flag ? 1 : 0);
saveCache(mPost);
}
private void initViews(View view) {
mEmptyLayout = (EmptyLayout) view.findViewById(R.id.error_layout);
mLocation.setOnClickListener(this);
mBtAttend.setOnClickListener(this);
mBtEventApply.setOnClickListener(this);
UIHelper.initWebView(mWebView);
}
@Override
public void onClick(View v) {
super.onClick(v);
int id = v.getId();
switch (id) {
case R.id.rl_event_location:
UIHelper.showEventLocation(getActivity(), mPost.getEvent()
.getCity(), mPost.getEvent().getSpot());
break;
case R.id.bt_event_attend:
showEventApplies();
break;
case R.id.bt_event_apply:
showEventApply();
break;
default:
break;
}
}
private void showEventApplies() {
Bundle args = new Bundle();
args.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, mPost.getEvent()
.getId());
UIHelper.showSimpleBack(getActivity(), SimpleBackPage.EVENT_APPLY, args);
}
private final AsyncHttpResponseHandler mApplyHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
Result rs = XmlUtils.toBean(ResultBean.class,
new ByteArrayInputStream(arg2)).getResult();
if (rs.OK()) {
AppContext.showToast("报名成功");
mEventApplyDialog.dismiss();
mPost.getEvent().setApplyStatus(Event.APPLYSTATUS_CHECKING);
notifyEventStatus();
} else {
AppContext.showToast(rs.getErrorMessage());
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
AppContext.showToast("报名失败");
}
@Override
public void onFinish() {
hideWaitDialog();
}
};
/**
* 显示活动报名对话框
*/
private void showEventApply() {
if (mPost.getEvent().getCategory() == 4) {
UIHelper.openSysBrowser(getActivity(), mPost.getEvent().getUrl());
return;
}
if (!AppContext.getInstance().isLogin()) {
UIHelper.showLoginActivity(getActivity());
return;
}
if (mEventApplyDialog == null) {
mEventApplyDialog = new EventApplyDialog(getActivity());
mEventApplyDialog.setCanceledOnTouchOutside(true);
mEventApplyDialog.setCancelable(true);
mEventApplyDialog.setTitle("活动报名");
mEventApplyDialog.setCanceledOnTouchOutside(true);
mEventApplyDialog.setNegativeButton(R.string.cancle, null);
mEventApplyDialog.setPositiveButton(R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface d, int which) {
EventApplyData data = null;
if ((data = mEventApplyDialog.getApplyData()) != null) {
data.setEvent(mPostId);
data.setUser(AppContext.getInstance()
.getLoginUid());
showWaitDialog(R.string.progress_submit);
OSChinaApi.eventApply(data, mApplyHandler);
}
}
});
}
mEventApplyDialog.show();
}
@Override
protected String getCacheKey() {
return new StringBuilder(POST_CACHE_KEY).append(mPostId).toString();
}
@Override
protected void sendRequestData() {
mEmptyLayout.setErrorType(EmptyLayout.NETWORK_LOADING);
OSChinaApi.getPostDetail(mPostId, mHandler);
}
@Override
protected Entity parseData(InputStream is) throws Exception {
return XmlUtils.toBean(PostDetail.class, is).getPost();
}
@Override
protected Entity readData(Serializable seri) {
return (Post) seri;
}
@Override
protected void executeOnLoadDataSuccess(Entity entity) {
mPost = (Post) entity;
fillUI();
fillWebViewBody();
((DetailActivity) getActivity()).toolFragment.setCommentCount(mPost
.getAnswerCount());
}
private void fillUI() {
mTvTitle.setText(mPost.getTitle());
mTvStartTime.setText(String.format(
getString(R.string.event_start_time), mPost.getEvent()
.getStartTime()));
mTvEndTime.setText(String.format(getString(R.string.event_end_time),
mPost.getEvent().getEndTime()));
mTvSpot.setText(mPost.getEvent().getCity() + " "
+ mPost.getEvent().getSpot());
notifyFavorite(mPost.getFavorite() == 1);
// 站外活动
if (mPost.getEvent().getCategory() == 4) {
mBtEventApply.setVisibility(View.VISIBLE);
mBtAttend.setVisibility(View.GONE);
mBtEventApply.setText("报名链接");
} else {
notifyEventStatus();
}
}
@Override
public int getCommentCount() {
return mPost.getAnswerCount();
}
// 显示活动 以及报名的状态
private void notifyEventStatus() {
int eventStatus = mPost.getEvent().getStatus();
int applyStatus = mPost.getEvent().getApplyStatus();
if (applyStatus == Event.APPLYSTATUS_ATTEND) {
mBtAttend.setVisibility(View.VISIBLE);
} else {
mBtAttend.setVisibility(View.GONE);
}
if (eventStatus == Event.EVNET_STATUS_APPLYING) {
mBtEventApply.setVisibility(View.VISIBLE);
mBtEventApply.setEnabled(false);
switch (applyStatus) {
case Event.APPLYSTATUS_CHECKING:
mBtEventApply.setText("待确认");
break;
case Event.APPLYSTATUS_CHECKED:
mBtEventApply.setText("已确认");
mBtEventApply.setVisibility(View.GONE);
mEventTip.setVisibility(View.VISIBLE);
break;
case Event.APPLYSTATUS_ATTEND:
mBtEventApply.setText("已出席");
break;
case Event.APPLYSTATUS_CANCLE:
mBtEventApply.setText("已取消");
mBtEventApply.setEnabled(true);
break;
case Event.APPLYSTATUS_REJECT:
mBtEventApply.setText("已拒绝");
break;
default:
mBtEventApply.setText("我要报名");
mBtEventApply.setEnabled(true);
break;
}
} else {
mBtEventApply.setVisibility(View.GONE);
}
}
private void fillWebViewBody() {
// 显示标签
StringBuffer body = new StringBuffer();
body.append(UIHelper.setHtmlCotentSupportImagePreview(mPost.getBody()));
body.append(UIHelper.WEB_STYLE).append(UIHelper.WEB_LOAD_IMAGES)
.append(getPostTags(mPost.getTags()))
.append("");
mWebView.loadDataWithBaseURL(null, body.toString(), "text/html",
"utf-8", null);
}
@SuppressWarnings("deprecation")
private String getPostTags(Post.Tags taglist) {
if (taglist == null)
return "";
StringBuffer tags = new StringBuffer();
for (String tag : taglist.getTags()) {
tags.append(String
.format(" %s ",
URLEncoder.encode(tag), tag));
}
return String.format("%s", tags);
}
@Override
protected int getFavoriteTargetId() {
return mPost != null ? mPost.getId() : -1;
}
@Override
protected int getFavoriteTargetType() {
return mPost != null ? FavoriteList.TYPE_POST : -1;
}
@Override
protected String getShareTitle() {
return mPost != null ? mPost.getTitle()
: getString(R.string.share_title_post);
}
@Override
protected String getShareContent() {
return mPost != null ? StringUtils.getSubString(0, 55,
getFilterHtmlBody(mPost.getBody())) : "";
}
@Override
protected String getShareUrl() {
return mPost != null ? mPost.getUrl().replace("http://www", "http://m")
: null;
}
@Override
public void onClickSendButton(Editable str) {
if (!TDevice.hasInternet()) {
AppContext.showToastShort(R.string.tip_network_error);
return;
}
if (!AppContext.getInstance().isLogin()) {
UIHelper.showLoginActivity(getActivity());
return;
}
if (TextUtils.isEmpty(str)) {
AppContext.showToastShort(R.string.tip_comment_content_empty);
return;
}
showWaitDialog(R.string.progress_submit);
OSChinaApi.publicComment(CommentList.CATALOG_POST, mPostId, AppContext
.getInstance().getLoginUid(), str.toString(), 0,
mCommentHandler);
}
@Override
public void onClickFlagButton() {}
@Override
public void onclickWriteComment() {
super.onclickWriteComment();
UIHelper.showComment(getActivity(), mPostId, CommentList.CATALOG_POST);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.refresh_menu, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
sendRequestData();
return super.onOptionsItemSelected(item);
}
}
EventAppliesFragment.java
package net.oschina.app.fragment;
import java.io.InputStream;
import java.io.Serializable;
import net.oschina.app.AppContext;
import net.oschina.app.adapter.EventApplyAdapter;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.BaseListFragment;
import net.oschina.app.bean.Apply;
import net.oschina.app.bean.EventAppliesList;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.XmlUtils;
import android.annotation.TargetApi;
import android.os.Build;
import android.view.View;
import android.widget.AdapterView;
/**
* 活动出席人员列表
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年12月12日 下午7:59:10
*
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class EventAppliesFragment extends BaseListFragment {
protected static final String TAG = EventAppliesFragment.class.getSimpleName();
private static final String CACHE_KEY_PREFIX = "event_apply_user_list";
@Override
public void initView(View view) {
super.initView(view);
}
@Override
protected EventApplyAdapter getListAdapter() {
return new EventApplyAdapter();
}
@Override
protected String getCacheKeyPrefix() {
return CACHE_KEY_PREFIX + "_" + mCatalog;
}
@Override
protected EventAppliesList parseList(InputStream is) throws Exception {
EventAppliesList list = XmlUtils.toBean(EventAppliesList.class, is);
return list;
}
@Override
protected EventAppliesList readList(Serializable seri) {
return ((EventAppliesList) seri);
}
@Override
protected void sendRequestData() {
OSChinaApi.getEventApplies(mCatalog, mCurrentPage, mHandler);
}
@Override
public void onItemClick(AdapterView> parent, View view, int position,
long id) {
Apply item = (Apply) mAdapter.getItem(position);
if (item != null) {
if (AppContext.getInstance().isLogin()) {
UIHelper.showMessageDetail(getActivity(), item.getId(), item.getName());
return;
}
UIHelper.showUserCenter(getActivity(), item.getId(),item.getName());
}
}
}
BaseFragmentInterface.java
package net.oschina.app.interf;
import android.view.View;
/**
* 基类fragment实现接口
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年9月25日 上午11:00:25
*
*/
public interface BaseFragmentInterface {
public void initView(View view);
public void initData();
}
BaseViewInterface.java
package net.oschina.app.interf;
/**
*
* @author deyi
*
*/
public interface BaseViewInterface {
public void initView();
public void initData();
}
ICallbackResult.java
package net.oschina.app.interf;
/**
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2014年11月18日 上午11:18:28
*
*/
public interface ICallbackResult {
public void OnBackResult(Object s);
}
OnTabReselectListener.java
package net.oschina.app.interf;
/**
* 当tabHost再次被点击时
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 创建时间:2014年11月17日 上午11:00:15
*
*/
public interface OnTabReselectListener {
public void onTabReselect();
}
OnWebViewImageListener.java
package net.oschina.app.interf;
/**
* 监听webview上的图片
*
* @author [email protected]
*
*/
public interface OnWebViewImageListener {
/**
* 点击webview上的图片,传入该缩略图的大图Url
* @param bigImageUrl
*/
void showImagePreview(String bigImageUrl);
}
DownloadService.java
package net.oschina.app.service;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import net.oschina.app.AppConfig;
import net.oschina.app.R;
import net.oschina.app.interf.ICallbackResult;
import net.oschina.app.ui.MainActivity;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TDevice;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.widget.RemoteViews;
/**
* download service
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年11月18日 下午3:02:36
*
*/
public class DownloadService extends Service {
public static final String BUNDLE_KEY_DOWNLOAD_URL = "download_url";
public static final String BUNDLE_KEY_TITLE = "title";
private final String tag = "download";
private static final int NOTIFY_ID = 0;
private int progress;
private NotificationManager mNotificationManager;
private boolean canceled;
private String downloadUrl;
private String mTitle = "正在下载%s";
private String saveFileName = AppConfig.DEFAULT_SAVE_FILE_PATH;
private ICallbackResult callback;
private DownloadBinder binder;
private boolean serviceIsDestroy = false;
private Context mContext = this;
private Thread downLoadThread;
private Notification mNotification;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
super.handleMessage(msg);
switch (msg.what) {
case 0:
// 下载完毕
mNotificationManager.cancel(NOTIFY_ID);
installApk();
break;
case 2:
// 取消通知
mNotificationManager.cancel(NOTIFY_ID);
break;
case 1:
int rate = msg.arg1;
if (rate < 100) {
RemoteViews contentview = mNotification.contentView;
contentview.setTextViewText(R.id.tv_download_state, mTitle + "(" + rate
+ "%" + ")");
contentview.setProgressBar(R.id.pb_download, 100, rate,
false);
} else {
// 下载完毕后变换通知形式
mNotification.flags = Notification.FLAG_AUTO_CANCEL;
mNotification.contentView = null;
Intent intent = new Intent(mContext, MainActivity.class);
// 告知已完成
intent.putExtra("completed", "yes");
// 更新参数,注意flags要使用FLAG_UPDATE_CURRENT
PendingIntent contentIntent = PendingIntent.getActivity(
mContext, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
mNotification.setLatestEventInfo(mContext, "下载完成",
"文件已下载完毕", contentIntent);
serviceIsDestroy = true;
stopSelf();// 停掉服务自身
}
mNotificationManager.notify(NOTIFY_ID, mNotification);
break;
}
}
};
@Override
public IBinder onBind(Intent intent) {
downloadUrl = intent.getStringExtra(BUNDLE_KEY_DOWNLOAD_URL);
saveFileName = saveFileName + getSaveFileName(downloadUrl);
mTitle = String.format(mTitle, intent.getStringExtra(BUNDLE_KEY_TITLE));
return binder;
}
private String getSaveFileName(String downloadUrl) {
if (downloadUrl == null || StringUtils.isEmpty(downloadUrl)) {
return "";
}
return downloadUrl.substring(downloadUrl.lastIndexOf("/"));
}
@Override
public void onCreate() {
super.onCreate();
binder = new DownloadBinder();
mNotificationManager = (NotificationManager) getSystemService(android.content.Context.NOTIFICATION_SERVICE);
stopForeground(true);// 这个不确定是否有作用
}
private void startDownload() {
canceled = false;
downloadApk();
}
/**
* 创建通知
*/
private void setUpNotification() {
int icon = R.drawable.ic_notification;
CharSequence tickerText = "准备下载";
long when = System.currentTimeMillis();
mNotification = new Notification(icon, tickerText, when);
;
// 放置在"正在运行"栏目中
mNotification.flags = Notification.FLAG_ONGOING_EVENT;
RemoteViews contentView = new RemoteViews(getPackageName(),
R.layout.download_notification_show);
contentView.setTextViewText(R.id.tv_download_state, mTitle);
// 指定个性化视图
mNotification.contentView = contentView;
Intent intent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
// 指定内容意图
mNotification.contentIntent = contentIntent;
mNotificationManager.notify(NOTIFY_ID, mNotification);
}
private void downloadApk() {
downLoadThread = new Thread(mdownApkRunnable);
downLoadThread.start();
}
/**
* 安装apk
*/
private void installApk() {
File apkfile = new File(saveFileName);
if (!apkfile.exists()) {
return;
}
TDevice.installAPK(mContext, apkfile);
}
private Runnable mdownApkRunnable = new Runnable() {
@Override
public void run() {
File file = new File(AppConfig.DEFAULT_SAVE_FILE_PATH);
if (!file.exists()) {
file.mkdirs();
}
String apkFile = saveFileName;
File saveFile = new File(apkFile);
try {
downloadUpdateFile(downloadUrl, saveFile);
} catch (Exception e) {
e.printStackTrace();
}
}
};
public long downloadUpdateFile(String downloadUrl, File saveFile)
throws Exception {
int downloadCount = 0;
int currentSize = 0;
long totalSize = 0;
int updateTotalSize = 0;
HttpURLConnection httpConnection = null;
InputStream is = null;
FileOutputStream fos = null;
try {
URL url = new URL(downloadUrl);
httpConnection = (HttpURLConnection) url.openConnection();
httpConnection
.setRequestProperty("User-Agent", "PacificHttpClient");
if (currentSize > 0) {
httpConnection.setRequestProperty("RANGE", "bytes="
+ currentSize + "-");
}
httpConnection.setConnectTimeout(10000);
httpConnection.setReadTimeout(20000);
updateTotalSize = httpConnection.getContentLength();
if (httpConnection.getResponseCode() == 404) {
throw new Exception("fail!");
}
is = httpConnection.getInputStream();
fos = new FileOutputStream(saveFile, false);
byte buffer[] = new byte[1024];
int readsize = 0;
while ((readsize = is.read(buffer)) > 0) {
fos.write(buffer, 0, readsize);
totalSize += readsize;
// 为了防止频繁的通知导致应用吃紧,百分比增加10才通知一次
if ((downloadCount == 0)
|| (int) (totalSize * 100 / updateTotalSize) - 10 >= downloadCount) {
downloadCount += 10;
// 更新进度
Message msg = mHandler.obtainMessage();
msg.what = 1;
msg.arg1 = downloadCount;
mHandler.sendMessage(msg);
if (callback != null)
callback.OnBackResult(progress);
}
}
// 下载完成通知安装
mHandler.sendEmptyMessage(0);
// 下载完了,cancelled也要设置
canceled = true;
} finally {
if (httpConnection != null) {
httpConnection.disconnect();
}
if (is != null) {
is.close();
}
if (fos != null) {
fos.close();
}
}
return totalSize;
}
public class DownloadBinder extends Binder {
public void start() {
if (downLoadThread == null || !downLoadThread.isAlive()) {
progress = 0;
setUpNotification();
new Thread() {
public void run() {
// 下载
startDownload();
};
}.start();
}
}
public void cancel() {
canceled = true;
}
public int getProgress() {
return progress;
}
public boolean isCanceled() {
return canceled;
}
public boolean serviceIsDestroy() {
return serviceIsDestroy;
}
public void cancelNotification() {
mHandler.sendEmptyMessage(2);
}
public void addCallback(ICallbackResult callback) {
DownloadService.this.callback = callback;
}
}
}
NoticeService.java
package net.oschina.app.service;
import java.io.ByteArrayInputStream;
import java.lang.ref.WeakReference;
import net.oschina.app.AppConfig;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.Notice;
import net.oschina.app.bean.NoticeDetail;
import net.oschina.app.bean.Result;
import net.oschina.app.bean.ResultBean;
import net.oschina.app.broadcast.AlarmReceiver;
import net.oschina.app.ui.MainActivity;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.XmlUtils;
import org.apache.http.Header;
import android.app.AlarmManager;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.net.Uri;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
import com.loopj.android.http.AsyncHttpResponseHandler;
public class NoticeService extends Service {
public static final String INTENT_ACTION_GET = "net.oschina.app.service.GET_NOTICE";
public static final String INTENT_ACTION_CLEAR = "net.oschina.app.service.CLEAR_NOTICE";
public static final String INTENT_ACTION_BROADCAST = "net.oschina.app.service.BROADCAST";
public static final String INTENT_ACTION_SHUTDOWN = "net.oschina.app.service.SHUTDOWN";
public static final String INTENT_ACTION_REQUEST = "net.oschina.app.service.REQUEST";
public static final String BUNDLE_KEY_TPYE = "bundle_key_type";
private static final long INTERVAL = 1000 * 120;
private AlarmManager mAlarmMgr;
private Notice mNotice;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (Constants.INTENT_ACTION_NOTICE.equals(action)) {
Notice notice = (Notice) intent.getSerializableExtra("notice_bean");
int atmeCount = notice.getAtmeCount();// @我
int msgCount = notice.getMsgCount();// 留言
int reviewCount = notice.getReviewCount();// 评论
int newFansCount = notice.getNewFansCount();// 新粉丝
int newLikeCount = notice.getNewLikeCount();// 点赞数
int activeCount = atmeCount + reviewCount + msgCount
+ newFansCount + newLikeCount;
if (activeCount == 0) {
NotificationManagerCompat.from(NoticeService.this).cancel(
R.string.you_have_news_messages);
}
} else if (INTENT_ACTION_BROADCAST.equals(action)) {
if (mNotice != null) {
UIHelper.sendBroadCast(NoticeService.this, mNotice);
}
} else if (INTENT_ACTION_SHUTDOWN.equals(action)) {
stopSelf();
} else if (INTENT_ACTION_REQUEST.equals(action)) {
requestNotice();
}
}
};
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public void onCreate() {
super.onCreate();
mAlarmMgr = (AlarmManager) getSystemService(ALARM_SERVICE);
startRequestAlarm();
requestNotice();
IntentFilter filter = new IntentFilter(INTENT_ACTION_BROADCAST);
filter.addAction(Constants.INTENT_ACTION_NOTICE);
filter.addAction(INTENT_ACTION_SHUTDOWN);
filter.addAction(INTENT_ACTION_REQUEST);
registerReceiver(mReceiver, filter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
cancelRequestAlarm();
unregisterReceiver(mReceiver);
super.onDestroy();
}
private void startRequestAlarm() {
cancelRequestAlarm();
// 从1秒后开始,每隔2分钟执行getOperationIntent()
mAlarmMgr.setRepeating(AlarmManager.RTC_WAKEUP,
System.currentTimeMillis() + 1000, INTERVAL,
getOperationIntent());
}
/**
* 即使启动PendingIntent的原进程结束了的话,PendingIntent本身仍然还存在,可在其他进程(
* PendingIntent被递交到的其他程序)中继续使用.
* 如果我在从系统中提取一个PendingIntent的,而系统中有一个和你描述的PendingIntent对等的PendingInent,
* 那么系统会直接返回和该PendingIntent其实是同一token的PendingIntent,
* 而不是一个新的token和PendingIntent。然而你在从提取PendingIntent时,通过FLAG_CANCEL_CURRENT参数,
* 让这个老PendingIntent的先cancel()掉,这样得到的pendingInten和其token的就是新的了。
*/
private void cancelRequestAlarm() {
mAlarmMgr.cancel(getOperationIntent());
}
/**
* OSC采用轮询方式实现消息推送
* 每次被调用都去执行一次{@link #AlarmReceiver}onReceive()方法
*
* @return
*/
private PendingIntent getOperationIntent() {
Intent intent = new Intent(this, AlarmReceiver.class);
PendingIntent operation = PendingIntent.getBroadcast(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
return operation;
}
private void clearNotice(int uid, int type) {
OSChinaApi.clearNotice(uid, type, mClearNoticeHandler);
}
private int lastNotifiyCount;
private void notification(Notice notice) {
int atmeCount = notice.getAtmeCount();
int msgCount = notice.getMsgCount();
int reviewCount = notice.getReviewCount();
int newFansCount = notice.getNewFansCount();
int newLikeCount = notice.getNewLikeCount();
int count = atmeCount + msgCount + reviewCount + newFansCount + newLikeCount;
if (count == 0) {
lastNotifiyCount = 0;
NotificationManagerCompat.from(this).cancel(
R.string.you_have_news_messages);
return;
}
if (count == lastNotifiyCount)
return;
lastNotifiyCount = count;
Resources res = getResources();
String contentTitle = res.getString(R.string.you_have_news_messages,
count);
String contentText;
StringBuffer sb = new StringBuffer();
if (atmeCount > 0) {
sb.append(getString(R.string.atme_count, atmeCount)).append(" ");
}
if (msgCount > 0) {
sb.append(getString(R.string.msg_count, msgCount)).append(" ");
}
if (reviewCount > 0) {
sb.append(getString(R.string.review_count, reviewCount))
.append(" ");
}
if (newFansCount > 0) {
sb.append(getString(R.string.fans_count, newFansCount));
}
if (newLikeCount > 0) {
sb.append(getString(R.string.like_count, newLikeCount));
}
contentText = sb.toString();
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("NOTICE", true);
PendingIntent pi = PendingIntent.getActivity(this, 1000, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this).setTicker(contentTitle).setContentTitle(contentTitle)
.setContentText(contentText).setAutoCancel(true)
.setContentIntent(pi).setSmallIcon(R.drawable.ic_notification);
if (AppContext.get(AppConfig.KEY_NOTIFICATION_SOUND, true)) {
builder.setSound(Uri.parse("android.resource://"
+ AppContext.getInstance().getPackageName() + "/"
+ R.raw.notificationsound));
}
if (AppContext.get(AppConfig.KEY_NOTIFICATION_VIBRATION, true)) {
long[] vibrate = { 0, 10, 20, 30 };
builder.setVibrate(vibrate);
}
Notification notification = builder.build();
NotificationManagerCompat.from(this).notify(
R.string.you_have_news_messages, notification);
}
private final AsyncHttpResponseHandler mGetNoticeHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
Notice notice = XmlUtils.toBean(NoticeDetail.class,
arg2).getNotice();
if (notice != null) {
UIHelper.sendBroadCast(NoticeService.this, notice);
if (AppContext.get(AppConfig.KEY_NOTIFICATION_ACCEPT, true)) {
notification(notice);
}
mNotice = notice;
} else {
// ResultBean resultBean = XmlUtils.toBean(ResultBean.class, arg2);
// if (resultBean != null && resultBean.getResult() != null) {
// AppContext appContext = AppContext.getInstance();
// if (appContext != null) {
// appContext.Logout();
// }
// }
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
};
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
arg3.printStackTrace();
}
};
private final AsyncHttpResponseHandler mClearNoticeHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
ResultBean rsb = XmlUtils.toBean(ResultBean.class,
new ByteArrayInputStream(arg2));
Result res = rsb.getResult();
if (res.OK() && rsb.getNotice() != null) {
mNotice = rsb.getNotice();
UIHelper.sendBroadCast(NoticeService.this, rsb.getNotice());
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {}
};
/**
* 请求是否有新通知
*/
private void requestNotice() {
OSChinaApi.getNotices(mGetNoticeHandler);
}
private static class ServiceStub extends INoticeService.Stub {
WeakReference mService;
ServiceStub(NoticeService service) {
mService = new WeakReference(service);
}
@Override
public void clearNotice(int uid, int type) throws RemoteException {
mService.get().clearNotice(uid, type);
}
@Override
public void scheduleNotice() throws RemoteException {
mService.get().startRequestAlarm();
}
@Override
public void requestNotice() throws RemoteException {
mService.get().requestNotice();
}
}
private final IBinder mBinder = new ServiceStub(this);
}
NoticeUtils.java
package net.oschina.app.service;
import java.util.HashMap;
import net.oschina.app.AppConfig;
import net.oschina.app.AppContext;
import net.oschina.app.util.TLog;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.RemoteException;
import android.util.Log;
public class NoticeUtils {
public static INoticeService sService = null;
private static HashMap sConnectionMap = new HashMap();
public static boolean bindToService(Context context) {
return bindToService(context, null);
}
public static boolean bindToService(Context context,
ServiceConnection callback) {
context.startService(new Intent(context, NoticeService.class));
ServiceBinder sb = new ServiceBinder(callback);
sConnectionMap.put(context, sb);
return context.bindService(
(new Intent()).setClass(context, NoticeService.class), sb, 0);
}
public static void unbindFromService(Context context) {
ServiceBinder sb = sConnectionMap.remove(context);
if (sb == null) {
Log.e("MusicUtils", "Trying to unbind for unknown Context");
return;
}
context.unbindService(sb);
if (sConnectionMap.isEmpty()) {
// presumably there is nobody interested in the service at this
// point,
// so don't hang on to the ServiceConnection
sService = null;
}
}
public static void clearNotice(int type) {
if (sService != null) {
try {
sService.clearNotice(AppContext.getInstance().getLoginUid(),
type);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public static void requestNotice(Context context) {
if (sService != null) {
try {
TLog.log("requestNotice...");
sService.requestNotice();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
context.sendBroadcast(new Intent(
NoticeService.INTENT_ACTION_REQUEST));
TLog.log("requestNotice,service is null");
}
}
public static void scheduleNotice() {
if (sService != null) {
try {
sService.scheduleNotice();
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
private static class ServiceBinder implements ServiceConnection {
ServiceConnection mCallback;
ServiceBinder(ServiceConnection callback) {
mCallback = callback;
}
@Override
public void onServiceConnected(ComponentName className,
android.os.IBinder service) {
sService = INoticeService.Stub.asInterface(service);
if (mCallback != null) {
mCallback.onServiceConnected(className, service);
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
if (mCallback != null) {
mCallback.onServiceDisconnected(className);
}
sService = null;
}
}
public static void tryToShutDown(Context context) {
if (AppContext.get(AppConfig.KEY_NOTIFICATION_DISABLE_WHEN_EXIT, true)) {
context.sendBroadcast(new Intent(
NoticeService.INTENT_ACTION_SHUTDOWN));
}
}
public static void startNotifyService(Context context) {
Intent service = new Intent(context, NoticeService.class);
context.startService(service);
}
}
PublicCommentTask.java
package net.oschina.app.service;
import android.os.Parcel;
import android.os.Parcelable;
public class PublicCommentTask implements Parcelable {
private int catalog;
private int id;
private int uid;
private String content;
private int isPostToMyZone;
public PublicCommentTask() {
}
public PublicCommentTask(Parcel source) {
catalog = source.readInt();
id = source.readInt();
uid = source.readInt();
content = source.readString();
isPostToMyZone = source.readInt();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(catalog);
dest.writeInt(id);
dest.writeInt(uid);
dest.writeString(content);
dest.writeInt(isPostToMyZone);
}
public int getCatalog() {
return catalog;
}
public void setCatalog(int catalog) {
this.catalog = catalog;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getUid() {
return uid;
}
public void setUid(int uid) {
this.uid = uid;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public int getIsPostToMyZone() {
return isPostToMyZone;
}
public void setIsPostToMyZone(int isPostToMyZone) {
this.isPostToMyZone = isPostToMyZone;
}
@Override
public int describeContents() {
return 0;
}
public static final Parcelable.Creator CREATOR = new Creator() {
@Override
public PublicCommentTask[] newArray(int size) {
return new PublicCommentTask[size];
}
@Override
public PublicCommentTask createFromParcel(Parcel source) {
return new PublicCommentTask(source);
}
};
}
ServerTaskService.java
package net.oschina.app.service;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.api.OperationResponseHandler;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.ListBaseAdapter;
import net.oschina.app.bean.Comment;
import net.oschina.app.bean.Result;
import net.oschina.app.bean.ResultBean;
import net.oschina.app.bean.Tweet;
import net.oschina.app.util.XmlUtils;
import android.app.IntentService;
import android.app.Notification;
import android.app.PendingIntent;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationManagerCompat;
public class ServerTaskService extends IntentService {
private static final String SERVICE_NAME = "ServerTaskService";
public static final String ACTION_PUB_BLOG_COMMENT = "net.oschina.app.ACTION_PUB_BLOG_COMMENT";
public static final String ACTION_PUB_COMMENT = "net.oschina.app.ACTION_PUB_COMMENT";
public static final String ACTION_PUB_POST = "net.oschina.app.ACTION_PUB_POST";
public static final String ACTION_PUB_TWEET = "net.oschina.app.ACTION_PUB_TWEET";
public static final String ACTION_PUB_SOFTWARE_TWEET = "net.oschina.app.ACTION_PUB_SOFTWARE_TWEET";
public static final String KEY_ADAPTER = "adapter";
public static final String BUNDLE_PUB_COMMENT_TASK = "BUNDLE_PUB_COMMENT_TASK";
public static final String BUNDLE_PUB_POST_TASK = "BUNDLE_PUB_POST_TASK";
public static final String BUNDLE_PUB_TWEET_TASK = "BUNDLE_PUB_TWEET_TASK";
public static final String BUNDLE_PUB_SOFTWARE_TWEET_TASK = "BUNDLE_PUB_SOFTWARE_TWEET_TASK";
public static final String KEY_SOFTID = "soft_id";
private static final String KEY_COMMENT = "comment_";
private static final String KEY_TWEET = "tweet_";
private static final String KEY_SOFTWARE_TWEET = "software_tweet_";
private static final String KEY_POST = "post_";
public static List penddingTasks = new ArrayList();
class PublicCommentResponseHandler extends OperationResponseHandler {
public PublicCommentResponseHandler(Looper looper, Object... args) {
super(looper, args);
}
@Override
public void onSuccess(int code, ByteArrayInputStream is, Object[] args)
throws Exception {
PublicCommentTask task = (PublicCommentTask) args[0];
final int id = task.getId() * task.getUid();
ResultBean resB = XmlUtils.toBean(ResultBean.class, is);
Result res = resB.getResult();
if (res.OK()) {
final Comment comment = resB.getComment();
// UIHelper.sendBroadCastCommentChanged(ServerTaskService.this,
// isBlog, task.getId(), task.getCatalog(),
// Comment.OPT_ADD, comment);
notifySimpleNotifycation(id,
getString(R.string.comment_publish_success),
getString(R.string.comment_blog),
getString(R.string.comment_publish_success), false,
true);
removePenddingTask(KEY_COMMENT + id);
} else {
onFailure(100, res.getErrorMessage(), args);
}
}
@Override
public void onFailure(int code, String errorMessage, Object[] args) {
PublicCommentTask task = (PublicCommentTask) args[0];
int id = task.getId() * task.getUid();
notifySimpleNotifycation(id,
getString(R.string.comment_publish_faile),
getString(R.string.comment_blog),
code == 100 ? errorMessage
: getString(R.string.comment_publish_faile), false,
true);
removePenddingTask(KEY_COMMENT + id);
}
@Override
public void onFinish() {
tryToStopServie();
}
}
class PublicTweetResponseHandler extends OperationResponseHandler {
String key = null;
public PublicTweetResponseHandler(Looper looper, Object... args) {
super(looper, args);
key = (String) args[1];
}
@Override
public void onSuccess(int code, ByteArrayInputStream is, Object[] args)
throws Exception {
Tweet tweet = (Tweet) args[0];
final int id = tweet.getId();
Result res = XmlUtils.toBean(ResultBean.class, is).getResult();
if (res.OK()) {
notifySimpleNotifycation(id,
getString(R.string.tweet_publish_success),
getString(R.string.tweet_public),
getString(R.string.tweet_publish_success), false, true);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
cancellNotification(id);
}
}, 3000);
removePenddingTask(key + id);
if (tweet.getImageFilePath() != null) {
File imgFile = new File(tweet.getImageFilePath());
if (imgFile.exists()) {
imgFile.delete();
}
}
} else {
onFailure(100, res.getErrorMessage(), args);
}
}
@Override
public void onFailure(int code, String errorMessage, Object[] args) {
Tweet tweet = (Tweet) args[0];
int id = tweet.getId();
notifySimpleNotifycation(id,
getString(R.string.tweet_publish_faile),
getString(R.string.tweet_public),
code == 100 ? errorMessage
: getString(R.string.tweet_publish_faile), false,
true);
removePenddingTask(key + id);
}
@Override
public void onFinish() {
tryToStopServie();
}
}
public ServerTaskService() {
this(SERVICE_NAME);
}
private synchronized void tryToStopServie() {
if (penddingTasks == null || penddingTasks.size() == 0) {
stopSelf();
}
}
private synchronized void addPenddingTask(String key) {
penddingTasks.add(key);
}
private synchronized void removePenddingTask(String key) {
penddingTasks.remove(key);
}
public ServerTaskService(String name) {
super(name);
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
if (ACTION_PUB_BLOG_COMMENT.equals(action)) {
PublicCommentTask task = intent
.getParcelableExtra(BUNDLE_PUB_COMMENT_TASK);
if (task != null) {
publicBlogComment(task);
}
} else if (ACTION_PUB_COMMENT.equals(action)) {
PublicCommentTask task = intent
.getParcelableExtra(BUNDLE_PUB_COMMENT_TASK);
if (task != null) {
publicComment(task);
}
} else if (ACTION_PUB_POST.equals(action)) {
// Post post = intent.getParcelableExtra(BUNDLE_PUBLIC_POST_TASK);
// if (post != null) {
// publicPost(post);
// }
} else if (ACTION_PUB_TWEET.equals(action)) {
Tweet tweet = intent.getParcelableExtra(BUNDLE_PUB_TWEET_TASK);
if (tweet != null) {
pubTweet(tweet);
}
} else if (ACTION_PUB_SOFTWARE_TWEET.equals(action)) {
Tweet tweet = intent
.getParcelableExtra(BUNDLE_PUB_SOFTWARE_TWEET_TASK);
int softid = intent.getIntExtra(KEY_SOFTID, -1);
if (tweet != null && softid != -1) {
pubSoftWareTweet(tweet, softid);
}
}
}
private void publicBlogComment(final PublicCommentTask task) {
int id = task.getId() * task.getUid();
addPenddingTask(KEY_COMMENT + id);
notifySimpleNotifycation(id, getString(R.string.comment_publishing),
getString(R.string.comment_blog),
getString(R.string.comment_publishing), true, false);
OSChinaApi.publicBlogComment(task.getId(), task.getUid(), task
.getContent(), new PublicCommentResponseHandler(
getMainLooper(), task, true));
}
private void publicComment(final PublicCommentTask task) {
int id = task.getId() * task.getUid();
addPenddingTask(KEY_COMMENT + id);
notifySimpleNotifycation(id, getString(R.string.comment_publishing),
getString(R.string.comment_blog),
getString(R.string.comment_publishing), true, false);
OSChinaApi.publicComment(task.getCatalog(), task.getId(),
task.getUid(), task.getContent(), task.getIsPostToMyZone(),
new PublicCommentResponseHandler(getMainLooper(), task, false));
}
// private void publicPost(Post post) {
// post.setId((int) System.currentTimeMillis());
// int id = post.getId();
// addPenddingTask(KEY_POST + id);
// notifySimpleNotifycation(id, getString(R.string.post_publishing),
// getString(R.string.post_public),
// getString(R.string.post_publishing), true, false);
// OSChinaApi.publicPost(post, new
// PublicPostResponseHandler(getMainLooper(),
// post));
// }
//
private void pubTweet(final Tweet tweet) {
tweet.setId((int) System.currentTimeMillis());
int id = tweet.getId();
addPenddingTask(KEY_TWEET + id);
notifySimpleNotifycation(id, getString(R.string.tweet_publishing),
getString(R.string.tweet_public),
getString(R.string.tweet_publishing), true, false);
OSChinaApi.pubTweet(tweet, new PublicTweetResponseHandler(
getMainLooper(), tweet, KEY_TWEET));
}
private void pubSoftWareTweet(final Tweet tweet, int softid) {
tweet.setId((int) System.currentTimeMillis());
int id = tweet.getId();
addPenddingTask(KEY_SOFTWARE_TWEET + id);
notifySimpleNotifycation(id, getString(R.string.tweet_publishing),
getString(R.string.tweet_public),
getString(R.string.tweet_publishing), true, false);
OSChinaApi.pubSoftWareTweet(tweet, softid,
new PublicTweetResponseHandler(getMainLooper(), tweet,
KEY_SOFTWARE_TWEET));
}
private void notifySimpleNotifycation(int id, String ticker, String title,
String content, boolean ongoing, boolean autoCancel) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(
this)
.setTicker(ticker)
.setContentTitle(title)
.setContentText(content)
.setAutoCancel(true)
.setOngoing(false)
.setOnlyAlertOnce(true)
.setContentIntent(
PendingIntent.getActivity(this, 0, new Intent(), 0))
.setSmallIcon(R.drawable.ic_notification);
// if (AppContext.isNotificationSoundEnable()) {
// builder.setDefaults(Notification.DEFAULT_SOUND);
// }
Notification notification = builder.build();
NotificationManagerCompat.from(this).notify(id, notification);
}
private void cancellNotification(int id) {
NotificationManagerCompat.from(this).cancel(id);
}
}
ServerTaskUtils.java
package net.oschina.app.service;
import net.oschina.app.bean.Tweet;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class ServerTaskUtils {
public static void publicBlogComment(Context context, PublicCommentTask task) {
Intent intent = new Intent(ServerTaskService.ACTION_PUB_BLOG_COMMENT);
Bundle bundle = new Bundle();
bundle.putParcelable(ServerTaskService.BUNDLE_PUB_COMMENT_TASK, task);
intent.putExtras(bundle);
context.startService(intent);
}
public static void publicNewsComment(Context context, PublicCommentTask task) {
Intent intent = new Intent(ServerTaskService.ACTION_PUB_COMMENT);
Bundle bundle = new Bundle();
bundle.putParcelable(ServerTaskService.BUNDLE_PUB_COMMENT_TASK, task);
intent.putExtras(bundle);
context.startService(intent);
}
public static void pubTweet(Context context, Tweet tweet) {
Intent intent = new Intent(ServerTaskService.ACTION_PUB_TWEET);
Bundle bundle = new Bundle();
bundle.putParcelable(ServerTaskService.BUNDLE_PUB_TWEET_TASK, tweet);
intent.putExtras(bundle);
context.startService(intent);
}
public static void pubSoftWareTweet(Context context, Tweet tweet, int softid) {
Intent intent = new Intent(ServerTaskService.ACTION_PUB_SOFTWARE_TWEET);
Bundle bundle = new Bundle();
bundle.putParcelable(ServerTaskService.BUNDLE_PUB_SOFTWARE_TWEET_TASK,
tweet);
bundle.putInt(ServerTaskService.KEY_SOFTID, softid);
intent.putExtras(bundle);
context.startService(intent);
}
public static void pubTweetComment(Context context, PublicCommentTask task) {
Intent intent = new Intent(ServerTaskService.ACTION_PUB_COMMENT);
Bundle bundle = new Bundle();
bundle.putParcelable(ServerTaskService.BUNDLE_PUB_COMMENT_TASK, task);
intent.putExtras(bundle);
context.startService(intent);
}
}
DynamicAdapter.java
package net.oschina.app.team.adapter;
import net.oschina.app.R;
import net.oschina.app.base.ListBaseAdapter;
import net.oschina.app.team.bean.TeamActive;
import net.oschina.app.ui.ImagePreviewActivity;
import net.oschina.app.util.StringUtils;
import net.oschina.app.widget.AvatarView;
import net.oschina.app.widget.TweetTextView;
import org.kymjs.kjframe.KJBitmap;
import org.kymjs.kjframe.bitmap.BitmapCallBack;
import org.kymjs.kjframe.bitmap.BitmapHelper;
import android.content.Context;
import android.graphics.Bitmap;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
/**
* Team动态界面ListView适配器 ([email protected])
*
* @author kymjs (https://github.com/kymjs)
*
*/
public class DynamicAdapter extends ListBaseAdapter {
private final Context context;
private final KJBitmap kjb = new KJBitmap();
public DynamicAdapter(Context cxt) {
this.context = cxt;
}
static class ViewHolder {
AvatarView img_head;
TextView tv_name;
TweetTextView tv_content;
TextView tv_client;
TextView tv_date;
TextView tv_commit;
TextView tv_title;
ImageView iv_pic;
}
@Override
protected View getRealView(int position, View v, ViewGroup parent) {
super.getRealView(position, v, parent);
ViewHolder holder = null;
TeamActive data = mDatas.get(position);
if (v == null || v.getTag() == null) {
v = View.inflate(context, R.layout.list_cell_team_active, null);
holder = new ViewHolder();
holder.img_head = (AvatarView) v
.findViewById(R.id.event_listitem_userface);
holder.tv_name = (TextView) v
.findViewById(R.id.event_listitem_username);
holder.tv_title = (TextView) v.findViewById(R.id.title);
holder.tv_content = (TweetTextView) v
.findViewById(R.id.event_listitem_content);
holder.tv_client = (TextView) v
.findViewById(R.id.event_listitem_client);
holder.iv_pic = (ImageView) v.findViewById(R.id.iv_pic);
holder.tv_date = (TextView) v
.findViewById(R.id.event_listitem_date);
holder.tv_commit = (TextView) v.findViewById(R.id.tv_comment_count);
v.setTag(holder);
} else {
holder = (ViewHolder) v.getTag();
}
holder.img_head.setAvatarUrl(data.getAuthor().getPortrait());
holder.img_head.setUserInfo(data.getAuthor().getId(), data.getAuthor()
.getName());
holder.tv_name.setText(data.getAuthor().getName());
setContent(holder.tv_content, stripTags(data.getBody().getTitle()));
String date = StringUtils.friendly_time2(data.getCreateTime());
String preDate = "";
if (position > 0) {
preDate = StringUtils.friendly_time2(mDatas.get(position - 1)
.getCreateTime());
}
if (preDate.equals(date)) {
holder.tv_title.setVisibility(View.GONE);
} else {
holder.tv_title.setText(date);
holder.tv_title.setVisibility(View.VISIBLE);
}
holder.tv_content.setMaxLines(3);
holder.tv_date.setText(StringUtils.friendly_time(data.getCreateTime()));
holder.tv_commit.setText(data.getReply());
String imgPath = data.getBody().getImage();
if (!StringUtils.isEmpty(imgPath)) {
holder.iv_pic.setVisibility(View.VISIBLE);
setTweetImage(holder.iv_pic, imgPath);
} else {
holder.iv_pic.setVisibility(View.GONE);
}
return v;
}
/**
* 移除字符串中的Html标签
*
* @author kymjs (https://github.com/kymjs)
* @param pHTMLString
* @return
*/
public static String stripTags(final String pHTMLString) {
// String str = pHTMLString.replaceAll("\\<.*?>", "");
String str = pHTMLString.replaceAll("\\t", "");
str = str.replaceAll("<\\s*img\\s+([^>]*)\\s*>", "").trim();
return str;
}
@Override
public TeamActive getItem(int arg0) {
super.getItem(arg0);
return mDatas.get(arg0);
}
/**
* 动态设置图片显示样式
*
* @author kymjs
*/
private void setTweetImage(final ImageView pic, final String url) {
pic.setVisibility(View.VISIBLE);
kjb.display(pic, url, R.drawable.pic_bg, 0, 0, new BitmapCallBack() {
@Override
public void onSuccess(Bitmap bitmap) {
super.onSuccess(bitmap);
if (bitmap != null) {
bitmap = BitmapHelper.scaleWithXY(bitmap,
360 / bitmap.getHeight());
pic.setImageBitmap(bitmap);
}
}
});
pic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
ImagePreviewActivity.showImagePrivew(context, 0,
new String[] { url });
}
});
}
}
DiaryPagerAdapter.java
package net.oschina.app.team.adapter;
import net.oschina.app.util.StringUtils;
import net.oschina.app.widget.DiaryPageContentView;
import android.content.Context;
import android.support.v4.view.PagerAdapter;
import android.view.View;
import android.view.ViewGroup;
/**
* 周报ViewPager适配器
*
* @author kymjs (http://www.kymjs.com)
*/
public class DiaryPagerAdapter extends PagerAdapter {
private final Context cxt;
private final int currentYear;
private final int teamId;
public DiaryPagerAdapter(Context cxt, int currentYear, int teamId) {
this.currentYear = currentYear;
this.cxt = cxt;
this.teamId = teamId;
}
@Override
public int getCount() {
return currentYear == 2015 ? StringUtils.getWeekOfYear() : 52;
}
@Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
View pagerView = new DiaryPageContentView(cxt, teamId, currentYear,
position + 1).getView();
(container).addView(pagerView);
return pagerView;
}
}
TeamDiscussAdapter.java
package net.oschina.app.team.adapter;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.base.ListBaseAdapter;
import net.oschina.app.team.bean.TeamDiscuss;
import net.oschina.app.util.HTMLUtil;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TypefaceUtils;
import net.oschina.app.widget.AvatarView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* team 讨论区帖子
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年10月9日 下午6:22:54
*
*/
public class TeamDiscussAdapter extends ListBaseAdapter {
static class ViewHolder {
@InjectView(R.id.tv_title)
TextView title;
@InjectView(R.id.tv_description)
TextView description;
@InjectView(R.id.tv_author)
TextView author;
@InjectView(R.id.tv_date)
TextView time;
@InjectView(R.id.tv_count)
TextView comment_count;
@InjectView(R.id.tv_vote_up)
TextView vote_up;
@InjectView(R.id.iv_face)
public AvatarView face;
public ViewHolder(View view) {
ButterKnife.inject(this, view);
}
}
@Override
protected View getRealView(int position, View convertView, ViewGroup parent) {
ViewHolder vh = null;
if (convertView == null || convertView.getTag() == null) {
convertView = getLayoutInflater(parent.getContext()).inflate(
R.layout.list_cell_team_discuss, null);
vh = new ViewHolder(convertView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
TeamDiscuss item = mDatas.get(position);
vh.face.setUserInfo(item.getAuthor().getId(), item.getAuthor()
.getName());
vh.face.setAvatarUrl(item.getAuthor().getPortrait());
vh.title.setText(item.getTitle());
String body = item.getBody().trim();
vh.description.setVisibility(View.GONE);
if (null != body || !StringUtils.isEmpty(body)) {
vh.description.setVisibility(View.VISIBLE);
vh.description.setText(HTMLUtil.replaceTag(item.getBody()).trim());
}
TypefaceUtils.setTypeface(vh.author, item.getAuthor().getName());
String faTime = AppContext.getInstance().getResources().getString(R.string.fa_clock_o);
TypefaceUtils.setTypeface(vh.time, faTime + " " + StringUtils.friendly_time(item.getCreateTime()));
String faVoteUp = AppContext.getInstance().getResources().getString(R.string.fa_thumbs_o_up);
TypefaceUtils.setTypeface(vh.vote_up, faVoteUp + " " + item.getVoteUp());
String commentCount = AppContext.getInstance().getResources().getString(R.string.fa_comment);
TypefaceUtils.setTypeface(vh.comment_count, commentCount + " " + item.getAnswerCount());
return convertView;
}
}
MainActivity.java
package net.oschina.app.ui;
import net.oschina.app.AppConfig;
import net.oschina.app.AppContext;
import net.oschina.app.AppManager;
import net.oschina.app.R;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.Notice;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.cache.DataCleanManager;
import net.oschina.app.fragment.MyInformationFragment;
import net.oschina.app.interf.BaseViewInterface;
import net.oschina.app.interf.OnTabReselectListener;
import net.oschina.app.service.NoticeUtils;
import net.oschina.app.util.UIHelper;
import net.oschina.app.util.UpdateManager;
import net.oschina.app.widget.BadgeView;
import net.oschina.app.widget.MyFragmentTabHost;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.app.Fragment;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.TabHost.OnTabChangeListener;
import android.widget.TabHost.TabContentFactory;
import android.widget.TabHost.TabSpec;
import android.widget.TextView;
import butterknife.ButterKnife;
import butterknife.InjectView;
import com.networkbench.agent.impl.NBSAppAgent;
@SuppressLint("InflateParams")
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class MainActivity extends ActionBarActivity implements
NavigationDrawerFragment.NavigationDrawerCallbacks,
OnTabChangeListener, BaseViewInterface, View.OnClickListener,
OnTouchListener {
private DoubleClickExitHelper mDoubleClickExit;
/**
* Fragment managing the behaviors, interactions and presentation of the
* navigation drawer.
*/
private NavigationDrawerFragment mNavigationDrawerFragment;
@InjectView(android.R.id.tabhost)
public MyFragmentTabHost mTabHost;
private BadgeView mBvNotice;
public static Notice mNotice;
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Constants.INTENT_ACTION_NOTICE)) {
mNotice = (Notice) intent.getSerializableExtra("notice_bean");
int atmeCount = mNotice.getAtmeCount();// @我
int msgCount = mNotice.getMsgCount();// 留言
int reviewCount = mNotice.getReviewCount();// 评论
int newFansCount = mNotice.getNewFansCount();// 新粉丝
int newLikeCount = mNotice.getNewLikeCount();// 收到赞
int activeCount = atmeCount + reviewCount + msgCount
+ newFansCount + newLikeCount;
Fragment fragment = getCurrentFragment();
if (fragment instanceof MyInformationFragment) {
((MyInformationFragment) fragment).setNotice();
} else {
if (activeCount > 0) {
mBvNotice.setText(activeCount + "");
mBvNotice.show();
} else {
mBvNotice.hide();
mNotice = null;
}
}
} else if (intent.getAction()
.equals(Constants.INTENT_ACTION_LOGOUT)) {
mBvNotice.hide();
mNotice = null;
}
}
};
/**
* Used to store the last screen title. For use in
* {@link #restoreActionBar()}.
*/
private CharSequence mTitle;
@InjectView(R.id.quick_option_iv)
View mAddBt;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.inject(this);
initView();
AppManager.getAppManager().addActivity(this);
handleIntent(getIntent());
// 注册听云的检测分析
NBSAppAgent.setLicenseKey("0ed0cc66c5cb45c0a91c6fa932ca99ac")
.withCrashReportEnabled(true).withLocationServiceEnabled(true)
.start(this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
handleIntent(intent);
}
/**
* 处理传进来的intent
*
* @author 火蚁 2015-1-28 下午3:48:44
*
* @return void
* @param intent
*/
private void handleIntent(Intent intent) {
if (intent == null)
return;
String action = intent.getAction();
if (action != null && action.equals(Intent.ACTION_VIEW)) {
UIHelper.showUrlRedirect(this, intent.getDataString());
} else if (intent.getBooleanExtra("NOTICE", false)) {
notifitcationBarClick(intent);
}
}
/**
* 从通知栏点击的时候相应
*
* @param fromWhich
*/
private void notifitcationBarClick(Intent fromWhich) {
if (fromWhich != null) {
boolean fromNoticeBar = fromWhich.getBooleanExtra("NOTICE", false);
if (fromNoticeBar) {
Intent toMyInfor = new Intent(this, SimpleBackActivity.class);
toMyInfor.putExtra(SimpleBackActivity.BUNDLE_KEY_PAGE,
SimpleBackPage.MY_MES.getValue());
startActivity(toMyInfor);
}
}
}
@Override
public void initView() {
mDoubleClickExit = new DoubleClickExitHelper(this);
mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
mTabHost.setup(this, getSupportFragmentManager(), R.id.realtabcontent);
if (android.os.Build.VERSION.SDK_INT > 10) {
mTabHost.getTabWidget().setShowDividers(0);
}
initTabs();
// 中间按键图片触发
mAddBt.setOnClickListener(this);
mTabHost.setCurrentTab(0);
mTabHost.setOnTabChangedListener(this);
IntentFilter filter = new IntentFilter(Constants.INTENT_ACTION_NOTICE);
filter.addAction(Constants.INTENT_ACTION_LOGOUT);
registerReceiver(mReceiver, filter);
NoticeUtils.bindToService(this);
if (AppContext.isFristStart()) {
mNavigationDrawerFragment.openDrawerMenu();
DataCleanManager.cleanInternalCache(AppContext.getInstance());
AppContext.setFristStart(false);
}
checkUpdate();
}
private void checkUpdate() {
if (!AppContext.get(AppConfig.KEY_CHECK_UPDATE, true)) {
return;
}
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
new UpdateManager(MainActivity.this, false).checkUpdate();
}
}, 2000);
}
@Override
protected void onDestroy() {
super.onDestroy();
NoticeUtils.unbindFromService(this);
unregisterReceiver(mReceiver);
mReceiver = null;
NoticeUtils.tryToShutDown(this);
}
@Override
public void initData() {
}
private void initTabs() {
MainTab[] tabs = MainTab.values();
final int size = tabs.length;
for (int i = 0; i < size; i++) {
MainTab mainTab = tabs[i];
TabSpec tab = mTabHost.newTabSpec(getString(mainTab.getResName()));
View indicator = LayoutInflater.from(getApplicationContext())
.inflate(R.layout.tab_indicator, null);
TextView title = (TextView) indicator.findViewById(R.id.tab_title);
Drawable drawable = this.getResources().getDrawable(
mainTab.getResIcon());
title.setCompoundDrawablesWithIntrinsicBounds(null, drawable, null,
null);
if (i == 2) {
indicator.setVisibility(View.INVISIBLE);
mTabHost.setNoTabChangedTag(getString(mainTab.getResName()));
}
title.setText(getString(mainTab.getResName()));
tab.setIndicator(indicator);
tab.setContent(new TabContentFactory() {
@Override
public View createTabContent(String tag) {
return new View(MainActivity.this);
}
});
mTabHost.addTab(tab, mainTab.getClz(), null);
if (mainTab.equals(MainTab.ME)) {
View cn = indicator.findViewById(R.id.tab_mes);
mBvNotice = new BadgeView(MainActivity.this, cn);
mBvNotice.setBadgePosition(BadgeView.POSITION_TOP_RIGHT);
mBvNotice.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
mBvNotice.setBackgroundResource(R.drawable.notification_bg);
mBvNotice.setGravity(Gravity.CENTER);
}
mTabHost.getTabWidget().getChildAt(i).setOnTouchListener(this);
}
}
@Override
public void onNavigationDrawerItemSelected(int position) {
// update the main content by replacing fragments
}
public void restoreActionBar() {
ActionBar actionBar = getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setTitle(mTitle);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main_activity_menu, menu);
if (!mNavigationDrawerFragment.isDrawerOpen()) {
restoreActionBar();
return true;
}
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.search:
UIHelper.showSimpleBack(this, SimpleBackPage.SEARCH);
break;
default:
break;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onTabChanged(String tabId) {
final int size = mTabHost.getTabWidget().getTabCount();
for (int i = 0; i < size; i++) {
View v = mTabHost.getTabWidget().getChildAt(i);
if (i == mTabHost.getCurrentTab()) {
v.setSelected(true);
} else {
v.setSelected(false);
}
}
if (tabId.equals(getString(MainTab.ME.getResName()))) {
mBvNotice.setText("");
mBvNotice.hide();
}
supportInvalidateOptionsMenu();
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
// 点击了快速操作按钮
case R.id.quick_option_iv:
showQuickOption();
break;
default:
break;
}
}
// 显示快速操作界面
private void showQuickOption() {
final QuickOptionDialog dialog = new QuickOptionDialog(
MainActivity.this);
dialog.setCancelable(true);
dialog.setCanceledOnTouchOutside(true);
dialog.show();
}
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
super.onTouchEvent(event);
boolean consumed = false;
// use getTabHost().getCurrentTabView to decide if the current tab is
// touched again
if (event.getAction() == MotionEvent.ACTION_DOWN
&& v.equals(mTabHost.getCurrentTabView())) {
// use getTabHost().getCurrentView() to get a handle to the view
// which is displayed in the tab - and to get this views context
Fragment currentFragment = getCurrentFragment();
if (currentFragment != null
&& currentFragment instanceof OnTabReselectListener) {
OnTabReselectListener listener = (OnTabReselectListener) currentFragment;
listener.onTabReselect();
consumed = true;
}
}
return consumed;
}
private Fragment getCurrentFragment() {
return getSupportFragmentManager().findFragmentByTag(
mTabHost.getCurrentTabTag());
}
/**
* 监听返回--是否退出程序
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
// 是否退出应用
if (AppContext.get(AppConfig.KEY_DOUBLE_CLICK_EXIT, true)) {
return mDoubleClickExit.onKeyDown(keyCode, event);
}
}
return super.onKeyDown(keyCode, event);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
// TODO Auto-generated method stub
// 当 API Level > 11 调用这个方法可能导致奔溃(android.os.Build.VERSION.SDK_INT > 11)
}
}
MainTab.java
package net.oschina.app.ui;
import net.oschina.app.R;
import net.oschina.app.fragment.ExploreFragment;
import net.oschina.app.fragment.MyInformationFragment;
import net.oschina.app.viewpagerfragment.NewsViewPagerFragment;
import net.oschina.app.viewpagerfragment.TweetsViewPagerFragment;
public enum MainTab {
NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new,
NewsViewPagerFragment.class),
TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet,
TweetsViewPagerFragment.class),
QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new,
null),
EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore,
ExploreFragment.class),
ME(4, R.string.main_tab_name_my, R.drawable.tab_icon_me,
MyInformationFragment.class);
private int idx;
private int resName;
private int resIcon;
private Class> clz;
private MainTab(int idx, int resName, int resIcon, Class> clz) {
this.idx = idx;
this.resName = resName;
this.resIcon = resIcon;
this.clz = clz;
}
public int getIdx() {
return idx;
}
public void setIdx(int idx) {
this.idx = idx;
}
public int getResName() {
return resName;
}
public void setResName(int resName) {
this.resName = resName;
}
public int getResIcon() {
return resIcon;
}
public void setResIcon(int resIcon) {
this.resIcon = resIcon;
}
public Class> getClz() {
return clz;
}
public void setClz(Class> clz) {
this.clz = clz;
}
}
DetailActivity.java
package net.oschina.app.ui;
import net.oschina.app.R;
import net.oschina.app.base.BaseActivity;
import net.oschina.app.base.BaseDetailFragment;
import net.oschina.app.base.BaseFragment;
import net.oschina.app.emoji.KJEmojiFragment;
import net.oschina.app.emoji.OnSendClickListener;
import net.oschina.app.emoji.ToolbarFragment;
import net.oschina.app.emoji.ToolbarFragment.OnActionClickListener;
import net.oschina.app.emoji.ToolbarFragment.ToolAction;
import net.oschina.app.fragment.BlogDetailFragment;
import net.oschina.app.fragment.EventDetailFragment;
import net.oschina.app.fragment.NewsDetailFragment;
import net.oschina.app.fragment.PostDetailFragment;
import net.oschina.app.fragment.SoftwareDetailFragment;
import net.oschina.app.fragment.TweetDetailFragment;
import net.oschina.app.team.fragment.TeamDiaryDetail;
import net.oschina.app.team.fragment.TeamDiscussDetailFragment;
import net.oschina.app.team.fragment.TeamIssueDetailFragment;
import net.oschina.app.team.fragment.TeamTweetDetailFragment;
import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.text.Editable;
import android.view.KeyEvent;
import android.view.View;
/**
* 详情activity(包括:资讯、博客、软件、问答、动弹)
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年10月11日 上午11:18:41
*
*/
public class DetailActivity extends BaseActivity implements OnSendClickListener {
public static final int DISPLAY_NEWS = 0;
public static final int DISPLAY_BLOG = 1;
public static final int DISPLAY_SOFTWARE = 2;
public static final int DISPLAY_POST = 3;
public static final int DISPLAY_TWEET = 4;
public static final int DISPLAY_EVENT = 5;
public static final int DISPLAY_TEAM_ISSUE_DETAIL = 6;
public static final int DISPLAY_TEAM_DISCUSS_DETAIL = 7;
public static final int DISPLAY_TEAM_TWEET_DETAIL = 8;
public static final int DISPLAY_TEAM_DIARY = 9;
public static final String BUNDLE_KEY_DISPLAY_TYPE = "BUNDLE_KEY_DISPLAY_TYPE";
private OnSendClickListener currentFragment;
public KJEmojiFragment emojiFragment = new KJEmojiFragment();
public ToolbarFragment toolFragment = new ToolbarFragment();
@Override
protected int getLayoutId() {
return R.layout.activity_detail;
}
@Override
protected boolean hasBackButton() {
return true;
}
@Override
protected int getActionBarTitle() {
return R.string.actionbar_title_detail;
}
@Override
protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
int displayType = getIntent().getIntExtra(BUNDLE_KEY_DISPLAY_TYPE,
DISPLAY_NEWS);
BaseFragment fragment = null;
int actionBarTitle = 0;
switch (displayType) {
case DISPLAY_NEWS:
actionBarTitle = R.string.actionbar_title_news;
fragment = new NewsDetailFragment();
break;
case DISPLAY_BLOG:
actionBarTitle = R.string.actionbar_title_blog;
fragment = new BlogDetailFragment();
break;
case DISPLAY_SOFTWARE:
actionBarTitle = R.string.actionbar_title_software;
fragment = new SoftwareDetailFragment();
break;
case DISPLAY_POST:
actionBarTitle = R.string.actionbar_title_question;
fragment = new PostDetailFragment();
break;
case DISPLAY_TWEET:
actionBarTitle = R.string.actionbar_title_tweet;
fragment = new TweetDetailFragment();
break;
case DISPLAY_EVENT:
actionBarTitle = R.string.actionbar_title_event_detail;
fragment = new EventDetailFragment();
break;
case DISPLAY_TEAM_ISSUE_DETAIL:
actionBarTitle = R.string.team_issue_detail;
fragment = new TeamIssueDetailFragment();
break;
case DISPLAY_TEAM_DISCUSS_DETAIL:
actionBarTitle = R.string.actionbar_title_question;
fragment = new TeamDiscussDetailFragment();
break;
case DISPLAY_TEAM_TWEET_DETAIL:
actionBarTitle = R.string.actionbar_dynamic_detail;
fragment = new TeamTweetDetailFragment();
break;
case DISPLAY_TEAM_DIARY:
actionBarTitle = R.string.team_diary_detail;
fragment = new TeamDiaryDetail();
break;
default:
break;
}
setActionBarTitle(actionBarTitle);
FragmentTransaction trans = getSupportFragmentManager()
.beginTransaction();
trans.replace(R.id.container, fragment);
trans.commitAllowingStateLoss();
if (fragment instanceof OnSendClickListener) {
currentFragment = (OnSendClickListener) fragment;
} else {
currentFragment = new OnSendClickListener() {
@Override
public void onClickSendButton(Editable str) {}
@Override
public void onClickFlagButton() {}
};
}
}
@Override
public void onClick(View v) {}
@Override
public void initView() {
if (currentFragment instanceof TweetDetailFragment
|| currentFragment instanceof TeamTweetDetailFragment
|| currentFragment instanceof TeamDiaryDetail
|| currentFragment instanceof TeamIssueDetailFragment
|| currentFragment instanceof TeamDiscussDetailFragment) {
getSupportFragmentManager().beginTransaction()
.replace(R.id.emoji_keyboard, emojiFragment).commit();
} else {
getSupportFragmentManager().beginTransaction()
.replace(R.id.emoji_keyboard, toolFragment).commit();
}
toolFragment.setOnActionClickListener(new OnActionClickListener() {
@Override
public void onActionClick(ToolAction action) {
switch (action) {
case ACTION_CHANGE:
case ACTION_WRITE_COMMENT:
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.footer_menu_slide_in,
R.anim.footer_menu_slide_out)
.replace(R.id.emoji_keyboard, emojiFragment)
.commit();
break;
case ACTION_FAVORITE:
((BaseDetailFragment) currentFragment)
.handleFavoriteOrNot();
break;
case ACTION_REPORT:
((BaseDetailFragment) currentFragment).onReportMenuClick();
break;
case ACTION_SHARE:
((BaseDetailFragment) currentFragment).handleShare();
break;
case ACTION_VIEW_COMMENT:
((BaseDetailFragment) currentFragment)
.onclickWriteComment();
break;
default:
break;
}
}
});
}
@Override
public void initData() {}
@Override
public void onClickSendButton(Editable str) {
currentFragment.onClickSendButton(str);
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
try {
if (emojiFragment.isShowEmojiKeyBoard()) {
emojiFragment.hideAllKeyBoard();
return true;
}
if (emojiFragment.getEditText().getTag() != null) {
emojiFragment.getEditText().setTag(null);
emojiFragment.getEditText().setHint("说点什么吧");
return true;
}
} catch (NullPointerException e) {
}
}
return super.onKeyDown(keyCode, event);
}
public void setCommentCount(int count) {
try {
toolFragment.setCommentCount(count);
} catch (Exception e) {
}
}
@Override
public void onClickFlagButton() {
getSupportFragmentManager()
.beginTransaction()
.setCustomAnimations(R.anim.footer_menu_slide_in,
R.anim.footer_menu_slide_out)
.replace(R.id.emoji_keyboard, toolFragment).commit();
try {
toolFragment.setCommentCount(((BaseDetailFragment) currentFragment)
.getCommentCount());
} catch (Exception e) {
}
}
}
DoubleClickExitHelper.java
package net.oschina.app.ui;
import net.oschina.app.AppManager;
import net.oschina.app.R;
import android.app.Activity;
import android.os.Handler;
import android.os.Looper;
import android.view.KeyEvent;
import android.widget.Toast;
/***
* 双击退出
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2015年1月5日 下午7:07:44
*
*/
public class DoubleClickExitHelper {
private final Activity mActivity;
private boolean isOnKeyBacking;
private Handler mHandler;
private Toast mBackToast;
public DoubleClickExitHelper(Activity activity) {
mActivity = activity;
mHandler = new Handler(Looper.getMainLooper());
}
/**
* Activity onKeyDown事件
* */
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode != KeyEvent.KEYCODE_BACK) {
return false;
}
if(isOnKeyBacking) {
mHandler.removeCallbacks(onBackTimeRunnable);
if(mBackToast != null){
mBackToast.cancel();
}
// 退出
AppManager.getAppManager().AppExit(mActivity);
return true;
} else {
isOnKeyBacking = true;
if(mBackToast == null) {
mBackToast = Toast.makeText(mActivity, R.string.tip_double_click_exit, 2000);
}
mBackToast.show();
mHandler.postDelayed(onBackTimeRunnable, 2000);
return true;
}
}
private Runnable onBackTimeRunnable = new Runnable() {
@Override
public void run() {
isOnKeyBacking = false;
if(mBackToast != null){
mBackToast.cancel();
}
}
};
}
EventLocationActivity.java
package net.oschina.app.ui;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.base.BaseActivity;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import com.baidu.location.BDLocation;
import com.baidu.location.BDLocationListener;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.mapapi.SDKInitializer;
import com.baidu.mapapi.map.BaiduMap;
import com.baidu.mapapi.map.BitmapDescriptorFactory;
import com.baidu.mapapi.map.InfoWindow;
import com.baidu.mapapi.map.InfoWindow.OnInfoWindowClickListener;
import com.baidu.mapapi.map.MapStatusUpdate;
import com.baidu.mapapi.map.MapStatusUpdateFactory;
import com.baidu.mapapi.map.MapView;
import com.baidu.mapapi.map.Marker;
import com.baidu.mapapi.map.MarkerOptions;
import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.navi.BaiduMapAppNotSupportNaviException;
import com.baidu.mapapi.navi.BaiduMapNavigation;
import com.baidu.mapapi.navi.NaviPara;
import com.baidu.mapapi.search.core.SearchResult;
import com.baidu.mapapi.search.geocode.GeoCodeOption;
import com.baidu.mapapi.search.geocode.GeoCodeResult;
import com.baidu.mapapi.search.geocode.GeoCoder;
import com.baidu.mapapi.search.geocode.OnGetGeoCoderResultListener;
import com.baidu.mapapi.search.geocode.ReverseGeoCodeResult;
/**
* 活动地图位置显示
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年12月15日 下午1:28:28
*
*/
@SuppressLint("InflateParams")
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class EventLocationActivity extends BaseActivity implements
OnGetGeoCoderResultListener {
GeoCoder mSearch = null; // 搜索模块,也可去掉地图模块独立使用
BaiduMap mBaiduMap = null;
MapView mMapView = null;
private String mCity;
private String mLocation;
@Override
protected boolean hasBackButton() {
return true;
}
@Override
protected int getActionBarTitle() {
return R.string.actionbar_title_event_location;
}
protected void onCreate(Bundle savedInstanceState) {
SDKInitializer.initialize(getApplicationContext());
super.onCreate(savedInstanceState);
}
@Override
protected int getLayoutId() {
return R.layout.fragment_event_location;
}
@Override
protected void onPause() {
mMapView.onPause();
super.onPause();
}
@Override
protected void onResume() {
mMapView.onResume();
super.onResume();
}
@Override
protected void onDestroy() {
mMapView.onDestroy();
mSearch.destroy();
super.onDestroy();
}
@Override
public void onGetGeoCodeResult(GeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
AppContext.showToast("抱歉,未能找到结果");
return;
}
mBaiduMap.clear();
final LatLng location = result.getLocation();
final Marker marker = (Marker) mBaiduMap
.addOverlay(new MarkerOptions()
.position(location)
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.icon_gcoding))
.draggable(true));
mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result
.getLocation()));
MapStatusUpdate msu = MapStatusUpdateFactory.zoomTo(14.0f);
mBaiduMap.setMapStatus(msu);
View view = mInflater.inflate(R.layout.event_spot_pupwindow, null,
false);
TextView spot = (TextView) view.findViewById(R.id.tv_spot);
spot.setText(mLocation);
OnInfoWindowClickListener listener = new OnInfoWindowClickListener() {
public void onInfoWindowClick() {
onClickInfoWindow(location);
}
};
InfoWindow mInfoWindow = new InfoWindow(
BitmapDescriptorFactory.fromView(view), location, -80, listener);
mBaiduMap.showInfoWindow(mInfoWindow);
}
@Override
public void onGetReverseGeoCodeResult(ReverseGeoCodeResult result) {
if (result == null || result.error != SearchResult.ERRORNO.NO_ERROR) {
return;
}
mBaiduMap.clear();
mBaiduMap.addOverlay(new MarkerOptions().position(result.getLocation())
.icon(BitmapDescriptorFactory
.fromResource(R.drawable.icon_gcoding)));
mBaiduMap.setMapStatus(MapStatusUpdateFactory.newLatLng(result
.getLocation()));
}
@Override
public void onClick(View v) {
}
private void onClickInfoWindow(final LatLng location) {
// 开启定位图层
mBaiduMap.setMyLocationEnabled(true);
// 定位初始化
final LocationClient mLocClient = new LocationClient(
EventLocationActivity.this);
mLocClient.registerLocationListener(new BDLocationListener() {
@Override
public void onReceivePoi(BDLocation arg0) {
}
@Override
public void onReceiveLocation(BDLocation arg0) {
mLocClient.stop();
LatLng start = new LatLng(arg0.getLatitude(), arg0
.getLongitude());
startNavi(start, location);
}
});
LocationClientOption option = new LocationClientOption();
option.setOpenGps(true);// 打开gps
option.setCoorType("bd09ll"); // 设置坐标类型
option.setScanSpan(1000);
mLocClient.setLocOption(option);
mLocClient.start();
}
/**
* 开始导航
*
* @param view
*/
private void startNavi(LatLng pt1, LatLng pt2) {
// 构建 导航参数
NaviPara para = new NaviPara();
para.startPoint = pt1;
para.endPoint = pt2;
try {
BaiduMapNavigation.openBaiduMapNavi(para, this);
} catch (BaiduMapAppNotSupportNaviException e) {
AppContext.showToast("抱歉,你的百度地图暂不支持打开导航");
}
}
@Override
public void initView() {
// 地图初始化
mMapView = (MapView) findViewById(R.id.bmapView);
mBaiduMap = mMapView.getMap();
// 初始化搜索模块,注册事件监听
mSearch = GeoCoder.newInstance();
mSearch.setOnGetGeoCodeResultListener(this);
Intent intent = getIntent();
mCity = intent.getStringExtra("city");
mLocation = intent.getStringExtra("location");
// Geo搜索
mSearch.geocode(new GeoCodeOption().city(mCity).address(mLocation));
}
@Override
public void initData() {
}
}
package net.oschina.app.ui;
import net.oschina.app.AppConfig;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.adapter.RecyclingPagerAdapter;
import net.oschina.app.base.BaseActivity;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.fragment.TweetPubFragment;
import net.oschina.app.ui.dialog.ImageMenuDialog;
import net.oschina.app.ui.dialog.ImageMenuDialog.OnMenuClickListener;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.UIHelper;
import net.oschina.app.widget.HackyViewPager;
import org.kymjs.kjframe.KJBitmap;
import org.kymjs.kjframe.bitmap.BitmapCallBack;
import uk.co.senab.photoview.PhotoView;
import uk.co.senab.photoview.PhotoViewAttacher.OnPhotoTapListener;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Bundle;
import android.support.v4.view.ViewPager.OnPageChangeListener;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
/**
* 图片预览界面
*
* @author kymjs
*/
public class ImagePreviewActivity extends BaseActivity implements
OnPageChangeListener {
public static final String BUNDLE_KEY_IMAGES = "bundle_key_images";
private static final String BUNDLE_KEY_INDEX = "bundle_key_index";
private HackyViewPager mViewPager;
private SamplePagerAdapter mAdapter;
private TextView mTvImgIndex;
private ImageView mIvMore;
private int mCurrentPostion = 0;
private String[] mImageUrls;
private KJBitmap kjb;
public static void showImagePrivew(Context context, int index,
String[] images) {
Intent intent = new Intent(context, ImagePreviewActivity.class);
intent.putExtra(BUNDLE_KEY_IMAGES, images);
intent.putExtra(BUNDLE_KEY_INDEX, index);
context.startActivity(intent);
}
@Override
protected boolean hasActionBar() {
getActionBar().hide();
return true;
}
@Override
protected int getLayoutId() {
return R.layout.activity_image_preview;
}
@Override
protected void init(Bundle savedInstanceState) {
super.init(savedInstanceState);
kjb = new KJBitmap();
mViewPager = (HackyViewPager) findViewById(R.id.view_pager);
mImageUrls = getIntent().getStringArrayExtra(BUNDLE_KEY_IMAGES);
int index = getIntent().getIntExtra(BUNDLE_KEY_INDEX, 0);
mAdapter = new SamplePagerAdapter(mImageUrls);
mViewPager.setAdapter(mAdapter);
mViewPager.setOnPageChangeListener(this);
mViewPager.setCurrentItem(index);
mTvImgIndex = (TextView) findViewById(R.id.tv_img_index);
mIvMore = (ImageView) findViewById(R.id.iv_more);
mIvMore.setOnClickListener(this);
onPageSelected(index);
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.iv_more:
showOptionMenu();
break;
default:
break;
}
}
@Override
public void initView() {}
@Override
public void initData() {}
private void showOptionMenu() {
final ImageMenuDialog dialog = new ImageMenuDialog(this);
dialog.show();
dialog.setCancelable(true);
dialog.setOnMenuClickListener(new OnMenuClickListener() {
@Override
public void onClick(TextView menuItem) {
if (menuItem.getId() == R.id.menu1) {
saveImg();
} else if (menuItem.getId() == R.id.menu2) {
sendTweet();
} else if (menuItem.getId() == R.id.menu3) {
copyUrl();
}
dialog.dismiss();
}
});
}
/**
* 复制链接
*/
private void copyUrl() {
String content = null;
if (mAdapter != null && mAdapter.getCount() > 0) {
content = mAdapter.getItem(mCurrentPostion);
TDevice.copyTextToBoard(content);
AppContext.showToastShort("已复制到剪贴板");
}
}
/**
* 发送到动弹
*/
private void sendTweet() {
if (mAdapter != null && mAdapter.getCount() > 0) {
String imgUrl = mAdapter.getItem(mCurrentPostion);
Bundle bundle = new Bundle();
bundle.putString(TweetPubFragment.FROM_IMAGEPAGE_KEY, imgUrl);
UIHelper.showSimpleBack(this, SimpleBackPage.TWEET_PUB, bundle);
finish();
}
}
/**
* 保存图片
*/
private void saveImg() {
if (mAdapter != null && mAdapter.getCount() > 0) {
final String imgUrl = mAdapter.getItem(mCurrentPostion);
final String filePath = AppConfig.DEFAULT_SAVE_IMAGE_PATH
+ getFileName(imgUrl);
kjb.saveImage(this, imgUrl, filePath);
AppContext.showToastShort(getString(R.string.tip_save_image_suc,
filePath));
} else {
AppContext.showToastShort(R.string.tip_save_image_faile);
}
}
private String getFileName(String imgUrl) {
int index = imgUrl.lastIndexOf('/') + 1;
if (index == -1) {
return System.currentTimeMillis() + ".jpeg";
}
return imgUrl.substring(index);
}
@Override
public void onPageScrollStateChanged(int arg0) {}
@Override
public void onPageScrolled(int arg0, float arg1, int arg2) {}
@Override
public void onPageSelected(int idx) {
mCurrentPostion = idx;
if (mImageUrls != null && mImageUrls.length > 1) {
if (mTvImgIndex != null) {
mTvImgIndex.setText((mCurrentPostion + 1) + "/"
+ mImageUrls.length);
}
}
}
class SamplePagerAdapter extends RecyclingPagerAdapter {
private String[] images = new String[] {};
SamplePagerAdapter(String[] images) {
this.images = images;
}
public String getItem(int position) {
return images[position];
}
@Override
public int getCount() {
return images.length;
}
@Override
@SuppressLint("InflateParams")
public View getView(int position, View convertView, ViewGroup container) {
ViewHolder vh = null;
if (convertView == null) {
convertView = LayoutInflater.from(container.getContext())
.inflate(R.layout.image_preview_item, null);
vh = new ViewHolder(convertView);
convertView.setTag(vh);
} else {
vh = (ViewHolder) convertView.getTag();
}
vh.image.setOnFinishListener(new OnPhotoTapListener() {
@Override
public void onPhotoTap(View view, float x, float y) {
ImagePreviewActivity.this.finish();
}
});
final ProgressBar bar = vh.progress;
KJBitmap kjbitmap = new KJBitmap();
kjbitmap.displayWithDefWH(vh.image, images[position],
new ColorDrawable(0x000000), new ColorDrawable(0x000000),
new BitmapCallBack() {
@Override
public void onPreLoad() {
super.onPreLoad();
bar.setVisibility(View.VISIBLE);
}
@Override
public void onFinish() {
super.onFinish();
bar.setVisibility(View.GONE);
}
@Override
public void onFailure(Exception arg0) {
AppContext.showToast(R.string.tip_load_image_faile);
}
});
return convertView;
}
}
static class ViewHolder {
PhotoView image;
ProgressBar progress;
ViewHolder(View view) {
image = (PhotoView) view.findViewById(R.id.photoview);
progress = (ProgressBar) view.findViewById(R.id.progress);
}
}
}
package net.oschina.app.ui;
import java.io.ByteArrayInputStream;
import net.oschina.app.AppConfig;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.api.ApiHttpClient;
import net.oschina.app.api.remote.OSChinaApi;
import net.oschina.app.base.BaseActivity;
import net.oschina.app.bean.Constants;
import net.oschina.app.bean.LoginUserBean;
import net.oschina.app.bean.Result;
import net.oschina.app.util.CyptoUtils;
import net.oschina.app.util.SimpleTextWatcher;
import net.oschina.app.util.StringUtils;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.TLog;
import net.oschina.app.util.XmlUtils;
import org.apache.http.Header;
import org.apache.http.client.CookieStore;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.cookie.Cookie;
import org.apache.http.protocol.HttpContext;
import org.kymjs.kjframe.http.HttpConfig;
import org.kymjs.kjframe.utils.KJLoger;
import android.content.Intent;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import butterknife.InjectView;
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
/**
* 用户登录界面
*
* @author kymjs (http://www.kymjs.com/)
*/
public class LoginActivity extends BaseActivity {
public static final int REQUEST_CODE_INIT = 0;
private static final String BUNDLE_KEY_REQUEST_CODE = "BUNDLE_KEY_REQUEST_CODE";
protected static final String TAG = LoginActivity.class.getSimpleName();
@InjectView(R.id.et_username)
EditText mEtUserName;
@InjectView(R.id.et_password)
EditText mEtPassword;
@InjectView(R.id.iv_clear_username)
View mIvClearUserName;
@InjectView(R.id.iv_clear_password)
View mIvClearPassword;
@InjectView(R.id.btn_login)
Button mBtnLogin;
@InjectView(R.id.qq_login)
Button mBtnQQLogin;
private final int requestCode = REQUEST_CODE_INIT;
private String mUserName;
private String mPassword;
private Tencent mTencent;
private final TextWatcher mUserNameWatcher = new SimpleTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
mIvClearUserName
.setVisibility(TextUtils.isEmpty(s) ? View.INVISIBLE
: View.VISIBLE);
}
};
private final TextWatcher mPassswordWatcher = new SimpleTextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before,
int count) {
mIvClearPassword
.setVisibility(TextUtils.isEmpty(s) ? View.INVISIBLE
: View.VISIBLE);
}
};
@Override
protected int getLayoutId() {
return R.layout.activity_login;
}
@Override
protected boolean hasBackButton() {
return true;
}
@Override
protected int getActionBarTitle() {
return R.string.login;
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.iv_clear_username:
mEtUserName.getText().clear();
mEtUserName.requestFocus();
break;
case R.id.iv_clear_password:
mEtPassword.getText().clear();
mEtPassword.requestFocus();
break;
case R.id.btn_login:
handleLogin();
break;
case R.id.qq_login:
qqLogin();
break;
default:
break;
}
}
private void handleLogin() {
if (!prepareForLogin()) {
return;
}
// if the data has ready
mUserName = mEtUserName.getText().toString();
mPassword = mEtPassword.getText().toString();
showWaitDialog(R.string.progress_login);
OSChinaApi.login(mUserName, mPassword, mHandler);
}
private final AsyncHttpResponseHandler mHandler = new AsyncHttpResponseHandler() {
@Override
public void onSuccess(int arg0, Header[] arg1, byte[] arg2) {
try {
AsyncHttpClient client = ApiHttpClient.getHttpClient();
HttpContext httpContext = client.getHttpContext();
CookieStore cookies = (CookieStore) httpContext
.getAttribute(ClientContext.COOKIE_STORE);
if (cookies != null) {
String tmpcookies = "";
for (Cookie c : cookies.getCookies()) {
TLog.log(TAG,
"cookie:" + c.getName() + " " + c.getValue());
tmpcookies += (c.getName() + "=" + c.getValue()) + ";";
}
TLog.log(TAG, "cookies:" + tmpcookies);
AppContext.getInstance().setProperty(AppConfig.CONF_COOKIE,
tmpcookies);
ApiHttpClient.setCookie(ApiHttpClient.getCookie(AppContext
.getInstance()));
HttpConfig.sCookie = tmpcookies;
}
LoginUserBean user = XmlUtils.toBean(LoginUserBean.class,
new ByteArrayInputStream(arg2));
Result res = user.getResult();
if (res.OK()) {
// 保存登录信息
user.getUser().setAccount(mUserName);
user.getUser().setPwd(mPassword);
user.getUser().setRememberMe(true);
AppContext.getInstance().saveUserInfo(user.getUser());
hideWaitDialog();
handleLoginSuccess();
} else {
AppContext.getInstance().cleanLoginInfo();
hideWaitDialog();
AppContext.showToast(res.getErrorMessage());
}
} catch (Exception e) {
e.printStackTrace();
onFailure(arg0, arg1, arg2, e);
}
}
@Override
public void onFailure(int arg0, Header[] arg1, byte[] arg2,
Throwable arg3) {
hideWaitDialog();
AppContext.showToast(R.string.tip_login_error_for_network);
}
};
private void handleLoginSuccess() {
Intent data = new Intent();
data.putExtra(BUNDLE_KEY_REQUEST_CODE, requestCode);
setResult(RESULT_OK, data);
this.sendBroadcast(new Intent(Constants.INTENT_ACTION_USER_CHANGE));
finish();
}
private boolean prepareForLogin() {
if (!TDevice.hasInternet()) {
AppContext.showToastShort(R.string.tip_no_internet);
return false;
}
String uName = mEtUserName.getText().toString();
if (StringUtils.isEmpty(uName)) {
AppContext.showToastShort(R.string.tip_please_input_username);
mEtUserName.requestFocus();
return false;
}
// 去除邮箱正确性检测
// if (!StringUtils.isEmail(uName)) {
// AppContext.showToastShort(R.string.tip_illegal_email);
// mEtUserName.requestFocus();
// return false;
// }
String pwd = mEtPassword.getText().toString();
if (StringUtils.isEmpty(pwd)) {
AppContext.showToastShort(R.string.tip_please_input_password);
mEtPassword.requestFocus();
return false;
}
return true;
}
@Override
public void initView() {
mIvClearUserName.setOnClickListener(this);
mIvClearPassword.setOnClickListener(this);
mBtnLogin.setOnClickListener(this);
mBtnQQLogin.setOnClickListener(this);
mEtUserName.addTextChangedListener(mUserNameWatcher);
mEtPassword.addTextChangedListener(mPassswordWatcher);
}
@Override
public void initData() {
mTencent = Tencent.createInstance(AppConfig.APP_QQ_KEY,
this.getApplicationContext());
mEtUserName.setText(AppContext.getInstance()
.getProperty("user.account"));
mEtPassword.setText(CyptoUtils.decode("oschinaApp", AppContext
.getInstance().getProperty("user.pwd")));
}
/**
* QQ登陆
*/
private void qqLogin() {
if (!mTencent.isSessionValid()) {
mTencent.login(this, "all", new AuthorListener());
}
}
// /**
// * 封装并返回QQ登陆数据
// */
// private User packQQLoginBean(User user, JSONObject obj) {
// user.setLoginType(QQ_LOGIN);
// if (obj.has("openid")) {
// user.setUserId(obj.optString("openid"));
// } else {
// user.setUserName(obj.optString("nickname"));
// user.setSex("男".equals(obj.optString("gender")) ? 1 : 2);
// user.setHeadUrl(obj.optString("figureurl_qq_1"));
// user.setPwd(user.getUserId());
// }
// return user;
// }
class AuthorListener implements IUiListener {
@Override
public void onCancel() {
KJLoger.debug(getClass().getName() + "用户取消登陆");
}
@Override
public void onComplete(Object arg0) {
// packQQLoginBean(user, obj);
AppContext.showToast("成功"); // 服务器端暂无
}
@Override
public void onError(UiError error) {
KJLoger.debug(getClass().getName() + "登陆失败" + error.errorDetail);
}
}
}
package net.oschina.app.ui;
import net.oschina.app.AppContext;
import net.oschina.app.R;
import net.oschina.app.util.QrCodeUtils;
import org.kymjs.kjframe.utils.FileUtils;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Bundle;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnLongClickListener;
import android.view.Window;
import android.widget.ImageView;
import com.google.zxing.WriterException;
public class MyQrodeDialog extends Dialog {
private ImageView mIvCode;
private Bitmap bitmap;
private MyQrodeDialog(Context context, boolean flag,
OnCancelListener listener) {
super(context, flag, listener);
}
@SuppressLint("InflateParams")
private MyQrodeDialog(Context context, int defStyle) {
super(context, defStyle);
View contentView = getLayoutInflater().inflate(
R.layout.dialog_my_qr_code, null);
mIvCode = (ImageView) contentView.findViewById(R.id.iv_qr_code);
try {
bitmap = QrCodeUtils.Create2DCode(String.format(
"http://my.oschina.net/u/%s", AppContext.getInstance()
.getLoginUid()));
mIvCode.setImageBitmap(bitmap);
} catch (WriterException e) {
e.printStackTrace();
}
requestWindowFeature(Window.FEATURE_NO_TITLE);
contentView.setOnLongClickListener(new OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
dismiss();
if (FileUtils.bitmapToFile(bitmap,
FileUtils.getSavePath("OSChina") + "/myqrcode.png")) {
AppContext.showToast("二维码已保存到oschina文件夹下");
} else {
AppContext.showToast("SD卡不可写,二维码保存失败");
}
return false;
}
});
super.setContentView(contentView);
}
public MyQrodeDialog(Context context) {
this(context, R.style.quick_option_dialog);
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
getWindow().setGravity(Gravity.CENTER);
}
}
package net.oschina.app.ui;
import net.oschina.app.AppManager;
import net.oschina.app.R;
import net.oschina.app.base.BaseFragment;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.UIHelper;
import net.oschina.app.widget.ActionBarDrawerToggle;
import net.oschina.app.widget.DrawerArrowDrawable;
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import butterknife.ButterKnife;
import butterknife.InjectView;
/**
* 侧滑菜单界面
*
* @author FireAnt(http://my.oschina.net/LittleDY)
* @created 2014年9月25日 下午6:00:05
*
*/
public class NavigationDrawerFragment extends BaseFragment implements
OnClickListener {
/**
* Remember the position of the selected item.
*/
private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
/**
* A pointer to the current callbacks instance (the Activity).
*/
private NavigationDrawerCallbacks mCallbacks;
/**
* Helper component that ties the action bar to the navigation drawer.
*/
private ActionBarDrawerToggle mDrawerToggle;
private DrawerArrowDrawable drawerArrow;
private DrawerLayout mDrawerLayout;
private View mDrawerListView;
private View mFragmentContainerView;
private int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState;
@InjectView(R.id.menu_item_quests)
View mMenu_item_quests;
@InjectView(R.id.menu_item_opensoft)
View mMenu_item_opensoft;
@InjectView(R.id.menu_item_blog)
View mMenu_item_blog;
@InjectView(R.id.menu_item_gitapp)
View mMenu_item_gitapp;
@InjectView(R.id.menu_item_rss)
View mMenu_item_rss;
@InjectView(R.id.menu_item_setting)
View mMenu_item_setting;
@InjectView(R.id.menu_item_exit)
View mMenu_item_exit;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mCurrentSelectedPosition = savedInstanceState
.getInt(STATE_SELECTED_POSITION);
mFromSavedInstanceState = true;
}
selectItem(mCurrentSelectedPosition);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
mDrawerListView = inflater.inflate(R.layout.fragment_navigation_drawer,
container, false);
mDrawerListView.setOnClickListener(this);
ButterKnife.inject(this, mDrawerListView);
initView(mDrawerListView);
initData();
return mDrawerListView;
}
@Override
public void onClick(View v) {
int id = v.getId();
switch (id) {
case R.id.menu_item_quests:
UIHelper.showSimpleBack(getActivity(), SimpleBackPage.QUEST);
break;
case R.id.menu_item_opensoft:
UIHelper.showSimpleBack(getActivity(),
SimpleBackPage.OPENSOURCE_SOFTWARE);
break;
case R.id.menu_item_blog:
UIHelper.showSimpleBack(getActivity(), SimpleBackPage.BLOG);
break;
case R.id.menu_item_gitapp:
boolean res = TDevice.openAppActivity(getActivity(),
"net.oschina.gitapp", "net.oschina.gitapp.WelcomePage");
if (!res) {
if (!TDevice.isHaveMarket(getActivity())) {
UIHelper.openSysBrowser(getActivity(),
"http://git.oschina.net/appclient");
} else {
TDevice.gotoMarket(getActivity(), "net.oschina.gitapp");
}
}
break;
case R.id.menu_item_rss:
break;
case R.id.menu_item_setting:
UIHelper.showSetting(getActivity());
break;
case R.id.menu_item_exit:
AppManager.getAppManager().AppExit(getActivity());
break;
default:
break;
}
mDrawerLayout.postDelayed(new Runnable() {
@Override
public void run() {
mDrawerLayout.closeDrawers();
}
}, 800);
}
@Override
public void initView(View view) {
mMenu_item_rss.setOnClickListener(this);
mMenu_item_opensoft.setOnClickListener(this);
mMenu_item_blog.setOnClickListener(this);
mMenu_item_quests.setOnClickListener(this);
mMenu_item_setting.setOnClickListener(this);
mMenu_item_exit.setOnClickListener(this);
mMenu_item_gitapp.setOnClickListener(this);
}
@Override
public void initData() {
}
public boolean isDrawerOpen() {
return mDrawerLayout != null
&& mDrawerLayout.isDrawerOpen(mFragmentContainerView);
}
/**
* Users of this fragment must call this method to set up the navigation
* drawer interactions.
*
* @param fragmentId
* The android:id of this fragment in its activity's layout.
* @param drawerLayout
* The DrawerLayout containing this fragment's UI.
*/
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
// set a custom shadow that overlays the main content when the drawer
// opens
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
// set up the drawer's list view with items and click listener
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
drawerArrow = new DrawerArrowDrawable(getActivity()) {
@Override
public boolean isLayoutRtl() {
return false;
}
};
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout,
drawerArrow, R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getActivity().invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getActivity().invalidateOptionsMenu();
}
};
mDrawerLayout.post(new Runnable() {
@Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
public void openDrawerMenu() {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
private void selectItem(int position) {
mCurrentSelectedPosition = position;
if (mDrawerLayout != null) {
mDrawerLayout.closeDrawer(mFragmentContainerView);
}
if (mCallbacks != null) {
mCallbacks.onNavigationDrawerItemSelected(position);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mCallbacks = (NavigationDrawerCallbacks) activity;
} catch (ClassCastException e) {
throw new ClassCastException(
"Activity must implement NavigationDrawerCallbacks.");
}
}
@Override
public void onDetach() {
super.onDetach();
mCallbacks = null;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
private ActionBar getActionBar() {
return ((ActionBarActivity) getActivity()).getSupportActionBar();
}
public static interface NavigationDrawerCallbacks {
void onNavigationDrawerItemSelected(int position);
}
}
package net.oschina.app.ui;
import net.oschina.app.R;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.fragment.TweetPubFragment;
import net.oschina.app.team.fragment.NoteEditFragment;
import net.oschina.app.util.UIHelper;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
public class QuickOptionDialog extends Dialog implements
android.view.View.OnClickListener {
private ImageView mClose;
public interface OnQuickOptionformClick {
void onQuickOptionClick(int id);
}
private OnQuickOptionformClick mListener;
private QuickOptionDialog(Context context, boolean flag,
OnCancelListener listener) {
super(context, flag, listener);
}
@SuppressLint("InflateParams")
private QuickOptionDialog(Context context, int defStyle) {
super(context, defStyle);
View contentView = getLayoutInflater().inflate(
R.layout.dialog_quick_option, null);
contentView.findViewById(R.id.ly_quick_option_text).setOnClickListener(
this);
contentView.findViewById(R.id.ly_quick_option_album)
.setOnClickListener(this);
contentView.findViewById(R.id.ly_quick_option_photo)
.setOnClickListener(this);
contentView.findViewById(R.id.ly_quick_option_voice)
.setOnClickListener(this);
contentView.findViewById(R.id.ly_quick_option_scan).setOnClickListener(
this);
contentView.findViewById(R.id.ly_quick_option_note).setOnClickListener(
this);
mClose = (ImageView) contentView.findViewById(R.id.iv_close);
Animation operatingAnim = AnimationUtils.loadAnimation(getContext(),
R.anim.quick_option_close);
LinearInterpolator lin = new LinearInterpolator();
operatingAnim.setInterpolator(lin);
mClose.startAnimation(operatingAnim);
mClose.setOnClickListener(this);
requestWindowFeature(Window.FEATURE_NO_TITLE);
contentView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
QuickOptionDialog.this.dismiss();
return true;
}
});
super.setContentView(contentView);
}
public QuickOptionDialog(Context context) {
this(context, R.style.quick_option_dialog);
}
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
getWindow().setGravity(Gravity.BOTTOM);
WindowManager m = getWindow().getWindowManager();
Display d = m.getDefaultDisplay();
WindowManager.LayoutParams p = getWindow().getAttributes();
p.width = d.getWidth();
getWindow().setAttributes(p);
}
public void setOnQuickOptionformClickListener(OnQuickOptionformClick lis) {
mListener = lis;
}
@Override
public void onClick(View v) {
final int id = v.getId();
switch (id) {
case R.id.iv_close:
dismiss();
break;
case R.id.ly_quick_option_text:
onClickTweetPub(R.id.ly_quick_option_text);
break;
case R.id.ly_quick_option_album:
onClickTweetPub(R.id.ly_quick_option_album);
break;
case R.id.ly_quick_option_photo:
onClickTweetPub(R.id.ly_quick_option_photo);
break;
case R.id.ly_quick_option_voice:
UIHelper.showSimpleBack(getContext(), SimpleBackPage.RECORD);
break;
case R.id.ly_quick_option_scan:
UIHelper.showScanActivity(getContext());
break;
case R.id.ly_quick_option_note:
// UIHelper.showSimpleBack(getContext(), SimpleBackPage.FIND_USER);
onClickNote();
//UIHelper.showSimpleBack(getContext(), SimpleBackPage.FIND_USER);
// onClickNote();
break;
default:
break;
}
if (mListener != null) {
mListener.onQuickOptionClick(id);
}
dismiss();
}
private void onClickTweetPub(int id) {
Bundle bundle = new Bundle();
int type = -1;
switch (id) {
case R.id.ly_quick_option_album:
type = TweetPubFragment.ACTION_TYPE_ALBUM;
break;
case R.id.ly_quick_option_photo:
type = TweetPubFragment.ACTION_TYPE_PHOTO;
break;
default:
break;
}
bundle.putInt(TweetPubFragment.ACTION_TYPE, type);
UIHelper.showTweetActivity(getContext(), SimpleBackPage.TWEET_PUB,
bundle);
}
private void onClickNote() {
Bundle bundle = new Bundle();
bundle.putInt(NoteEditFragment.NOTE_FROMWHERE_KEY,
NoteEditFragment.QUICK_DIALOG);
UIHelper.showSimpleBack(getContext(), SimpleBackPage.NOTE_EDIT, bundle);
}
}
package net.oschina.app.ui;
import net.oschina.app.R;
import net.oschina.app.bean.Report;
import net.oschina.app.ui.dialog.CommonDialog;
import net.oschina.app.ui.dialog.DialogHelper;
import net.oschina.app.util.TDevice;
import android.annotation.SuppressLint;
import android.content.Context;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.EditText;
import android.widget.TextView;
public class ReportDialog extends CommonDialog implements
android.view.View.OnClickListener {
private static final int MAX_CONTENT_LENGTH = 250;
private TextView mTvReason;
private TextView mTvLink;
private EditText mEtContent;
private String[] reasons;
private String mLink;
private int mReportId;
public ReportDialog(Context context, String link, int reportId) {
this(context, R.style.dialog_common, link, reportId);
}
private ReportDialog(Context context, int defStyle, String link,
int reportId) {
super(context, defStyle);
mLink = link;
mReportId = reportId;
initViews(context);
}
private ReportDialog(Context context, boolean flag,
OnCancelListener listener) {
super(context, flag, listener);
}
@SuppressLint("InflateParams")
private void initViews(Context context) {
reasons = getContext().getResources().getStringArray(
R.array.report_reason);
View view = getLayoutInflater()
.inflate(R.layout.dialog_report, null);
mTvReason = (TextView) view.findViewById(R.id.tv_reason);
mTvReason.setOnClickListener(this);
mTvReason.setText(reasons[0]);
mTvLink = (TextView) view.findViewById(R.id.tv_link);
mTvLink.setText(mLink);
mEtContent = (EditText) view.findViewById(R.id.et_content);
super.setContent(view, 0);
}
@Override
public void onClick(View v) {
if (v.getId() == R.id.tv_reason) {
selectReason();
}
}
private void selectReason() {
String reason = mTvReason.getText().toString();
int idx = 0;
for (int i = 0; i < reasons.length; i++) {
if (reasons[i].equals(reason)) {
idx = i;
break;
}
}
final CommonDialog dialog = DialogHelper
.getPinterestDialogCancelable(getContext());
dialog.setTitle(R.string.report_reson);
dialog.setItems(reasons, idx, new OnItemClickListener() {
@Override
public void onItemClick(AdapterView> parent, View view,
int position, long id) {
dialog.dismiss();
mTvReason.setText(reasons[position]);
}
});
dialog.setNegativeButton(R.string.cancle, null);
dialog.show();
}
public Report getReport() {
String text = mEtContent.getText().toString();
TDevice.hideSoftKeyboard(mEtContent);
Report report = new Report();
report.setReportId(mReportId);
report.setLinkAddress(mLink);
report.setReason(mTvReason.getText().toString());
report.setOtherReason(text);
return report;
}
}
package net.oschina.app.ui;
import net.oschina.app.R;
import net.oschina.app.ui.dialog.CommonDialog;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.Bundle;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
/**
* 分享界面dialog
*
* @author kymjs
*
*/
public class ShareDialog extends CommonDialog implements
android.view.View.OnClickListener {
public interface OnSharePlatformClick {
void onPlatformClick(int id);
}
private OnSharePlatformClick mListener;
private ShareDialog(Context context, boolean flag, OnCancelListener listener) {
super(context, flag, listener);
}
@SuppressLint("InflateParams")
private ShareDialog(Context context, int defStyle) {
super(context, defStyle);
View shareView = getLayoutInflater().inflate(
R.layout.dialog_cotent_share, null);
shareView.findViewById(R.id.ly_share_qq).setOnClickListener(this);
shareView.findViewById(R.id.ly_share_copy_link)
.setOnClickListener(this);
shareView.findViewById(R.id.ly_share_more_option).setOnClickListener(
this);
shareView.findViewById(R.id.ly_share_sina_weibo).setOnClickListener(
this);
shareView.findViewById(R.id.ly_share_weichat).setOnClickListener(this);
shareView.findViewById(R.id.ly_share_weichat_circle)
.setOnClickListener(this);
setContent(shareView, 0);
}
public ShareDialog(Context context) {
this(context, R.style.dialog_bottom);
}
@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
getWindow().setGravity(Gravity.BOTTOM);
WindowManager m = getWindow().getWindowManager();
Display d = m.getDefaultDisplay();
WindowManager.LayoutParams p = getWindow().getAttributes();
p.width = d.getWidth();
getWindow().setAttributes(p);
}
public void setOnPlatformClickListener(OnSharePlatformClick lis) {
mListener = lis;
}
@Override
public void onClick(View v) {
final int id = v.getId();
if (mListener != null) {
mListener.onPlatformClick(id);
}
}
}
package net.oschina.app.ui;
import java.util.ArrayList;
import net.oschina.app.bean.SimpleBackPage;
import net.oschina.app.fragment.TweetPubFragment;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
/**
* 对动弹界面的一个封装,用于相应系统分享
*
* @author kymjs (https://github.com/kymjs)
*
*/
public class TweetActivity extends SimpleBackActivity {
private TweetPubFragment currentFragment;
public static String FROM_KEY = "image_shared_key";
@Override
protected void onCreate(Bundle savedInstanceState) {
Intent intent = getIntent();
if (intent.getIntExtra(FROM_KEY, -1) != 1) {
mPageValue = SimpleBackPage.TWEET_PUB.getValue();
}
super.onCreate(savedInstanceState);
respondExternal(intent);
}
/**
* 响应从图片分享进入的事件
*
* @param intent
*/
private void respondExternal(Intent intent) {
currentFragment = (TweetPubFragment) mFragment.get();
String action = intent.getAction();
String type = intent.getType();
if (Intent.ACTION_SEND.equals(action) && type != null) {
if ("text/plain".equals(type)) {
handleSendText(intent); // Handle text being sent
} else if (type.startsWith("image/")) {
handleSendImage(intent); // Handle single image being sent
}
} else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) {
if (type.startsWith("image/")) {
handleSendMultipleImages(intent); // Handle multiple images
// being sent
}
} else {
// Handle other intents, such as being started from the home screen
}
}
void handleSendText(Intent intent) {
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
String sharedTitle = intent.getStringExtra(Intent.EXTRA_TITLE);
if (sharedText != null) {
currentFragment.setContentText(sharedText);
}
}
void handleSendImage(Intent intent) {
Uri imageUri = (Uri) intent.getParcelableExtra(Intent.EXTRA_STREAM);
if (imageUri != null) {
currentFragment.setContentImage(getAbsoluteImagePath(imageUri));
}
}
void handleSendMultipleImages(Intent intent) {
ArrayList imageUris = intent
.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
if (imageUris != null) {
currentFragment.setContentImage(getAbsoluteImagePath(imageUris
.get(0)));
}
}
protected String getAbsoluteImagePath(Uri uri) {
// can post image
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = managedQuery(uri, proj, // Which columns to return
null, // WHERE clause; which rows to return (all rows)
null, // WHERE clause selection arguments (none)
null); // Order-by clause (ascending by name)
if (cursor != null) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
} else {
// 如果游标为空说明获取的已经是绝对路径了
return uri.getPath();
}
}
}
package net.oschina.app.ui.dialog;
import net.oschina.app.R;
import net.oschina.app.util.TDevice;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.view.Window;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;
public class CommonDialog extends Dialog {
public DialogInterface.OnClickListener listener;
protected View barDivider;
protected View buttonDivider;
protected FrameLayout container;
protected View content;
private final int contentPadding;
protected DialogTitleView headerVw;
protected Button negativeBt;
protected Button positiveBt;
protected DialogInterface.OnClickListener dismissClick = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
};
public CommonDialog(Context context) {
this(context, R.style.dialog_common);
}
public CommonDialog(Context context, int defStyle) {
super(context, defStyle);
contentPadding = (int) getContext().getResources().getDimension(
R.dimen.global_dialog_padding);
init(context);
}
protected CommonDialog(Context context, boolean flag,
DialogInterface.OnCancelListener listener) {
super(context, flag, listener);
contentPadding = (int) getContext().getResources().getDimension(
R.dimen.global_dialog_padding);
init(context);
}
@SuppressLint("InflateParams")
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
protected void init(final Context context) {
setCancelable(false);
requestWindowFeature(Window.FEATURE_NO_TITLE);
content = LayoutInflater.from(context).inflate(
R.layout.dialog_common, null);
headerVw = (DialogTitleView) content.findViewById(R.id.dialog_header);
container = (FrameLayout) content.findViewById(R.id.content_container);
barDivider = content.findViewById(R.id.button_bar_divider);
buttonDivider = content.findViewById(R.id.button_divder);
positiveBt = (Button) content.findViewById(R.id.positive_bt);
negativeBt = (Button) content.findViewById(R.id.negative_bt);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
// TODO Check content view height and change height
} else {
// content.addOnLayoutChangeListener(new OnLayoutChangeListener() {
//
// @Override
// public void onLayoutChange(View v, int left, int top,
// int right, int bottom, int oldLeft, int oldTop,
// int oldRight, int oldBottom) {
// int height = v.getHeight();
// int contentHeight = container.getHeight();
// int winHeight = BaseApplication.getDisplaySize()[1];
// int needHeight = height - winHeight * 8 / 10;
// if (needHeight > 0) {
// container
// .setLayoutParams(new LinearLayout.LayoutParams(
// LayoutParams.MATCH_PARENT,
// contentHeight - needHeight));
// }
// }
// });
}
super.setContentView(content);
}
public TextView getTitleTextView() {
return headerVw.titleTv;
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
if (TDevice.isTablet()) {
int maxWidth = (int) TDevice.dpToPixel(360f);
if (maxWidth < TDevice.getScreenWidth()) {
WindowManager.LayoutParams params = getWindow().getAttributes();
params.width = maxWidth;
getWindow().setAttributes(params);
}
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
this.dismiss();
}
public void setContent(View view) {
setContent(view, contentPadding);
}
public void setContent(View view, int padding) {
container.removeAllViews();
container.setPadding(padding, padding, padding, padding);
FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);
container.addView(view, lp);
}
@Override
public void setContentView(int i) {
setContent(null);
}
@Override
public void setContentView(View view) {
setContentView(null, null);
}
@Override
public void setContentView(View view,
android.view.ViewGroup.LayoutParams layoutparams) {
throw new Error("Dialog: User setContent (View view) instead!");
}
public void setItems(BaseAdapter adapter,
AdapterView.OnItemClickListener onItemClickListener) {
ListView listview = new ListView(content.getContext());
listview.setLayoutParams(new FrameLayout.LayoutParams(-1, -2));
listview.setDivider(null);
listview.setAdapter(adapter);
listview.setOnItemClickListener(onItemClickListener);
setContent(listview, 0);
}
public void setItems(CharSequence[] items,
AdapterView.OnItemClickListener onItemClickListener) {
ListView listview = new ListView(content.getContext());
listview.setLayoutParams(new FrameLayout.LayoutParams(-1, -2));
listview.setAdapter(new DialogAdapter(items));
listview.setDivider(null);
listview.setOnItemClickListener(onItemClickListener);
setContent(listview, 0);
}
public void setItemsWithoutChk(CharSequence[] items,
AdapterView.OnItemClickListener onItemClickListener) {
ListView listview = new ListView(content.getContext());
listview.setLayoutParams(new FrameLayout.LayoutParams(-1, -2));
DialogAdapter adapter = new DialogAdapter(items);
adapter.setShowChk(false);
listview.setDivider(null);
listview.setAdapter(adapter);
listview.setOnItemClickListener(onItemClickListener);
setContent(listview, 0);
}
public void setItems(CharSequence[] items, int index,
AdapterView.OnItemClickListener onItemClickListener) {
ListView listview = new ListView(content.getContext());
listview.setCacheColorHint(0);
listview.setDivider(null);
listview.setLayoutParams(new FrameLayout.LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
listview.setAdapter(new DialogAdapter(items, index));
listview.setOnItemClickListener(onItemClickListener);
setContent(listview, 0);
}
public void setMessage(int resId) {
setMessage(getContext().getResources().getString(resId));
}
public void setMessage(Spanned spanned) {
ScrollView scrollView = new ScrollView(getContext());
scrollView.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT));
TextView tvMessage = new TextView(getContext(), null,
R.style.dialog_pinterest_text);
tvMessage.setLayoutParams(new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.WRAP_CONTENT));
tvMessage.setPadding(contentPadding, contentPadding, contentPadding,
contentPadding);
tvMessage.setLineSpacing(0.0F, 1.3F);
tvMessage.setText(spanned);
tvMessage.setTextColor(getContext().getResources().getColor(
R.color.black));
ScrollView.LayoutParams lp = new ScrollView.LayoutParams(
ScrollView.LayoutParams.MATCH_PARENT,
ScrollView.LayoutParams.WRAP_CONTENT);
scrollView.addView(tvMessage, lp);
setContent(scrollView, 0);
}
public void setMessage(String message) {
setMessage(Html.fromHtml(message));
}
public void setNegativeButton(int negative,
DialogInterface.OnClickListener listener) {
setNegativeButton(getContext().getString(negative), listener);
}
public void setNegativeButton(String text,
final DialogInterface.OnClickListener listener) {
if (!TextUtils.isEmpty(text)) {
negativeBt.setText(text);
negativeBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null)
listener.onClick(CommonDialog.this, 0);
else
dismissClick.onClick(CommonDialog.this, 0);
}
});
negativeBt.setVisibility(View.VISIBLE);
if (positiveBt.getVisibility() == View.VISIBLE)
buttonDivider.setVisibility(View.VISIBLE);
} else {
negativeBt.setVisibility(View.GONE);
buttonDivider.setVisibility(View.GONE);
}
if (positiveBt.getVisibility() == View.VISIBLE
|| negativeBt.getVisibility() == View.VISIBLE)
barDivider.setVisibility(View.VISIBLE);
else
barDivider.setVisibility(View.GONE);
}
public void setPositiveButton(int positive,
DialogInterface.OnClickListener listener) {
setPositiveButton(getContext().getString(positive), listener);
}
public void setPositiveButton(String positive,
final DialogInterface.OnClickListener listener) {
if (!TextUtils.isEmpty(positive)) {
positiveBt.setText(positive);
positiveBt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (listener != null)
listener.onClick(CommonDialog.this, 0);
else
dismissClick.onClick(CommonDialog.this, 0);
}
});
positiveBt.setVisibility(View.VISIBLE);
if (negativeBt.getVisibility() == View.VISIBLE)
buttonDivider.setVisibility(View.VISIBLE);
} else {
positiveBt.setVisibility(View.GONE);
buttonDivider.setVisibility(View.GONE);
}
if (positiveBt.getVisibility() == View.VISIBLE
|| negativeBt.getVisibility() == View.VISIBLE)
barDivider.setVisibility(View.VISIBLE);
else
barDivider.setVisibility(View.GONE);
}
public void setSubTitle(int i) {
setSubTitle((getContext().getResources().getString(i)));
}
public void setSubTitle(CharSequence subtitle) {
if (subtitle != null && subtitle.length() > 0) {
headerVw.subTitleTv.setText(subtitle);
headerVw.subTitleTv.setVisibility(View.VISIBLE);
} else {
headerVw.subTitleTv.setVisibility(View.GONE);
}
}
@Override
public void setTitle(int title) {
setTitle((getContext().getResources().getString(title)));
}
@Override
public void setTitle(CharSequence title) {
if (title != null && title.length() > 0) {
headerVw.titleTv.setText(title);
headerVw.setVisibility(View.VISIBLE);
} else {
headerVw.setVisibility(View.GONE);
}
}
}
package net.oschina.app.ui.dialog;
import net.oschina.app.R;
import net.oschina.app.util.TDevice;
import net.oschina.app.util.TLog;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class CommonToast {
public static final long DURATION_LONG = 5000L;
public static final long DURATION_MEDIUM = 3500L;
public static final long DURATION_SHORT = 2500L;
private long _duration = 3500l;
private ToastView _toastVw;
public CommonToast(Activity activity) {
init(activity);
}
public CommonToast(Activity activity, String message, int icon,
String action, int actionIcon, long l) {
_duration = l;
init(activity);
setMessage(message);
setMessageIc(icon);
setAction(action);
setActionIc(actionIcon);
}
private void init(Activity activity) {
_toastVw = new ToastView(activity);
setLayoutGravity(81);
}
public long getDuration() {
return _duration;
}
public void setAction(String s) {
_toastVw.actionTv.setText(s);
}
public void setActionIc(int i) {
_toastVw.actionIv.setImageResource(i);
}
public void setDuration(long l) {
_duration = l;
}
public void setLayoutGravity(int i) {
if (i != 0) {
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(-2,
-2);
params.gravity = i;
int j = (int) TDevice.dpToPixel(16F);
params.setMargins(j, j, j, j);
_toastVw.setLayoutParams(params);
}
}
public void setMessage(String s) {
_toastVw.messageTv.setText(s);
}
public void setMessageIc(int i) {
_toastVw.messageIc.setImageResource(i);
}
public void show() {
final ViewGroup content = (ViewGroup) ((Activity) _toastVw.getContext())
.findViewById(android.R.id.content);
if (content != null) {
ObjectAnimator.ofFloat(_toastVw, "alpha", 0.0F).setDuration(0L)
.start();
content.addView(_toastVw);
ObjectAnimator.ofFloat(_toastVw, "alpha", 0.0F, 1.0F)
.setDuration(167L).start();
_toastVw.postDelayed(new Runnable() {
@Override
public void run() {
ObjectAnimator animator = ObjectAnimator.ofFloat(_toastVw,
"alpha", 1.0F, 0.0F);
animator.setDuration(100L);
animator.addListener(new AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationRepeat(Animator animation) {
// TODO Auto-generated method stub
}
@Override
public void onAnimationEnd(Animator animation) {
content.removeView(_toastVw);
}
@Override
public void onAnimationCancel(Animator animation) {
}
});
animator.start();
}
}, _duration);
} else {
TLog.error("Toast not shown! Content view is null!");
}
}
private class ToastView extends FrameLayout {
public ImageView actionIv;
public TextView actionTv;
public ImageView messageIc;
public TextView messageTv;
public ToastView(Context context) {
this(context, null);
}
public ToastView(Context context, AttributeSet attributeset) {
this(context, attributeset, 0);
}
public ToastView(Context context, AttributeSet attributeset, int i) {
super(context, attributeset, i);
init();
}
private void init() {
LayoutInflater.from(getContext()).inflate(
R.layout.view_base_toast, this, true);
messageTv = (TextView) findViewById(R.id.title_tv);
messageIc = (ImageView) findViewById(R.id.icon_iv);
actionTv = (TextView) findViewById(R.id.title_tv);
actionIv = (ImageView) findViewById(R.id.icon_iv);
}
}
}
package net.oschina.app.ui.dialog;
import net.oschina.app.R;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.RadioButton;
import android.widget.TextView;
public class DialogAdapter extends BaseAdapter {
private CharSequence[] _items;
private int select;
private boolean showChk = true;
public DialogAdapter(CharSequence[] items, int selectIdx) {
_items = items;
this.select = selectIdx;
}
public DialogAdapter(CharSequence[] items) {
_items = items;
}
@Override
public int getCount() {
return _items.length;
}
@Override
public String getItem(int i) {
return _items[i].toString();// super.getItem(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public View getView(int i, View view, ViewGroup viewgroup) {
DialogHolder vh = null;
if (view == null) {
vh = new DialogHolder();
view = LayoutInflater.from(viewgroup.getContext()).inflate(
R.layout.list_cell_dialog, null, false);
vh.titleTv = (TextView) view.findViewById(R.id.title_tv);
vh.divider = view.findViewById(R.id.list_divider);
vh.checkIv = (RadioButton) view.findViewById(R.id.rb_select);
view.setTag(vh);
} else {
vh = (DialogHolder) view.getTag();
}
vh.titleTv.setText(getItem(i));
if (i == -1 + getCount()) {
vh.divider.setVisibility(View.GONE);
} else {
vh.divider.setVisibility(View.VISIBLE);
}
if(showChk) {
vh.checkIv.setVisibility(View.VISIBLE);
if (select == i) {
vh.checkIv.setChecked(true);
} else {
vh.checkIv.setChecked(false);
}
} else{
vh.checkIv.setVisibility(View.GONE);
}
return view;
}
public boolean isShowChk() {
return showChk;
}
public void setShowChk(boolean showChk) {
this.showChk = showChk;
}
private class DialogHolder {
public View divider;
public TextView titleTv;
public RadioButton checkIv;
}
}
package net.oschina.app.ui.dialog;
public interface DialogControl {
public abstract void hideWaitDialog();
public abstract WaitDialog showWaitDialog();
public abstract WaitDialog showWaitDialog(int resid);
public abstract WaitDialog showWaitDialog(String text);
}
package net.oschina.app.ui.dialog;
import net.oschina.app.R;
import android.app.Activity;
import android.content.Context;
public class DialogHelper {
public static CommonDialog getPinterestDialog(Context context) {
return new CommonDialog(context, R.style.dialog_common);
}
public static CommonDialog getPinterestDialogCancelable(Context context) {
CommonDialog dialog = new CommonDialog(context,
R.style.dialog_common);
dialog.setCanceledOnTouchOutside(true);
return dialog;
}
public static WaitDialog getWaitDialog(Activity activity, int message) {
WaitDialog dialog = null;
try {
dialog = new WaitDialog(activity, R.style.dialog_waiting);
dialog.setMessage(message);
} catch (Exception e) {
e.printStackTrace();
}
return dialog;
}
public static WaitDialog getWaitDialog(Activity activity, String message) {
WaitDialog dialog = null;
try {
dialog = new WaitDialog(activity, R.style.dialog_waiting);
dialog.setMessage(message);
} catch (Exception ex) {
ex.printStackTrace();
}
return dialog;
}
public static WaitDialog getCancelableWaitDialog(Activity activity,
String message) {
WaitDialog dialog = null;
try {
dialog = new WaitDialog(activity, R.style.dialog_waiting);
dialog.setMessage(message);
dialog.setCancelable(true);
} catch (Exception ex) {
ex.printStackTrace();
}
return dialog;
}
}
package net.oschina.app.ui.dialog;
import net.oschina.app.R;
import net.oschina.app.util.TDevice;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
public class WaitDialog extends Dialog {
private TextView _messageTv;
public WaitDialog(Context context) {
super(context);
init(context);
}
public WaitDialog(Context context, int defStyle) {
super(context, defStyle);
init(context);
}
protected WaitDialog(Context context, boolean cancelable,DialogInterface.OnCancelListener listener) {
super(context, cancelable, listener);
init(context);
}
public static boolean dismiss(WaitDialog dialog) {
if (dialog != null) {
dialog.dismiss();
return false;
} else {
return true;
}
}
@Override
public void onBackPressed() {
super.onBackPressed();
this.dismiss();
}
public static void hide(Context context) {
if (context instanceof DialogControl)
((DialogControl) context).hideWaitDialog();
}
public static boolean hide(WaitDialog dialog) {
if (dialog != null) {
dialog.hide();
return false;
} else {
return true;
}
}
private void init(Context context) {
setCancelable(false);
requestWindowFeature(Window.FEATURE_NO_TITLE);
View view = LayoutInflater.from(context).inflate(R.layout.dialog_wait, null);
_messageTv = (TextView) view.findViewById(R.id.waiting_tv);
setContentView(view);
}
public static void show(Context context) {
if (context instanceof DialogControl)
((DialogControl) context).showWaitDialog();
}
public static boolean show(WaitDialog waitdialog) {
boolean flag;
if (waitdialog != null) {
waitdialog.show();
flag = false;
} else {
flag = true;
}
return flag;
}
@Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
if (TDevice.isTablet()) {
int i = (int) TDevice.dpToPixel(360F);
if (i < TDevice.getScreenWidth()) {
WindowManager.LayoutParams params = getWindow()
.getAttributes();
params.width = i;
getWindow().setAttributes(params);
}
}
}
public void setMessage(int message) {
_messageTv.setText(message);
}
public void setMessage(String message) {
_messageTv.setText(message);
}
public void hideMessage() {
_messageTv.setVisibility(View.GONE);
}
}