diff --git a/.gitignore b/.gitignore index 5e9997b..07f8722 100644 --- a/.gitignore +++ b/.gitignore @@ -10,12 +10,14 @@ *.class # libs -libs/ # generated files bin/ +.idea/ +.gradle/ gen/ target/ +build/ # Local configuration file (sdk path, etc) local.properties diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs deleted file mode 100644 index 99f26c0..0000000 --- a/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index b080d2d..0000000 --- a/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,4 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/README-cn.md b/README-cn.md new file mode 100644 index 0000000..43f9896 --- /dev/null +++ b/README-cn.md @@ -0,0 +1,46 @@ +Cube-SDK 是一个开发框架。这个框架致力于快速实现需求,解放生产力。 + +![Screen Shot](https://raw.githubusercontent.com/etao-open-source/cube-sdk/dev/screen-shot.png) + +文档: http://cube-sdk.liaohuqiu.net/cn + +Demo 项目移到了这里: https://github.com/liaohuqiu/android-cube-app + +### 在项目中引入 + + +项目现在已经发布到了maven中央库,有 `aar` and `apklib` 和两种格式 + +##### 在 pom.xml 中 + +引用apklib: + +```xml + + in.srain.cube + cube-sdk + apklib + 1.0.42 + +``` + +或者引入aar: + +``` + + in.srain.cube + cube-sdk + aar + 1.0.42 + +``` + +##### 在 Gradle / Android Studio + +``` gradle +compile 'in.srain.cube:cube-sdk:1.0.42@aar' +````` + +##### eclipse + +直接将core文件夹下的内容作为一个类库加载,然后在项目中引用 \ No newline at end of file diff --git a/README.md b/README.md index 624883d..26a4c7b 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,48 @@ -`Cube` is a light package for Android development. +##[中文说明](https://github.com/etao-open-source/cube-sdk/blob/master/README-cn.md) + + +`Cube` is a light package for Android development. + +![Screen Shot](https://raw.githubusercontent.com/etao-open-source/cube-sdk/dev/screen-shot.png) + +DEMO project has been moved to [HERE](https://github.com/liaohuqiu/android-cube-app). All of the `readme` content and document are moved to Github Pages, please visit the Github Pages for more imformation: -### Usage +http://cube-sdk.liaohuqiu.net -It's in Maven Central: +### Import to your project + +Cube-SDK has been pushed to Maven Central, both in `aar` and `apklib` format. + +##### Using in pom.xml ```xml in.srain.cube cube-sdk apklib - 1.0.34 + 1.0.42 ``` -###[`Github Pages`](http://cube-sdk.liaohuqiu.net) +or: + +``` + + in.srain.cube + cube-sdk + aar + 1.0.42 + +``` -###[`中文版文档`](http://cube-sdk.liaohuqiu.net/cn) +###### Gradle / Android Studio ---- +``` gradle +compile 'in.srain.cube:cube-sdk:1.0.42@aar' +````` -* srain@php.net -* twitter: https://twitter.com/liaohuqiu -* weibo: http://weibo.com/liaohuqiu -* QQ交流群: 271918140 +###### Eclipse +Load the content into you eclipse, it's library project. Then use it in your application project. diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..d3e17c0 --- /dev/null +++ b/build.gradle @@ -0,0 +1,14 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.12.+' + } +} + +allprojects { + repositories { + jcenter() + } +} \ No newline at end of file diff --git a/core/README.md b/core/README.md deleted file mode 100644 index 30d8404..0000000 --- a/core/README.md +++ /dev/null @@ -1,4 +0,0 @@ -srain-sdk -=============== - -###a android develop framework diff --git a/core/build.gradle b/core/build.gradle new file mode 100644 index 0000000..9feb5c2 --- /dev/null +++ b/core/build.gradle @@ -0,0 +1,91 @@ +buildscript { + repositories { + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:0.12.+' + } +} + +allprojects { + repositories { + jcenter() + mavenCentral(); + } +} + +apply plugin: 'com.android.library' + +android { + compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION) + buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION + + defaultConfig { + applicationId "in.srain.cube" + minSdkVersion 8 + targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION) + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['resources'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + // aidl.srcDirs = ['src'] + // renderscript.srcDirs = ['src'] + } + + androidTest.setRoot('tests') + } +} + +task copyLibs << { + + // copy jars + copy { + from configurations.compile + into "libs" + + // exclude: apkilib, aar, support-v* + eachFile { file -> + if (file.name.contains("apklib") || file.name.contains("aar")) { + file.exclude() + } + } + } + + // copy source + copy { + + def sourceList = configurations.compile.incoming.dependencies.collect { dependency -> + dependency.artifact { artifact -> + artifact.name = dependency.name + artifact.type = 'source' + artifact.extension = 'jar' + artifact.classifier = 'sources' + } + dependency + } + from(configurations.detachedConfiguration(sourceList as Dependency[]).resolvedConfiguration. + resolvedConfiguration.lenientConfiguration.getFiles(Specs.SATISFIES_ALL)) { + } + + into("libs") + + // exclude: apkilib, aar, support-v* + eachFile { file -> + if (file.name.contains("apklib") || file.name.contains("aar") || file.name.contains("support-v4")) { + file.exclude() + } + } + } +} + +dependencies { + compile 'in.srain.cube:clog:1.0.2' + // compile 'com.android.support:support-v4:20.0.0' + compile 'com.google.android:support-v4:r7' +} +apply from: './gradle-mvn-push.gradle' diff --git a/core/gradle-mvn-push.gradle b/core/gradle-mvn-push.gradle new file mode 100644 index 0000000..8fdff20 --- /dev/null +++ b/core/gradle-mvn-push.gradle @@ -0,0 +1,125 @@ +apply plugin: 'maven' +apply plugin: 'signing' + +def isReleaseBuild() { + return VERSION_NAME.contains("SNAPSHOT") == false +} + +def getReleaseRepositoryUrl() { + if (VERSION_NAME.contains("-ali") == true) { + return 'http://mvnrepo.taobao.ali.com/mvn/repository'; + } + return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL + : "https://oss.sonatype.org/service/local/staging/deploy/maven2/" +} + +def getSnapshotRepositoryUrl() { + // only publish to snapshots + if (VERSION_NAME.contains("-ali") == true) { + return 'http://mvnrepo.taobao.ali.com/mvn/snapshots/'; + } + return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL + : "https://oss.sonatype.org/content/repositories/snapshots/" +} + +def getRepositoryUsername() { + if (VERSION_NAME.contains("-ali") == true) { + return ALI_USERNAME + } + return hasProperty('OSS_USERNAME') ? OSS_USERNAME : '' +} + +def getRepositoryPassword() { + if (VERSION_NAME.contains("-ali") == true) { + return ALI_PWD + } + return hasProperty('OSS_PWD') ? OSS_PWD : '' +} + +afterEvaluate { project -> + uploadArchives { + repositories { + mavenDeployer { + beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) } + + pom.groupId = POM_GROUP + pom.artifactId = POM_ARTIFACT_ID + pom.version = VERSION_NAME + + repository(url: getReleaseRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) + } + snapshotRepository(url: getSnapshotRepositoryUrl()) { + authentication(userName: getRepositoryUsername(), password: getRepositoryPassword()) + } + + pom.project { + name POM_NAME + packaging POM_PACKAGING + description POM_DESCRIPTION + url POM_URL + + scm { + url POM_SCM_URL + connection POM_SCM_CONNECTION + developerConnection POM_SCM_DEV_CONNECTION + } + + licenses { + license { + name POM_LICENCE_NAME + url POM_LICENCE_URL + distribution POM_LICENCE_DIST + } + } + + developers { + developer { + id POM_DEVELOPER_ID + name POM_DEVELOPER_NAME + } + } + } + } + } + } + + signing { + required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") } + sign configurations.archives + } + + task apklib(type: Zip) { + + appendix = extension = 'apklib' + + from 'AndroidManifest.xml' + into('res') { + from 'res' + } + into('src') { + from 'src' + } + } + + task androidJavadocs(type: Javadoc) { + source = android.sourceSets.main.java.srcDirs + classpath += project.files(android.getBootClasspath().join(File.pathSeparator)) + } + + task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) { + classifier = 'javadoc' + from androidJavadocs.destinationDir + } + + task androidSourcesJar(type: Jar) { + classifier = 'sources' + from android.sourceSets.main.java.srcDirs + } + + artifacts { + archives androidSourcesJar + archives androidJavadocsJar + archives apklib + } +} diff --git a/core/gradle.properties b/core/gradle.properties new file mode 100644 index 0000000..92d589d --- /dev/null +++ b/core/gradle.properties @@ -0,0 +1,24 @@ +VERSION_NAME=1.0.42 + +ANDROID_BUILD_MIN_SDK_VERSION=8 +ANDROID_BUILD_TARGET_SDK_VERSION=16 +ANDROID_BUILD_SDK_VERSION=19 +ANDROID_BUILD_TOOLS_VERSION=20.0.0 + +POM_GROUP=in.srain.cube +POM_ARTIFACT_ID=cube-sdk +POM_PACKAGING=aar + +POM_NAME=Cube SDK +POM_DESCRIPTION=Cube SDK, library for Android development + +POM_URL=https://github.com/etao-open-source/cube-sdk +POM_SCM_URL=https://github.com/etao-open-source/cube-sdk +POM_SCM_CONNECTION=scm:https://github.com/etao-open-source/cube-sdk.git +POM_SCM_DEV_CONNECTION=scm:https://github.com/etao-open-source/cube-sdk.git + +POM_LICENCE_NAME=Apache 2 +POM_LICENCE_URL= +POM_LICENCE_DIST=repo +POM_DEVELOPER_ID=liaohuqiu +POM_DEVELOPER_NAME=liaohuqiu diff --git a/core/libs/android-support-v4.jar b/core/libs/android-support-v4.jar deleted file mode 100644 index 96644ed..0000000 Binary files a/core/libs/android-support-v4.jar and /dev/null differ diff --git a/core/libs/clog-1.0.2-sources.jar b/core/libs/clog-1.0.2-sources.jar new file mode 100644 index 0000000..7654089 Binary files /dev/null and b/core/libs/clog-1.0.2-sources.jar differ diff --git a/core/libs/clog-1.0.2.jar b/core/libs/clog-1.0.2.jar new file mode 100644 index 0000000..1561d39 Binary files /dev/null and b/core/libs/clog-1.0.2.jar differ diff --git a/core/libs/support-v4-r7.jar b/core/libs/support-v4-r7.jar new file mode 100644 index 0000000..382255e Binary files /dev/null and b/core/libs/support-v4-r7.jar differ diff --git a/core/pom.xml b/core/pom.xml index 6a4fcb6..0f1dc34 100755 --- a/core/pom.xml +++ b/core/pom.xml @@ -5,34 +5,40 @@ in.srain - cube-parent - 1.1.1 + cube-parent-for-oss + 1.0.1-SNAPSHOT in.srain.cube cube-sdk - apklib + aar Cube SDK - 1.0.34 + 1.0.42 com.google.android android - 4.4.0 + 4.1.1.4 provided com.google.android support-v4 - r18 + r7 + + + + in.srain.cube + clog + 1.0.2 - 3.7.0 - 16 + 3.8.2 + 19 @@ -46,8 +52,7 @@ ${android.maven.plugin.version} - ${env.ANDROID_HOME} - ${android.compile.apilevel} + ${android.compile.api_level} false diff --git a/core/pom_build.xml b/core/pom_build.xml deleted file mode 100755 index 9973b2e..0000000 --- a/core/pom_build.xml +++ /dev/null @@ -1,43 +0,0 @@ - - - - 4.0.0 - - in.srain.cube - cube-sdk - apklib - CUBE: Library for Android development - 1.0.11-SNAPSHOT - - - - com.google.android - android - 4.1.1.4 - - - com.google.android - support-v4 - r6 - - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - true - - - D:\andriod\adt\sdk\ - 16 - - true - - - - - diff --git a/core/res/drawable-xhdpi/ptr_pulltorefresh_arrow.png b/core/res/drawable-xhdpi/ptr_pulltorefresh_arrow.png deleted file mode 100755 index 4544edf..0000000 Binary files a/core/res/drawable-xhdpi/ptr_pulltorefresh_arrow.png and /dev/null differ diff --git a/core/res/drawable-xxhdpi/cube_mints_icon_top_back.png b/core/res/drawable-xxhdpi/cube_mints_icon_top_back.png new file mode 100644 index 0000000..58a7e48 Binary files /dev/null and b/core/res/drawable-xxhdpi/cube_mints_icon_top_back.png differ diff --git a/sample-and-tests/res/layout/item_home.xml b/core/res/layout/cube_mints_base_block_menu_item.xml similarity index 66% rename from sample-and-tests/res/layout/item_home.xml rename to core/res/layout/cube_mints_base_block_menu_item.xml index 979620a..13d34d6 100755 --- a/sample-and-tests/res/layout/item_home.xml +++ b/core/res/layout/cube_mints_base_block_menu_item.xml @@ -5,10 +5,12 @@ android:layout_gravity="center"> + android:padding="5dp" + android:textColor="@color/cube_mints_white" /> \ No newline at end of file diff --git a/core/res/layout/cube_mints_base_content_frame_with_title_header.xml b/core/res/layout/cube_mints_base_content_frame_with_title_header.xml new file mode 100755 index 0000000..e203dda --- /dev/null +++ b/core/res/layout/cube_mints_base_content_frame_with_title_header.xml @@ -0,0 +1,21 @@ + + + + + + + + \ No newline at end of file diff --git a/sample-and-tests/res/layout/fragment_home.xml b/core/res/layout/cube_mints_base_fragment_block_menu.xml similarity index 65% rename from sample-and-tests/res/layout/fragment_home.xml rename to core/res/layout/cube_mints_base_fragment_block_menu.xml index 6a9a61f..6d06e3c 100755 --- a/sample-and-tests/res/layout/fragment_home.xml +++ b/core/res/layout/cube_mints_base_fragment_block_menu.xml @@ -1,18 +1,18 @@ + android:layout_height="match_parent" + android:background="@color/cube_mints_white"> + android:padding="@dimen/cube_mints_content_view_padding" /> \ No newline at end of file diff --git a/core/res/layout/cube_mints_base_header_bar_title.xml b/core/res/layout/cube_mints_base_header_bar_title.xml new file mode 100755 index 0000000..3a1bebc --- /dev/null +++ b/core/res/layout/cube_mints_base_header_bar_title.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/res/layout/ptr_header.xml b/core/res/layout/ptr_header.xml deleted file mode 100755 index 712f7d8..0000000 --- a/core/res/layout/ptr_header.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/core/res/values-zh/cube_core_strings.xml b/core/res/values-zh/cube_core_strings.xml new file mode 100644 index 0000000..e94763b --- /dev/null +++ b/core/res/values-zh/cube_core_strings.xml @@ -0,0 +1,6 @@ + + + + 再按一次,退出程序 + + \ No newline at end of file diff --git a/core/res/values/attrs_ptr.xml b/core/res/values/attrs_ptr.xml deleted file mode 100755 index 1a9752f..0000000 --- a/core/res/values/attrs_ptr.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/core/res/values/dotview_attrs.xml b/core/res/values/cube_core_attrs_dotview.xml similarity index 100% rename from core/res/values/dotview_attrs.xml rename to core/res/values/cube_core_attrs_dotview.xml diff --git a/core/res/values/more_action_view_attrs.xml b/core/res/values/cube_core_attrs_more_action_view.xml similarity index 100% rename from core/res/values/more_action_view_attrs.xml rename to core/res/values/cube_core_attrs_more_action_view.xml diff --git a/core/res/values/attrs_scrollheaderframe.xml b/core/res/values/cube_core_attrs_scrollheaderframe.xml similarity index 100% rename from core/res/values/attrs_scrollheaderframe.xml rename to core/res/values/cube_core_attrs_scrollheaderframe.xml diff --git a/core/res/values/cube_core_attrs_slider_banner.xml b/core/res/values/cube_core_attrs_slider_banner.xml new file mode 100755 index 0000000..3f9d376 --- /dev/null +++ b/core/res/values/cube_core_attrs_slider_banner.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/core/res/values/cube_core_colors_holo.xml b/core/res/values/cube_core_colors_holo.xml new file mode 100644 index 0000000..d8a5566 --- /dev/null +++ b/core/res/values/cube_core_colors_holo.xml @@ -0,0 +1,42 @@ + + + + #ff33b5e5 + + #ff99cc00 + + #ffff4444 + + #ff0099cc + + #ff669900 + + #ffcc0000 + + #ffaa66cc + + #ffffbb33 + + #ffff8800 + + #ff00ddff + + + diff --git a/core/res/values/cube_core_strings.xml b/core/res/values/cube_core_strings.xml new file mode 100644 index 0000000..0d2c4cc --- /dev/null +++ b/core/res/values/cube_core_strings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/core/res/values/cube_core_styles.xml b/core/res/values/cube_core_styles.xml new file mode 100644 index 0000000..2318d0a --- /dev/null +++ b/core/res/values/cube_core_styles.xml @@ -0,0 +1,17 @@ + + + + + + + + + \ No newline at end of file diff --git a/core/res/values/cube_mints_colors.xml b/core/res/values/cube_mints_colors.xml new file mode 100644 index 0000000..c882f31 --- /dev/null +++ b/core/res/values/cube_mints_colors.xml @@ -0,0 +1,15 @@ + + + + #ffffff + #333333 + #666666 + #999999 + #f1f1f1 + #000000 + #373737 + #007edf + #007edf + #4d90fe + + \ No newline at end of file diff --git a/core/res/values/cube_mints_dimens.xml b/core/res/values/cube_mints_dimens.xml new file mode 100644 index 0000000..188aa71 --- /dev/null +++ b/core/res/values/cube_mints_dimens.xml @@ -0,0 +1,5 @@ + + + 44dp + 12.5dp + \ No newline at end of file diff --git a/core/res/values/cube_mints_strings.xml b/core/res/values/cube_mints_strings.xml new file mode 100644 index 0000000..4aad7f7 --- /dev/null +++ b/core/res/values/cube_mints_strings.xml @@ -0,0 +1,6 @@ + + + + Tap back once more to exit. + + \ No newline at end of file diff --git a/core/src/in/srain/cube/Cube.java b/core/src/in/srain/cube/Cube.java index e5b8a2e..97fd924 100755 --- a/core/src/in/srain/cube/Cube.java +++ b/core/src/in/srain/cube/Cube.java @@ -2,6 +2,7 @@ import android.app.Application; import android.content.Context; +import android.provider.Settings; import android.util.DisplayMetrics; import android.view.WindowManager; import in.srain.cube.util.LocalDisplay; @@ -17,18 +18,11 @@ public static void onCreate(Application app) { instance = new Cube(app); } - public static void onTerminate() { - - } - private Cube(Application application) { mApplication = application; // local display - DisplayMetrics dm = new DisplayMetrics(); - WindowManager wm = (WindowManager) application.getSystemService(Context.WINDOW_SERVICE); - wm.getDefaultDisplay().getMetrics(dm); - LocalDisplay.init(dm); + LocalDisplay.init(application); // network status NetworkStatusManager.init(application); @@ -42,8 +36,8 @@ public Context getContext() { return mApplication; } - public String getRootDirNameInSDCard() { - return "cube_sdk"; + public String getAndroidId() { + String id = Settings.Secure.getString(mApplication.getContentResolver(), Settings.Secure.ANDROID_ID); + return id; } - } diff --git a/core/src/in/srain/cube/app/CubeFragment.java b/core/src/in/srain/cube/app/CubeFragment.java index 54a98de..1ba62c2 100755 --- a/core/src/in/srain/cube/app/CubeFragment.java +++ b/core/src/in/srain/cube/app/CubeFragment.java @@ -1,15 +1,29 @@ package in.srain.cube.app; +import android.app.Activity; import android.os.Bundle; import android.support.v4.app.Fragment; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import in.srain.cube.app.lifecycle.IComponentContainer; +import in.srain.cube.app.lifecycle.LifeCycleComponent; +import in.srain.cube.app.lifecycle.LifeCycleComponentManager; +import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; -public abstract class CubeFragment extends Fragment implements ICubeFragement { +/** + * Implement {@link ICubeFragment}, {@link IComponentContainer} + *

+ * Ignore {@link LifeCycleComponentManager#onBecomesPartiallyInvisible} + */ +public abstract class CubeFragment extends Fragment implements ICubeFragment, IComponentContainer { + private static final boolean DEBUG = Debug.DEBUG_LIFE_CYCLE; protected Object mDataIn; + private boolean mFirstResume = true; + + private LifeCycleComponentManager mComponentContainer = new LifeCycleComponentManager(); protected abstract View createView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState); @@ -17,43 +31,163 @@ public CubeFragmentActivity getContext() { return (CubeFragmentActivity) getActivity(); } - // =========================================================== - // implements IBaseFragment - // =========================================================== + /** + * =========================================================== + * Implements {@link ICubeFragment} + * =========================================================== + */ @Override - public void onComeIn(Object data) { + public void onEnter(Object data) { mDataIn = data; - showStatus("onComeIn"); + if (DEBUG) { + showStatus("onEnter"); + } } @Override public void onLeave() { - showStatus("onLeave"); + if (DEBUG) { + showStatus("onLeave"); + } + mComponentContainer.onBecomesTotallyInvisible(); + } + + @Override + public void onBackWithData(Object data) { + if (DEBUG) { + showStatus("onBackWithData"); + } + mComponentContainer.onBecomesVisibleFromTotallyInvisible(); + } + + @Override + public boolean processBackPressed() { + return false; + } + + @Override + public void onBack() { + if (DEBUG) { + showStatus("onBack"); + } + mComponentContainer.onBecomesVisibleFromTotallyInvisible(); } + /** + * =========================================================== + * Implements {@link IComponentContainer} + * =========================================================== + */ @Override - public void onBack(Object data) { - showStatus("onBack"); + public void addComponent(LifeCycleComponent component) { + mComponentContainer.addComponent(component); } + /** + * Not add self to back stack when removed, so only when Activity stop + */ @Override public void onStop() { super.onStop(); - showStatus("onStop"); + if (DEBUG) { + showStatus("onStop"); + } + onLeave(); } + /** + * Only when Activity resume, not very precise. + * When activity recover from partly invisible, onBecomesPartiallyInvisible will be triggered. + */ @Override public void onResume() { super.onResume(); - showStatus("onResume"); + if (!mFirstResume) { + onBack(); + } + if (mFirstResume) { + mFirstResume = false; + } + if (DEBUG) { + showStatus("onResume"); + } } @Override - public boolean stayWhenBackPressed() { - return false; + public void onAttach(Activity activity) { + super.onAttach(activity); + if (DEBUG) { + showStatus("onAttach"); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (DEBUG) { + showStatus("onCreate"); + } + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + if (DEBUG) { + showStatus("onActivityCreated"); + } + } + + @Override + public void onStart() { + super.onStart(); + if (DEBUG) { + showStatus("onStart"); + } + } + + @Override + public void onPause() { + super.onPause(); + if (DEBUG) { + showStatus("onPause"); + } + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + if (DEBUG) { + showStatus("onDestroyView"); + } + } + + @Override + public void onDestroy() { + super.onDestroy(); + if (DEBUG) { + showStatus("onDestroy"); + } + mComponentContainer.onDestroy(); + } + + @Override + public void onDetach() { + super.onDetach(); + if (DEBUG) { + showStatus("onDetach"); + } + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + if (DEBUG) { + showStatus("onCreateView"); + } + return super.onCreateView(inflater, container, savedInstanceState); } private void showStatus(String status) { - Log.d("test", String.format("%s %s", this.getClass().getName(), status)); + final String[] className = ((Object) this).getClass().getName().split("\\."); + CLog.d("cube-lifecycle", "%s %s", className[className.length - 1], status); } } diff --git a/core/src/in/srain/cube/app/CubeFragmentActivity.java b/core/src/in/srain/cube/app/CubeFragmentActivity.java index 5d15537..83c1465 100755 --- a/core/src/in/srain/cube/app/CubeFragmentActivity.java +++ b/core/src/in/srain/cube/app/CubeFragmentActivity.java @@ -1,18 +1,24 @@ package in.srain.cube.app; import android.content.Context; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentTransaction; +import android.text.TextUtils; import android.view.View; import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.Toast; -import in.srain.cube.app.FragmentParam.TYPE; +import in.srain.cube.util.CLog; public abstract class CubeFragmentActivity extends FragmentActivity { - private final static String TAG_SP = "_"; + private final static String LOG_TAG = "cube-fragment"; + + public static boolean DEBUG = true; + protected CubeFragment currentFragment; + private boolean mCloseWarned; /** * return the string id of close warning @@ -25,45 +31,19 @@ public abstract class CubeFragmentActivity extends FragmentActivity { protected abstract int getFragmentContainerId(); - protected CubeFragment currentFragment; - private boolean mCloseWarned; - - public void pushFragmentToBackStatck(Class cls, Object data) { - FragmentParam param = new FragmentParam(); - param.cls = cls; - param.data = data; - param.addToBackStack = true; - - processFragement(param); - } - - public void addFragment(Class cls, Object data) { - + public void pushFragmentToBackStack(Class cls, Object data) { FragmentParam param = new FragmentParam(); param.cls = cls; param.data = data; - param.addToBackStack = false; - processFragement(param); - } - - public void replaceFragment(Class cls, Object data) { - - FragmentParam param = new FragmentParam(); - param.cls = cls; - param.data = data; - param.type = TYPE.REPLACE; - param.addToBackStack = false; - - processFragement(param); + goToThisFragment(param); } protected String getFragmentTag(FragmentParam param) { - StringBuilder sb = new StringBuilder(param.cls.toString()); return sb.toString(); } - private void processFragement(FragmentParam param) { + private void goToThisFragment(FragmentParam param) { int containerId = getFragmentContainerId(); Class cls = param.cls; if (cls == null) { @@ -71,32 +51,35 @@ private void processFragement(FragmentParam param) { } try { String fragmentTag = getFragmentTag(param); - CubeFragment fragment = (CubeFragment) getSupportFragmentManager().findFragmentByTag(fragmentTag); + FragmentManager fm = getSupportFragmentManager(); + if (DEBUG) { + CLog.d(LOG_TAG, "before operate, stack entry count: %s", fm.getBackStackEntryCount()); + } + CubeFragment fragment = (CubeFragment) fm.findFragmentByTag(fragmentTag); if (fragment == null) { fragment = (CubeFragment) cls.newInstance(); } - fragment.onComeIn(param.data); - if (currentFragment != null) { + if (currentFragment != null && currentFragment != fragment) { currentFragment.onLeave(); } + fragment.onEnter(param.data); - FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); - if (param.type == TYPE.ADD) { - if (fragment.isAdded()) { - ft.show(fragment); - } else { - ft.add(containerId, fragment, fragmentTag); + FragmentTransaction ft = fm.beginTransaction(); + if (fragment.isAdded()) { + if (DEBUG) { + CLog.d(LOG_TAG, "%s has been added, will be shown again.", fragmentTag); } + ft.show(fragment); } else { - ft.replace(containerId, fragment, fragmentTag); + if (DEBUG) { + CLog.d(LOG_TAG, "%s is added.", fragmentTag); + } + ft.add(containerId, fragment, fragmentTag); } - currentFragment = fragment; - if (param.addToBackStack) { - ft.addToBackStack(fragmentTag); - } - ft.commitAllowingStateLoss(); + ft.addToBackStack(fragmentTag); + ft.commitAllowingStateLoss(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { @@ -112,7 +95,7 @@ public void goToFragment(Class cls, Object data) { CubeFragment fragment = (CubeFragment) getSupportFragmentManager().findFragmentByTag(cls.toString()); if (fragment != null) { currentFragment = fragment; - fragment.onBack(data); + fragment.onBackWithData(data); } getSupportFragmentManager().popBackStackImmediate(cls.toString(), 0); } @@ -120,11 +103,9 @@ public void goToFragment(Class cls, Object data) { public void popTopFragment(Object data) { FragmentManager fm = getSupportFragmentManager(); fm.popBackStackImmediate(); - currentFragment = null; - int cnt = fm.getBackStackEntryCount(); - String name = fm.getBackStackEntryAt(cnt - 1).getName(); - currentFragment = (CubeFragment) fm.findFragmentByTag(name); - currentFragment.onBack(data); + if (tryToUpdateCurrentAfterPop() && currentFragment != null) { + currentFragment.onBackWithData(data); + } } public void popToRoot(Object data) { @@ -135,32 +116,74 @@ public void popToRoot(Object data) { popTopFragment(data); } + /** + * process the return back logic + * return true if back pressed event has been processed and should stay in current view + * + * @return + */ + protected boolean processBackPressed() { + return false; + } + + /** + * process back pressed + */ @Override public void onBackPressed() { + + // process back for fragment + if (processBackPressed()) { + return; + } + + // process back for fragment boolean enableBackPressed = true; if (currentFragment != null) { - enableBackPressed = !currentFragment.stayWhenBackPressed(); + enableBackPressed = !currentFragment.processBackPressed(); } if (enableBackPressed) { int cnt = getSupportFragmentManager().getBackStackEntryCount(); - if (cnt <= 0) { + if (cnt <= 1 && isTaskRoot()) { String closeWarningHint = getCloseWarning(); - if (!mCloseWarned && closeWarningHint != null && closeWarningHint.length() == 0) { + if (!mCloseWarned && !TextUtils.isEmpty(closeWarningHint)) { Toast toast = Toast.makeText(this, closeWarningHint, Toast.LENGTH_SHORT); toast.show(); mCloseWarned = true; } else { - returnBack(); + doReturnBack(); } } else { mCloseWarned = false; - returnBack(); + doReturnBack(); + } + } + } + + private boolean tryToUpdateCurrentAfterPop() { + FragmentManager fm = getSupportFragmentManager(); + int cnt = fm.getBackStackEntryCount(); + if (cnt > 0) { + String name = fm.getBackStackEntryAt(cnt - 1).getName(); + Fragment fragment = fm.findFragmentByTag(name); + if (fragment != null && fragment instanceof CubeFragment) { + currentFragment = (CubeFragment) fragment; } + return true; } + return false; } - private void returnBack() { - super.onBackPressed(); + protected void doReturnBack() { + int count = getSupportFragmentManager().getBackStackEntryCount(); + if (count <= 1) { + finish(); + } else { + getSupportFragmentManager().popBackStackImmediate(); + if (tryToUpdateCurrentAfterPop() && currentFragment != null) { + currentFragment.onBack(); + } + } } public void hideKeyboardForCurrentFocus() { diff --git a/core/src/in/srain/cube/app/FragmentParam.java b/core/src/in/srain/cube/app/FragmentParam.java index 75a5d6f..6e96cba 100755 --- a/core/src/in/srain/cube/app/FragmentParam.java +++ b/core/src/in/srain/cube/app/FragmentParam.java @@ -3,15 +3,7 @@ public class FragmentParam { - enum TYPE { - ADD, REPLACE - } - - ; - public CubeFragment from; public Class cls; public Object data; - public TYPE type = TYPE.ADD; - public boolean addToBackStack = true; } \ No newline at end of file diff --git a/core/src/in/srain/cube/app/ICubeFragement.java b/core/src/in/srain/cube/app/ICubeFragement.java deleted file mode 100755 index a5a525e..0000000 --- a/core/src/in/srain/cube/app/ICubeFragement.java +++ /dev/null @@ -1,12 +0,0 @@ -package in.srain.cube.app; - -public interface ICubeFragement { - - void onComeIn(Object data); - - void onLeave(); - - void onBack(Object data); - - boolean stayWhenBackPressed(); -} \ No newline at end of file diff --git a/core/src/in/srain/cube/app/ICubeFragment.java b/core/src/in/srain/cube/app/ICubeFragment.java new file mode 100755 index 0000000..b719c25 --- /dev/null +++ b/core/src/in/srain/cube/app/ICubeFragment.java @@ -0,0 +1,32 @@ +package in.srain.cube.app; + +/** + * provide some method to make Fragment act like Activity in BackStack + *

+ * When a Fragment becomes invisible totally, {@link #onLeave} will be called. + *

+ * When a Fragment becomes visible from totally invisible, {@link #onBack()} or {@link #onBackWithData(Object)} will be called. + */ +public interface ICubeFragment { + + /** + * pass the data from {@link CubeFragmentActivity#pushFragmentToBackStack(Class, Object)}to this fragment + * + * @param data + */ + void onEnter(Object data); + + void onLeave(); + + void onBack(); + + void onBackWithData(Object data); + + /** + * process the return back logic + * return true if back pressed event has been processed and should stay in current view + * + * @return + */ + boolean processBackPressed(); +} \ No newline at end of file diff --git a/core/src/in/srain/cube/app/XActivity.java b/core/src/in/srain/cube/app/XActivity.java index f8c2aa9..9bc8c39 100755 --- a/core/src/in/srain/cube/app/XActivity.java +++ b/core/src/in/srain/cube/app/XActivity.java @@ -1,8 +1,11 @@ package in.srain.cube.app; +import android.os.Bundle; +import android.util.Log; import in.srain.cube.app.lifecycle.IComponentContainer; import in.srain.cube.app.lifecycle.LifeCycleComponent; import in.srain.cube.app.lifecycle.LifeCycleComponentManager; +import in.srain.cube.util.Debug; /** * 1. manager the components when move from a lifetime to another @@ -13,32 +16,68 @@ public abstract class XActivity extends CubeFragmentActivity implements ICompone private LifeCycleComponentManager mComponentContainer = new LifeCycleComponentManager(); + private static final boolean DEBUG = Debug.DEBUG_LIFE_CYCLE; + @Override protected void onRestart() { super.onStart(); - mComponentContainer.onRestart(); + mComponentContainer.onBecomesVisibleFromTotallyInvisible(); + if (DEBUG) { + showStatus("onRestart"); + } + } + + @Override + protected void onPause() { + super.onPause(); + mComponentContainer.onBecomesPartiallyInvisible(); + if (DEBUG) { + showStatus("onPause"); + } } @Override protected void onResume() { super.onResume(); - mComponentContainer.onResume(); + mComponentContainer.onBecomesVisibleFromPartiallyInvisible(); + if (DEBUG) { + showStatus("onResume"); + } + } + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + if (DEBUG) { + showStatus("onCreate"); + } } @Override protected void onStop() { super.onStop(); - mComponentContainer.onStop(); + mComponentContainer.onBecomesTotallyInvisible(); + if (DEBUG) { + showStatus("onStop"); + } } @Override protected void onDestroy() { super.onDestroy(); mComponentContainer.onDestroy(); + if (DEBUG) { + showStatus("onDestroy"); + } } @Override public void addComponent(LifeCycleComponent component) { mComponentContainer.addComponent(component); } + + private void showStatus(String status) { + final String[] className = ((Object) this).getClass().getName().split("\\."); + Log.d("cube-lifecycle", String.format("%s %s", className[className.length - 1], status)); + } } diff --git a/core/src/in/srain/cube/app/lifecycle/LifeCycleComponent.java b/core/src/in/srain/cube/app/lifecycle/LifeCycleComponent.java index cb0679d..ec25102 100755 --- a/core/src/in/srain/cube/app/lifecycle/LifeCycleComponent.java +++ b/core/src/in/srain/cube/app/lifecycle/LifeCycleComponent.java @@ -2,13 +2,32 @@ public interface LifeCycleComponent { - public void onRestart(); + /** + * The UI becomes partially invisible. + * like {@link android.app.Activity#onPause} + */ + public void onBecomesPartiallyInvisible(); - public void onPause(); + /** + * The UI becomes visible from partially or totally invisible. + * like {@link android.app.Activity#onResume} + */ + public void onBecomesVisible(); - public void onResume(); + /** + * The UI becomes totally invisible. + * like {@link android.app.Activity#onStop} + */ + public void onBecomesTotallyInvisible(); - public void onStop(); + /** + * The UI becomes visible from totally invisible. + * like {@link android.app.Activity#onRestart} + */ + public void onBecomesVisibleFromTotallyInvisible(); + /** + * like {@link android.app.Activity#onDestroy} + */ public void onDestroy(); } diff --git a/core/src/in/srain/cube/app/lifecycle/LifeCycleComponentManager.java b/core/src/in/srain/cube/app/lifecycle/LifeCycleComponentManager.java index 37cb9b0..3151d4f 100755 --- a/core/src/in/srain/cube/app/lifecycle/LifeCycleComponentManager.java +++ b/core/src/in/srain/cube/app/lifecycle/LifeCycleComponentManager.java @@ -1,87 +1,110 @@ package in.srain.cube.app.lifecycle; -import android.content.Context; - -import java.lang.ref.WeakReference; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; public class LifeCycleComponentManager implements IComponentContainer { - private HashMap> mComponentList; + private HashMap mComponentList; - public static void tryAddComponentToContainer(LifeCycleComponent component, Context context) { - if (context instanceof IComponentContainer) { - ((IComponentContainer) context).addComponent(component); - } else { - throw new IllegalArgumentException("componentContainerContext should impletemnts IComponentContainer"); - } + public LifeCycleComponentManager() { } - public LifeCycleComponentManager() { - mComponentList = new HashMap>(); + /** + * Try to add component to container + * + * @param component + * @param matrixContainer + */ + public static void tryAddComponentToContainer(LifeCycleComponent component, Object matrixContainer) { + tryAddComponentToContainer(component, matrixContainer, true); + } + + public static boolean tryAddComponentToContainer(LifeCycleComponent component, Object matrixContainer, boolean throwEx) { + if (matrixContainer instanceof IComponentContainer) { + ((IComponentContainer) matrixContainer).addComponent(component); + return true; + } else { + if (throwEx) { + throw new IllegalArgumentException("componentContainerContext should implements IComponentContainer"); + } + return false; + } } public void addComponent(LifeCycleComponent component) { if (component != null) { - mComponentList.put(component.toString(), new WeakReference(component)); + if (mComponentList == null) { + mComponentList = new HashMap(); + } + mComponentList.put(component.toString(), component); } } - public void onRestart() { + public void onBecomesVisibleFromTotallyInvisible() { - for (Iterator>> it = mComponentList.entrySet().iterator(); it.hasNext(); ) { - LifeCycleComponent component = it.next().getValue().get(); - if (null != component) { - component.onRestart(); - } else { - it.remove(); + if (mComponentList == null) { + return; + } + + Iterator> it = mComponentList.entrySet().iterator(); + while (it.hasNext()) { + LifeCycleComponent component = it.next().getValue(); + if (component != null) { + component.onBecomesVisibleFromTotallyInvisible(); } } } - public void onStop() { - Iterator>> it = mComponentList.entrySet().iterator(); + public void onBecomesTotallyInvisible() { + if (mComponentList == null) { + return; + } + Iterator> it = mComponentList.entrySet().iterator(); while (it.hasNext()) { - LifeCycleComponent component = it.next().getValue().get(); - if (null != component) { - component.onStop(); - } else { - it.remove(); + LifeCycleComponent component = it.next().getValue(); + if (component != null) { + component.onBecomesTotallyInvisible(); } } } - public void onPause() { - for (Iterator>> it = mComponentList.entrySet().iterator(); it.hasNext(); ) { - LifeCycleComponent component = it.next().getValue().get(); - if (null != component) { - component.onPause(); - } else { - it.remove(); + public void onBecomesPartiallyInvisible() { + if (mComponentList == null) { + return; + } + Iterator> it = mComponentList.entrySet().iterator(); + while (it.hasNext()) { + LifeCycleComponent component = it.next().getValue(); + if (component != null) { + component.onBecomesPartiallyInvisible(); } } } - public void onResume() { - for (Iterator>> it = mComponentList.entrySet().iterator(); it.hasNext(); ) { - LifeCycleComponent component = it.next().getValue().get(); - if (null != component) { - component.onResume(); - } else { - it.remove(); + public void onBecomesVisibleFromPartiallyInvisible() { + if (mComponentList == null) { + return; + } + Iterator> it = mComponentList.entrySet().iterator(); + while (it.hasNext()) { + LifeCycleComponent component = it.next().getValue(); + if (component != null) { + component.onBecomesVisible(); } } } public void onDestroy() { - for (Iterator>> it = mComponentList.entrySet().iterator(); it.hasNext(); ) { - LifeCycleComponent component = it.next().getValue().get(); - if (null != component) { + if (mComponentList == null) { + return; + } + Iterator> it = mComponentList.entrySet().iterator(); + while (it.hasNext()) { + LifeCycleComponent component = it.next().getValue(); + if (component != null) { component.onDestroy(); - } else { - it.remove(); } } } diff --git a/core/src/in/srain/cube/cache/CacheInfo.java b/core/src/in/srain/cube/cache/CacheInfo.java new file mode 100644 index 0000000..5e800a2 --- /dev/null +++ b/core/src/in/srain/cube/cache/CacheInfo.java @@ -0,0 +1,61 @@ +package in.srain.cube.cache; + +import in.srain.cube.request.JsonData; +import org.json.JSONObject; + +/** + * A description for the data in cache system + */ +public class CacheInfo { + + private String mData; + private long mTime; + private int mSize; + + public static CacheInfo createForNow(String data) { + CacheInfo info = new CacheInfo(data); + info.mTime = (int) (System.currentTimeMillis() / 1000); + return info; + } + + public static CacheInfo createInvalidated(String data) { + return create(data, -2); + } + + public static CacheInfo createFromJson(JsonData jsonData) { + return create(jsonData.optString("data"), jsonData.optInt("time")); + } + + private static CacheInfo create(String data, long time) { + CacheInfo cacheInfo = new CacheInfo(data); + cacheInfo.mTime = time; + return cacheInfo; + } + + private CacheInfo(String data) { + this.mData = data; + mSize = (data.getBytes().length + 8); + } + + public int getSize() { + return mSize; + } + + public long getTime() { + return mTime; + } + + public String getData() { + return mData; + } + + public String getCacheData() { + JSONObject jsonObject = new JSONObject(); + try { + jsonObject.put("time", mTime); + jsonObject.put("data", mData); + } catch (Exception e) { + } + return jsonObject.toString(); + } +} diff --git a/core/src/in/srain/cube/cache/CacheManager.java b/core/src/in/srain/cube/cache/CacheManager.java new file mode 100755 index 0000000..3d39521 --- /dev/null +++ b/core/src/in/srain/cube/cache/CacheManager.java @@ -0,0 +1,371 @@ +package in.srain.cube.cache; + +import android.content.Context; +import android.support.v4.util.LruCache; +import android.text.TextUtils; +import in.srain.cube.concurrent.SimpleExecutor; +import in.srain.cube.concurrent.SimpleTask; +import in.srain.cube.file.FileUtil; +import in.srain.cube.file.LruFileCache; +import in.srain.cube.request.JsonData; +import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; + +/** + * @author http://www.liaohuqiu.net + */ +public class CacheManager { + + private static final boolean DEBUG = Debug.DEBUG_CACHE; + private static final String LOG_TAG = "cube_cache"; + + private LruCache mMemoryCache; + private LruFileCache mFileCache; + + private static final byte AFTER_READ_FROM_FILE = 0x01; + private static final byte AFTER_READ_FROM_ASSERT = 0x02; + private static final byte AFTER_CONVERT = 0x04; + + private static final byte DO_READ_FROM_FILE = 0x01; + private static final byte DO_READ_FROM_ASSERT = 0x02; + private static final byte DO_CONVERT = 0x04; + + private static final byte CONVERT_FOR_MEMORY = 0x03; + private static final byte CONVERT_FOR_FILE = 0x01; + private static final byte CONVERT_FOR_ASSERT = 0x02; + private static final byte CONVERT_FOR_CREATE = 0x04; + + private Context mContext; + + public CacheManager(Context content, String cacheDir, int memoryCacheSizeInKB, int fileCacheSizeInKB) { + mContext = content; + + mMemoryCache = new LruCache(memoryCacheSizeInKB * 1024) { + @Override + protected int sizeOf(String key, CacheInfo value) { + return (value.getSize() + key.getBytes().length); + } + }; + mFileCache = new LruFileCache(content, cacheDir, fileCacheSizeInKB * 1024); + mFileCache.initDiskCacheAsync(); + if (DEBUG) { + CLog.d(LOG_TAG, "init file cache. dir: %s => %s, size: %s, used: %s", cacheDir, mFileCache.getCachePath(), mFileCache.getMaxSize(), mFileCache.getUsedSpace()); + } + } + + public void requestCache(ICacheAble cacheAble) { + InnerCacheTask task = new InnerCacheTask(cacheAble); + task.beginQuery(); + } + + public void continueAfterCreateData(ICacheAble cacheAble, final String data) { + setCacheData(cacheAble.getCacheKey(), data); + InnerCacheTask task = new InnerCacheTask(cacheAble); + task.beginConvertDataAsync(CONVERT_FOR_CREATE); + } + + public void setCacheData(final String cacheKey, final String data) { + if (TextUtils.isEmpty(cacheKey) || TextUtils.isEmpty(data)) { + return; + } + if (DEBUG) { + CLog.d(LOG_TAG, "%s, setCacheData", cacheKey); + } + SimpleExecutor.getInstance().execute( + + new Runnable() { + @Override + public void run() { + CacheInfo cacheInfo = CacheInfo.createForNow(data); + putDataToMemoryCache(cacheKey, cacheInfo); + mFileCache.write(cacheKey, cacheInfo.getCacheData()); + mFileCache.flushDiskCacheAsyncWithDelay(1000); + } + } + ); + } + + private class InnerCacheTask extends SimpleTask { + + private ICacheAble mCacheAble; + + private CacheInfo mRawData; + private T1 mResult; + private byte mWorkType = 0; + private byte mConvertFor = 0; + private byte mCurrentStatus = 0; + + public InnerCacheTask(ICacheAble cacheAble) { + mCacheAble = cacheAble; + } + + void beginQuery() { + + if (mCacheAble.cacheIsDisabled()) { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, Cache is disabled, query from server", mCacheAble.getCacheKey()); + } + mCacheAble.createDataForCache(CacheManager.this); + return; + } + + String cacheKey = mCacheAble.getCacheKey(); + + // try to find in runtime cache + mRawData = mMemoryCache.get(cacheKey); + if (mRawData != null) { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, exist in list", mCacheAble.getCacheKey()); + } + beginConvertDataAsync(CONVERT_FOR_MEMORY); + return; + } + + // try read from cache data + boolean hasFileCache = mFileCache.has(mCacheAble.getCacheKey()); + if (hasFileCache) { + beginQueryFromCacheFileAsync(); + return; + } + + // try to read from assert cache file + String assertInitDataPath = mCacheAble.getAssertInitDataPath(); + if (assertInitDataPath != null && assertInitDataPath.length() > 0) { + beginQueryFromAssertCacheFileAsync(); + return; + } + + if (DEBUG) { + CLog.d(LOG_TAG, "%s, cache file not exist", mCacheAble.getCacheKey()); + } + mCacheAble.createDataForCache(CacheManager.this); + } + + @Override + public void doInBackground() { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, doInBackground: mWorkType: %s", mCacheAble.getCacheKey(), mWorkType); + } + switch (mWorkType) { + + case DO_READ_FROM_FILE: + doQueryFromCacheFileInBackground(); + setCurrentStatus(AFTER_READ_FROM_FILE); + break; + + case DO_READ_FROM_ASSERT: + doQueryFromAssertCacheFileInBackground(); + setCurrentStatus(AFTER_READ_FROM_ASSERT); + break; + + case DO_CONVERT: + doConvertDataInBackground(); + setCurrentStatus(AFTER_CONVERT); + break; + + default: + break; + } + } + + @Override + public void onFinish() { + switch (mCurrentStatus) { + case AFTER_READ_FROM_FILE: + beginConvertDataAsync(CONVERT_FOR_FILE); + break; + case AFTER_READ_FROM_ASSERT: + beginConvertDataAsync(CONVERT_FOR_ASSERT); + break; + + case AFTER_CONVERT: + done(); + break; + + default: + break; + } + } + + private void beginQueryFromCacheFileAsync() { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, beginQueryFromCacheFileAsync", mCacheAble.getCacheKey()); + } + mWorkType = DO_READ_FROM_FILE; + restart(); + SimpleExecutor.getInstance().execute(this); + } + + private void beginQueryFromAssertCacheFileAsync() { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, beginQueryFromAssertCacheFileAsync", mCacheAble.getCacheKey()); + } + mWorkType = DO_READ_FROM_ASSERT; + restart(); + SimpleExecutor.getInstance().execute(this); + } + + private void beginConvertDataAsync(byte convertFor) { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, beginConvertDataAsync", mCacheAble.getCacheKey()); + } + mConvertFor = convertFor; + mWorkType = DO_CONVERT; + restart(); + SimpleExecutor.getInstance().execute(this); + } + + private void doQueryFromCacheFileInBackground() { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, try read cache data from file", mCacheAble.getCacheKey()); + } + + String cacheContent = mFileCache.read(mCacheAble.getCacheKey()); + JsonData jsonData = JsonData.create(cacheContent); + mRawData = CacheInfo.createFromJson(jsonData); + } + + private void doQueryFromAssertCacheFileInBackground() { + + if (DEBUG) { + CLog.d(LOG_TAG, "%s, try read cache data from assert file", mCacheAble.getCacheKey()); + } + + String cacheContent = FileUtil.readAssert(mContext, mCacheAble.getAssertInitDataPath()); + mRawData = CacheInfo.createInvalidated(cacheContent); + putDataToMemoryCache(mCacheAble.getCacheKey(), mRawData); + } + + private void doConvertDataInBackground() { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, doConvertDataInBackground", mCacheAble.getCacheKey()); + } + JsonData data = JsonData.create(mRawData.getData()); + mResult = mCacheAble.processRawDataFromCache(data); + } + + private void setCurrentStatus(byte status) { + mCurrentStatus = status; + if (DEBUG) { + CLog.d(LOG_TAG, "%s, setCurrentStatus: %s", mCacheAble.getCacheKey(), status); + } + } + + private void done() { + + long lastTime = mRawData.getTime(); + long timeInterval = System.currentTimeMillis() / 1000 - lastTime; + boolean outOfDate = timeInterval > mCacheAble.getCacheTime() || timeInterval < 0; + + switch (mConvertFor) { + case CONVERT_FOR_ASSERT: + mCacheAble.onCacheData(CacheResultType.FROM_INIT_FILE, mResult, outOfDate); + break; + case CONVERT_FOR_CREATE: + mCacheAble.onCacheData(CacheResultType.FROM_CREATED, mResult, outOfDate); + break; + case CONVERT_FOR_FILE: + mCacheAble.onCacheData(CacheResultType.FROM_INIT_FILE, mResult, outOfDate); + break; + case CONVERT_FOR_MEMORY: + mCacheAble.onCacheData(CacheResultType.FROM_CACHE_FILE, mResult, outOfDate); + break; + } + if (outOfDate) { + mCacheAble.createDataForCache(CacheManager.this); + } + } + } + + private void putDataToMemoryCache(String key, CacheInfo data) { + if (TextUtils.isEmpty(key)) { + return; + } + if (DEBUG) { + CLog.d(LOG_TAG, "%s, set cache to runtime cache list", key); + } + mMemoryCache.put(key, data); + } + + /** + * delete cache by key + * + * @param key + */ + public void invalidateCache(String key) { + if (DEBUG) { + CLog.d(LOG_TAG, "%s, invalidateCache", key); + } + mFileCache.delete(key); + mMemoryCache.remove(key); + } + + /** + * clear the memory cache + */ + public void clearMemoryCache() { + if (mMemoryCache != null) { + mMemoryCache.evictAll(); + } + } + + /** + * get the spaced has been used + * + * @return + */ + public int getMemoryCacheUsedSpace() { + return mMemoryCache.size(); + } + + /** + * get the spaced max space in config + * + * @return + */ + public int getMemoryCacheMaxSpace() { + return mMemoryCache.maxSize(); + } + + /** + * clear the disk cache + */ + public void clearDiskCache() { + if (null != mFileCache) { + mFileCache.clearCache(); + } + } + + /** + * return the file cache path + * + * @return + */ + public String getFileCachePath() { + if (null != mFileCache) { + return mFileCache.getCachePath(); + } + return null; + } + + /** + * get the used space in file cache + * + * @return + */ + public long getFileCacheUsedSpace() { + return null != mFileCache ? mFileCache.getUsedSpace() : 0; + } + + /** + * get the max space for file cache + * + * @return + */ + public long getFileCacheMaxSpace() { + if (null != mFileCache) { + return mFileCache.getMaxSize(); + } + return 0; + } +} \ No newline at end of file diff --git a/core/src/in/srain/cube/cache/CacheResultType.java b/core/src/in/srain/cube/cache/CacheResultType.java new file mode 100644 index 0000000..8f8da1b --- /dev/null +++ b/core/src/in/srain/cube/cache/CacheResultType.java @@ -0,0 +1,8 @@ +package in.srain.cube.cache; + +public enum CacheResultType { + FROM_INIT_FILE, + FROM_CACHE_FILE, + FROM_CREATED, + FROM_MEMORY, +} \ No newline at end of file diff --git a/core/src/in/srain/cube/cache/ICacheAble.java b/core/src/in/srain/cube/cache/ICacheAble.java new file mode 100644 index 0000000..6b62f7c --- /dev/null +++ b/core/src/in/srain/cube/cache/ICacheAble.java @@ -0,0 +1,50 @@ +package in.srain.cube.cache; + +import in.srain.cube.request.JsonData; + +/** + * Describe the behaviour of a object who can be cached + */ +public interface ICacheAble { + + /** + * In seconds + * + * @return + */ + public long getCacheTime(); + + public String getCacheKey(); + + /** + * file path under /res, For example: "/cache_init/test.json"; + */ + public String getAssertInitDataPath(); + + /** + * We need to process the data from data source, do some filter of convert the structure. + *

+ * As the "Assert Data" is a special data source, we also need to do the same work. + */ + public T processRawDataFromCache(JsonData rawData); + + /** + * when data loaded from cache + * + * @param cacheData + * @param outOfDate + */ + public void onCacheData(CacheResultType cacheResultType, T cacheData, boolean outOfDate); + + /** + * create data when no cache is available. + */ + public void createDataForCache(CacheManager cacheManager); + + /** + * temporarily disable cache. The data will no be load from cache and will also not put into cache + * + * @return + */ + public boolean cacheIsDisabled(); +} diff --git a/core/src/in/srain/cube/cache/IFileCache.java b/core/src/in/srain/cube/cache/IFileCache.java index 8ef1981..ebc056a 100644 --- a/core/src/in/srain/cube/cache/IFileCache.java +++ b/core/src/in/srain/cube/cache/IFileCache.java @@ -1,7 +1,5 @@ package in.srain.cube.cache; -import java.io.InputStream; - public interface IFileCache { public String getCachePath(); @@ -10,7 +8,7 @@ public interface IFileCache { public void clearCache(); - public int getMaxSize(); + public long getMaxSize(); public boolean has(String key); } diff --git a/core/src/in/srain/cube/cache/Query.java b/core/src/in/srain/cube/cache/Query.java new file mode 100644 index 0000000..6675f88 --- /dev/null +++ b/core/src/in/srain/cube/cache/Query.java @@ -0,0 +1,119 @@ +package in.srain.cube.cache; + +import android.text.TextUtils; +import in.srain.cube.request.JsonData; + +public class Query implements ICacheAble { + + public enum RequestType { + USE_CACHE_NOT_EXPIRED, + USE_DATA_CREATED, + USE_CACHE_ANYWAY, + FAIL, + } + + private QueryHandler mHandler; + private CacheManager mCacheManager; + + public Query(CacheManager cacheManager) { + mCacheManager = cacheManager; + } + + public void continueAfterCreateData(final String data) { + if (!TextUtils.isEmpty(data)) { + mCacheManager.continueAfterCreateData(this, data); + } else { + queryFail(); + } + } + + private void queryFail() { + mHandler.onQueryFinish(RequestType.FAIL, null, true); + } + + public void setHandler(QueryHandler handler) { + mHandler = handler; + } + + public void query() { + mCacheManager.requestCache(this); + } + + @Override + public long getCacheTime() { + if (mHandler != null) { + return mHandler.getCacheTime(); + } + return 0; + } + + @Override + public String getCacheKey() { + if (mHandler != null) { + return mHandler.getCacheKey(); + } + return null; + } + + @Override + public String getAssertInitDataPath() { + if (mHandler != null) { + return mHandler.getAssertInitDataPath(); + } + return null; + } + + @Override + public T processRawDataFromCache(JsonData rawData) { + if (mHandler != null) { + return (T) mHandler.processRawDataFromCache(rawData); + } + return null; + } + + @Override + public void onCacheData(CacheResultType cacheResultType, T cacheData, boolean outOfDate) { + switch (cacheResultType) { + case FROM_CACHE_FILE: + break; + case FROM_INIT_FILE: + break; + case FROM_MEMORY: + break; + case FROM_CREATED: + break; + } + + if (outOfDate) { + if (mHandler != null && mHandler.useCacheAnyway()) { + mHandler.onQueryFinish(RequestType.USE_CACHE_ANYWAY, cacheData, outOfDate); + } + } else { + switch (cacheResultType) { + case FROM_CACHE_FILE: + break; + case FROM_INIT_FILE: + break; + case FROM_MEMORY: + break; + case FROM_CREATED: + break; + } + mHandler.onQueryFinish(RequestType.USE_CACHE_NOT_EXPIRED, cacheData, true); + } + } + + @Override + public void createDataForCache(CacheManager cacheManager) { + if (mHandler != null) { + continueAfterCreateData(mHandler.createDataForCache(this)); + } else { + queryFail(); + } + } + + @Override + public boolean cacheIsDisabled() { + return mHandler != null && mHandler.disableCache(); + } +} diff --git a/core/src/in/srain/cube/cache/QueryHandler.java b/core/src/in/srain/cube/cache/QueryHandler.java new file mode 100644 index 0000000..837356c --- /dev/null +++ b/core/src/in/srain/cube/cache/QueryHandler.java @@ -0,0 +1,54 @@ +package in.srain.cube.cache; + +import in.srain.cube.request.JsonData; + +public interface QueryHandler { + + public static abstract class DefaultHandler implements QueryHandler { + + @Override + public JsonData processRawDataFromCache(JsonData rawData) { + return rawData; + } + + @Override + public boolean useCacheAnyway() { + return false; + } + } + + public long getCacheTime(); + + public String getCacheKey(); + + public String getAssertInitDataPath(); + + /** + * We need to process the data from data source, do some filter of convert the structure. + *

+ * As the "Assert Data" is a special data source, we also need to do the same work. + */ + public T processRawDataFromCache(JsonData rawData); + + /** + * when query finish + * + * @param cacheData + * @param outOfDate + */ + public void onQueryFinish(Query.RequestType requestType, T cacheData, boolean outOfDate); + + /** + * just using cache data if existent, no matter it is expired or not + * + * @return + */ + public boolean useCacheAnyway(); + + /** + * create data when cache data is no existent + */ + public String createDataForCache(Query query); + + public boolean disableCache(); +} diff --git a/core/src/in/srain/cube/file/DiskLruCache.java b/core/src/in/srain/cube/file/DiskLruCache.java index d342f36..e29a3eb 100755 --- a/core/src/in/srain/cube/file/DiskLruCache.java +++ b/core/src/in/srain/cube/file/DiskLruCache.java @@ -430,13 +430,6 @@ private synchronized void rebuildJournal() throws IOException { } 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(); } @@ -724,6 +717,10 @@ public Editor edit() throws IOException { return DiskLruCache.this.edit(key, sequenceNumber); } + public boolean has(int index) { + return index < ins.length; + } + /** * Returns the unbuffered stream with the value for {@code index}. */ diff --git a/core/src/in/srain/cube/file/FileUtil.java b/core/src/in/srain/cube/file/FileUtil.java index 2f3d47c..a478394 100755 --- a/core/src/in/srain/cube/file/FileUtil.java +++ b/core/src/in/srain/cube/file/FileUtil.java @@ -17,41 +17,63 @@ public class FileUtil { /** * Get a usable cache directory (external if available, internal otherwise). + * . + * Check if media is mounted or storage is built-in, if so, try and use external cache folder + * otherwise use internal cache folder + * . + * If both of them can not meet the requirement, use the bigger one. * * @param context The context to use * @param uniqueName A unique folder name to append to the cache folder * @return The cache folder */ - public static File getDiskCacheDir(Context context, String uniqueName, int requireSpace) { - // Check if media is mounted or storage is built-in, if so, try and use external cache folder - // otherwise use internal cache folder + public static CacheDirInfo getDiskCacheDir(Context context, String uniqueName, long requireSpace) { File sdPath = null; File internalPath = null; - File cacheFile = null; Long sdCardFree = 0L; - Long internalFree = 0L; + + boolean usingInternal = false; + if (hasSDCardMounted()) { sdPath = getExternalCacheDir(context); sdCardFree = getUsableSpace(sdPath); } + + CacheDirInfo cacheDirInfo = new CacheDirInfo(); + cacheDirInfo.requireSize = requireSpace; + + // sd card can not meet the requirement + // try to use the build-in storage if (sdPath == null || sdCardFree < requireSpace) { internalPath = context.getCacheDir(); - internalFree = getUsableSpace(internalPath); + long internalFree = getUsableSpace(internalPath); + // both lower then requirement, choose the bigger one if (internalFree < requireSpace) { - - cacheFile = internalFree > sdCardFree ? internalPath : sdPath; - + if (internalFree > sdCardFree) { + usingInternal = true; + cacheDirInfo.realSize = internalFree; + } else { + usingInternal = false; + cacheDirInfo.realSize = sdCardFree; + } + cacheDirInfo.isNotEnough = true; } else { - cacheFile = internalPath; + usingInternal = true; + cacheDirInfo.realSize = requireSpace; } - } else { - cacheFile = sdPath; + usingInternal = false; + cacheDirInfo.realSize = requireSpace; } - String cachePath = cacheFile.getPath(); - return new File(cachePath + File.separator + uniqueName); + cacheDirInfo.isInternal = usingInternal; + if (usingInternal) { + cacheDirInfo.path = new File(internalPath.getPath() + File.separator + uniqueName); + } else { + cacheDirInfo.path = new File(sdPath.getPath() + File.separator + uniqueName); + } + return cacheDirInfo; } /** @@ -150,15 +172,14 @@ public static boolean hasSDCardMounted() { } } - public static String wantFilesPath(Context context, boolean externalStorageFirst, String specifiedPathForExtenalStoage) { - + /** + * external: "/storage/emulated/0/Android/data/in.srain.sample/files" + * internal: "/data/data/in.srain.sample/files" + */ + public static String wantFilesPath(Context context, boolean externalStorageFirst) { String path = null; if (externalStorageFirst && hasSDCardMounted()) { - if (specifiedPathForExtenalStoage != null && specifiedPathForExtenalStoage.length() != 0) - path = Environment.getExternalStorageDirectory() + "/" + specifiedPathForExtenalStoage + "/files"; - else { - path = Environment.getExternalStorageDirectory() + "/" + context.getPackageName() + "/files"; - } + path = context.getExternalFilesDir("").getAbsolutePath(); } else { path = context.getFilesDir().getAbsolutePath(); } @@ -260,4 +281,12 @@ public static String read(String filePath) { } return null; } + + public static class CacheDirInfo { + public File path; + public boolean isInternal = false; + public boolean isNotEnough = false; + public long realSize; + public long requireSize; + } } \ No newline at end of file diff --git a/core/src/in/srain/cube/file/LruFileCache.java b/core/src/in/srain/cube/file/LruFileCache.java index f6eb056..73385f9 100755 --- a/core/src/in/srain/cube/file/LruFileCache.java +++ b/core/src/in/srain/cube/file/LruFileCache.java @@ -7,7 +7,8 @@ import in.srain.cube.concurrent.SimpleTask; import in.srain.cube.file.DiskLruCache.Editor; -import java.io.*; +import java.io.File; +import java.io.IOException; public class LruFileCache implements IFileCache { @@ -27,17 +28,22 @@ public class LruFileCache implements IFileCache { private boolean mDiskCacheStarting = true; private boolean mDiskCacheReady = false; private File mDiskCacheDir; - private int mDiskCacheSize; + private long mDiskCacheSize; - private long mLastFlushTime = 0; + private boolean mIsDelayFlushing = false; protected enum FileCacheTaskType { init_cache, close_cache, flush_cache } - public LruFileCache(Context context, String path, int size) { + public LruFileCache(Context context, String path, long size) { mDiskCacheSize = size; - mDiskCacheDir = FileUtil.getDiskCacheDir(context, path, size); + FileUtil.CacheDirInfo cacheDirInfo = FileUtil.getDiskCacheDir(context, path, size); + mDiskCacheDir = cacheDirInfo.path; + mDiskCacheSize = cacheDirInfo.realSize; + if (cacheDirInfo.isNotEnough) { + Log.e(TAG, String.format("no enough space for initDiskCache %s %s", cacheDirInfo.requireSize, cacheDirInfo.realSize)); + } } public static LruFileCache getDefault(Context context) { @@ -62,17 +68,13 @@ public void initDiskCache() { if (!mDiskCacheDir.exists()) { mDiskCacheDir.mkdirs(); } - if (FileUtil.getUsableSpace(mDiskCacheDir) > mDiskCacheSize) { - try { - mDiskLruCache = DiskLruCache.open(mDiskCacheDir, 1, 1, mDiskCacheSize); - if (DEBUG) { - Log.d(TAG, "Disk cache initialized " + this); - } - } catch (final IOException e) { - Log.e(TAG, "initDiskCache - " + e); + try { + mDiskLruCache = DiskLruCache.open(mDiskCacheDir, 1, 1, mDiskCacheSize); + if (DEBUG) { + Log.d(TAG, "Disk cache initialized " + this); } - } else { - Log.e(TAG, String.format("no enough space for initDiskCache %s %s", FileUtil.getUsableSpace(mDiskCacheDir), mDiskCacheSize)); + } catch (final IOException e) { + Log.e(TAG, "initDiskCache - " + e); } } } @@ -90,13 +92,10 @@ public void write(String key, String str) { synchronized (mDiskCacheLock) { if (mDiskLruCache != null) { try { - DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key); - if (snapshot == null) { - final Editor editor = mDiskLruCache.edit(key); - if (editor != null) { - editor.set(DISK_CACHE_INDEX, str); - editor.commit(); - } + final Editor editor = mDiskLruCache.edit(key); + if (editor != null) { + editor.set(DISK_CACHE_INDEX, str); + editor.commit(); } } catch (final IOException e) { e.printStackTrace(); @@ -147,22 +146,47 @@ public String read(String fileCacheKey) { } public boolean has(String key) { - try { - Editor editor = mDiskLruCache.edit(key); - if (editor != null) { - return editor.has(DISK_CACHE_INDEX); + synchronized (mDiskCacheLock) { + while (mDiskCacheStarting) { + try { + if (DEBUG) { + Log.d(TAG, "check has wait " + this); + } + mDiskCacheLock.wait(); + } catch (InterruptedException e) { + } + } + if (mDiskLruCache != null) { + try { + DiskLruCache.Snapshot snapshot = mDiskLruCache.get(key); + if (snapshot == null) { + return false; + } + return snapshot.has(DISK_CACHE_INDEX); + } catch (IOException e) { + e.printStackTrace(); + } } - } catch (IOException e) { - e.printStackTrace(); } return false; } public void delete(String key) { - try { - mDiskLruCache.remove(key); - } catch (IOException e) { - e.printStackTrace(); + synchronized (mDiskCacheLock) { + while (mDiskCacheStarting) { + try { + if (DEBUG) { + Log.d(TAG, "delete wait " + this); + } + mDiskCacheLock.wait(); + } catch (InterruptedException e) { + } + } + try { + mDiskLruCache.remove(key); + } catch (IOException e) { + e.printStackTrace(); + } } } @@ -206,11 +230,7 @@ public void clearCache() { */ public void flushDiskCache() { synchronized (mDiskCacheLock) { - long now = System.currentTimeMillis(); - if (now - 1000 < mLastFlushTime) { - return; - } - mLastFlushTime = now; + mIsDelayFlushing = false; if (mDiskLruCache != null) { try { mDiskLruCache.flush(); @@ -281,6 +301,15 @@ public void onFinish() { void execute() { SimpleExecutor.getInstance().execute(this); } + + void execute(int delay) { + SimpleTask.postDelay(new Runnable() { + @Override + public void run() { + execute(); + } + }, delay); + } } /** @@ -313,6 +342,20 @@ public void flushDiskCacheAsync() { new FileCacheTask(FileCacheTaskType.flush_cache).execute(); } + /** + * flush the data to disk cache + */ + public void flushDiskCacheAsyncWithDelay(int delay) { + if (DEBUG) { + Log.d(TAG, "flushDishCacheAsync"); + } + if (mIsDelayFlushing) { + return; + } + mIsDelayFlushing = true; + new FileCacheTask(FileCacheTaskType.flush_cache).execute(delay); + } + @Override public String getCachePath() { return mDiskCacheDir.getPath(); @@ -327,7 +370,7 @@ public long getUsedSpace() { } @Override - public int getMaxSize() { + public long getMaxSize() { return mDiskCacheSize; } } diff --git a/core/src/in/srain/cube/image/CubeImageView.java b/core/src/in/srain/cube/image/CubeImageView.java index dd23388..8df90b9 100755 --- a/core/src/in/srain/cube/image/CubeImageView.java +++ b/core/src/in/srain/cube/image/CubeImageView.java @@ -33,6 +33,7 @@ public class CubeImageView extends ImageView { private ImageReuseInfo mImageReuseInfo; private ImageTask mImageTask; + private boolean mClearWhenDetached = true; public CubeImageView(Context context) { super(context); @@ -42,26 +43,38 @@ public CubeImageView(Context context, AttributeSet attrs) { super(context, attrs); } - /** - * @see android.widget.ImageView#onDetachedFromWindow() - */ - @Override - protected void onDetachedFromWindow() { - // This has been detached from Window, so clear the drawable + public void setClearDrawableWhenDetached(boolean clearWhenDetached) { + mClearWhenDetached = clearWhenDetached; + } + + public void clearDrawable() { setImageDrawable(null); if (null != mImageTask && null != mImageLoader) { mImageLoader.detachImageViewFromImageTask(mImageTask, this); clearLoadTask(); } + } + /** + * @see android.widget.ImageView#onDetachedFromWindow() + */ + @Override + protected void onDetachedFromWindow() { + // This has been detached from Window, so clear the drawable + // If this view is recycled ??? + if (mClearWhenDetached) { + clearDrawable(); + } super.onDetachedFromWindow(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - tryLoadImage(); + if (mClearWhenDetached) { + tryLoadImage(); + } } /** diff --git a/core/src/in/srain/cube/image/ImageLoader.java b/core/src/in/srain/cube/image/ImageLoader.java index 67367e4..dd5b72e 100755 --- a/core/src/in/srain/cube/image/ImageLoader.java +++ b/core/src/in/srain/cube/image/ImageLoader.java @@ -4,26 +4,25 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; -import android.util.Log; +import in.srain.cube.app.CubeFragment; +import in.srain.cube.app.lifecycle.LifeCycleComponent; +import in.srain.cube.app.lifecycle.LifeCycleComponentManager; import in.srain.cube.concurrent.SimpleTask; import in.srain.cube.image.iface.ImageLoadHandler; +import in.srain.cube.image.iface.ImageLoadProgressHandler; import in.srain.cube.image.iface.ImageResizer; import in.srain.cube.image.iface.ImageTaskExecutor; -import in.srain.cube.image.impl.DefaultImageLoadHandler; -import in.srain.cube.image.impl.DefaultImageResizer; -import in.srain.cube.image.impl.DefaultImageTaskExecutor; import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; /** - * Manager the ImageTask loading list, - * * @author http://www.liaohuqiu.net */ -public class ImageLoader { +public class ImageLoader implements LifeCycleComponent { private static final String MSG_ATTACK_TO_RUNNING_TASK = "%s attach to running: %s"; @@ -32,13 +31,14 @@ public class ImageLoader { private static final String MSG_TASK_CANCEL = "%s onCancel"; private static final String MSG_TASK_HIT_CACHE = "%s hit cache %s %s"; - protected static final boolean DEBUG = CLog.DEBUG_IMAGE; - protected static final String Log_TAG = "cube_image"; + protected static final boolean DEBUG = Debug.DEBUG_IMAGE; + protected static final String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG; protected ImageTaskExecutor mImageTaskExecutor; protected ImageResizer mImageResizer; protected ImageProvider mImageProvider; protected ImageLoadHandler mImageLoadHandler; + protected ImageLoadProgressHandler mLoadProgressHandler; protected boolean mPauseWork = false; protected boolean mExitTasksEarly = false; @@ -65,11 +65,6 @@ public ImageLoader(Context context, ImageProvider imageProvider, ImageTaskExecut mLoadWorkList = new HashMap(); } - public static ImageLoader createDefault(Context context) { - DefaultImageLoadHandler imageLoadHandler = new DefaultImageLoadHandler(context); - return new ImageLoader(context, ImageProvider.getDefault(context), DefaultImageTaskExecutor.getInstance(), DefaultImageResizer.getInstance(), imageLoadHandler); - } - public void setImageLoadHandler(ImageLoadHandler imageLoadHandler) { mImageLoadHandler = imageLoadHandler; } @@ -95,9 +90,9 @@ public ImageProvider getImageProvider() { */ public void preLoadImages(String[] urls) { int len = urls.length; - len = 10; for (int i = 0; i < len; i++) { final ImageTask imageTask = createImageTask(urls[i], 0, 0, null); + imageTask.setIsPreLoad(); addImageTask(imageTask, null); } } @@ -137,7 +132,7 @@ public void detachImageViewFromImageTask(ImageTask imageTask, CubeImageView imag task.cancel(true); } if (DEBUG) { - Log.d(Log_TAG, String.format("%s previous work is cancelled.", imageTask)); + CLog.d(LOG_TAG, "%s previous work is cancelled.", imageTask); } } } @@ -157,7 +152,7 @@ public void addImageTask(ImageTask imageTask, CubeImageView imageView) { if (runningTask != null) { if (imageView != null) { if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_ATTACK_TO_RUNNING_TASK, imageTask, runningTask.getImageTask())); + CLog.d(LOG_TAG, MSG_ATTACK_TO_RUNNING_TASK, imageTask, runningTask.getImageTask()); } runningTask.getImageTask().addImageView(imageView); } @@ -190,9 +185,9 @@ public boolean queryCache(ImageTask imageTask, CubeImageView imageView) { } if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_TASK_HIT_CACHE, imageTask, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight())); + CLog.d(LOG_TAG, MSG_TASK_HIT_CACHE, imageTask, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); if (drawable.getIntrinsicWidth() == 270) { - Log.d(Log_TAG, String.format(MSG_TASK_HIT_CACHE, imageTask, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight())); + CLog.d(LOG_TAG, MSG_TASK_HIT_CACHE, imageTask, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight()); } } imageTask.addImageView(imageView); @@ -206,6 +201,15 @@ public void setTaskOrder(ImageTaskOrder order) { } } + /** + * flush un-cached image to disk + */ + public void flushFileCache() { + if (mImageProvider != null) { + mImageProvider.flushFileCache(); + } + } + /** * Inner class to process the image loading task in background threads. * @@ -227,7 +231,7 @@ public ImageTask getImageTask() { @Override public void doInBackground() { if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_TASK_DO_IN_BACKGROUND, mImageTask)); + CLog.d(LOG_TAG, MSG_TASK_DO_IN_BACKGROUND, mImageTask); } if (mImageTask.getStatistics() != null) { @@ -239,7 +243,7 @@ public void doInBackground() { while (mPauseWork && !isCancelled()) { try { if (DEBUG) { - Log.d(Log_TAG, String.format("%s wait to begin", mImageTask)); + CLog.d(LOG_TAG, "%s wait to begin", mImageTask); } mPauseWorkLock.wait(); } catch (InterruptedException e) { @@ -253,7 +257,7 @@ public void doInBackground() { // the cache if (!isCancelled() && !mExitTasksEarly && (mImageTask.isPreLoad() || mImageTask.stillHasRelatedImageView())) { try { - bitmap = mImageProvider.fetchBitmapData(mImageTask, mImageResizer); + bitmap = mImageProvider.fetchBitmapData(ImageLoader.this, mImageTask, mImageResizer); if (mImageTask.getStatistics() != null) { mImageTask.getStatistics().afterDecode(); } @@ -273,7 +277,7 @@ public void doInBackground() { @Override public void onFinish() { if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_TASK_FINISH, mImageTask)); + CLog.d(LOG_TAG, MSG_TASK_FINISH, mImageTask); } if (mExitTasksEarly) { return; @@ -289,7 +293,7 @@ public void onFinish() { @Override public void onCancel() { if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_TASK_CANCEL, mImageTask)); + CLog.d(LOG_TAG, MSG_TASK_CANCEL, mImageTask); } mLoadWorkList.remove(mImageTask.getIdentityKey()); mImageTask.onCancel(); @@ -313,7 +317,7 @@ public void pauseWork() { mExitTasksEarly = false; setPause(true); if (DEBUG) { - Log.d(Log_TAG, String.format("work_status: pauseWork %s", this)); + CLog.d(LOG_TAG, "work_status: pauseWork %s", this); } } @@ -324,7 +328,7 @@ public void resumeWork() { mExitTasksEarly = false; setPause(false); if (DEBUG) { - Log.d(Log_TAG, String.format("work_status: resumeWork %s", this)); + CLog.d(LOG_TAG, "work_status: resumeWork %s", this); } } @@ -333,7 +337,7 @@ public void resumeWork() { */ public void recoverWork() { if (DEBUG) { - Log.d(Log_TAG, String.format("work_status: recoverWork %s", this)); + CLog.d(LOG_TAG, "work_status: recoverWork %s", this); } mExitTasksEarly = false; setPause(false); @@ -351,20 +355,21 @@ public void recoverWork() { */ public void stopWork() { if (DEBUG) { - Log.d(Log_TAG, String.format("work_status: stopWork %s", this)); + CLog.d(LOG_TAG, "work_status: stopWork %s", this); } mExitTasksEarly = true; setPause(false); - if (null != mImageProvider) { - mImageProvider.flushFileCache(); - } + flushFileCache(); } /** * Drop all the work, clear the work list. */ public void destroy() { + if (DEBUG) { + CLog.d(LOG_TAG, "work_status: destroy %s", this); + } mExitTasksEarly = true; setPause(false); @@ -379,4 +384,77 @@ public void destroy() { } mLoadWorkList.clear(); } + + /** + * The UI becomes partially invisible. + * like {@link android.app.Activity#onPause} + */ + @Override + public void onBecomesPartiallyInvisible() { + pauseWork(); + } + + /** + * The UI becomes visible from partially invisible. + * like {@link android.app.Activity#onResume} + */ + @Override + public void onBecomesVisible() { + resumeWork(); + } + + /** + * The UI becomes totally invisible. + * like {@link android.app.Activity#onStop} + */ + @Override + public void onBecomesTotallyInvisible() { + stopWork(); + } + + /** + * The UI becomes visible from totally invisible. + * like {@link android.app.Activity#onRestart} + */ + @Override + public void onBecomesVisibleFromTotallyInvisible() { + recoverWork(); + } + + /** + * like {@link android.app.Activity#onDestroy} + */ + @Override + public void onDestroy() { + destroy(); + } + + /** + * try to attach to {@link in.srain.cube.app.lifecycle.IComponentContainer} + */ + public ImageLoader tryToAttachToContainer(Object object) { + tryToAttachToContainer(object, true); + return this; + } + + /** + * try to attach to {@link in.srain.cube.app.lifecycle.IComponentContainer} + */ + public ImageLoader tryToAttachToContainer(Object object, boolean throwEx) { + LifeCycleComponentManager.tryAddComponentToContainer(this, object, throwEx); + return this; + } + + /** + * Process LifeCycle + * + * @param fragment + * @return + */ + public ImageLoader attachToCubeFragment(CubeFragment fragment) { + if (fragment != null) { + LifeCycleComponentManager.tryAddComponentToContainer(this, fragment); + } + return this; + } } diff --git a/core/src/in/srain/cube/image/ImageLoaderFactory.java b/core/src/in/srain/cube/image/ImageLoaderFactory.java index e039c6c..b7283bf 100755 --- a/core/src/in/srain/cube/image/ImageLoaderFactory.java +++ b/core/src/in/srain/cube/image/ImageLoaderFactory.java @@ -1,31 +1,79 @@ package in.srain.cube.image; import android.content.Context; -import in.srain.cube.image.iface.ImageLoadHandler; -import in.srain.cube.image.iface.ImageResizer; -import in.srain.cube.image.iface.ImageTaskExecutor; -import in.srain.cube.image.impl.DefaultImageLoadHandler; -import in.srain.cube.image.impl.DefaultImageResizer; -import in.srain.cube.image.impl.DefaultImageTaskExecutor; +import in.srain.cube.file.FileUtil; +import in.srain.cube.image.iface.*; +import in.srain.cube.image.impl.*; /** - * Manager the ImageTask loading list, + * Create an {@link ImageLoader}. + * If Context is {@link in.srain.cube.app.lifecycle.IComponentContainer}, add {@link ImageLoader} into it. * * @author http://www.liaohuqiu.net */ public class ImageLoaderFactory { + private static ImageProvider sMutableImageProvider; + private static ImageProvider sStableImageProvider; + private static ImageResizer sDefaultImageResizer; private static ImageTaskExecutor sDefaultImageTaskExecutor; private static ImageLoadHandler sDefaultImageLoadHandler; - private static ImageProvider sDefaultImageProvider; + + public static void init(Context context) { + int mutableDiskCacheSizeInKB = 1024 * 10; + int stableDiskCacheSizeInKB = 1024 * 10; + float percent = 0.2f; + int memoryCacheSizeInKB = Math.round(percent * Runtime.getRuntime().maxMemory() / 1024); + init(context, mutableDiskCacheSizeInKB, stableDiskCacheSizeInKB, memoryCacheSizeInKB); + } + + public static void init(Context context, int mutableDiskCacheSizeInKB, int stableDiskCacheSizeInKB, int memoryCacheSizeInKB) { + + FileUtil.CacheDirInfo dirInfo1 = FileUtil.getDiskCacheDir(context, "mutable_image", mutableDiskCacheSizeInKB * 1024); + FileUtil.CacheDirInfo dirInfo2 = FileUtil.getDiskCacheDir(context, "stable_image", stableDiskCacheSizeInKB * 1024); + + ImageFileProvider mutableImageFileProvider = new LruImageFileProvider(dirInfo1.realSize, dirInfo1.path); + ImageFileProvider stableImageFileProvider = new LruImageFileProvider(dirInfo2.realSize, dirInfo2.path); + + ImageMemoryCache defaultMemoryCache = new DefaultMemoryCache(memoryCacheSizeInKB); + + mutableImageFileProvider.initDiskCacheAsync(); + stableImageFileProvider.initDiskCacheAsync(); + + sMutableImageProvider = new ImageProvider(context, defaultMemoryCache, mutableImageFileProvider); + sStableImageProvider = new ImageProvider(context, defaultMemoryCache, stableImageFileProvider); + } + + public static ImageLoader createStableImageLoader(Context context) { + return createStableImageLoader(context, sDefaultImageLoadHandler); + } + + public static ImageLoader createStableImageLoader(Context context, ImageLoadHandler imageLoadHandler) { + return createInner(context, sStableImageProvider, imageLoadHandler); + } public static ImageLoader create(Context context) { - ImageLoader imageLoader = create(context, sDefaultImageProvider, sDefaultImageTaskExecutor, sDefaultImageResizer, sDefaultImageLoadHandler); - return imageLoader; + return createMutableImageLoader(context, sDefaultImageLoadHandler); + } + + public static ImageLoader create(Context context, ImageLoadHandler imageLoadHandler) { + return createMutableImageLoader(context, imageLoadHandler); + } + + public static ImageLoader createMutableImageLoader(Context context) { + return createMutableImageLoader(context, sDefaultImageLoadHandler); + } + + public static ImageLoader createMutableImageLoader(Context context, ImageLoadHandler imageLoadHandler) { + return createInner(context, sMutableImageProvider, imageLoadHandler); } - public static ImageLoader create(Context context, ImageProvider imageProvider, ImageTaskExecutor imageTaskExecutor, ImageResizer imageResizer, ImageLoadHandler imageLoadHandler) { + private static ImageLoader createInner(Context context, ImageProvider imageProvider, ImageLoadHandler imageLoadHandler) { + return create(context, imageProvider, sDefaultImageTaskExecutor, sDefaultImageResizer, imageLoadHandler); + } + + private static ImageLoader create(Context context, ImageProvider imageProvider, ImageTaskExecutor imageTaskExecutor, ImageResizer imageResizer, ImageLoadHandler imageLoadHandler) { if (imageProvider == null) { imageProvider = ImageProvider.getDefault(context); @@ -42,7 +90,8 @@ public static ImageLoader create(Context context, ImageProvider imageProvider, I if (imageLoadHandler == null) { imageLoadHandler = new DefaultImageLoadHandler(context); } - return new ImageLoader(context, imageProvider, imageTaskExecutor, imageResizer, imageLoadHandler); + ImageLoader imageLoader = new ImageLoader(context, imageProvider, imageTaskExecutor, imageResizer, imageLoadHandler); + return imageLoader; } public static void setDefaultImageResizer(ImageResizer imageResizer) { @@ -58,6 +107,14 @@ public static void setDefaultImageLoadHandler(ImageLoadHandler imageLoadHandler) } public static void setDefaultImageProvider(ImageProvider imageProvider) { - sDefaultImageProvider = imageProvider; + sMutableImageProvider = imageProvider; + } + + public static void setMutableImageProvider(ImageProvider imageProvider) { + sMutableImageProvider = imageProvider; + } + + public static void setStableImageProvider(ImageProvider imageProvider) { + sMutableImageProvider = imageProvider; } } diff --git a/core/src/in/srain/cube/image/ImageProvider.java b/core/src/in/srain/cube/image/ImageProvider.java index 25fff6f..e95fdd2 100755 --- a/core/src/in/srain/cube/image/ImageProvider.java +++ b/core/src/in/srain/cube/image/ImageProvider.java @@ -15,7 +15,7 @@ import in.srain.cube.image.iface.ImageResizer; import in.srain.cube.image.impl.DefaultMemoryCache; import in.srain.cube.image.impl.LruImageFileProvider; -import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import in.srain.cube.util.Version; import java.io.FileDescriptor; @@ -32,9 +32,9 @@ */ public class ImageProvider { - protected static final boolean DEBUG = CLog.DEBUG_IMAGE; + protected static final boolean DEBUG = Debug.DEBUG_IMAGE; - protected static final String TAG = "image_provider"; + protected static final String TAG = Debug.DEBUG_IMAGE_LOG_TAG_PROVIDER; private static final String MSG_FETCH_BEGIN = "%s fetchBitmapData"; private static final String MSG_FETCH_BEGIN_IDENTITY_KEY = "%s identityKey: %s"; @@ -122,7 +122,7 @@ public void addBitmapToMemCache(String key, BitmapDrawable drawable) { *

* If no file cache can be used, download then save to file. */ - public Bitmap fetchBitmapData(ImageTask imageTask, ImageResizer imageResizer) { + public Bitmap fetchBitmapData(ImageLoader imageLoader, ImageTask imageTask, ImageResizer imageResizer) { Bitmap bitmap = null; if (mImageFileProvider != null) { FileInputStream inputStream = null; @@ -187,6 +187,7 @@ public Bitmap fetchBitmapData(ImageTask imageTask, ImageResizer imageResizer) { imageTask.getStatistics().afterDownload(); } if (inputStream == null) { + imageTask.onLoadError(ImageTask.ERROR_NETWORK, imageLoader.getImageLoadHandler()); Log.e(TAG, imageTask + " download fail: " + fileCacheKey); } } @@ -276,11 +277,11 @@ public void clearDiskCache() { } } - public int getMemoryCacheMaxSpace() { + public long getMemoryCacheMaxSpace() { return mMemoryCache.getMaxSize(); } - public int getMemoryCacheUsedSpace() { + public long getMemoryCacheUsedSpace() { return mMemoryCache.getUsedSpace(); } @@ -337,7 +338,7 @@ private static int getBytesPerPixel(Config config) { * @param value * @return size in bytes */ - @TargetApi(VERSION_CODES.KITKAT) + @TargetApi(19) // @TargetApi(VERSION_CODES.KITKAT) public static int getBitmapSize(BitmapDrawable value) { if (null == value) { return 0; diff --git a/core/src/in/srain/cube/image/ImageTask.java b/core/src/in/srain/cube/image/ImageTask.java index d6ec83c..61db904 100755 --- a/core/src/in/srain/cube/image/ImageTask.java +++ b/core/src/in/srain/cube/image/ImageTask.java @@ -4,6 +4,7 @@ import android.graphics.drawable.BitmapDrawable; import in.srain.cube.image.iface.ImageLoadHandler; import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import in.srain.cube.util.Encrypt; import java.lang.ref.WeakReference; @@ -15,7 +16,7 @@ */ public class ImageTask { - protected static final String Log_TAG = "cube_image_task"; + protected static final String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG_TASK; private static final Object sPoolSync = new Object(); private static ImageTask sTop; private static int sPoolSize = 0; @@ -29,6 +30,9 @@ public class ImageTask { private final static int STATUS_LOADING = 0x02; private final static int STATUS_DONE = 0x04; private final static int STATUS_CANCELED = 0x08; + private final static int STATUS_FAIL = 0x10; + + public final static int ERROR_NETWORK = 0x01; private int mFlag = 0; protected int mId = 0; @@ -82,8 +86,8 @@ public static ImageTask obtain() { sPoolSize--; return m; } - if (CLog.DEBUG_IMAGE) { - CLog.d(Log_TAG, "obtain, pool remain: %d", sPoolSize); + if (Debug.DEBUG_IMAGE) { + CLog.d(LOG_TAG, "obtain, pool remain: %d", sPoolSize); } } return null; @@ -102,8 +106,8 @@ public void tryToRecycle() { sTop = this; sPoolSize++; } - if (CLog.DEBUG_IMAGE) { - CLog.d(Log_TAG, "recycle, pool remain: %d", sPoolSize); + if (Debug.DEBUG_IMAGE) { + CLog.d(LOG_TAG, "recycle, pool remain: %d", sPoolSize); } } } @@ -270,17 +274,21 @@ public boolean stillHasRelatedImageView() { public void onLoading(ImageLoadHandler handler) { mFlag = mFlag | STATUS_LOADING; - if (null == handler || null == mFirstImageViewHolder) { + if (null == handler) { return; } - ImageViewHolder holder = mFirstImageViewHolder; - do { - final CubeImageView imageView = holder.getImageView(); - if (null != imageView) { - handler.onLoading(this, imageView); - } - } while ((holder = holder.mNext) != null); + if (mFirstImageViewHolder == null) { + handler.onLoading(this, null); + } else { + ImageViewHolder holder = mFirstImageViewHolder; + do { + final CubeImageView imageView = holder.getImageView(); + if (null != imageView) { + handler.onLoading(this, imageView); + } + } while ((holder = holder.mNext) != null); + } } /** @@ -293,23 +301,25 @@ public void onLoadFinish(BitmapDrawable drawable, ImageLoadHandler handler) { mFlag &= ~STATUS_LOADING; mFlag |= STATUS_DONE; - if (null == handler || null == mFirstImageViewHolder) { + if (null == handler) { return; } if (null != mImageTaskStatistics) { mImageTaskStatistics.showBegin(); } - - ImageViewHolder holder = mFirstImageViewHolder; - do { - final CubeImageView imageView = holder.getImageView(); - if (null != imageView) { - imageView.onLoadFinish(); - handler.onLoadFinish(this, imageView, drawable); - } - } while ((holder = holder.mNext) != null); - + if (mFirstImageViewHolder == null) { + handler.onLoadFinish(this, null, drawable); + } else { + ImageViewHolder holder = mFirstImageViewHolder; + do { + final CubeImageView imageView = holder.getImageView(); + if (null != imageView) { + imageView.onLoadFinish(); + handler.onLoadFinish(this, imageView, drawable); + } + } while ((holder = holder.mNext) != null); + } if (null != mImageTaskStatistics) { mImageTaskStatistics.showComplete(ImageProvider.getBitmapSize(drawable)); } @@ -320,6 +330,24 @@ public void onCancel() { mFlag |= STATUS_CANCELED; } + public void onLoadError(int reason, ImageLoadHandler handler) { + mFlag &= ~STATUS_LOADING; + mFlag |= STATUS_FAIL; + if (mFirstImageViewHolder == null) { + handler.onLoadError(this, null, reason); + } else { + ImageViewHolder holder = mFirstImageViewHolder; + do { + final CubeImageView imageView = holder.getImageView(); + if (null != imageView) { + imageView.onLoadFinish(); + handler.onLoadError(this, imageView, reason); + } + } while ((holder = holder.mNext) != null); + + } + } + /** * If you have a thumbnail web service which can return multiple size image according the url, *

diff --git a/core/src/in/srain/cube/image/drawable/RecyclingBitmapDrawable.java b/core/src/in/srain/cube/image/drawable/RecyclingBitmapDrawable.java index 6cdf40b..7f5225d 100755 --- a/core/src/in/srain/cube/image/drawable/RecyclingBitmapDrawable.java +++ b/core/src/in/srain/cube/image/drawable/RecyclingBitmapDrawable.java @@ -4,6 +4,7 @@ import android.graphics.Bitmap; import android.graphics.drawable.BitmapDrawable; import android.util.Log; +import in.srain.cube.util.Debug; /** * A BitmapDrawable that keeps track of whether it is being displayed or cached. @@ -14,7 +15,7 @@ */ public class RecyclingBitmapDrawable extends BitmapDrawable { - static final String LOG_TAG = "cube_image"; + private final static String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG; static final boolean DEBUG = false; private int mCacheRefCount = 0; diff --git a/core/src/in/srain/cube/image/iface/ImageFileProvider.java b/core/src/in/srain/cube/image/iface/ImageFileProvider.java index 4df01aa..eba06d6 100755 --- a/core/src/in/srain/cube/image/iface/ImageFileProvider.java +++ b/core/src/in/srain/cube/image/iface/ImageFileProvider.java @@ -3,9 +3,9 @@ import in.srain.cube.cache.IFileCache; import java.io.FileInputStream; -import java.io.InputStream; public interface ImageFileProvider extends IFileCache { + public FileInputStream getInputStream(String key); public FileInputStream downloadAndGetInputStream(String key, String url); diff --git a/core/src/in/srain/cube/image/iface/ImageLoadHandler.java b/core/src/in/srain/cube/image/iface/ImageLoadHandler.java index f385a6d..f1302f4 100755 --- a/core/src/in/srain/cube/image/iface/ImageLoadHandler.java +++ b/core/src/in/srain/cube/image/iface/ImageLoadHandler.java @@ -29,9 +29,6 @@ public interface ImageLoadHandler { /** * Some errors has occurred - * - * @param imageView - * @param imageTask */ - void onLoadError(CubeImageView imageView, ImageTask imageTask); + void onLoadError(ImageTask imageTask, CubeImageView imageView, int errorCode); } \ No newline at end of file diff --git a/core/src/in/srain/cube/image/iface/ImageLoadProgressHandler.java b/core/src/in/srain/cube/image/iface/ImageLoadProgressHandler.java new file mode 100644 index 0000000..5864b4e --- /dev/null +++ b/core/src/in/srain/cube/image/iface/ImageLoadProgressHandler.java @@ -0,0 +1,12 @@ +package in.srain.cube.image.iface; + +import in.srain.cube.image.CubeImageView; +import in.srain.cube.image.ImageTask; + +/** + * Define load progress + */ +public interface ImageLoadProgressHandler { + + void onProgressChange(ImageTask imageTask, CubeImageView cubeImageView, int loaded, int total); +} diff --git a/core/src/in/srain/cube/image/iface/ImageMemoryCache.java b/core/src/in/srain/cube/image/iface/ImageMemoryCache.java index 12145a8..5263b46 100755 --- a/core/src/in/srain/cube/image/iface/ImageMemoryCache.java +++ b/core/src/in/srain/cube/image/iface/ImageMemoryCache.java @@ -12,7 +12,17 @@ public interface ImageMemoryCache { public void delete(String key); - public int getMaxSize(); - - public int getUsedSpace(); + /** + * max byte + * + * @return + */ + public long getMaxSize(); + + /** + * used byte + * + * @return + */ + public long getUsedSpace(); } diff --git a/core/src/in/srain/cube/image/impl/DefaultImageLoadHandler.java b/core/src/in/srain/cube/image/impl/DefaultImageLoadHandler.java index b739214..dfaffda 100755 --- a/core/src/in/srain/cube/image/impl/DefaultImageLoadHandler.java +++ b/core/src/in/srain/cube/image/impl/DefaultImageLoadHandler.java @@ -14,7 +14,7 @@ import in.srain.cube.image.ImageTask; import in.srain.cube.image.drawable.RoundedDrawable; import in.srain.cube.image.iface.ImageLoadHandler; -import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import in.srain.cube.util.Version; /** @@ -26,8 +26,8 @@ */ public class DefaultImageLoadHandler implements ImageLoadHandler { - private final static boolean DEBUG = CLog.DEBUG_IMAGE; - private final static String Log_TAG = "cube_image"; + private final static boolean DEBUG = Debug.DEBUG_IMAGE; + private final static String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG; private final static String MSG_LOADING = "%s onLoading"; private final static String MSG_LOAD_ERROR = "%s load error"; private final static String MSG_LOAD_FINISH = "%s onLoadFinish %s %s %s %s"; @@ -135,8 +135,11 @@ public void setLoadingImageColor(String colorString) { @Override public void onLoading(ImageTask imageTask, CubeImageView imageView) { + if (imageView == null) { + return; + } if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_LOADING, imageTask)); + Log.d(LOG_TAG, String.format(MSG_LOADING, imageTask)); } if (Version.hasHoneycomb()) { if (mLoadingDrawable != null && imageView != null && imageView.getDrawable() != mLoadingDrawable) { @@ -148,9 +151,9 @@ public void onLoading(ImageTask imageTask, CubeImageView imageView) { } @Override - public void onLoadError(CubeImageView imageView, ImageTask imageTask) { + public void onLoadError(ImageTask imageTask, CubeImageView imageView, int errorCode) { if (DEBUG) { - Log.d(Log_TAG, String.format(MSG_LOAD_ERROR, imageTask)); + Log.d(LOG_TAG, String.format(MSG_LOAD_ERROR, imageTask)); } if (Version.hasHoneycomb()) { if (mErrorDrawable != null && imageView != null && imageView.getDrawable() != mErrorDrawable) { @@ -164,6 +167,10 @@ public void onLoadError(CubeImageView imageView, ImageTask imageTask) { @Override public void onLoadFinish(ImageTask imageTask, CubeImageView imageView, BitmapDrawable drawable) { + if (imageView == null) { + return; + } + Drawable d = drawable; if (drawable != null) { @@ -203,7 +210,7 @@ public void onLoadFinish(ImageTask imageTask, CubeImageView imageView, BitmapDra w = oldDrawable.getIntrinsicWidth(); h = oldDrawable.getIntrinsicHeight(); } - Log.d(Log_TAG, String.format(MSG_LOAD_FINISH, imageTask, w, h, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight())); + Log.d(LOG_TAG, String.format(MSG_LOAD_FINISH, imageTask, w, h, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight())); } imageView.setImageDrawable(drawable); } diff --git a/core/src/in/srain/cube/image/impl/DefaultMemoryCache.java b/core/src/in/srain/cube/image/impl/DefaultMemoryCache.java index a63e668..abf1314 100755 --- a/core/src/in/srain/cube/image/impl/DefaultMemoryCache.java +++ b/core/src/in/srain/cube/image/impl/DefaultMemoryCache.java @@ -6,12 +6,12 @@ import in.srain.cube.image.ImageProvider; import in.srain.cube.image.drawable.RecyclingBitmapDrawable; import in.srain.cube.image.iface.ImageMemoryCache; -import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; public class DefaultMemoryCache implements ImageMemoryCache { - protected static final boolean DEBUG = CLog.DEBUG_IMAGE; - protected static final String TAG = "image_provider"; + protected static final boolean DEBUG = Debug.DEBUG_IMAGE; + protected static final String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG_PROVIDER; private LruCache mMemoryCache; private static DefaultMemoryCache sDefault; @@ -28,7 +28,7 @@ public DefaultMemoryCache(int cacheSizeInKB) { // Set up memory cache if (DEBUG) { - Log.d(TAG, "Memory cache created (size = " + cacheSizeInKB + " KB)"); + Log.d(LOG_TAG, "Memory cache created (size = " + cacheSizeInKB + " KB)"); } mMemoryCache = new LruCache(cacheSizeInKB) { @@ -96,7 +96,7 @@ public void clear() { if (mMemoryCache != null) { mMemoryCache.evictAll(); if (DEBUG) { - Log.d(TAG, "Memory cache cleared"); + Log.d(LOG_TAG, "Memory cache cleared"); } } } @@ -107,12 +107,12 @@ public void delete(String key) { } @Override - public int getMaxSize() { + public long getMaxSize() { return mMemoryCache.maxSize() * 1024; } @Override - public int getUsedSpace() { + public long getUsedSpace() { return mMemoryCache.size() * 1024; } } diff --git a/core/src/in/srain/cube/image/impl/LruImageFileProvider.java b/core/src/in/srain/cube/image/impl/LruImageFileProvider.java index 583b643..a00a2c1 100755 --- a/core/src/in/srain/cube/image/impl/LruImageFileProvider.java +++ b/core/src/in/srain/cube/image/impl/LruImageFileProvider.java @@ -10,7 +10,7 @@ import in.srain.cube.file.DiskLruCache.Editor; import in.srain.cube.file.FileUtil; import in.srain.cube.image.iface.ImageFileProvider; -import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import java.io.*; @@ -23,9 +23,8 @@ */ public class LruImageFileProvider implements ImageFileProvider { - protected static final boolean DEBUG = CLog.DEBUG_IMAGE; - - protected static final String TAG = "image_provider"; + protected static final boolean DEBUG = Debug.DEBUG_IMAGE; + protected static final String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG_PROVIDER; private static final String DEFAULT_CACHE_DIR = "cube-image"; private static final int DEFAULT_CACHE_SIZE = 1024 * 1024 * 10; @@ -41,7 +40,7 @@ public class LruImageFileProvider implements ImageFileProvider { private boolean mDiskCacheStarting = true; private boolean mDiskCacheReady = false; private File mDiskCacheDir; - private int mDiskCacheSize; + private long mDiskCacheSize; private long mLastFlushTime = 0; @@ -56,8 +55,12 @@ public FileInputStream downloadAndGetInputStream(String fileCacheKey, String url Editor editor = open(fileCacheKey); if (editor != null) { OutputStream outputStream = editor.newOutputStream(0); - SimpleDownloader.downloadUrlToStream(url, outputStream); - editor.commit(); + boolean ret = SimpleDownloader.downloadUrlToStream(url, outputStream); + if (ret) { + editor.commit(); + } else { + editor.abort(); + } } } catch (IOException e) { e.printStackTrace(); @@ -69,14 +72,15 @@ protected enum FileCacheTaskType { init_cache, close_cache, flush_cache } - public LruImageFileProvider(int sizeInKB, File path) { - mDiskCacheSize = sizeInKB; + public LruImageFileProvider(long size, File path) { + mDiskCacheSize = size; mDiskCacheDir = path; } public static LruImageFileProvider getDefault(Context context) { if (null == sDefault) { - sDefault = new LruImageFileProvider(DEFAULT_CACHE_SIZE, FileUtil.getDiskCacheDir(context, DEFAULT_CACHE_DIR, DEFAULT_CACHE_SIZE)); + FileUtil.CacheDirInfo cacheDirInfo = FileUtil.getDiskCacheDir(context, DEFAULT_CACHE_DIR, DEFAULT_CACHE_SIZE); + sDefault = new LruImageFileProvider(cacheDirInfo.realSize, cacheDirInfo.path); sDefault.initDiskCacheAsync(); } return sDefault; @@ -87,7 +91,7 @@ public static LruImageFileProvider getDefault(Context context) { */ public void initDiskCache() { if (DEBUG) { - Log.d(TAG, "initDiskCache " + this); + Log.d(LOG_TAG, "initDiskCache " + this); } // Set up disk cache synchronized (mDiskCacheLock) { @@ -100,13 +104,13 @@ public void initDiskCache() { try { mDiskLruCache = DiskLruCache.open(mDiskCacheDir, 1, 1, mDiskCacheSize); if (DEBUG) { - Log.d(TAG, "Disk cache initialized " + this); + Log.d(LOG_TAG, "Disk cache initialized " + this); } } catch (final IOException e) { - Log.e(TAG, "initDiskCache - " + e); + Log.e(LOG_TAG, "initDiskCache - " + e); } } else { - Log.e(TAG, String.format("no enough space for initDiskCache %s %s", FileUtil.getUsableSpace(mDiskCacheDir), mDiskCacheSize)); + Log.e(LOG_TAG, String.format("no enough space for initDiskCache %s %s", FileUtil.getUsableSpace(mDiskCacheDir), mDiskCacheSize)); } } } @@ -144,9 +148,9 @@ public void write(String key, Bitmap bitmap) { } } } catch (final IOException e) { - Log.e(TAG, "addBitmapToCache - " + e); + Log.e(LOG_TAG, "addBitmapToCache - " + e); } catch (Exception e) { - Log.e(TAG, "addBitmapToCache - " + e); + Log.e(LOG_TAG, "addBitmapToCache - " + e); } finally { try { if (out != null) { @@ -168,7 +172,7 @@ private FileInputStream read(String fileCacheKey) { while (mDiskCacheStarting) { try { if (DEBUG) { - Log.d(TAG, "read wait " + this); + Log.d(LOG_TAG, "read wait " + this); } mDiskCacheLock.wait(); } catch (InterruptedException e) { @@ -181,7 +185,7 @@ private FileInputStream read(String fileCacheKey) { snapshot = mDiskLruCache.get(fileCacheKey); } catch (final IOException e) { - Log.e(TAG, "getBitmapFromDiskCache - " + e); + Log.e(LOG_TAG, "getBitmapFromDiskCache - " + e); } if (snapshot == null) { @@ -199,7 +203,7 @@ public Editor open(String key) throws IOException { if (null != mDiskLruCache) { return mDiskLruCache.edit(key); } else { - Log.e(TAG, "mDiskLruCache is null"); + Log.e(LOG_TAG, "mDiskLruCache is null"); return null; } } @@ -217,11 +221,11 @@ public void clearCache() { try { mDiskLruCache.delete(); if (DEBUG) { - Log.d(TAG, "Disk cache cleared"); + Log.d(LOG_TAG, "Disk cache cleared"); } } catch (IOException e) { e.printStackTrace(); - Log.e(TAG, "clearCache - " + e); + Log.e(LOG_TAG, "clearCache - " + e); } mDiskLruCache = null; @@ -244,10 +248,10 @@ public void flushDiskCache() { try { mDiskLruCache.flush(); if (DEBUG) { - Log.d(TAG, "Disk cache flushed"); + Log.d(LOG_TAG, "Disk cache flushed"); } } catch (IOException e) { - Log.e(TAG, "flush - " + e); + Log.e(LOG_TAG, "flush - " + e); } } } @@ -264,11 +268,11 @@ public void closeDiskCache() { mDiskLruCache.close(); mDiskLruCache = null; if (DEBUG) { - Log.d(TAG, "Disk cache closed"); + Log.d(LOG_TAG, "Disk cache closed"); } } } catch (IOException e) { - Log.e(TAG, "close - " + e); + Log.e(LOG_TAG, "close - " + e); } } } @@ -319,7 +323,7 @@ void excute() { */ public void initDiskCacheAsync() { if (DEBUG) { - Log.d(TAG, "initDiskCacheAsync " + this); + Log.d(LOG_TAG, "initDiskCacheAsync " + this); } new FileCacheTask(FileCacheTaskType.init_cache).excute(); } @@ -329,7 +333,7 @@ public void initDiskCacheAsync() { */ public void closeDiskCacheAsync() { if (DEBUG) { - Log.d(TAG, "closeDiskCacheAsync"); + Log.d(LOG_TAG, "closeDiskCacheAsync"); } new FileCacheTask(FileCacheTaskType.close_cache).excute(); } @@ -340,7 +344,7 @@ public void closeDiskCacheAsync() { @Override public void flushDiskCacheAsync() { if (DEBUG) { - Log.d(TAG, "flushDishCacheAsync"); + Log.d(LOG_TAG, "flushDishCacheAsync"); } new FileCacheTask(FileCacheTaskType.flush_cache).excute(); } @@ -359,7 +363,7 @@ public long getUsedSpace() { } @Override - public int getMaxSize() { + public long getMaxSize() { return mDiskCacheSize; } diff --git a/core/src/in/srain/cube/image/impl/SimpleDownloader.java b/core/src/in/srain/cube/image/impl/SimpleDownloader.java index df63488..783b38e 100755 --- a/core/src/in/srain/cube/image/impl/SimpleDownloader.java +++ b/core/src/in/srain/cube/image/impl/SimpleDownloader.java @@ -2,6 +2,7 @@ import android.os.Build; import android.util.Log; +import in.srain.cube.util.Debug; import java.io.*; import java.net.HttpURLConnection; @@ -12,7 +13,7 @@ */ public class SimpleDownloader { - private static final String TAG = "image_provider"; + protected static final String LOG_TAG = Debug.DEBUG_IMAGE_LOG_TAG_PROVIDER; private static final int IO_BUFFER_SIZE = 8 * 1024; @@ -39,7 +40,7 @@ public static boolean downloadUrlToStream(String urlString, OutputStream outputS } return true; } catch (final IOException e) { - Log.e(TAG, "Error in downloadBitmap - " + e); + Log.e(LOG_TAG, "Error in downloadBitmap - " + e); } finally { if (urlConnection != null) { urlConnection.disconnect(); diff --git a/core/src/in/srain/cube/mints/base/BlockMenuFragment.java b/core/src/in/srain/cube/mints/base/BlockMenuFragment.java new file mode 100755 index 0000000..cdef039 --- /dev/null +++ b/core/src/in/srain/cube/mints/base/BlockMenuFragment.java @@ -0,0 +1,123 @@ +package in.srain.cube.mints.base; + +import android.graphics.Color; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.ViewGroup; +import android.widget.TextView; +import in.srain.cube.R; +import in.srain.cube.util.LocalDisplay; +import in.srain.cube.views.block.BlockListAdapter; +import in.srain.cube.views.block.BlockListView; +import in.srain.cube.views.block.BlockListView.OnItemClickListener; + +import java.util.ArrayList; + +public abstract class BlockMenuFragment extends TitleBaseFragment { + + private BlockListView mBlockListView; + private ArrayList mItemInfos = new ArrayList(); + private int mSize = 0; + private BlockListAdapter mBlockListAdapter = new BlockListAdapter() { + + @Override + public View getView(LayoutInflater layoutInflater, int position) { + return getViewForBlock(layoutInflater, position); + } + }; + + protected int getLayoutId() { + return R.layout.cube_mints_base_fragment_block_menu; + } + + protected View getViewForBlock(LayoutInflater layoutInflater, int position) { + ItemInfo itemInfo = mBlockListAdapter.getItem(position); + + ViewGroup view = (ViewGroup) layoutInflater.inflate(R.layout.cube_mints_base_block_menu_item, null); + + if (itemInfo != null) { + TextView textView = ((TextView) view.findViewById(R.id.cube_mints_base_block_menu_item_title)); + textView.setText(itemInfo.mTitle); + view.setBackgroundColor(itemInfo.getColor()); + } + return view; + } + + protected abstract void addItemInfo(ArrayList itemInfos); + + protected abstract void setupViews(); + + @Override + protected View createView(final LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View view = inflater.inflate(getLayoutId(), null); + mBlockListView = (BlockListView) view.findViewById(R.id.fragment_block_menu_block_list); + addItemInfo(mItemInfos); + setupList(); + setupViews(); + return view; + } + + protected void setupList() { + + mSize = (LocalDisplay.SCREEN_WIDTH_PIXELS - LocalDisplay.dp2px(25 + 5 + 5)) / 3; + + int horizontalSpacing = LocalDisplay.dp2px(5); + int verticalSpacing = LocalDisplay.dp2px(10.5f); + + mBlockListView.setOnItemClickListener(new OnItemClickListener() { + + @Override + public void onItemClick(View v, int position) { + ItemInfo itemInfo = mBlockListAdapter.getItem(position); + if (itemInfo != null) { + itemInfo.mOnClickListener.onClick(v); + } + } + }); + + mBlockListAdapter.setSpace(horizontalSpacing, verticalSpacing); + mBlockListAdapter.setBlockSize(mSize, mSize); + mBlockListAdapter.setColumnNum(3); + mBlockListView.setAdapter(mBlockListAdapter); + mBlockListAdapter.displayBlocks(mItemInfos); + } + + protected ItemInfo newItemInfo(String title, int color, OnClickListener onClickListener) { + return new ItemInfo(title, getResources().getColor(color), onClickListener); + } + + protected ItemInfo newItemInfo(String title, String color, OnClickListener onClickListener) { + return new ItemInfo(title, Color.parseColor(color), onClickListener); + } + + protected ItemInfo newItemInfo(int title, String color, OnClickListener onClickListener) { + return new ItemInfo(getString(title), Color.parseColor(color), onClickListener); + } + + protected ItemInfo newItemInfo(int title, int color, OnClickListener onClickListener) { + return new ItemInfo(getString(title), getResources().getColor(color), onClickListener); + } + + @Override + protected boolean enableDefaultBack() { + return false; + } + + protected static class ItemInfo { + private int mColor; + private String mTitle; + private OnClickListener mOnClickListener; + + public ItemInfo(String title, int color, OnClickListener onClickListener) { + mTitle = title; + mColor = color; + mOnClickListener = onClickListener; + } + + private int getColor() { + return mColor; + } + } +} diff --git a/core/src/in/srain/cube/mints/base/DemoBaseActivity.java b/core/src/in/srain/cube/mints/base/DemoBaseActivity.java new file mode 100644 index 0000000..54f6655 --- /dev/null +++ b/core/src/in/srain/cube/mints/base/DemoBaseActivity.java @@ -0,0 +1,17 @@ +package in.srain.cube.mints.base; + +import in.srain.cube.R; +import in.srain.cube.app.XActivity; + +public abstract class DemoBaseActivity extends XActivity { + + @Override + protected String getCloseWarning() { + return getString(R.string.cube_mints_exit_tip); + } + + @Override + protected int getFragmentContainerId() { + return 0; + } +} \ No newline at end of file diff --git a/core/src/in/srain/cube/mints/base/TitleBaseActivity.java b/core/src/in/srain/cube/mints/base/TitleBaseActivity.java new file mode 100755 index 0000000..fdb0772 --- /dev/null +++ b/core/src/in/srain/cube/mints/base/TitleBaseActivity.java @@ -0,0 +1,64 @@ +package in.srain.cube.mints.base; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.LinearLayout; +import in.srain.cube.R; + +public abstract class TitleBaseActivity extends DemoBaseActivity { + + protected TitleHeaderBar mTitleHeaderBar; + protected LinearLayout mContentContainer; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + initViews(); + } + + protected int getFrameLayoutId() { + return R.layout.cube_mints_base_content_frame_with_title_header; + } + + protected void initViews() { + super.setContentView(getFrameLayoutId()); + + mTitleHeaderBar = (TitleHeaderBar) findViewById(R.id.cube_mints_content_frame_title_header); + mContentContainer = (LinearLayout) findViewById(R.id.cube_mints_content_frame_content); + + if (enableDefaultBack()) { + mTitleHeaderBar.setLeftOnClickListener(new OnClickListener() { + + @Override + public void onClick(View v) { + if (!processBackPressed()) { + doReturnBack(); + } + } + }); + } else { + mTitleHeaderBar.getLeftViewContainer().setVisibility(View.INVISIBLE); + } + } + + protected boolean enableDefaultBack() { + return true; + } + + @Override + public void setContentView(int layoutResID) { + View view = LayoutInflater.from(this).inflate(layoutResID, null); + mContentContainer.addView(view); + } + + + protected void setHeaderTitle(int id) { + mTitleHeaderBar.getTitleTextView().setText(id); + } + + protected void setHeaderTitle(String title) { + mTitleHeaderBar.setTitle(title); + } +} diff --git a/sample-and-tests/src/in/srain/cube/sample/activity/TitleBaseFragment.java b/core/src/in/srain/cube/mints/base/TitleBaseFragment.java similarity index 69% rename from sample-and-tests/src/in/srain/cube/sample/activity/TitleBaseFragment.java rename to core/src/in/srain/cube/mints/base/TitleBaseFragment.java index bb2dd5e..23a795b 100755 --- a/sample-and-tests/src/in/srain/cube/sample/activity/TitleBaseFragment.java +++ b/core/src/in/srain/cube/mints/base/TitleBaseFragment.java @@ -1,4 +1,4 @@ -package in.srain.cube.sample.activity; +package in.srain.cube.mints.base; import android.os.Bundle; import android.view.LayoutInflater; @@ -6,17 +6,10 @@ import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.LinearLayout; +import in.srain.cube.R; import in.srain.cube.app.CubeFragment; -import in.srain.cube.sample.R; -import in.srain.cube.sample.ui.views.header.TitleHeaderBar; /** - * 带页头的 页面基类 - *

- *

- * 使用一个orientation="vertical", LinearLayout,包含一个统一的页头{@link TitleHeaderBar} , 内容置于页头下部 - *

- *

* http://www.liaohuqiu.net/unified-title-header/ * * @author http://www.liaohuqiu.net @@ -29,13 +22,11 @@ public abstract class TitleBaseFragment extends CubeFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View view = inflater.inflate(R.layout.fragment_title_base, null); - LinearLayout contentContainer = (LinearLayout) view.findViewById(R.id.ly_main_content_container); + ViewGroup view = (ViewGroup) inflater.inflate(getFrameLayoutId(), null); + LinearLayout contentContainer = (LinearLayout) view.findViewById(R.id.cube_mints_content_frame_content); - // 页头逻辑处理 - mTitleHeaderBar = (TitleHeaderBar) view.findViewById(R.id.ly_header_bar_title_wrap); + mTitleHeaderBar = (TitleHeaderBar) view.findViewById(R.id.cube_mints_content_frame_title_header); if (enableDefaultBack()) { - mTitleHeaderBar.getLeftTextView().setText(R.string.base_title_return); mTitleHeaderBar.setLeftOnClickListener(new OnClickListener() { @Override @@ -48,37 +39,31 @@ public void onClick(View v) { } mContentContainer = contentContainer; - View contentView = createView(inflater, container, savedInstanceState); + View contentView = createView(inflater, view, savedInstanceState); contentView.setLayoutParams(new LinearLayout.LayoutParams(-1, -1)); contentContainer.addView(contentView); return view; } - private void onBackPressed() { - getContext().onBackPressed(); + protected int getFrameLayoutId() { + return R.layout.cube_mints_base_content_frame_with_title_header; } /** - * 是否使用默认的返回处理 - * - * @return + * make it looks like Activity */ + private void onBackPressed() { + getContext().onBackPressed(); + } + protected boolean enableDefaultBack() { return true; } - /** - * 设置标题 - * - * @param id - */ protected void setHeaderTitle(int id) { mTitleHeaderBar.getTitleTextView().setText(id); } - /** - * 设置标题 - */ protected void setHeaderTitle(String title) { mTitleHeaderBar.getTitleTextView().setText(title); } diff --git a/core/src/in/srain/cube/mints/base/TitleHeaderBar.java b/core/src/in/srain/cube/mints/base/TitleHeaderBar.java new file mode 100755 index 0000000..cc32ff4 --- /dev/null +++ b/core/src/in/srain/cube/mints/base/TitleHeaderBar.java @@ -0,0 +1,145 @@ +package in.srain.cube.mints.base; + +import android.content.Context; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.RelativeLayout; +import android.widget.TextView; +import in.srain.cube.R; + +public class TitleHeaderBar extends RelativeLayout { + + private TextView mCenterTitleTextView; + private ImageView mLeftReturnImageView; + private RelativeLayout mLeftViewContainer; + private RelativeLayout mRightViewContainer; + private RelativeLayout mCenterViewContainer; + + private String title; + + public TitleHeaderBar(Context context) { + this(context, null); + } + + public TitleHeaderBar(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public TitleHeaderBar(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + LayoutInflater.from(context).inflate(R.layout.cube_mints_base_header_bar_title, this); + mLeftViewContainer = (RelativeLayout) findViewById(R.id.ly_title_bar_left); + mCenterViewContainer = (RelativeLayout) findViewById(R.id.ly_title_bar_center); + mRightViewContainer = (RelativeLayout) findViewById(R.id.ly_title_bar_right); + mLeftReturnImageView = (ImageView) findViewById(R.id.iv_title_bar_left); + mCenterTitleTextView = (TextView) findViewById(R.id.tv_title_bar_title); + } + + public ImageView getLeftImageView() { + return mLeftReturnImageView; + } + + public TextView getTitleTextView() { + return mCenterTitleTextView; + } + + public void setTitle(String title) { + this.title = title; + mCenterTitleTextView.setText(title); + } + + private RelativeLayout.LayoutParams makeLayoutParams(View view) { + ViewGroup.LayoutParams lpOld = view.getLayoutParams(); + RelativeLayout.LayoutParams lp = null; + if (lpOld == null) { + lp = new RelativeLayout.LayoutParams(-2, -1); + } else { + lp = new RelativeLayout.LayoutParams(lpOld.width, lpOld.height); + } + return lp; + } + + /** + * set customized view to left side + * + * @param view the view to be added to left side + */ + public void setCustomizedLeftView(View view) { + mLeftReturnImageView.setVisibility(GONE); + RelativeLayout.LayoutParams lp = makeLayoutParams(view); + lp.addRule(CENTER_VERTICAL); + lp.addRule(ALIGN_PARENT_LEFT); + getLeftViewContainer().addView(view, lp); + } + + /** + * set customized view to left side + * + * @param layoutId the xml layout file id + */ + public void setCustomizedLeftView(int layoutId) { + View view = inflate(getContext(), layoutId, null); + setCustomizedLeftView(view); + } + + /** + * set customized view to center + * + * @param view the view to be added to center + */ + public void setCustomizedCenterView(View view) { + mCenterTitleTextView.setVisibility(GONE); + RelativeLayout.LayoutParams lp = makeLayoutParams(view); + lp.addRule(CENTER_IN_PARENT); + getCenterViewContainer().addView(view, lp); + } + + /** + * set customized view to center + * + * @param layoutId the xml layout file id + */ + public void setCustomizedCenterView(int layoutId) { + View view = inflate(getContext(), layoutId, null); + setCustomizedCenterView(view); + } + + /** + * set customized view to right side + * + * @param view the view to be added to right side + */ + public void setCustomizedRightView(View view) { + RelativeLayout.LayoutParams lp = makeLayoutParams(view); + lp.addRule(CENTER_VERTICAL); + lp.addRule(ALIGN_PARENT_RIGHT); + getRightViewContainer().addView(view, lp); + } + + public RelativeLayout getLeftViewContainer() { + return mLeftViewContainer; + } + + public RelativeLayout getCenterViewContainer() { + return mCenterViewContainer; + } + + public RelativeLayout getRightViewContainer() { + return mRightViewContainer; + } + + public void setLeftOnClickListener(OnClickListener l) { + mLeftViewContainer.setOnClickListener(l); + } + + public void setCenterOnClickListener(OnClickListener l) { + mCenterViewContainer.setOnClickListener(l); + } + + public void setRightOnClickListener(OnClickListener l) { + mRightViewContainer.setOnClickListener(l); + } +} \ No newline at end of file diff --git a/core/src/in/srain/cube/request/CacheAbleRequest.java b/core/src/in/srain/cube/request/CacheAbleRequest.java index 8ff69d8..06613cb 100755 --- a/core/src/in/srain/cube/request/CacheAbleRequest.java +++ b/core/src/in/srain/cube/request/CacheAbleRequest.java @@ -1,8 +1,11 @@ package in.srain.cube.request; import android.text.TextUtils; +import in.srain.cube.cache.CacheManager; +import in.srain.cube.cache.CacheResultType; import in.srain.cube.concurrent.SimpleTask; import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import java.net.URI; import java.net.URISyntaxException; @@ -17,11 +20,10 @@ public static enum ResultType { USE_CACHE_ON_FAIL, } - protected static final boolean DEBUG = CLog.DEBUG_REQUEST_CACHE; - protected static final String LOG_TAG = "cube_request_cache"; + protected static final boolean DEBUG = Debug.DEBUG_CACHE; + protected static final String LOG_TAG = "cube_cache_request"; private CacheAbleRequestHandler mHandler; - private CacheAbleRequestPrePreHandler mPreHandler; private T mCacheData; private boolean mOutOfDate; @@ -31,12 +33,27 @@ public static enum ResultType { private boolean mHasTimeout = false; private boolean mUseCacheAnyway = false; private boolean mHasNotified = false; + protected boolean mForceQueryFromServer = false; - public CacheAbleRequest(CacheAbleRequestPrePreHandler preHandler, final CacheAbleRequestHandler handler) { - mPreHandler = preHandler; + private String mInitDataPath; + private boolean mDisableCache = false; + private long mCacheTime; + + public CacheAbleRequest() { + } + + public CacheAbleRequest(final CacheAbleRequestHandler handler) { + setCacheAbleRequestHandler(handler); + } + + public void setCacheAbleRequestHandler(CacheAbleRequestHandler handler) { mHandler = handler; } + public void forceQueryFromServer(boolean force) { + mForceQueryFromServer = force; + } + // =========================================================== // Override parent // =========================================================== @@ -45,6 +62,17 @@ public void doSendRequest() { RequestCacheManager.getInstance().requestCache(this); } + /** + * prepare request + */ + @Override + protected void prepareRequest() { + + } + + // =========================================================== + // Override Interface + // =========================================================== @Override public void setTimeout(int timeOut) { mTimeout = timeOut; @@ -76,16 +104,6 @@ public void onRequestSuccess(T data) { } } - @Override - public void prepareRequest() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, prepareRequest", getCacheKey()); - } - if (mPreHandler != null) { - mPreHandler.prepareRequest(this); - } - } - @Override public void onRequestFail(FailData failData) { if (DEBUG) { @@ -96,7 +114,7 @@ public void onRequestFail(FailData failData) { } if (null != mHandler) { mHandler.onRequestFail(failData); - if (mCacheData != null && !disableCache() && !mUseCacheAnyway) { + if (mCacheData != null && !cacheIsDisabled() && !mUseCacheAnyway) { notifyRequestFinish(ResultType.USE_CACHE_ON_FAIL, true); } else { mHandler.onRequestFail(null); @@ -105,9 +123,9 @@ public void onRequestFail(FailData failData) { } @Override - public void queryFromServer() { + public void createDataForCache(CacheManager cacheManager) { if (DEBUG) { - CLog.d(LOG_TAG, "%s, queryFromServer", getCacheKey()); + CLog.d(LOG_TAG, "%s, createDataForCache", getCacheKey()); } if (hasBeenCanceled()) { return; @@ -120,21 +138,25 @@ protected void doQueryFromServer() { SimpleRequestManager.sendRequest(this); } + protected boolean cacheRequestResult() { + return mForceQueryFromServer || !cacheIsDisabled(); + } + @Override - public boolean disableCache() { - if (mPreHandler != null) { - return mPreHandler.disableCache(); + public boolean cacheIsDisabled() { + if (mForceQueryFromServer) { + return true; } - return false; + return mDisableCache; } // =========================================================== // Implements Interface {@link ICacheAble} // =========================================================== @Override - public void onCacheData(T data, boolean outOfDate) { + public void onCacheData(CacheResultType cacheResultType, T data, boolean outOfDate) { if (DEBUG) { - CLog.d(LOG_TAG, "%s, onCacheData, out of date: %s", getCacheKey(), outOfDate); + CLog.d(LOG_TAG, "%s, onQueryFinish, out of date: %s", getCacheKey(), outOfDate); } if (hasBeenCanceled()) { return; @@ -155,28 +177,28 @@ public void onCacheData(T data, boolean outOfDate) { } @Override - public int getCacheTime() { - return mPreHandler.getCacheTime(); + public long getCacheTime() { + return mCacheTime; } @Override public String getCacheKey() { if (mCacheKey == null) { - String cacheKey = mPreHandler.getSpecificCacheKey(); - if (TextUtils.isEmpty(cacheKey)) { - - String url = getRequestData().getRequestUrl(); - try { - URI uri = null; - uri = new URI(url); - cacheKey = uri.getPath(); - if (cacheKey.startsWith("/")) { - cacheKey = cacheKey.substring(1); - } - cacheKey = cacheKey.replace("/", "-"); - } catch (URISyntaxException e) { - e.printStackTrace(); + String cacheKey = null; + String url = getRequestData().getRequestUrl(); + try { + URI uri = null; + uri = new URI(url); + cacheKey = uri.getPath(); + if (cacheKey.startsWith("/")) { + cacheKey = cacheKey.substring(1); } + cacheKey = cacheKey.replace("/", "-"); + } catch (URISyntaxException e) { + e.printStackTrace(); + } + if (TextUtils.isEmpty(cacheKey)) { + throw new RuntimeException("Cache key is null"); } mCacheKey = cacheKey; } @@ -185,7 +207,7 @@ public String getCacheKey() { @Override public String getAssertInitDataPath() { - return mPreHandler.getInitFileAssertPath(); + return mInitDataPath; } @Override @@ -194,8 +216,8 @@ public T onDataFromServer(String data) { CLog.d(LOG_TAG, "%s, onDataFromServer", getCacheKey()); } // cache the data - if (!TextUtils.isEmpty(data) && !disableCache()) { - RequestCacheManager.getInstance().cacheRequest(this, data); + if (!TextUtils.isEmpty(data) && cacheRequestResult()) { + RequestCacheManager.getInstance().setCacheData(this.getCacheKey(), data); } return super.onDataFromServer(data); } @@ -207,7 +229,6 @@ public T processOriginDataFromServer(JsonData rawData) { @Override public T processRawDataFromCache(JsonData rawData) { - return mHandler.processOriginData(rawData); } @@ -245,4 +266,24 @@ public void run() { }, mTimeout); } } + + public CacheAbleRequest setCacheKey(String cacheKey) { + mCacheKey = cacheKey; + return this; + } + + public CacheAbleRequest setDisableCache(boolean disable) { + mDisableCache = disable; + return this; + } + + public CacheAbleRequest setInitDataPath(String path) { + mInitDataPath = path; + return this; + } + + public CacheAbleRequest setCacheTime(long cacheTime) { + mCacheTime = cacheTime; + return this; + } } diff --git a/core/src/in/srain/cube/request/CacheAbleRequestDefaultPrePreHandler.java b/core/src/in/srain/cube/request/CacheAbleRequestDefaultPrePreHandler.java deleted file mode 100755 index a5822ff..0000000 --- a/core/src/in/srain/cube/request/CacheAbleRequestDefaultPrePreHandler.java +++ /dev/null @@ -1,9 +0,0 @@ -package in.srain.cube.request; - -public abstract class CacheAbleRequestDefaultPrePreHandler implements CacheAbleRequestPrePreHandler { - - @Override - public boolean disableCache() { - return false; - } -} \ No newline at end of file diff --git a/core/src/in/srain/cube/request/CacheAbleRequestPrePreHandler.java b/core/src/in/srain/cube/request/CacheAbleRequestPrePreHandler.java deleted file mode 100755 index 13453e1..0000000 --- a/core/src/in/srain/cube/request/CacheAbleRequestPrePreHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package in.srain.cube.request; - -public interface CacheAbleRequestPrePreHandler extends RequestPreHandler { - - /** - * Once the cache key is specified, the data will be cached by using this key, - *

- * or else, the url path return by getRequestUrl() will be used, after '/' has been replaced into '-'. - */ - public String getSpecificCacheKey(); - - public String getInitFileAssertPath(); - - public boolean disableCache(); - - /** - * Indicate how long the data should be cached - * - * @return - */ - public int getCacheTime(); -} \ No newline at end of file diff --git a/core/src/in/srain/cube/request/CacheData.java b/core/src/in/srain/cube/request/CacheData.java deleted file mode 100644 index 171ef7b..0000000 --- a/core/src/in/srain/cube/request/CacheData.java +++ /dev/null @@ -1,43 +0,0 @@ -package in.srain.cube.request; - -import org.json.JSONObject; - -import java.util.HashMap; - -public class CacheData { - - public String data; - public int time; - public int mSize; - - public static CacheData create(String data) { - CacheData cacheData = new CacheData(data); - cacheData.time = (int) (System.currentTimeMillis() / 1000); - return cacheData; - } - - public static CacheData create(String data, int time) { - CacheData cacheData = new CacheData(data); - cacheData.time = time; - return cacheData; - } - - private CacheData(String data) { - this.data = data; - mSize = (data.getBytes().length + 8); - } - - public int getSize() { - return mSize; - } - - public String getCacheData() { - JSONObject jsonObject = new JSONObject(); - try { - jsonObject.put("time", time); - jsonObject.put("data", data); - } catch (Exception e) { - } - return jsonObject.toString(); - } -} diff --git a/core/src/in/srain/cube/request/FailData.java b/core/src/in/srain/cube/request/FailData.java index 8341448..ca39b00 100644 --- a/core/src/in/srain/cube/request/FailData.java +++ b/core/src/in/srain/cube/request/FailData.java @@ -1,4 +1,9 @@ package in.srain.cube.request; public class FailData { + public Object object; + + public FailData(Object o) { + object = o; + } } diff --git a/core/src/in/srain/cube/request/ICacheAbleRequest.java b/core/src/in/srain/cube/request/ICacheAbleRequest.java index b9b6520..05638d0 100644 --- a/core/src/in/srain/cube/request/ICacheAbleRequest.java +++ b/core/src/in/srain/cube/request/ICacheAbleRequest.java @@ -1,38 +1,11 @@ package in.srain.cube.request; -/** - * A CacheAble Request wrap - */ -public interface ICacheAbleRequest extends IRequest { +import in.srain.cube.cache.ICacheAble; - public int getCacheTime(); - - public String getCacheKey(); - - public String getAssertInitDataPath(); - - /** - * We need to process the data from data source, do some filter of convert the structure. - *

- * As the "Assert Data" is a special data source, we also need to do the same work. - */ - public T processRawDataFromCache(JsonData rawData); - - /** - * when data loaded from cache - * - * @param cacheData - * @param outOfDate - */ - public void onCacheData(T cacheData, boolean outOfDate); - - /** - * process query data from server - */ - public void queryFromServer(); +public interface ICacheAbleRequest extends ICacheAble, IRequest { /** - * disable cache + * check cache is disabled *

* 1. will not load cache *

@@ -40,7 +13,7 @@ public interface ICacheAbleRequest extends IRequest { * * @return */ - public boolean disableCache(); + public boolean cacheIsDisabled(); /** * set a timeout, when request time over this value, cache data will be used. diff --git a/core/src/in/srain/cube/request/IRequest.java b/core/src/in/srain/cube/request/IRequest.java index 8095e37..ae02fe3 100755 --- a/core/src/in/srain/cube/request/IRequest.java +++ b/core/src/in/srain/cube/request/IRequest.java @@ -8,10 +8,8 @@ public interface IRequest { public void onRequestFail(FailData failData); - public void prepareRequest(); - /** - * send request, {@link IRequest#prepareRequest} should be called. + * send request */ public void send(); diff --git a/core/src/in/srain/cube/request/JsonData.java b/core/src/in/srain/cube/request/JsonData.java index 1137f20..eb4ce0e 100755 --- a/core/src/in/srain/cube/request/JsonData.java +++ b/core/src/in/srain/cube/request/JsonData.java @@ -5,13 +5,10 @@ import org.json.JSONObject; import org.json.JSONTokener; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; +import java.util.*; @SuppressWarnings("rawtypes") -public class JsonData { +public final class JsonData { private Object mJson; private static final String EMPTY_STRING = ""; @@ -20,6 +17,10 @@ public static JsonData newMap() { return create(new HashMap()); } + public static JsonData newList() { + return create(new ArrayList()); + } + public static JsonData create(String str) { Object object = null; if (str != null && str.length() >= 0) { @@ -40,6 +41,9 @@ public static JsonData create(Object o) { if (o instanceof Map) { json.mJson = new JSONObject((Map) o); } + if (o instanceof Collection) { + json.mJson = new JSONArray((Collection) o); + } return json; } @@ -69,34 +73,66 @@ public String optString(String name) { return optMapOrNew().optString(name); } + public String optString(String name, String fallback) { + return optMapOrNew().optString(name, fallback); + } + public String optString(int index) { return optArrayOrNew().optString(index); } + public String optString(int index, String fallback) { + return optArrayOrNew().optString(index, fallback); + } + public int optInt(String name) { return optMapOrNew().optInt(name); } + public int optInt(String name, int fallback) { + return optMapOrNew().optInt(name, fallback); + } + public int optInt(int index) { return optArrayOrNew().optInt(index); } + public int optInt(int index, int fallback) { + return optArrayOrNew().optInt(index, fallback); + } + public boolean optBoolean(String name) { return optMapOrNew().optBoolean(name); } + public boolean optBoolean(String name, boolean fallback) { + return optMapOrNew().optBoolean(name, fallback); + } + public boolean optBoolean(int index) { return optArrayOrNew().optBoolean(index); } + public boolean optBoolean(int index, boolean fallback) { + return optArrayOrNew().optBoolean(index, fallback); + } + public double optDouble(String name) { return optMapOrNew().optDouble(name); } + public double optDouble(String name, double fallback) { + return optMapOrNew().optDouble(name, fallback); + } + public double optDouble(int index) { return optArrayOrNew().optDouble(index); } + public double optDouble(int index, double fallback) { + return optArrayOrNew().optDouble(index, fallback); + } + public boolean has(String name) { return optMapOrNew().has(name); } @@ -112,10 +148,18 @@ public JSONObject optMapOrNew() { return new JSONObject(); } + private Object valueForPut(Object value) { + if (value instanceof JsonData) { + return ((JsonData) value).getRawData(); + } else { + return value; + } + } + public void put(String key, Object value) { if (mJson instanceof JSONObject) { try { - ((JSONObject) mJson).put(key, value); + ((JSONObject) mJson).put(key, valueForPut(value)); } catch (JSONException e) { e.printStackTrace(); } @@ -124,20 +168,68 @@ public void put(String key, Object value) { public void put(Object value) { if (mJson instanceof JSONArray) { - ((JSONArray) mJson).put(value); + ((JSONArray) mJson).put(valueForPut(value)); } } public void put(int index, Object value) { if (mJson instanceof JSONArray) { try { - ((JSONArray) mJson).put(index, value); + ((JSONArray) mJson).put(index, valueForPut(value)); } catch (JSONException e) { e.printStackTrace(); } } } + public JsonData editMap(int index) { + if (has(index)) { + return optJson(index); + } + JsonData map = JsonData.newMap(); + put(index, map); + return map; + } + + public JsonData editMap() { + JsonData map = JsonData.newMap(); + put(map); + return map; + } + + public JsonData editMap(String key) { + if (has(key)) { + return optJson(key); + } + JsonData map = JsonData.newMap(); + put(key, map); + return map; + } + + public JsonData editList(String key) { + if (has(key)) { + return optJson(key); + } + JsonData list = JsonData.newList(); + put(key, list); + return list; + } + + public JsonData editList(int index) { + if (has(index)) { + return optJson(index); + } + JsonData list = JsonData.newList(); + put(index, list); + return list; + } + + public JsonData editList() { + JsonData list = JsonData.newList(); + put(list); + return list; + } + public JSONArray optArrayOrNew() { if (mJson instanceof JSONArray) { return (JSONArray) mJson; diff --git a/core/src/in/srain/cube/request/RequestBase.java b/core/src/in/srain/cube/request/RequestBase.java index 6622533..f4c823e 100644 --- a/core/src/in/srain/cube/request/RequestBase.java +++ b/core/src/in/srain/cube/request/RequestBase.java @@ -39,4 +39,9 @@ protected void onCancel() { * implement this method to process request data */ protected abstract void doSendRequest(); + + /** + * prepare request + */ + protected abstract void prepareRequest(); } diff --git a/core/src/in/srain/cube/request/RequestCacheManager.java b/core/src/in/srain/cube/request/RequestCacheManager.java old mode 100755 new mode 100644 index 14fd7f0..4af2a33 --- a/core/src/in/srain/cube/request/RequestCacheManager.java +++ b/core/src/in/srain/cube/request/RequestCacheManager.java @@ -1,366 +1,20 @@ package in.srain.cube.request; import android.content.Context; -import android.support.v4.util.LruCache; -import android.text.TextUtils; -import in.srain.cube.concurrent.SimpleExecutor; -import in.srain.cube.concurrent.SimpleTask; -import in.srain.cube.file.FileUtil; -import in.srain.cube.file.LruFileCache; -import in.srain.cube.util.CLog; -import org.json.JSONObject; +import in.srain.cube.cache.CacheManager; -/** - * @author http://www.liaohuqiu.net - */ public class RequestCacheManager { - private static final boolean DEBUG = CLog.DEBUG_REQUEST_CACHE; - private static final String LOG_TAG = "cube_request_cache"; + private static CacheManager sInstance; - private static final String THREAD_NAME = "Cube-Request-Cache"; - - private static RequestCacheManager mInstance; - - private LruCache mMemoryCache; - private LruFileCache mFileCache; - - private static final int AFTER_READ_FROM_FILE = 0x01; - private static final int AFTER_READ_FROM_ASSERT = 0x02; - private static final int AFTER_CONVERT = 0x04; - - private static final int DO_READ_FROM_FILE = 0x01; - private static final int DO_READ_FROM_ASSERT = 0x02; - private static final int DO_CONVERT = 0x04; - - private Context mContext; - - private RequestCacheManager() { - } - - /** - * init cache - */ - public void init(Context content, String cacheDir) { - init(content, cacheDir, 1024 * 10, 1024 * 10); - } - - public void init(Context content, String cacheDir, int memoryCacheSizeInKB, int fileCacheSizeInKB) { - mContext = content; - - mMemoryCache = new LruCache(memoryCacheSizeInKB * 1024) { - @Override - protected int sizeOf(String key, CacheData value) { - return (value.getSize() + key.getBytes().length); - } - }; - mFileCache = new LruFileCache(content, cacheDir, fileCacheSizeInKB * 1024); - mFileCache.initDiskCacheAsync(); - if (DEBUG) { - CLog.d(LOG_TAG, "init file cache. dir: %s => %s, size: %s, used: %s", cacheDir, mFileCache.getCachePath(), mFileCache.getMaxSize(), mFileCache.getUsedSpace()); - } - } - - public static RequestCacheManager getInstance() { - if (null == mInstance) - mInstance = new RequestCacheManager(); - return mInstance; - } - - public void requestCache(ICacheAbleRequest cacheAbleRequest) { - ReadCacheTask task = new ReadCacheTask(cacheAbleRequest); - task.beginQuery(); - } - - public void cacheRequest(final ICacheAbleRequest cacheAble, final String data) { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, cacheRequest", cacheAble.getCacheKey()); - } - new Thread(new Runnable() { - @Override - public void run() { - CacheData cacheData = CacheData.create(data); - setCacheData(cacheAble.getCacheKey(), cacheData); - mFileCache.write(cacheAble.getCacheKey(), cacheData.getCacheData()); - } - }, THREAD_NAME).start(); - } - - private JsonData makeCacheFormatJsonData(JsonData data, int time) { - JSONObject jsonObject = new JSONObject(); - if (time == 0) - time = (int) (System.currentTimeMillis() / 1000); - try { - jsonObject.put("time", time); - jsonObject.put("data", data.getRawData()); - } catch (Exception e) { - } - return JsonData.create(jsonObject); - } - - private class ReadCacheTask extends SimpleTask { - - private ICacheAbleRequest mCacheAble; - - private CacheData mRawData; - private T1 mResult; - private int mWorkType = 0; - private int mCurrentStatus = 0; - - public ReadCacheTask(ICacheAbleRequest cacheAble) { - mCacheAble = cacheAble; - } - - void beginQuery() { - - if (mCacheAble.disableCache()) { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, Cache is disabled, query from server", mCacheAble.getCacheKey()); - } - mCacheAble.queryFromServer(); - return; - } - - String cacheKey = mCacheAble.getCacheKey(); - - // try to find in runtime cache - mRawData = mMemoryCache.get(cacheKey); - if (mRawData != null) { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, exist in list", mCacheAble.getCacheKey()); - } - beginConvertDataAsync(); - return; - } - - // try read from cache data - boolean hasFileCache = mFileCache.has(mCacheAble.getCacheKey()); - if (hasFileCache) { - beginQueryFromCacheFileAsync(); - return; - } - - // try to read from assert cache file - String assertInitDataPath = mCacheAble.getAssertInitDataPath(); - if (assertInitDataPath != null && assertInitDataPath.length() > 0) { - beginQueryFromAssertCacheFileAsync(); - return; - } - - if (DEBUG) { - CLog.d(LOG_TAG, "%s, cache file not exist", mCacheAble.getCacheKey()); - } - mCacheAble.queryFromServer(); - } - - @Override - public void doInBackground() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, doInBackground: mWorkType: %s", mCacheAble.getCacheKey(), mWorkType); - } - switch (mWorkType) { - - case DO_READ_FROM_FILE: - doQueryFromCacheFileInBackground(); - break; - - case DO_READ_FROM_ASSERT: - doQueryFromAssertCacheFileInBackground(); - break; - - case DO_CONVERT: - doConvertDataInBackground(); - break; - - default: - break; - } - } - - @Override - public void onFinish() { - switch (mCurrentStatus) { - case AFTER_READ_FROM_FILE: - case AFTER_READ_FROM_ASSERT: - beginConvertDataAsync(); - break; - - case AFTER_CONVERT: - done(); - break; - - default: - break; - } - } - - private void beginQueryFromCacheFileAsync() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, beginQueryFromCacheFileAsync", mCacheAble.getCacheKey()); - } - mWorkType = DO_READ_FROM_FILE; - restart(); - SimpleExecutor.getInstance().execute(this); - } - - private void beginQueryFromAssertCacheFileAsync() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, beginQueryFromAssertCacheFileAsync", mCacheAble.getCacheKey()); - } - mWorkType = DO_READ_FROM_ASSERT; - restart(); - SimpleExecutor.getInstance().execute(this); - } - - private void beginConvertDataAsync() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, beginConvertDataAsync", mCacheAble.getCacheKey()); - } - mWorkType = DO_CONVERT; - restart(); - SimpleExecutor.getInstance().execute(this); - } - - private void doQueryFromCacheFileInBackground() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, try read cache data from file", mCacheAble.getCacheKey()); - } - - String cacheContent = mFileCache.read(mCacheAble.getCacheKey()); - JsonData jsonData = JsonData.create(cacheContent); - mRawData = CacheData.create(jsonData.optString("data"), jsonData.optInt("time")); - - setCurrentStatus(AFTER_READ_FROM_FILE); - } - - private void doQueryFromAssertCacheFileInBackground() { - - if (DEBUG) { - CLog.d(LOG_TAG, "%s, try read cache data from assert file", mCacheAble.getCacheKey()); - } - - String cacheContent = FileUtil.readAssert(mContext, mCacheAble.getAssertInitDataPath()); - mRawData = CacheData.create(cacheContent, -2); - setCacheData(mCacheAble.getCacheKey(), mRawData); - - setCurrentStatus(AFTER_READ_FROM_ASSERT); - } - - private void doConvertDataInBackground() { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, doConvertDataInBackground", mCacheAble.getCacheKey()); - } - JsonData data = JsonData.create(mRawData.data); - mResult = mCacheAble.processRawDataFromCache(data); - setCurrentStatus(AFTER_CONVERT); - } - - private void setCurrentStatus(int status) { - mCurrentStatus = status; - if (DEBUG) { - CLog.d(LOG_TAG, "%s, setCurrentStatus: %s", mCacheAble.getCacheKey(), status); - } - } - - private void done() { - - int lastTime = mRawData.time; - long timeInterval = System.currentTimeMillis() / 1000 - lastTime; - boolean outOfDate = timeInterval > mCacheAble.getCacheTime() || timeInterval < 0; - mCacheAble.onCacheData(mResult, outOfDate); - if (outOfDate) { - mCacheAble.queryFromServer(); - } + public static CacheManager getInstance() { + if (sInstance == null) { + throw new RuntimeException("Call RequestCacheManager::init() first"); } + return sInstance; } - private void setCacheData(String key, CacheData data) { - if (TextUtils.isEmpty(key)) { - return; - } - if (DEBUG) { - CLog.d(LOG_TAG, "%s, set cache to runtime cache list", key); - } - mMemoryCache.put(key, data); - } - - /** - * delete cache by key - * - * @param key - */ - public void invalidateCache(String key) { - if (DEBUG) { - CLog.d(LOG_TAG, "%s, invalidateCache", key); - } - mFileCache.delete(key); - mMemoryCache.remove(key); - } - - /** - * clear the memory cache - */ - public void clearMemoryCache() { - if (mMemoryCache != null) { - mMemoryCache.evictAll(); - } - } - - /** - * get the spaced has been used - * - * @return - */ - public int getMemoryCacheUsedSpace() { - return mMemoryCache.size(); - } - - /** - * get the spaced max space in config - * @return - */ - public int getMemoryCacheMaxSpace() { - return mMemoryCache.maxSize(); - } - - /** - * clear the disk cache - */ - public void clearDiskCache() { - if (null != mFileCache) { - mFileCache.clearCache(); - } - } - - /** - * return the file cache path - * - * @return - */ - public String getFileCachePath() { - if (null != mFileCache) { - return mFileCache.getCachePath(); - } - return null; - } - - /** - * get the used space in file cache - * - * @return - */ - public long getFileCacheUsedSpace() { - return null != mFileCache ? mFileCache.getUsedSpace() : 0; - } - - /** - * get the max space for file cache - * @return - */ - public long getFileCacheMaxSpace() { - if (null != mFileCache) { - return mFileCache.getMaxSize(); - } - return 0; + public static void init(Context content, String cacheDir, int memoryCacheSizeInKB, int fileCacheSizeInKB) { + sInstance = new CacheManager(content, cacheDir, memoryCacheSizeInKB, fileCacheSizeInKB); } -} \ No newline at end of file +} diff --git a/core/src/in/srain/cube/request/RequestData.java b/core/src/in/srain/cube/request/RequestData.java index b0b414b..9fb1886 100644 --- a/core/src/in/srain/cube/request/RequestData.java +++ b/core/src/in/srain/cube/request/RequestData.java @@ -1,14 +1,112 @@ package in.srain.cube.request; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + public class RequestData { + private static final String CHAR_QM = "?"; + private static final String CHAR_AND = "&"; + private static final String CHAR_EQ = "="; + private static final String CHAR_SET = "UTF-8"; + public String mUrl; - public void setRequestUrl(String url) { - mUrl = url; + private HashMap mQueryData; + private HashMap mPostData; + private boolean mUsePost = false; + + public static String buildQueryString(Map data, String url) { + + StringBuilder sb = new StringBuilder(); + boolean append = false; + if (url != null) { + sb.append(url); + if (url.contains(CHAR_QM)) { + append = true; + } else { + sb.append(CHAR_QM); + } + } + Iterator> it = data.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry item = it.next(); + if (append) { + sb.append(CHAR_AND); + } else { + append = true; + } + + try { + sb.append(URLEncoder.encode(item.getKey(), CHAR_SET)); + sb.append(CHAR_EQ); + sb.append(URLEncoder.encode(item.getValue().toString(), CHAR_SET)); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + } + return sb.toString(); + } + + public void addPostData(String key, Object data) { + if (mPostData == null) { + mPostData = new HashMap(); + } + mPostData.put(key, data); + } + + public void addPostData(Map data) { + if (mPostData == null) { + mPostData = new HashMap(); + } + mPostData.putAll(data); + } + + public void addQueryData(String key, Object data) { + if (mQueryData == null) { + mQueryData = new HashMap(); + } + mQueryData.put(key, data); + } + + public void addQueryData(Map data) { + if (mQueryData == null) { + mQueryData = new HashMap(); + } + mQueryData.putAll(data); } public String getRequestUrl() { + if (mQueryData != null) { + return buildQueryString(mQueryData, mUrl); + } return mUrl; } + + public void setRequestUrl(String url) { + mUrl = url; + } + + public HashMap getQueryData() { + return mQueryData; + } + + public HashMap getPostData() { + return mPostData; + } + + public void usePost(boolean use) { + mUsePost = use; + } + + public String getPostString() { + return buildQueryString(mPostData, null); + } + + public boolean shouldPost() { + return mUsePost || (mPostData != null && mPostData.size() > 0); + } } diff --git a/core/src/in/srain/cube/request/RequestPreHandler.java b/core/src/in/srain/cube/request/RequestPreHandler.java deleted file mode 100755 index 376cd6d..0000000 --- a/core/src/in/srain/cube/request/RequestPreHandler.java +++ /dev/null @@ -1,5 +0,0 @@ -package in.srain.cube.request; - -public interface RequestPreHandler { - public void prepareRequest(RequestBase request); -} \ No newline at end of file diff --git a/core/src/in/srain/cube/request/SimpleJsonRequest.java b/core/src/in/srain/cube/request/SimpleJsonRequest.java index 6ff00fa..23350f4 100755 --- a/core/src/in/srain/cube/request/SimpleJsonRequest.java +++ b/core/src/in/srain/cube/request/SimpleJsonRequest.java @@ -5,7 +5,7 @@ */ public class SimpleJsonRequest extends SimpleRequest { - public SimpleJsonRequest(RequestPreHandler requestPreHandler, RequestJsonHandler succHandler) { - super(requestPreHandler, succHandler); + public SimpleJsonRequest(RequestJsonHandler requestHandler) { + super(requestHandler); } } \ No newline at end of file diff --git a/core/src/in/srain/cube/request/SimpleRequest.java b/core/src/in/srain/cube/request/SimpleRequest.java index 9a96fa5..64bb1c3 100755 --- a/core/src/in/srain/cube/request/SimpleRequest.java +++ b/core/src/in/srain/cube/request/SimpleRequest.java @@ -6,24 +6,27 @@ public class SimpleRequest extends RequestBase implements IRequest { private RequestHandler mRequestHandler; - private RequestPreHandler mRequestPreHandler; - public SimpleRequest(RequestPreHandler requestPreHandler, RequestHandler handler) { - mRequestPreHandler = requestPreHandler; + public SimpleRequest() { + + } + + public SimpleRequest(RequestHandler handler) { + setRequestHandler(handler); + } + + public SimpleRequest setRequestHandler(RequestHandler handler) { mRequestHandler = handler; + return this; } @Override protected void doSendRequest() { - this.prepareRequest(); SimpleRequestManager.sendRequest(this); } @Override - public void prepareRequest() { - if (null != mRequestPreHandler) { - mRequestPreHandler.prepareRequest(this); - } + protected void prepareRequest() { } @Override diff --git a/core/src/in/srain/cube/request/SimpleRequestManager.java b/core/src/in/srain/cube/request/SimpleRequestManager.java index 8555b99..428b6ea 100644 --- a/core/src/in/srain/cube/request/SimpleRequestManager.java +++ b/core/src/in/srain/cube/request/SimpleRequestManager.java @@ -3,12 +3,9 @@ import android.os.Handler; import android.os.Message; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; +import java.io.*; +import java.net.HttpURLConnection; import java.net.URL; -import java.net.URLConnection; /** * @author http://www.liaohuqiu.net @@ -45,21 +42,27 @@ public void handleMessage(Message msg) { public void run() { T data = null; try { + + RequestData requestData = request.getRequestData(); StringBuilder sb = new StringBuilder(); URL url = new URL(request.getRequestData().getRequestUrl()); - URLConnection urlConnection = url.openConnection(); - InputStream ips = new BufferedInputStream(urlConnection.getInputStream()); - BufferedReader buf = new BufferedReader(new InputStreamReader(ips, "UTF-8")); + HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection(); - String s; - while (true) { - s = buf.readLine(); - if (s == null || s.length() == 0) - break; - sb.append(s); + if (requestData.shouldPost()) { + urlConnection.setRequestMethod("POST"); + OutputStreamWriter writer = new OutputStreamWriter(urlConnection.getOutputStream()); + writer.write(requestData.getPostString()); + writer.flush(); + } + InputStream ips = new BufferedInputStream(urlConnection.getInputStream()); + BufferedReader reader = new BufferedReader(new InputStreamReader(ips, "UTF-8")); + char[] buffer = new char[1024]; + int bufferLength; + while ((bufferLength = reader.read(buffer, 0, buffer.length)) > 0) { + sb.append(buffer, 0, bufferLength); } - buf.close(); + reader.close(); ips.close(); data = request.onDataFromServer(sb.toString()); } catch (Exception e) { diff --git a/core/src/in/srain/cube/uri/CustomizedUri.java b/core/src/in/srain/cube/uri/CustomizedUri.java new file mode 100644 index 0000000..fc7eb6d --- /dev/null +++ b/core/src/in/srain/cube/uri/CustomizedUri.java @@ -0,0 +1,115 @@ +package in.srain.cube.uri; + +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.text.TextUtils; +import in.srain.cube.request.JsonData; + +public class CustomizedUri { + + private static final String KEY = "CUBE_URL"; + private JsonData mQueryData; + private String mPath = null; + private String mQuery = null; + private String mUrl = null; + + public String getPath() { + return mPath; + } + + public String getQueryString() { + return mQuery; + } + + public JsonData getQueryData() { + return mQueryData; + } + + public String getUrl() { + return mUrl; + } + + public static CustomizedUri parse(String url, String customizedSchema) { + if (TextUtils.isEmpty(url)) { + throw new RuntimeException("url is null"); + } + + if (TextUtils.isEmpty(url)) { + throw new RuntimeException("url is null"); + } + + if (!url.startsWith(customizedSchema)) { + return null; + } + return new CustomizedUri(url, customizedSchema.length()); + } + + public void writeToBundle(Intent intent) { + intent.putExtra(KEY, getUrl()); + } + + public static CustomizedUri fromIntent(Intent intent, String schema) { + if (intent == null) { + return null; + } + String url = intent.getStringExtra(KEY); + if (TextUtils.isEmpty(url)) { + return null; + } + return parse(url, schema); + } + + private CustomizedUri(String url, int len) { + mUrl = url; + + // process segment + int pos_seg = url.indexOf('#'); + if (pos_seg > 0) { + url = url.substring(0, pos_seg); + } + + // process query + int pos_sp = url.indexOf('?'); + if (pos_sp > 0) { + mQuery = url.substring(pos_sp + 1); + url = url.substring(0, pos_sp); + } + mPath = url.substring(len); + + if (!TextUtils.isEmpty(mQuery)) { + parseQuery(); + } + } + + private void parseQuery() { + + mQueryData = JsonData.newMap(); + String query = mQuery; + int start = 0; + do { + int nextAmpersand = query.indexOf('&', start); + + // to next & or to the end of String + int end = nextAmpersand != -1 ? nextAmpersand : query.length(); + + // no more key-value + int separator = query.indexOf('=', start); + if (separator > end || separator == -1) { + break; + } + + // make sure key is no empty + if (separator != start) { + mQueryData.put(Uri.decode(query.substring(start, separator)), + Uri.decode(query.substring(separator + 1, end))); + } + // Move start to end of name. + if (nextAmpersand != -1) { + start = nextAmpersand + 1; + } else { + break; + } + } while (true); + } +} diff --git a/core/src/in/srain/cube/util/CLog.java b/core/src/in/srain/cube/util/CLog.java deleted file mode 100755 index 34f97f6..0000000 --- a/core/src/in/srain/cube/util/CLog.java +++ /dev/null @@ -1,128 +0,0 @@ -package in.srain.cube.util; - -import android.util.Log; - -public class CLog { - - public static boolean DEBUG_IMAGE = false; - public static boolean DEBUG_LIST = false; - public static boolean DEBUG_SCROLL_HEADER_FRAME = false; - public static boolean DEBUG_PTR_FRAME = false; - public static boolean DEBUG_REQUEST_CACHE = false; - - public static final int LEVEL_NONE = -1; - public static final int LEVEL_VERBOSE = 0; - public static final int LEVEL_DEBUG = 1; - public static final int LEVEL_INFO = 2; - public static final int LEVEL_WARNING = 3; - public static final int LEVEL_ERROR = 4; - public static final int LEVEL_FATAL = 5; - - private static int sLevel = LEVEL_VERBOSE; - - public void setLogLevel(int level) { - sLevel = level; - } - - public static void v(String tag, String msg) { - if (sLevel >= LEVEL_VERBOSE) { - return; - } - Log.v(tag, msg); - } - - public static void v(String tag, String msg, Object... args) { - if (sLevel >= LEVEL_VERBOSE) { - return; - } - if (args.length > 0) { - msg = String.format(msg, args); - } - v(tag, msg); - } - - public static void d(String tag, String msg) { - if (sLevel >= LEVEL_DEBUG) { - return; - } - Log.d(tag, msg); - } - - public static void d(String tag, String msg, Object... args) { - if (sLevel >= LEVEL_DEBUG) { - return; - } - if (args.length > 0) { - msg = String.format(msg, args); - } - Log.d(tag, msg); - } - - public static void i(String tag, String msg) { - if (sLevel >= LEVEL_INFO) { - return; - } - Log.i(tag, msg); - } - - public static void i(String tag, String msg, Object... args) { - if (sLevel >= LEVEL_INFO) { - return; - } - if (args.length > 0) { - msg = String.format(msg, args); - } - i(tag, msg); - } - - public static void w(String tag, String msg) { - if (sLevel >= LEVEL_WARNING) { - return; - } - Log.w(tag, msg); - } - - public static void w(String tag, String msg, Object... args) { - if (sLevel >= LEVEL_WARNING) { - return; - } - if (args.length > 0) { - msg = String.format(msg, args); - } - w(tag, msg); - } - - public static void e(String tag, String msg) { - if (sLevel >= LEVEL_ERROR) { - return; - } - Log.e(tag, msg); - } - - public static void e(String tag, String msg, Object... args) { - if (sLevel >= LEVEL_ERROR) { - return; - } - if (args.length > 0) { - msg = String.format(msg, args); - } - e(tag, msg); - } - - public static void f(String tag, String msg) { - if (sLevel >= LEVEL_FATAL) { - return; - } - Log.wtf(tag, msg); - } - - public static void f(String tag, String msg, Object... args) { - if (sLevel >= LEVEL_FATAL) { - return; - } - if (args.length > 0) { - msg = String.format(msg, args); - } - f(tag, msg); - } -} diff --git a/core/src/in/srain/cube/util/Debug.java b/core/src/in/srain/cube/util/Debug.java new file mode 100644 index 0000000..ea4eb1f --- /dev/null +++ b/core/src/in/srain/cube/util/Debug.java @@ -0,0 +1,21 @@ +package in.srain.cube.util; + +/** + * Created by srain on 11/3/14. + */ +public class Debug { + public static boolean DEBUG_CACHE = false; + public static boolean DEBUG_IMAGE = false; + + public static String DEBUG_IMAGE_LOG_TAG = "cube_image"; + public static String DEBUG_IMAGE_LOG_TAG_TASK = "cube_image_task"; + public static String DEBUG_IMAGE_LOG_TAG_PROVIDER = "cube_image_provider"; + + public static boolean DEBUG_SCROLL_HEADER_FRAME = false; + public static boolean DEBUG_PAGE_INDICATOR = false; + public static boolean DEBUG_LIST = false; + public static boolean DEBUG_PTR_FRAME = false; + + // print lifecycle information by log tag "cube-lifecycle" + public static boolean DEBUG_LIFE_CYCLE = true; +} diff --git a/core/src/in/srain/cube/util/Env.java b/core/src/in/srain/cube/util/Env.java new file mode 100644 index 0000000..367fbd0 --- /dev/null +++ b/core/src/in/srain/cube/util/Env.java @@ -0,0 +1,30 @@ +package in.srain.cube.util; + +public class Env { + + private static final String ENV_PROD = "prod"; + private static final String ENV_PRE = "pre"; + private static final String ENV_DEV = "dev"; + + private static String sEnvTag = ENV_DEV; + + public static boolean isProd() { + return ENV_PROD.equals(sEnvTag); + } + + public static boolean isPre() { + return ENV_PRE.equals(sEnvTag); + } + + public static boolean isDev() { + return ENV_DEV.equals(sEnvTag); + } + + public static String getEnvTag() { + return sEnvTag; + } + + public static void setEnvTag(String tag) { + sEnvTag = tag; + } +} diff --git a/core/src/in/srain/cube/util/LocalDisplay.java b/core/src/in/srain/cube/util/LocalDisplay.java index 6c9fef3..b497c9c 100755 --- a/core/src/in/srain/cube/util/LocalDisplay.java +++ b/core/src/in/srain/cube/util/LocalDisplay.java @@ -1,7 +1,9 @@ package in.srain.cube.util; +import android.content.Context; import android.util.DisplayMetrics; import android.view.View; +import android.view.WindowManager; public class LocalDisplay { @@ -10,9 +12,16 @@ public class LocalDisplay { public static float SCREEN_DENSITY; public static int SCREEN_WIDTH_DP; public static int SCREEN_HEIGHT_DP; + private static boolean sInitialed; - public static void init(DisplayMetrics dm) { - + public static void init(Context context) { + if (sInitialed || context == null) { + return; + } + sInitialed = true; + DisplayMetrics dm = new DisplayMetrics(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + wm.getDefaultDisplay().getMetrics(dm); SCREEN_WIDTH_PIXELS = dm.widthPixels; SCREEN_HEIGHT_PIXELS = dm.heightPixels; SCREEN_DENSITY = dm.density; @@ -25,11 +34,11 @@ public static int dp2px(float dp) { return (int) (dp * scale + 0.5f); } - public static int designedDP2px(float desingDP) { + public static int designedDP2px(float designedDp) { if (SCREEN_WIDTH_DP != 320) { - desingDP = desingDP * SCREEN_WIDTH_DP / 320f; + designedDp = designedDp * SCREEN_WIDTH_DP / 320f; } - return dp2px(desingDP); + return dp2px(designedDp); } public static void setPadding(final View view, float left, float top, float right, float bottom) { diff --git a/core/src/in/srain/cube/util/ResourceMan.java b/core/src/in/srain/cube/util/ResourceMan.java new file mode 100644 index 0000000..221dc7f --- /dev/null +++ b/core/src/in/srain/cube/util/ResourceMan.java @@ -0,0 +1,16 @@ +package in.srain.cube.util; + +import java.lang.reflect.Field; + +public class ResourceMan { + + public static int getResId(String variableName, Class c) { + try { + Field idField = c.getDeclaredField(variableName); + return idField.getInt(idField); + } catch (Exception e) { + e.printStackTrace(); + return -1; + } + } +} diff --git a/core/src/in/srain/cube/util/Version.java b/core/src/in/srain/cube/util/Version.java index f44437a..9cd9d69 100755 --- a/core/src/in/srain/cube/util/Version.java +++ b/core/src/in/srain/cube/util/Version.java @@ -30,7 +30,7 @@ private Version() { } - @TargetApi(VERSION_CODES.HONEYCOMB) + @TargetApi(11) // @TargetApi(VERSION_CODES.HONEYCOMB) public static void enableStrictMode() { if (Version.hasGingerbread()) { StrictMode.ThreadPolicy.Builder threadPolicyBuilder = new StrictMode.ThreadPolicy.Builder().detectAll().penaltyLog(); @@ -51,41 +51,41 @@ public static void enableStrictMode() { public static boolean hasFroyo() { // Can use static final constants like FROYO, declared in later versions // of the OS since they are inlined at compile time. This is guaranteed behavior. - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO; + return Build.VERSION.SDK_INT >= 8; // VERSION_CODES.FROYO; } /** * API level is or higher than 9 */ public static boolean hasGingerbread() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD; + return Build.VERSION.SDK_INT >= 9; // VERSION_CODES.GINGERBREAD; } /** * API level is or higher than 11 */ public static boolean hasHoneycomb() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB; + return Build.VERSION.SDK_INT >= 11; // VERSION_CODES.HONEYCOMB; } /** * API level is or higher than 12 */ public static boolean hasHoneycombMR1() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR1; + return Build.VERSION.SDK_INT >= 12; // VERSION_CODES.HONEYCOMB_MR1; } /** * API level is or higher than 16 */ public static boolean hasJellyBean() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN; + return Build.VERSION.SDK_INT >= 16; // VERSION_CODES.JELLY_BEAN; } /** * API level is higher than 19 */ public static boolean hasKitKat() { - return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; + return Build.VERSION.SDK_INT >= 19; // VERSION_CODES.KITKAT; } -} +} \ No newline at end of file diff --git a/core/src/in/srain/cube/views/DotView.java b/core/src/in/srain/cube/views/DotView.java index a159919..919df61 100644 --- a/core/src/in/srain/cube/views/DotView.java +++ b/core/src/in/srain/cube/views/DotView.java @@ -7,11 +7,11 @@ import android.util.AttributeSet; import android.view.Gravity; import android.view.View; -import android.view.View.OnClickListener; import android.widget.LinearLayout; import in.srain.cube.R; +import in.srain.cube.views.banner.PagerIndicator; -public class DotView extends LinearLayout implements OnClickListener { +public class DotView extends LinearLayout implements PagerIndicator { public interface OnDotClickHandler { public void onDotClick(int index); @@ -55,6 +55,7 @@ public DotView(Context context, AttributeSet attrs) { mLittleDotSize = (int) (mDotSpan / 2 + mDotRadius * 2); } + @Override public final void setNum(int num) { if (num < 0) return; @@ -72,15 +73,17 @@ public final void setNum(int num) { } dot.setLayoutParams(new LayoutParams((int) mLittleDotSize, (int) mDotRadius * 2, 1)); dot.setClickable(true); - dot.setOnClickListener(this); + dot.setOnClickListener(mDotClickHandler); addView(dot); } } + @Override public int getTotal() { return mTotal; } + @Override public int getCurrentIndex() { return mCurrent; } @@ -89,13 +92,14 @@ public void setOnDotClickHandler(OnDotClickHandler handler) { mOnDotClickHandler = handler; } - @Override - public void onClick(View v) { - - if (v instanceof LittleDot && null != mOnDotClickHandler) { - mOnDotClickHandler.onDotClick(((LittleDot) v).getIndex()); + private OnClickListener mDotClickHandler = new OnClickListener() { + @Override + public void onClick(View v) { + if (v instanceof LittleDot && null != mOnDotClickHandler) { + mOnDotClickHandler.onDotClick(((LittleDot) v).getIndex()); + } } - } + }; public final void setSelected(int index) { if (index >= getChildCount() || index < 0 || mCurrent == index) diff --git a/core/src/in/srain/cube/views/ScrollGallery.java b/core/src/in/srain/cube/views/ScrollGallery.java deleted file mode 100644 index ab9167c..0000000 --- a/core/src/in/srain/cube/views/ScrollGallery.java +++ /dev/null @@ -1,63 +0,0 @@ -package in.srain.cube.views; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.widget.Gallery; - -/** - * A Gallery which can scroll to left or right. - * - * @author huqiu.lhq - * @deprecated As a extend of Gallery, it is deprecated. - */ -@Deprecated -public class ScrollGallery extends Gallery { - - public ScrollGallery(Context context) { - super(context); - } - - public ScrollGallery(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public ScrollGallery(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - private boolean isScrollingLeft(MotionEvent e1, MotionEvent e2) { - return e2.getX() > e1.getX(); - } - - public boolean playNext() { - int current = getSelectedItemPosition(); - int total = computeHorizontalScrollRange(); - if (total > 0 && current < total - 1) { - onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null); - return true; - } - return false; - } - - public boolean playPrevious() { - int current = getSelectedItemPosition(); - int total = computeHorizontalScrollRange(); - if (total > 0 && current > 0) { - onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, null); - return true; - } - return false; - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (isScrollingLeft(e1, e2)) { - playPrevious(); - } else { - playNext(); - } - return true; - } -} diff --git a/core/src/in/srain/cube/views/ScrollHeaderFrame.java b/core/src/in/srain/cube/views/ScrollHeaderFrame.java index 29237fc..0704704 100755 --- a/core/src/in/srain/cube/views/ScrollHeaderFrame.java +++ b/core/src/in/srain/cube/views/ScrollHeaderFrame.java @@ -11,13 +11,14 @@ import android.widget.RelativeLayout; import in.srain.cube.R; import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; /** * @author http://www.liaohuqiu.net */ public class ScrollHeaderFrame extends RelativeLayout { - private static final boolean DEBUG = CLog.DEBUG_SCROLL_HEADER_FRAME; + private static final boolean DEBUG = Debug.DEBUG_SCROLL_HEADER_FRAME; private static final String LOG_TAG = ScrollHeaderFrame.class.getName(); private int mHeaderHeight; @@ -70,6 +71,7 @@ public View getHeaderView() { public void setHandler(IScrollHeaderFrameHandler handler) { mIScrollHeaderFrameHandler = handler; + CLog.d(LOG_TAG, "setHandler: %s", this); } @Override @@ -86,7 +88,7 @@ protected void onFinishInflate() { protected void onLayout(boolean changed, int l, int t, int r, int b) { super.onLayout(changed, l, t, r, b); if (DEBUG) { - Log.d(LOG_TAG, String.format("onLayout: %s, %s %s %s", l, t, r, b)); + Log.d(LOG_TAG, String.format("onLayout: current %s, %s %s %s %s", mCurrentPos, l, t, r, b)); } int headerHeight = mHeaderContainer.getMeasuredHeight(); @@ -96,22 +98,23 @@ protected void onLayout(boolean changed, int l, int t, int r, int b) { int w = getMeasuredWidth(); int h = getMeasuredHeight(); + int pos = 0; - // mHeaderContainer.layout(0, mCurrentPos, w, mCurrentPos + headerHeight); - mContentViewContainer.layout(0, mCurrentPos + headerHeight, w, h); + mHeaderContainer.layout(0, pos, w, pos + headerHeight); + mContentViewContainer.layout(0, pos + headerHeight, w, h + headerHeight); } /** * if deltaY > 0, tryToMove the content down */ - private void tryToMove(float deltaY) { + private boolean tryToMove(float deltaY) { // has reached the bottom if ((deltaY > 0 && mCurrentPos == 0)) { if (DEBUG) { Log.d(LOG_TAG, String.format("has reached the bottom")); } - return; + return false; } // has reached the top @@ -119,7 +122,7 @@ private void tryToMove(float deltaY) { if (DEBUG) { Log.d(LOG_TAG, String.format("has reached the top")); } - return; + return false; } int to = mCurrentPos + (int) deltaY; @@ -139,27 +142,28 @@ private void tryToMove(float deltaY) { } to = 0; } - moveTo(to); + return moveTo(to); } - private void moveTo(int to) { + private boolean moveTo(int to) { if (DEBUG) { Log.d(LOG_TAG, String.format("moveTo: %s %s, %s", to, mCurrentPos, mHeaderHeight)); } if (mCurrentPos == to) { - return; + return false; } + int y = mCurrentPos - to; mCurrentPos = to; - invalidate(); - requestLayout(); updatePos(); + return true; } private void updatePos() { int change = mCurrentPos - mLastPos; - mHeaderContainer.offsetTopAndBottom(change); - mContentViewContainer.offsetTopAndBottom(change); + // mHeaderContainer.scrollTo(0, -change); + // mContentViewContainer.scrollTo(0, -change); + scrollTo(0, -change); } @Override @@ -169,18 +173,16 @@ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int h = getMeasuredHeight(); mHeaderHeight = mHeaderContainer.getMeasuredHeight(); - h = h - (mHeaderHeight + mCurrentPos); - if (DEBUG) { Log.d(LOG_TAG, String.format("onMeasure %s getMeasuredHeight: %s", h, mHeaderContainer.getMeasuredHeight())); } - mContentViewContainer.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY)); + mContentViewContainer.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(h, MeasureSpec.AT_MOST)); } @Override public boolean dispatchTouchEvent(MotionEvent e) { - if (mDisabled) { + if (!isEnabled() || mDisabled) { return super.dispatchTouchEvent(e); } boolean handled = super.dispatchTouchEvent(e); @@ -213,18 +215,21 @@ public boolean dispatchTouchEvent(MotionEvent e) { Log.d(LOG_TAG, String.format("ACTION_MOVE: %s, speed: %s, moveUp: %s, canMoveUp: %s, moveDown: %s, canMoveDown: %s", speed, deltaY, moveUp, canMoveUp, moveDown, canMoveDown)); } - if (speed >= 10 && moveDown && mIScrollHeaderFrameHandler != null) { - moveTo(0); - } // disable move when header not reach top if (moveDown && mIScrollHeaderFrameHandler != null && !mIScrollHeaderFrameHandler.hasReachTop()) { return handled; } + if (speed >= 5 && moveDown && mIScrollHeaderFrameHandler != null) { + moveTo(0); + return handled; + } + if (speed >= 5 && moveUp && mIScrollHeaderFrameHandler != null) { + moveTo(-mHeaderHeight); + return handled; + } + if ((moveUp && canMoveUp) || (moveDown && canMoveDown)) { - if (moveDown && mIScrollHeaderFrameHandler == null) { - deltaY = deltaY * 0.3f; - } tryToMove(deltaY); } break; diff --git a/core/src/in/srain/cube/views/banner/BannerAdapter.java b/core/src/in/srain/cube/views/banner/BannerAdapter.java new file mode 100644 index 0000000..dd4f533 --- /dev/null +++ b/core/src/in/srain/cube/views/banner/BannerAdapter.java @@ -0,0 +1,32 @@ +package in.srain.cube.views.banner; + +import android.support.v4.view.PagerAdapter; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +public abstract class BannerAdapter extends PagerAdapter { + + @Override + public Object instantiateItem(ViewGroup container, int position) { + View view = getView(LayoutInflater.from(container.getContext()), position); + container.addView(view); + return view; + } + + public int getPositionForIndicator(int position) { + return position; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + container.removeView((View) object); + } + + public abstract View getView(LayoutInflater layoutInflater, int position); + + @Override + public boolean isViewFromObject(View view, Object o) { + return view == o; + } +} diff --git a/core/src/in/srain/cube/views/banner/PagerIndicator.java b/core/src/in/srain/cube/views/banner/PagerIndicator.java new file mode 100644 index 0000000..93f29d5 --- /dev/null +++ b/core/src/in/srain/cube/views/banner/PagerIndicator.java @@ -0,0 +1,12 @@ +package in.srain.cube.views.banner; + +public interface PagerIndicator { + + public void setNum(int num); + + public int getTotal(); + + public void setSelected(int index); + + public int getCurrentIndex(); +} diff --git a/core/src/in/srain/cube/views/banner/SliderBanner.java b/core/src/in/srain/cube/views/banner/SliderBanner.java new file mode 100755 index 0000000..df144e7 --- /dev/null +++ b/core/src/in/srain/cube/views/banner/SliderBanner.java @@ -0,0 +1,141 @@ +package in.srain.cube.views.banner; + +import android.content.Context; +import android.content.res.TypedArray; +import android.support.v4.view.ViewPager; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.widget.RelativeLayout; +import in.srain.cube.R; +import in.srain.cube.views.DotView; +import in.srain.cube.views.mix.AutoPlayer; + +public class SliderBanner extends RelativeLayout { + + private ViewPager mViewPager; + private BannerAdapter mBannerAdapter; + private ViewPager.OnPageChangeListener mOnPageChangeListener; + + private PagerIndicator mPagerIndicator; + private AutoPlayer mAutoPlayer; + + protected int mIdForViewPager; + protected int mIdForIndicator; + protected int mTimeInterval = 2000; + + public SliderBanner(Context context) { + this(context, null); + } + + public SliderBanner(Context context, AttributeSet attrs) { + super(context, attrs); + TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.SliderBanner, 0, 0); + if (arr != null) { + if (arr.hasValue(R.styleable.SliderBanner_slider_banner_pager)) { + mIdForViewPager = arr.getResourceId(R.styleable.SliderBanner_slider_banner_pager, 0); + } + if (arr.hasValue(R.styleable.SliderBanner_slider_banner_indicator)) { + mIdForIndicator = arr.getResourceId(R.styleable.SliderBanner_slider_banner_indicator, 0); + } + mTimeInterval = arr.getInt(R.styleable.SliderBanner_slider_banner_time_interval, mTimeInterval); + arr.recycle(); + } + } + + @Override + protected void onFinishInflate() { + mViewPager = (ViewPager) findViewById(mIdForViewPager); + mPagerIndicator = (DotView) findViewById(mIdForIndicator); + + mViewPager.setOnTouchListener(new OnTouchListener() { + @Override + public boolean onTouch(View view, MotionEvent motionEvent) { + requestDisallowInterceptTouchEvent(true); + return false; + } + }); + mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { + @Override + public void onPageScrolled(int i, float v, int i2) { + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrolled(i, v, i2); + } + } + + @Override + public void onPageSelected(int position) { + + if (mPagerIndicator != null) { + mPagerIndicator.setSelected(mBannerAdapter.getPositionForIndicator(position)); + } + mAutoPlayer.skipNext(); + + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageSelected(position); + } + } + + @Override + public void onPageScrollStateChanged(int i) { + if (mOnPageChangeListener != null) { + mOnPageChangeListener.onPageScrollStateChanged(i); + } + } + }); + + mAutoPlayer = new AutoPlayer(mGalleryPlayable).setPlayRecycleMode(AutoPlayer.PlayRecycleMode.play_back); + mAutoPlayer.setTimeInterval(mTimeInterval); + } + + public void setTimeInterval(int interval) { + mAutoPlayer.setTimeInterval(interval); + } + + public void setAdapter(BannerAdapter adapter) { + mBannerAdapter = adapter; + mViewPager.setAdapter(adapter); + } + + public void beginPlay() { + mAutoPlayer.play(); + } + + public void setOnPageChangeListener(ViewPager.OnPageChangeListener listener) { + mOnPageChangeListener = listener; + } + + public void setDotNum(int num) { + if (mPagerIndicator != null) { + mPagerIndicator.setNum(num); + } + } + + private AutoPlayer.Playable mGalleryPlayable = new AutoPlayer.Playable() { + + @Override + public void playTo(int to) { + mViewPager.setCurrentItem(to, true); + } + + @Override + public void playNext() { + mViewPager.setCurrentItem(mViewPager.getCurrentItem() + 1, true); + } + + @Override + public void playPrevious() { + mViewPager.setCurrentItem(mViewPager.getCurrentItem() - 1, true); + } + + @Override + public int getTotal() { + return mBannerAdapter.getCount(); + } + + @Override + public int getCurrent() { + return mViewPager.getCurrentItem(); + } + }; +} diff --git a/core/src/in/srain/cube/views/block/BlockListView.java b/core/src/in/srain/cube/views/block/BlockListView.java index b3ea6ff..0a3425e 100755 --- a/core/src/in/srain/cube/views/block/BlockListView.java +++ b/core/src/in/srain/cube/views/block/BlockListView.java @@ -15,7 +15,7 @@ public interface OnItemClickListener { private static final int INDEX_TAG = 0x04 << 24; - private BlockListAdapter mBlockListAdpater; + private BlockListAdapter mBlockListAdapter; private LayoutInflater mLayoutInflater; @@ -38,23 +38,23 @@ public void setAdapter(BlockListAdapter adapter) { if (adapter == null) { throw new IllegalArgumentException("adapter should not be null"); } - mBlockListAdpater = adapter; + mBlockListAdapter = adapter; adapter.registerView(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); - if (null != mBlockListAdpater) { - mBlockListAdpater.registerView(null); + if (null != mBlockListAdapter) { + mBlockListAdapter.registerView(null); } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - if (null != mBlockListAdpater) { - mBlockListAdpater.registerView(this); + if (null != mBlockListAdapter) { + mBlockListAdapter.registerView(this); } } @@ -73,25 +73,35 @@ public void onClick(View v) { } }; + @Override + protected void onLayout(boolean changed, int l, int t, int r, int b) { + super.onLayout(changed, l, t, r, b); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + public void onDataListChange() { removeAllViews(); - int len = mBlockListAdpater.getCount(); - int w = mBlockListAdpater.getBlockWidth(); - int h = mBlockListAdpater.getBlockHeight(); - int cloumnNum = mBlockListAdpater.getCloumnNum(); + int len = mBlockListAdapter.getCount(); + int w = mBlockListAdapter.getBlockWidth(); + int h = mBlockListAdapter.getBlockHeight(); + int columnNum = mBlockListAdapter.getCloumnNum(); - int horizontalSpacing = mBlockListAdpater.getHorizontalSpacing(); - int verticalSpacing = mBlockListAdpater.getVerticalSpacing(); + int horizontalSpacing = mBlockListAdapter.getHorizontalSpacing(); + int verticalSpacing = mBlockListAdapter.getVerticalSpacing(); boolean blockDescendant = getDescendantFocusability() == ViewGroup.FOCUS_BLOCK_DESCENDANTS; for (int i = 0; i < len; i++) { RelativeLayout.LayoutParams lyp = new RelativeLayout.LayoutParams(w, h); - int row = i / cloumnNum; - int clo = i % cloumnNum; + int row = i / columnNum; + int clo = i % columnNum; int left = 0; int top = 0; @@ -102,12 +112,13 @@ public void onDataListChange() { top = (verticalSpacing + h) * row; } lyp.setMargins(left, top, 0, 0); - View view = mBlockListAdpater.getView(mLayoutInflater, i); + View view = mBlockListAdapter.getView(mLayoutInflater, i); if (!blockDescendant) { view.setOnClickListener(mOnClickListener); } view.setTag(INDEX_TAG, i); addView(view, lyp); } + requestLayout(); } } diff --git a/core/src/in/srain/cube/views/list/ListPageInfo.java b/core/src/in/srain/cube/views/list/ListPageInfo.java index c1df345..e43adfb 100755 --- a/core/src/in/srain/cube/views/list/ListPageInfo.java +++ b/core/src/in/srain/cube/views/list/ListPageInfo.java @@ -7,7 +7,7 @@ public class ListPageInfo { private int mNumPerPage = 0; private int mStart = 0; - private int mTotal; + private boolean mHasMore; private boolean mIsBusy = false; private List mDataList; @@ -17,11 +17,21 @@ public ListPageInfo(int numPerPage) { } public void updateListInfo(List dataList, int total) { + addMore(dataList); + mHasMore = mDataList.size() < total; + mIsBusy = false; + } + + private void addMore(List dataList) { if (mStart == 0 || mDataList == null) { mDataList = new ArrayList(); } mDataList.addAll(dataList); - mTotal = total; + } + + public void updateListInfo(List dataList, boolean hasMore) { + addMore(dataList); + mHasMore = hasMore; mIsBusy = false; } @@ -41,10 +51,6 @@ public int getStart() { return mStart; } - public int getTotal() { - return mTotal; - } - public int getNumPerPage() { return mNumPerPage; } @@ -84,7 +90,7 @@ public int getListLength() { } public boolean hasMore() { - return mDataList == null || mDataList.size() < mTotal; + return mDataList == null || mHasMore; } public boolean isFirstPage() { diff --git a/core/src/in/srain/cube/views/list/ListViewDataAdapter.java b/core/src/in/srain/cube/views/list/ListViewDataAdapter.java index 632ff93..0dfd979 100755 --- a/core/src/in/srain/cube/views/list/ListViewDataAdapter.java +++ b/core/src/in/srain/cube/views/list/ListViewDataAdapter.java @@ -12,6 +12,10 @@ public class ListViewDataAdapter extends ListViewDataAdapterBase mItemDataList = new ArrayList(); + public ListViewDataAdapter() { + + } + /** * @param viewHolderCreator The view holder creator will create a View Holder that extends {@link ViewHolderBase} */ diff --git a/core/src/in/srain/cube/views/list/ListViewDataAdapterBase.java b/core/src/in/srain/cube/views/list/ListViewDataAdapterBase.java index 763e9b4..6d561e5 100755 --- a/core/src/in/srain/cube/views/list/ListViewDataAdapterBase.java +++ b/core/src/in/srain/cube/views/list/ListViewDataAdapterBase.java @@ -1,13 +1,14 @@ package in.srain.cube.views.list; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; -import java.util.HashSet; +import java.lang.reflect.Constructor; +import java.lang.reflect.Modifier; /** * A adapter using View Holder to display the item of a list view; @@ -20,8 +21,16 @@ public abstract class ListViewDataAdapterBase extends BaseAdapter private static String LOG_TAG = "cube_list"; protected ViewHolderCreator mViewHolderCreator; - protected HashSet mCreatedTag = new HashSet(); - private boolean mEnableCreateViewForMeasure = true; + protected ViewHolderCreator mLazyCreator; + protected boolean mForceCreateView = false; + + public ListViewDataAdapterBase() { + + } + + public ListViewDataAdapterBase(final Object enclosingInstance, final Class cls) { + setViewHolderClass(enclosingInstance, cls); + } /** * @param viewHolderCreator The view holder creator will create a View Holder that extends {@link ViewHolderBase} @@ -30,38 +39,88 @@ public ListViewDataAdapterBase(ViewHolderCreator viewHolderCreator mViewHolderCreator = viewHolderCreator; } - public void setEnableCreateViewForMeasure(boolean enable) { - mEnableCreateViewForMeasure = enable; + public void setViewHolderCreator(ViewHolderCreator viewHolderCreator) { + mViewHolderCreator = viewHolderCreator; + } + + public void setViewHolderClass(final Object enclosingInstance, final Class cls) { + if (cls == null) { + throw new IllegalArgumentException("ViewHolderClass is null."); + } + mLazyCreator = new ViewHolderCreator() { + @Override + public ViewHolderBase createViewHolder() { + Object object = null; + try { + // top class + if (cls.getEnclosingClass() == null) { + Constructor constructor = cls.getDeclaredConstructor(); + constructor.setAccessible(true); + object = constructor.newInstance(); + } else { + if (Modifier.isStatic(cls.getModifiers())) { + Constructor constructor = cls.getDeclaredConstructor(); + constructor.setAccessible(true); + object = constructor.newInstance(); + } else { + Constructor constructor = cls.getDeclaredConstructor(enclosingInstance.getClass()); + constructor.setAccessible(true); + object = constructor.newInstance(enclosingInstance); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + if (object == null || !(object instanceof ViewHolderBase)) { + throw new IllegalArgumentException("ViewHolderClass can not be initiated"); + } + return (ViewHolderBase) object; + } + }; + } + + private ViewHolderBase createViewHolder() { + if (mViewHolderCreator == null && mLazyCreator == null) { + throw new RuntimeException("view holder creator is null"); + } + if (mViewHolderCreator != null) { + return mViewHolderCreator.createViewHolder(); + } + if (mLazyCreator != null) { + return mLazyCreator.createViewHolder(); + } + return null; + } + + public void forceCreateView(boolean yes) { + mForceCreateView = yes; } @SuppressWarnings("unchecked") @Override public View getView(int position, View convertView, ViewGroup parent) { - if (mEnableCreateViewForMeasure && convertView == null) { - - } - if (CLog.DEBUG_LIST) { - Log.d(LOG_TAG, String.format("getView %s", position)); + if (Debug.DEBUG_LIST) { + CLog.d(LOG_TAG, "getView %s", position); } ItemDataType itemData = getItem(position); - if (convertView == null) { + ViewHolderBase holderBase = null; + if (mForceCreateView || convertView == null || (!(convertView.getTag() instanceof ViewHolderBase))) { LayoutInflater inflater = LayoutInflater.from(parent.getContext()); - ViewHolderBase holderBase = mViewHolderCreator.createViewHolder(); - + holderBase = createViewHolder(); if (holderBase != null) { convertView = holderBase.createView(inflater); if (convertView != null) { - holderBase.setItemData(position); - holderBase.showData(position, itemData); - convertView.setTag(holderBase); + if (!mForceCreateView) { + convertView.setTag(holderBase); + } } } } else { - ViewHolderBase holderBase = (ViewHolderBase) convertView.getTag(); - if (holderBase != null) { - holderBase.setItemData(position); - holderBase.showData(position, itemData); - } + holderBase = (ViewHolderBase) convertView.getTag(); + } + if (holderBase != null) { + holderBase.setItemData(position, convertView); + holderBase.showData(position, itemData); } return convertView; } diff --git a/core/src/in/srain/cube/views/list/PagedListDataModel.java b/core/src/in/srain/cube/views/list/PagedListDataModel.java index bc013eb..3d2ec34 100755 --- a/core/src/in/srain/cube/views/list/PagedListDataModel.java +++ b/core/src/in/srain/cube/views/list/PagedListDataModel.java @@ -51,6 +51,13 @@ protected void setRequestResult(List list, int total) { } } + protected void setRequestResult(List list, boolean hasMore) { + mListPageInfo.updateListInfo(list, hasMore); + if (null != mPagedListDataHandler) { + mPagedListDataHandler.onPageDataLoaded(mListPageInfo); + } + } + public ListPageInfo getListPageInfo() { return mListPageInfo; } diff --git a/core/src/in/srain/cube/views/list/ViewHolderBase.java b/core/src/in/srain/cube/views/list/ViewHolderBase.java index 8f151ca..a161d9e 100755 --- a/core/src/in/srain/cube/views/list/ViewHolderBase.java +++ b/core/src/in/srain/cube/views/list/ViewHolderBase.java @@ -8,7 +8,7 @@ *

* http://developer.android.com/training/improving-layouts/smooth-scrolling.html *

- * Using A View Holder in Listview getView() method is a good practice in using listview; + * Using A View Holder in ListView getView() method is a good practice in using ListView; *

* This class encapsulate the base operate of a View Holder: createView / showData * @@ -19,6 +19,7 @@ public abstract class ViewHolderBase { protected int mLastPosition; protected int mPosition = -1; + protected View mCurrentView; /** * create a view from resource Xml file, and hold the view that may be used in displaying data. @@ -26,20 +27,20 @@ public abstract class ViewHolderBase { public abstract View createView(LayoutInflater layoutInflater); /** - * using the holed views to display data + * using the held views to display data */ public abstract void showData(int position, ItemDataType itemData); - public void setItemData(int position) { - + public void setItemData(int position, View view) { mLastPosition = mPosition; mPosition = position; + mCurrentView = view; } /** * Check if the View Holder is still display the same data after back to screen. *

- * A view in a listview or gridview may go down the screen and then back, + * A view in a ListView or GridView may go down the screen and then back, *

* for efficiency, in getView() method, a convertView will be reused. *

diff --git a/core/src/in/srain/cube/views/mix/AutoPlayer.java b/core/src/in/srain/cube/views/mix/AutoPlayer.java index a11bc2c..8c2b4a0 100755 --- a/core/src/in/srain/cube/views/mix/AutoPlayer.java +++ b/core/src/in/srain/cube/views/mix/AutoPlayer.java @@ -1,11 +1,7 @@ package in.srain.cube.views.mix; import android.os.Handler; -import android.os.Message; - -import java.lang.ref.WeakReference; -import java.util.Timer; -import java.util.TimerTask; +import android.os.Looper; /** * A player who can play a @Playable object. It can play next till end and play previous till head. @@ -47,40 +43,14 @@ public enum PlayRecycleMode { private int mTimeInterval = 5000; private Playable mPlayable; - private Timer mTimer; - private TimerTask mTimerTask; + private Runnable mTimerTask; private boolean mSkipNext = false; private int mTotal; private boolean mPlaying = false; - private final static int PLAY_NEXT_FRAME = 0x1; - - /** - * Inner Handler to process the thread-cross action. - */ - private static class InnerHandler extends Handler { - WeakReference mPlayer; - - public InnerHandler(AutoPlayer player) { - mPlayer = new WeakReference(player); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case PLAY_NEXT_FRAME: - mPlayer.get().playNextFrame(); - break; - - default: - break; - } - } - } - - public AutoPlayer(Playable playerable) { - mPlayable = playerable; + public AutoPlayer(Playable playable) { + mPlayable = playable; } public void play() { @@ -101,17 +71,17 @@ public void play(int start, PlayDirection direction) { mPlaying = true; playTo(start); - final Handler handler = new InnerHandler(this); - mTimerTask = new TimerTask() { - + final Handler handler = new Handler(Looper.myLooper()); + mTimerTask = new Runnable() { @Override public void run() { - handler.sendEmptyMessage(PLAY_NEXT_FRAME); + playNextFrame(); + if (mPlaying) { + handler.postDelayed(mTimerTask, mTimeInterval); + } } }; - - mTimer = new Timer(); - mTimer.schedule(mTimerTask, mTimeInterval, mTimeInterval); + handler.postDelayed(mTimerTask, mTimeInterval); } public void play(int start) { @@ -124,10 +94,6 @@ public void stop() { } mPlaying = false; - - mTimerTask.cancel(); - mTimer.cancel(); - mTimer = null; } public AutoPlayer setTimeInterval(int timeInterval) { @@ -135,7 +101,7 @@ public AutoPlayer setTimeInterval(int timeInterval) { return this; } - public AutoPlayer setPlayRecycelMode(PlayRecycleMode playRecycleMode) { + public AutoPlayer setPlayRecycleMode(PlayRecycleMode playRecycleMode) { mPlayRecycleMode = playRecycleMode; return this; } diff --git a/core/src/in/srain/cube/views/pager/TabPageIndicator.java b/core/src/in/srain/cube/views/pager/TabPageIndicator.java index 5f0fa5b..e3fd2aa 100755 --- a/core/src/in/srain/cube/views/pager/TabPageIndicator.java +++ b/core/src/in/srain/cube/views/pager/TabPageIndicator.java @@ -26,6 +26,8 @@ import android.view.ViewGroup; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; +import in.srain.cube.util.CLog; +import in.srain.cube.util.Debug; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; @@ -36,6 +38,9 @@ */ public class TabPageIndicator extends HorizontalScrollView implements PageIndicator { + private static final String LOG_TAG = "cube_page_indicator"; + private static final boolean DEBUG = Debug.DEBUG_PAGE_INDICATOR; + /** * Interface for a callback when the selected tab has been reselected. */ @@ -137,7 +142,7 @@ public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final int newWidth = getMeasuredWidth(); if (lockedExpanded && oldWidth != newWidth) { - // Recenter the tab display if we're at a new (scrollable) size. + // Re-center the tab display if we're at a new (scrollable) size. updateTab(mSelectedTabIndex); } } @@ -190,6 +195,9 @@ public void onPageScrolled(int i, float v, int i1) { @Override public void onPageSelected(int i) { + if (DEBUG) { + CLog.d(LOG_TAG, "onPageSelected: %s", i); + } moveToItem(i); } @@ -225,10 +233,8 @@ public void notifyDataSetChanged() { view.setTag(viewHolder); mTabLayout.addView(view, new LinearLayout.LayoutParams(0, MATCH_PARENT, 1)); } - if (mSelectedTabIndex > count) { - mSelectedTabIndex = count - 1; - } - moveToItem(mSelectedTabIndex); + mSelectedTabIndex = mViewPager.getCurrentItem(); + updateTab(mSelectedTabIndex); requestLayout(); } @@ -239,14 +245,22 @@ public void setViewPager(ViewPager view, int initialPosition) { } public void moveToItem(int item) { + if (DEBUG) { + CLog.d(LOG_TAG, "moveToItem: %s", item); + } if (mViewPager == null) { throw new IllegalStateException("ViewPager has not been bound."); } if (mSelectedTabIndex == item) { - return; + // return; } mSelectedTabIndex = item; + + // will lead to call moveToItem again, but will not hit here :) mViewPager.setCurrentItem(item); + if (DEBUG) { + CLog.d(LOG_TAG, "mViewPager.setCurrentItem: %s", item); + } if (mListener != null) { mListener.onPageSelected(item); } diff --git a/core/src/in/srain/cube/views/ptr/PtrFrame.java b/core/src/in/srain/cube/views/ptr/PtrFrame.java deleted file mode 100755 index 2507920..0000000 --- a/core/src/in/srain/cube/views/ptr/PtrFrame.java +++ /dev/null @@ -1,508 +0,0 @@ -package in.srain.cube.views.ptr; - -import android.content.Context; -import android.content.res.TypedArray; -import android.graphics.PointF; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewGroup; -import android.view.animation.LinearInterpolator; -import android.view.animation.RotateAnimation; -import android.widget.RelativeLayout; -import android.widget.Scroller; -import in.srain.cube.R; -import in.srain.cube.util.CLog; -import in.srain.cube.util.Version; - -public class PtrFrame extends RelativeLayout { - - private static final boolean DEBUG = CLog.DEBUG_PTR_FRAME; - private static int ID = 1; - private final String LOG_TAG = "PtrFrame" + ++ID; - - // =========================================================== - // Interface - // =========================================================== - public interface PtrHandler { - /** - * if content is empty or the first child is in view, should do refresh - * after release - */ - public boolean checkCanDoRefresh(); - - public void onRefresh(); - - public void onBackToTop(); - - public void onRelease(); - - public void crossRotateLineFromTop(boolean isInTouching); - - public void crossRotateLineFromBottom(boolean isInTouching); - } - - // =========================================================== - // enumeration - // =========================================================== - public enum State { - FREE, PREPARE_REFRESH - } - - // =========================================================== - // Fields - // =========================================================== - private int mHeaderId = 0; - private int mContainerId = 0; - private int mRotateViewId = 0; - - private float mResistance = 1.5f; - - private int mDurationClose = 300; - private int mDurationToCloseHeader = 300; - private int mRotateAniTime = 150; - - private float mRatioOfHeaderToRotate = 1.5f; - private float mRatioOfHeaderToRefresh = 1.5f; - private boolean mKeepHeaderWhenRefresh = false; - - private int mOffsetToRotateView = 0; - private int mOffsetToRefresh = 0; - - private RotateAnimation mFlipAnimation; - private RotateAnimation mReverseFlipAnimation; - - protected View mRotateView; - protected View mHeaderContainer; - protected ViewGroup mContentViewContainer; - - private State mState; - private int mHeaderHeight; - - private ScrollChecker mScrollChecker; - - private int mCurrentPos = 0; - private int mLastPos = 0; - private int mPagingTouchSlop; - - private PtrHandler mPtrHandler; - - private PointF mPtLastMove = new PointF(); - - private boolean mIsRefreshing = false; - private boolean mPreventForHorizontal = false; - private boolean mIsInTouching = false; - - public PtrFrame(Context context) { - this(context, null); - } - - public PtrFrame(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public PtrFrame(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - - if (DEBUG) { - CLog.d(LOG_TAG, "PtrFrame(Context context, AttributeSet attrs, int defStyle)"); - } - - TypedArray arr = context.obtainStyledAttributes(attrs, R.styleable.PtrFrame, 0, 0); - if (arr != null) { - - mHeaderId = arr.getResourceId(R.styleable.PtrFrame_ptr_header, mHeaderId); - mContainerId = arr.getResourceId(R.styleable.PtrFrame_ptr_content, mContainerId); - mRotateViewId = arr.getResourceId(R.styleable.PtrFrame_ptr_rotate_view, mRotateViewId); - - mResistance = arr.getFloat(R.styleable.PtrFrame_ptr_resistance, mResistance); - - mDurationClose = arr.getInt(R.styleable.PtrFrame_ptr_duration_to_close, mDurationClose); - mDurationToCloseHeader = arr.getInt(R.styleable.PtrFrame_ptr_duration_to_close_header, mDurationToCloseHeader); - mRotateAniTime = arr.getInt(R.styleable.PtrFrame_ptr_rotate_ani_time, mRotateAniTime); - - mRatioOfHeaderToRotate = arr.getFloat(R.styleable.PtrFrame_ptr_ratio_of_header_to_rotate, mRatioOfHeaderToRotate); - mRatioOfHeaderToRefresh = arr.getFloat(R.styleable.PtrFrame_ptr_ratio_of_header_to_refresh, mRatioOfHeaderToRefresh); - mKeepHeaderWhenRefresh = arr.getBoolean(R.styleable.PtrFrame_ptr_keep_header_when_refresh, mKeepHeaderWhenRefresh); - arr.recycle(); - } - - mScrollChecker = new ScrollChecker(); - - final ViewConfiguration conf = ViewConfiguration.get(getContext()); - mPagingTouchSlop = conf.getScaledTouchSlop() * 2; - - setDrawingCacheEnabled(false); - setBackgroundDrawable(null); - setClipChildren(false); - - mFlipAnimation = new RotateAnimation(0, -180, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); - mFlipAnimation.setInterpolator(new LinearInterpolator()); - mFlipAnimation.setDuration(mRotateAniTime); - mFlipAnimation.setFillAfter(true); - - mReverseFlipAnimation = new RotateAnimation(-180, 0, RotateAnimation.RELATIVE_TO_SELF, 0.5f, RotateAnimation.RELATIVE_TO_SELF, 0.5f); - mReverseFlipAnimation.setInterpolator(new LinearInterpolator()); - mReverseFlipAnimation.setDuration(mRotateAniTime); - mReverseFlipAnimation.setFillAfter(true); - } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - - if (mHeaderId != 0) { - mHeaderContainer = findViewById(mHeaderId); - } - if (mContainerId != 0) { - mContentViewContainer = (ViewGroup) findViewById(mContainerId); - } - if (mRotateViewId != 0) { - mRotateView = findViewById(mRotateViewId); - } - - if (DEBUG) { - CLog.d(LOG_TAG, "onFinishInflate"); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - - if (mHeaderContainer != null && mHeaderHeight != mHeaderContainer.getMeasuredHeight()) { - mHeaderHeight = mHeaderContainer.getMeasuredHeight(); - mCurrentPos = mHeaderContainer.getBottom(); - mOffsetToRotateView = (int) (mHeaderHeight * mRatioOfHeaderToRotate); - mOffsetToRefresh = (int) (mHeaderHeight * mRatioOfHeaderToRefresh); - } - - if (DEBUG) { - CLog.d(LOG_TAG, "onMeasure, mHeaderHeight: %s, mCurrentPos: %s", mHeaderHeight, mCurrentPos); - } - } - - @Override - protected void onLayout(boolean flag, int i, int j, int k, int l) { - - int w = getMeasuredWidth(); - int h = getMeasuredHeight(); - - if (DEBUG) { - CLog.d(LOG_TAG, "onLayout mHeaderHeight: %s, mCurrentPos: %s", mHeaderHeight, mCurrentPos); - } - - if (Version.hasHoneycomb()) { - if (mHeaderContainer != null) { - mHeaderContainer.layout(0, -mHeaderHeight + mCurrentPos, w, mCurrentPos); - } - if (mContentViewContainer != null) { - mContentViewContainer.layout(0, mCurrentPos, w, h + mCurrentPos); - } - } else { - if (mHeaderContainer != null) { - mHeaderContainer.layout(0, -mHeaderHeight + mCurrentPos, w, mCurrentPos); - } - if (mContentViewContainer != null) { - mContentViewContainer.layout(0, mCurrentPos, w, h + mCurrentPos); - } - // FrameLayout.LayoutParams lyp1 = new LayoutParams(w, mHeaderHeight); - // mHeaderContainer.setLayoutParams(lyp1); - - // FrameLayout.LayoutParams lyp2 = new LayoutParams(w, h - mHeaderHeight); - // lyp2.setMargins(0, mHeaderHeight, 0, 0); - // mHeaderContainer.setLayoutParams(lyp2); - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent e) { - int action = e.getAction(); - switch (action) { - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mIsInTouching = false; - if (mCurrentPos > 0) { - release(); - return true; - } else { - return super.dispatchTouchEvent(e); - } - - case MotionEvent.ACTION_DOWN: - mIsInTouching = true; - mPtLastMove.set(e.getX(), e.getY()); - mPreventForHorizontal = false; - return super.dispatchTouchEvent(e); - - case MotionEvent.ACTION_MOVE: - float offsetX = e.getX() - mPtLastMove.x; - float offsetY = (int) (e.getY() - mPtLastMove.y); - mPtLastMove.set(e.getX(), e.getY()); - if (!mPreventForHorizontal && (Math.abs(offsetX) > mPagingTouchSlop || Math.abs(offsetX) > 2 * Math.abs(offsetY))) { - if (frameIsMoved()) { - mPreventForHorizontal = true; - } - } - if (mPreventForHorizontal) { - return super.dispatchTouchEvent(e); - } - - mScrollChecker.abortIfWorking(); - - boolean moveDown = offsetY > 0; - boolean moveUp = !moveDown; - boolean canMoveUp = mCurrentPos > 0; - - if (DEBUG) { - // CLog.d(LOG_TAG, "ACTION_MOVE: offsetY:%s, mCurrentPos: %s, moveUp: %s, canMoveUp: %s, moveDown: %s", offsetY, mCurrentPos, moveUp, canMoveUp, moveDown); - } - - // disable move when header not reach top - if (moveDown && mPtrHandler != null && !mPtrHandler.checkCanDoRefresh()) { - return super.dispatchTouchEvent(e); - } - - if ((moveUp && canMoveUp) || moveDown) { - offsetY = (float) ((double) offsetY / mResistance); - movePos(offsetY); - return true; - } - } - return super.dispatchTouchEvent(e); - } - - /** - * if deltaY > 0, move the content down - */ - private void movePos(float deltaY) { - // has reached the top - if ((deltaY < 0 && mCurrentPos == 0)) { - if (DEBUG) { - CLog.e(LOG_TAG, String.format("has reached the top")); - } - return; - } - - int to = mCurrentPos + (int) deltaY; - - // over top - if (to < 0) { - if (DEBUG) { - CLog.e(LOG_TAG, String.format("over top")); - } - to = 0; - } - - mCurrentPos = to; - updatePos(); - mLastPos = mCurrentPos; - } - - private void updatePos() { - int change = mCurrentPos - mLastPos; - // if (Version.hasHoneycomb()) { - // mHeaderContainer.offsetTopAndBottom(change); - // mContentViewContainer.offsetTopAndBottom(change); - // } else { - // mHeaderContainer.setPadding(0, mCurrentPos, 0, 0); - // mContentViewContainer.setPadding(0, mCurrentPos, 0, 0); - // } - RelativeLayout.LayoutParams lyp = (LayoutParams) mHeaderContainer.getLayoutParams(); - lyp.setMargins(0, mCurrentPos, 0, 0); - ((LayoutParams) mContentViewContainer.getLayoutParams()).setMargins(0, mCurrentPos, 0, 0); - requestLayout(); - - if (mCurrentPos < mOffsetToRotateView && mLastPos >= mOffsetToRotateView) { - if (null != mPtrHandler) { - mPtrHandler.crossRotateLineFromBottom(mIsInTouching); - } - if (mRotateView != null) { - mRotateView.clearAnimation(); - if (mIsInTouching) { - mRotateView.startAnimation(mReverseFlipAnimation); - } - } - } else if (mCurrentPos > mOffsetToRotateView && mLastPos <= mOffsetToRotateView) { - if (null != mPtrHandler) { - mPtrHandler.crossRotateLineFromTop(mIsInTouching); - } - if (mRotateView != null) { - mRotateView.clearAnimation(); - if (mIsInTouching) { - mRotateView.startAnimation(mFlipAnimation); - } - } - } - invalidate(); - onUpdatePos(mLastPos, mCurrentPos); - } - - protected void onUpdatePos(int last, int now) { - - } - - private void release() { - if (mPtrHandler != null) { - mPtrHandler.onRelease(); - } - if (mCurrentPos >= mOffsetToRefresh) { - mState = State.PREPARE_REFRESH; - } - if (mKeepHeaderWhenRefresh && mCurrentPos >= mOffsetToRefresh) { - mScrollChecker.scrollTo(mHeaderHeight, mDurationClose); - } else { - mScrollChecker.scrollTo(0, mDurationClose); - } - } - - private void notifyRefresh() { - if (mPtrHandler != null && !mIsRefreshing) { - mIsRefreshing = true; - mPtrHandler.onRefresh(); - } - } - - private void notifyBackToTop() { - if (mPtrHandler != null) { - mPtrHandler.onBackToTop(); - } - } - - private void notifyScrollFinish() { - if (mState == State.PREPARE_REFRESH) { - mState = State.FREE; - notifyRefresh(); - } - if (mCurrentPos == 0) { - notifyBackToTop(); - } - } - - private boolean frameIsMoved() { - return mLastPos == -mHeaderHeight; - } - - public void refreshComplete() { - if (mIsRefreshing) { - mIsRefreshing = false; - if (mKeepHeaderWhenRefresh) { - mScrollChecker.scrollTo(0, mDurationToCloseHeader); - } - } - } - - public void doRefresh() { - int deltaY = mHeaderHeight - mCurrentPos; - movePos(deltaY); - notifyRefresh(); - } - - public void reset() { - mIsRefreshing = false; - } - - public View getContent() { - return mContentViewContainer; - } - - public void setPtrHandler(PtrHandler ptrHandler) { - mPtrHandler = ptrHandler; - } - - public void setRotateView(int id) { - mRotateView = findViewById(id); - } - - public void setRotateView(View view) { - mRotateView = view; - } - - public void setResistance(float resistance) { - mResistance = resistance; - } - - public void setDurationClose(int duration) { - mDurationClose = duration; - } - - public void setDurationToCloseHeader(int duration) { - mDurationToCloseHeader = duration; - } - - public void setKeepHeaderWhenRefresh(boolean keepOrNot) { - mKeepHeaderWhenRefresh = keepOrNot; - } - - class ScrollChecker implements Runnable { - - private int mLastFlingY; - private Scroller mScroller; - private boolean mIsRunning = false; - private int mStart; - private int mTo; - - public ScrollChecker() { - mScroller = new android.widget.Scroller(getContext()); - } - - public void run() { - boolean finish = !mScroller.computeScrollOffset() || mScroller.isFinished(); - int curY = mScroller.getCurrY(); - int deltaY = curY - mLastFlingY; - if (DEBUG) { - // CLog.d(LOG_TAG, "scroll: %s, start: %s, to: %s, mCurrentPos: %s, current :%s, last: %s, delta: %s", finish, mStart, mTo, mCurrentPos, curY, mLastFlingY, deltaY); - } - if (!finish) { - mLastFlingY = curY; - movePos(deltaY); - post(this); - } else { - finish(); - } - } - - private void finish() { - if (DEBUG) { - // CLog.d(LOG_TAG, "finish, mCurrentPos:%s", mCurrentPos); - } - reset(); - notifyScrollFinish(); - } - - private void reset() { - mIsRunning = false; - mLastFlingY = 0; - removeCallbacks(this); - } - - public void abortIfWorking() { - if (mIsRunning) { - if (!mScroller.isFinished()) { - mScroller.forceFinished(true); - } - reset(); - } - } - - public void scrollTo(int to, int duration) { - mStart = mCurrentPos; - mTo = to; - int distance = to - mStart; - if (DEBUG) { - CLog.d(LOG_TAG, "scrollTo: start: %s, distance:%s, to:%s", mStart, distance, to); - } - if (mCurrentPos == 0) { - return; - } - removeCallbacks(this); - - mLastFlingY = 0; - mScroller = new android.widget.Scroller(getContext()); - mScroller.startScroll(0, 0, 0, distance, duration); - post(this); - mIsRunning = true; - } - } -} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..23beb69 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,4 @@ +ANDROID_BUILD_MIN_SDK_VERSION=8 +ANDROID_BUILD_TARGET_SDK_VERSION=16 +ANDROID_BUILD_SDK_VERSION=16 +ANDROID_BUILD_TOOLS_VERSION=20.0.0 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..0087cd3 Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..71cce15 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Wed Dec 03 16:32:39 CST 2014 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..91a7e26 --- /dev/null +++ b/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/pom.xml b/pom.xml index f5ac370..1abc144 100644 --- a/pom.xml +++ b/pom.xml @@ -11,54 +11,10 @@ in.srain cube-parent - 1.1.1-SNAPSHOT + 1.1.1 pom Cube SDK Parent - Cube SDK, library for Android development - http://cube-sdk.liaohuqiu.net - 2014 - - - core - - - - https://github.com/etao-open-source/cube-sdk - scm:git:git:@github.com:etao-open-source/cube-sdk.git - scm:git:git@github.com:etao-open-source/cube-sdk.git - - - - - Huqiu Liao - liaohuqiu@gmail.com - liaohuqiu - http://www.liaohuqiu.net - +8 - - developer - - - - - - - Apache License Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - repo - - - - - Huqiu Liao - http://www.liaohuqiu.net - - - - GitHub Issues - https://github.com/etao-open-source/cube-sdk/issues - UTF-8 diff --git a/sample-and-tests/.settings/org.eclipse.core.resources.prefs b/sample-and-tests/.settings/org.eclipse.core.resources.prefs deleted file mode 100755 index 99f26c0..0000000 --- a/sample-and-tests/.settings/org.eclipse.core.resources.prefs +++ /dev/null @@ -1,2 +0,0 @@ -eclipse.preferences.version=1 -encoding/=UTF-8 diff --git a/sample-and-tests/.settings/org.eclipse.jdt.core.prefs b/sample-and-tests/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 107056a..0000000 --- a/sample-and-tests/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,12 +0,0 @@ -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/sample-and-tests/AndroidManifest.xml b/sample-and-tests/AndroidManifest.xml deleted file mode 100755 index 0152457..0000000 --- a/sample-and-tests/AndroidManifest.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/assets/request_init/demo/image-list.json b/sample-and-tests/assets/request_init/demo/image-list.json deleted file mode 100644 index a47eba8..0000000 --- a/sample-and-tests/assets/request_init/demo/image-list.json +++ /dev/null @@ -1 +0,0 @@ -{"data":{"time":"2014-08-27 02:13:01 UTC","list":[{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201311\/04\/20131104193715_NCexN.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201408\/09\/20140809210610_iTSJx.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/blog\/201401\/07\/20140107223310_LH3Uy.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201405\/09\/20140509222156_kVexJ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201306\/14\/20130614185903_raNR3.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201112\/11\/20111211191621_HU4Bj.thumb.jpg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201408\/07\/20140807224553_VXaUc.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/29\/20140729105929_GQLwC.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201408\/04\/20140804160432_LnFeB.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201408\/04\/20140804161101_JVJea.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/blog\/201408\/04\/20140804093210_FxFNd.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201408\/04\/20140804160314_hRKtv.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201408\/01\/20140801080524_SnGfE.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/23\/20140723140958_NSWfE.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/22\/20140722153305_WHejQ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/21\/20140721010148_ZBQwe.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201407\/23\/20140723085122_cmteu.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/23\/20140723130620_Z2yJB.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/blog\/201407\/20\/20140720204738_NXxLE.thumb.jpeg"},{"pic":"http:\/\/cdn.duitang.com\/uploads\/item\/201407\/20\/20140720134916_VGfyh.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717113117_mUssJ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717121501_wfFEm.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717121431_w4AV8.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717121918_TtJjY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/11\/20140711234806_FNLBQ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/18\/20140718121437_UyiAS.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/17\/20140717114829_RiCXR.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/17\/20140717120301_wGFYL.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/11\/20140511121106_JXS4B.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/10\/20140510094144_kfLji.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/09\/20140509201906_kERjy.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/08\/20140508193226_UaSGB.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201405\/05\/20140505201747_aPNtf.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/06\/20140506104824_jPWQj.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/05\/20140505201105_MkXdn.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/03\/20140503205822_GCzta.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/03\/20140503205535_cCHPB.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201405\/03\/20140503204354_xxSQX.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191307_GTxFd.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191247_BG2cU.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191114_MzYtw.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201404\/06\/20140406191127_fazJA.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/10\/20140710081204_vYnCi.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/15\/20140715133758_M2Y3J.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201407\/13\/20140713190806_TGJHm.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/05\/20140705223413_5r3ze.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/13\/20140713012526_tcy5u.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/13\/20140713121424_Gy43T.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201407\/15\/20140715033844_tcvrY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/10\/20140710181106_4HHay.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/06\/20140706122850_8PER3.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/07\/20140707192042_8xKXF.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/07\/20140707063954_mVa3y.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201407\/08\/20140708093733_AFFhc.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201407\/07\/20140707161220_unvzn.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201407\/07\/20140707113856_hBf3R.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201308\/26\/20130826090203_NtuYA.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201407\/07\/20140707145925_dHeKV.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625101534_xiZxN.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201406\/30\/20140630150534_EWUVY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625121626_ZmT5n.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/blog\/201307\/31\/20130731231806_4yGxV.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/28\/20140628122218_fLQyP.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201406\/26\/20140626131831_MrdKP.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/blog\/201406\/16\/20140616165201_nuKWj.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625140308_KP4rn.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625121604_2auuA.thumb.jpeg"},{"pic":"http:\/\/img4.duitang.com\/uploads\/item\/201406\/25\/20140625131625_LmmLZ.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625132851_mPmKY.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625133312_ZtmW4.thumb.jpeg"},{"pic":"http:\/\/img5.duitang.com\/uploads\/item\/201406\/25\/20140625164858_AuafS.thumb.jpeg"}]},"server_time":"2014-08-27 02:13:01"} \ No newline at end of file diff --git a/sample-and-tests/ic_launcher-web.png b/sample-and-tests/ic_launcher-web.png deleted file mode 100644 index a18cbb4..0000000 Binary files a/sample-and-tests/ic_launcher-web.png and /dev/null differ diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpClient.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpClient.java deleted file mode 100644 index 05b420f..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpClient.java +++ /dev/null @@ -1,805 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -package com.loopj.android.http; - -import java.io.IOException; -import java.io.InputStream; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.zip.GZIPInputStream; - -import org.apache.http.Header; -import org.apache.http.HeaderElement; -import org.apache.http.HttpEntity; -import org.apache.http.HttpRequest; -import org.apache.http.HttpRequestInterceptor; -import org.apache.http.HttpResponse; -import org.apache.http.HttpResponseInterceptor; -import org.apache.http.HttpVersion; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CookieStore; -import org.apache.http.client.HttpClient; -import org.apache.http.client.methods.HttpDelete; -import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpPut; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.client.protocol.ClientContext; -import org.apache.http.conn.params.ConnManagerParams; -import org.apache.http.conn.params.ConnPerRouteBean; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.entity.HttpEntityWrapper; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.BasicHttpContext; -import org.apache.http.protocol.HttpContext; -import org.apache.http.protocol.SyncBasicHttpContext; - -import android.content.Context; -import android.util.Log; - -/** - * The AsyncHttpClient can be used to make asynchronous GET, POST, PUT and - * DELETE HTTP requests in your Android applications. Requests can be made with - * additional parameters by passing a {@link RequestParams} instance, and - * responses can be handled by passing an anonymously overridden - * {@link AsyncHttpResponseHandler} instance. - *

- * For example: - *

- * - *

- * AsyncHttpClient client = new AsyncHttpClient();
- * client.get("http://www.google.com", new AsyncHttpResponseHandler() {
- * 	@Override
- * 	public void onSuccess(String response) {
- * 		System.out.println(response);
- * 	}
- * });
- * 
- */ -public class AsyncHttpClient { - private static final String VERSION = "1.4.3"; - - private static final int DEFAULT_MAX_CONNECTIONS = 10; - private static final int DEFAULT_SOCKET_TIMEOUT = 10 * 1000; - private static final int DEFAULT_MAX_RETRIES = 5; - private static final int DEFAULT_SOCKET_BUFFER_SIZE = 8192; - private static final String HEADER_ACCEPT_ENCODING = "Accept-Encoding"; - private static final String ENCODING_GZIP = "gzip"; - - private static int maxConnections = DEFAULT_MAX_CONNECTIONS; - private static int socketTimeout = DEFAULT_SOCKET_TIMEOUT; - - private final DefaultHttpClient httpClient; - private final HttpContext httpContext; - private ThreadPoolExecutor threadPool; - private final Map>>> requestMap; - private final Map clientHeaderMap; - - public final ArrayList httpRequests; - - /** - * Creates a new AsyncHttpClient. - */ - public AsyncHttpClient() { - BasicHttpParams httpParams = new BasicHttpParams(); - - ConnManagerParams.setTimeout(httpParams, socketTimeout); - ConnManagerParams.setMaxConnectionsPerRoute(httpParams, - new ConnPerRouteBean(maxConnections)); - ConnManagerParams.setMaxTotalConnections(httpParams, - DEFAULT_MAX_CONNECTIONS); - - HttpConnectionParams.setSoTimeout(httpParams, socketTimeout); - HttpConnectionParams.setConnectionTimeout(httpParams, socketTimeout); - HttpConnectionParams.setTcpNoDelay(httpParams, true); - HttpConnectionParams.setSocketBufferSize(httpParams, - DEFAULT_SOCKET_BUFFER_SIZE); - - HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1); - HttpProtocolParams.setUserAgent(httpParams, String.format( - "android-async-http/%s (http://loopj.com/android-async-http)", - VERSION)); - - SchemeRegistry schemeRegistry = new SchemeRegistry(); - schemeRegistry.register(new Scheme("http", PlainSocketFactory - .getSocketFactory(), 80)); - schemeRegistry.register(new Scheme("https", SSLSocketFactory - .getSocketFactory(), 443)); - ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager( - httpParams, schemeRegistry); - - httpContext = new SyncBasicHttpContext(new BasicHttpContext()); - httpClient = new DefaultHttpClient(cm, httpParams); - httpClient.addRequestInterceptor(new HttpRequestInterceptor() { - public void process(HttpRequest request, HttpContext context) { - if (!request.containsHeader(HEADER_ACCEPT_ENCODING)) { - request.addHeader(HEADER_ACCEPT_ENCODING, ENCODING_GZIP); - } - for (String header : clientHeaderMap.keySet()) { - request.addHeader(header, clientHeaderMap.get(header)); - } - } - }); - - httpClient.addResponseInterceptor(new HttpResponseInterceptor() { - public void process(HttpResponse response, HttpContext context) { - final HttpEntity entity = response.getEntity(); - if (entity == null) { - return; - } - final Header encoding = entity.getContentEncoding(); - if (encoding != null) { - for (HeaderElement element : encoding.getElements()) { - if (element.getName().equalsIgnoreCase(ENCODING_GZIP)) { - response.setEntity(new InflatingEntity(response - .getEntity())); - break; - } - } - } - } - }); - - httpClient.setHttpRequestRetryHandler(new RetryHandler( - DEFAULT_MAX_RETRIES)); - - threadPool = (ThreadPoolExecutor) Executors.newCachedThreadPool(); - - requestMap = new WeakHashMap>>>(); - clientHeaderMap = new HashMap(); - httpRequests = new ArrayList(); - } - - /** - * Get the underlying HttpClient instance. This is useful for setting - * additional fine-grained settings for requests by accessing the client's - * ConnectionManager, HttpParams and SchemeRegistry. - */ - public HttpClient getHttpClient() { - return this.httpClient; - } - - /** - * Get the underlying HttpContext instance. This is useful for getting and - * setting fine-grained settings for requests by accessing the context's - * attributes such as the CookieStore. - */ - public HttpContext getHttpContext() { - return this.httpContext; - } - - /** - * Sets an optional CookieStore to use when making requests - * - * @param cookieStore - * The CookieStore implementation to use, usually an instance of - * {@link PersistentCookieStore} - */ - public void setCookieStore(CookieStore cookieStore) { - httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore); - } - - /** - * Overrides the threadpool implementation used when queuing/pooling - * requests. By default, Executors.newCachedThreadPool() is used. - * - * @param threadPool - * an instance of {@link ThreadPoolExecutor} to use for - * queuing/pooling requests. - */ - public void setThreadPool(ThreadPoolExecutor threadPool) { - this.threadPool = threadPool; - } - - /** - * Sets the User-Agent header to be sent with each request. By default, - * "Android Asynchronous Http Client/VERSION (http://loopj.com/android-async-http/)" - * is used. - * - * @param userAgent - * the string to use in the User-Agent header. - */ - public void setUserAgent(String userAgent) { - HttpProtocolParams.setUserAgent(this.httpClient.getParams(), userAgent); - } - - /** - * Sets the connection time oout. By default, 10 seconds - * - * @param timeout - * the connect/socket timeout in milliseconds - */ - public void setTimeout(int timeout) { - final HttpParams httpParams = this.httpClient.getParams(); - ConnManagerParams.setTimeout(httpParams, timeout); - HttpConnectionParams.setSoTimeout(httpParams, timeout); - HttpConnectionParams.setConnectionTimeout(httpParams, timeout); - } - - /** - * Sets the SSLSocketFactory to user when making requests. By default, a - * new, default SSLSocketFactory is used. - * - * @param sslSocketFactory - * the socket factory to use for https requests. - */ - public void setSSLSocketFactory(SSLSocketFactory sslSocketFactory) { - this.httpClient.getConnectionManager().getSchemeRegistry() - .register(new Scheme("https", sslSocketFactory, 443)); - } - - /** - * Sets headers that will be added to all requests this client makes (before - * sending). - * - * @param header - * the name of the header - * @param value - * the contents of the header - */ - public void addHeader(String header, String value) { - clientHeaderMap.put(header, value); - } - - /** - * Sets basic authentication for the request. Uses AuthScope.ANY. This is - * the same as setBasicAuth('username','password',AuthScope.ANY) - * - * @param username - * @param password - */ - public void setBasicAuth(String user, String pass) { - AuthScope scope = AuthScope.ANY; - setBasicAuth(user, pass, scope); - } - - /** - * Sets basic authentication for the request. You should pass in your - * AuthScope for security. It should be like this - * setBasicAuth("username","password", new - * AuthScope("host",port,AuthScope.ANY_REALM)) - * - * @param username - * @param password - * @param scope - * - an AuthScope object - * - */ - public void setBasicAuth(String user, String pass, AuthScope scope) { - UsernamePasswordCredentials credentials = new UsernamePasswordCredentials( - user, pass); - this.httpClient.getCredentialsProvider().setCredentials(scope, - credentials); - } - - /** - * Cancels any pending (or potentially active) requests associated with the - * passed Context. - *

- * Note: This will only affect requests which were created with a - * non-null android Context. This method is intended to be used in the - * onDestroy method of your android activities to destroy all requests which - * are no longer required. - * - * @param context - * the android Context instance associated to the request. - * @param mayInterruptIfRunning - * specifies if active requests should be cancelled along with - * pending requests. - */ - public void cancelRequests(Context context, boolean mayInterruptIfRunning) { - List>> requestList = requestMap.get(context); - if (requestList != null) { - for (WeakReference> requestRef : requestList) { - Future request = requestRef.get(); - if (request != null) { - request.cancel(mayInterruptIfRunning); - } - } - } - requestMap.remove(context); - } - - // - // HTTP GET Requests - // - - /** - * Perform a HTTP GET request, without any parameters. - * - * @param url - * the URL to send the request to. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest get(String url, - AsyncHttpResponseHandler responseHandler) { - return get(null, url, null, responseHandler); - } - - /** - * Perform a HTTP GET request with parameters. - * - * @param url - * the URL to send the request to. - * @param params - * additional GET parameters to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void get(String url, RequestParams params, - AsyncHttpResponseHandler responseHandler) { - get(null, url, params, responseHandler); - } - - /** - * Perform a HTTP GET request without any parameters and track the Android - * Context which initiated the request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void get(Context context, String url, - AsyncHttpResponseHandler responseHandler) { - get(context, url, null, responseHandler); - } - - /** - * Perform a HTTP GET request and track the Android Context which initiated - * the request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param params - * additional GET parameters to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest get(Context context, String url, - RequestParams params, AsyncHttpResponseHandler responseHandler) { - return sendRequest(httpClient, httpContext, new HttpGet( - getUrlWithQueryString(url, params)), null, responseHandler, - context); - } - - /** - * Perform a HTTP GET request and track the Android Context which initiated - * the request with customized headers - * - * @param url - * the URL to send the request to. - * @param headers - * set headers only for this request - * @param params - * additional GET parameters to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest get(Context context, String url, Header[] headers, - RequestParams params, AsyncHttpResponseHandler responseHandler) { - HttpUriRequest request = new HttpGet(getUrlWithQueryString(url, params)); - if (headers != null) - request.setHeaders(headers); - return sendRequest(httpClient, httpContext, request, null, - responseHandler, context); - } - - // - // HTTP POST Requests - // - - /** - * Perform a HTTP POST request, without any parameters. - * - * @param url - * the URL to send the request to. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest post(String url, - AsyncHttpResponseHandler responseHandler) { - return post(null, url, null, responseHandler); - } - - /** - * Perform a HTTP POST request with parameters. - * - * @param url - * the URL to send the request to. - * @param params - * additional POST parameters or files to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest post(String url, RequestParams params, - AsyncHttpResponseHandler responseHandler) { - return post(null, url, params, responseHandler); - } - - /** - * Perform a HTTP POST request and track the Android Context which initiated - * the request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param params - * additional POST parameters or files to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest post(Context context, String url, - RequestParams params, AsyncHttpResponseHandler responseHandler) { - return post(context, url, paramsToEntity(params, responseHandler), - null, responseHandler); - } - - /** - * Perform a HTTP POST request and track the Android Context which initiated - * the request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param entity - * a raw {@link HttpEntity} to send with the request, for - * example, use this to send string/json/xml payloads to a server - * by passing a {@link org.apache.http.entity.StringEntity}. - * @param contentType - * the content type of the payload you are sending, for example - * application/json if sending a json payload. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest post(Context context, String url, - HttpEntity entity, String contentType, - AsyncHttpResponseHandler responseHandler) { - return sendRequest(httpClient, httpContext, - addEntityToRequestBase(new HttpPost(url), entity), contentType, - responseHandler, context); - } - - /** - * Perform a HTTP POST request and track the Android Context which initiated - * the request. Set headers only for this request - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param headers - * set headers only for this request - * @param params - * additional POST parameters to send with the request. - * @param contentType - * the content type of the payload you are sending, for example - * application/json if sending a json payload. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest post(Context context, String url, Header[] headers, - RequestParams params, String contentType, - AsyncHttpResponseHandler responseHandler) { - HttpEntityEnclosingRequestBase request = new HttpPost(url); - if (params != null) - request.setEntity(paramsToEntity(params, responseHandler)); - if (headers != null) - request.setHeaders(headers); - return sendRequest(httpClient, httpContext, request, contentType, - responseHandler, context); - } - - /** - * Perform a HTTP POST request and track the Android Context which initiated - * the request. Set headers only for this request - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param headers - * set headers only for this request - * @param entity - * a raw {@link HttpEntity} to send with the request, for - * example, use this to send string/json/xml payloads to a server - * by passing a {@link org.apache.http.entity.StringEntity}. - * @param contentType - * the content type of the payload you are sending, for example - * application/json if sending a json payload. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public AsyncHttpRequest post(Context context, String url, Header[] headers, - HttpEntity entity, String contentType, - AsyncHttpResponseHandler responseHandler) { - HttpEntityEnclosingRequestBase request = addEntityToRequestBase( - new HttpPost(url), entity); - if (headers != null) - request.setHeaders(headers); - return sendRequest(httpClient, httpContext, request, contentType, - responseHandler, context); - } - - // - // HTTP PUT Requests - // - - /** - * Perform a HTTP PUT request, without any parameters. - * - * @param url - * the URL to send the request to. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void put(String url, AsyncHttpResponseHandler responseHandler) { - put(null, url, null, responseHandler); - } - - /** - * Perform a HTTP PUT request with parameters. - * - * @param url - * the URL to send the request to. - * @param params - * additional PUT parameters or files to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void put(String url, RequestParams params, - AsyncHttpResponseHandler responseHandler) { - put(null, url, params, responseHandler); - } - - /** - * Perform a HTTP PUT request and track the Android Context which initiated - * the request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param params - * additional PUT parameters or files to send with the request. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void put(Context context, String url, RequestParams params, - AsyncHttpResponseHandler responseHandler) { - put(context, url, paramsToEntity(params, responseHandler), null, - responseHandler); - } - - /** - * Perform a HTTP PUT request and track the Android Context which initiated - * the request. And set one-time headers for the request - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param entity - * a raw {@link HttpEntity} to send with the request, for - * example, use this to send string/json/xml payloads to a server - * by passing a {@link org.apache.http.entity.StringEntity}. - * @param contentType - * the content type of the payload you are sending, for example - * application/json if sending a json payload. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void put(Context context, String url, HttpEntity entity, - String contentType, AsyncHttpResponseHandler responseHandler) { - sendRequest(httpClient, httpContext, - addEntityToRequestBase(new HttpPut(url), entity), contentType, - responseHandler, context); - } - - /** - * Perform a HTTP PUT request and track the Android Context which initiated - * the request. And set one-time headers for the request - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param headers - * set one-time headers for this request - * @param entity - * a raw {@link HttpEntity} to send with the request, for - * example, use this to send string/json/xml payloads to a server - * by passing a {@link org.apache.http.entity.StringEntity}. - * @param contentType - * the content type of the payload you are sending, for example - * application/json if sending a json payload. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void put(Context context, String url, Header[] headers, - HttpEntity entity, String contentType, - AsyncHttpResponseHandler responseHandler) { - HttpEntityEnclosingRequestBase request = addEntityToRequestBase( - new HttpPut(url), entity); - if (headers != null) - request.setHeaders(headers); - sendRequest(httpClient, httpContext, request, contentType, - responseHandler, context); - } - - // - // HTTP DELETE Requests - // - - /** - * Perform a HTTP DELETE request. - * - * @param url - * the URL to send the request to. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void delete(String url, AsyncHttpResponseHandler responseHandler) { - delete(null, url, responseHandler); - } - - /** - * Perform a HTTP DELETE request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void delete(Context context, String url, - AsyncHttpResponseHandler responseHandler) { - final HttpDelete delete = new HttpDelete(url); - sendRequest(httpClient, httpContext, delete, null, responseHandler, - context); - } - - /** - * Perform a HTTP DELETE request. - * - * @param context - * the Android Context which initiated the request. - * @param url - * the URL to send the request to. - * @param headers - * set one-time headers for this request - * @param responseHandler - * the response handler instance that should handle the response. - */ - public void delete(Context context, String url, Header[] headers, - AsyncHttpResponseHandler responseHandler) { - final HttpDelete delete = new HttpDelete(url); - if (headers != null) - delete.setHeaders(headers); - sendRequest(httpClient, httpContext, delete, null, responseHandler, - context); - } - - // Private stuff - protected AsyncHttpRequest sendRequest(DefaultHttpClient client, - HttpContext httpContext, HttpUriRequest uriRequest, - String contentType, AsyncHttpResponseHandler responseHandler, - Context context) { - if (contentType != null) { - uriRequest.addHeader("Content-Type", contentType); - } - - AsyncHttpRequest httpRequest = new AsyncHttpRequest(client, - httpContext, uriRequest, responseHandler); - Future request = threadPool.submit(httpRequest); - httpRequest.futureRef = new WeakReference>(request); - - if (context != null) { - // Add request to request map - List>> requestList = requestMap - .get(context); - if (requestList == null) { - requestList = new LinkedList>>(); - requestMap.put(context, requestList); - } - - requestList.add(new WeakReference>(request)); - - // TODO: Remove dead weakrefs from requestLists? - } - - return httpRequest; - } - - public static String getUrlWithQueryString(String url, RequestParams params) { - if (params != null) { - String paramString = params.getParamString(); - if (url.indexOf("?") == -1) { - url += "?" + paramString; - } else { - url += "&" + paramString; - } - } - - return url; - } - - private HttpEntity paramsToEntity(RequestParams params, - AsyncHttpResponseHandler progressHandler) { - HttpEntity entity = null; - - if (params != null) { - entity = params.getEntity(progressHandler); - } - - return entity; - } - - private HttpEntityEnclosingRequestBase addEntityToRequestBase( - HttpEntityEnclosingRequestBase requestBase, HttpEntity entity) { - if (entity != null) { - requestBase.setEntity(entity); - } - - return requestBase; - } - - private static class InflatingEntity extends HttpEntityWrapper { - public InflatingEntity(HttpEntity wrapped) { - super(wrapped); - } - - @Override - public InputStream getContent() throws IOException { - return new GZIPInputStream(wrappedEntity.getContent()); - } - - @Override - public long getContentLength() { - return -1; - } - } -} diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpRequest.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpRequest.java deleted file mode 100644 index d4be833..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpRequest.java +++ /dev/null @@ -1,152 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ - -package com.loopj.android.http; - -import java.io.IOException; -import java.lang.ref.WeakReference; -import java.net.ConnectException; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.util.Hashtable; -import java.util.concurrent.Future; - -import org.apache.http.HttpResponse; -import org.apache.http.client.HttpRequestRetryHandler; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.client.AbstractHttpClient; -import org.apache.http.protocol.HttpContext; - -public class AsyncHttpRequest implements Runnable { - private final AbstractHttpClient client; - private final HttpContext context; - private final HttpUriRequest request; - private final AsyncHttpResponseHandler responseHandler; - private boolean isBinaryRequest; - private int executionCount; - - public String responseString; - public byte[] responseData; - - public Hashtable userInfo = new Hashtable(); - public WeakReference> futureRef; - - public AsyncHttpRequest(AbstractHttpClient client, HttpContext context, HttpUriRequest request, AsyncHttpResponseHandler responseHandler) { - this.client = client; - this.context = context; - this.request = request; - this.responseHandler = responseHandler; - - if (responseHandler != null) - this.responseHandler.context = this; - if (responseHandler instanceof BinaryHttpResponseHandler) { - this.isBinaryRequest = true; - } - } - - public void run() { - try { - if (responseHandler != null) { - responseHandler.sendStartMessage(); - } - - makeRequestWithRetries(); - - if (responseHandler != null) { - responseHandler.sendFinishMessage(); - } - } catch (IOException e) { - if (responseHandler != null) { - responseHandler.sendFinishMessage(); - if (this.isBinaryRequest) { - responseHandler.sendFailureMessage(e, (byte[]) null); - } else { - responseHandler.sendFailureMessage(e, (String) null); - } - } - } - } - - private void makeRequest() throws IOException { - if (!Thread.currentThread().isInterrupted()) { - try { - HttpResponse response = client.execute(request, context); - if (!Thread.currentThread().isInterrupted()) { - if (responseHandler != null) { - responseHandler.sendResponseMessage(response); - } - } else { - // TODO: should raise InterruptedException? this block is - // reached whenever the request is cancelled before its - // response is received - } - } catch (IOException e) { - if (!Thread.currentThread().isInterrupted()) { - throw e; - } - } - } - } - - private void makeRequestWithRetries() throws ConnectException { - // This is an additional layer of retry logic lifted from droid-fu - // See: - // https://github.com/kaeppler/droid-fu/blob/master/src/main/java/com/github/droidfu/http/BetterHttpRequestBase.java - boolean retry = true; - IOException cause = null; - HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); - while (retry) { - try { - makeRequest(); - return; - } catch (UnknownHostException e) { - if (responseHandler != null) { - responseHandler.sendFailureMessage(e, "can't resolve host"); - } - return; - } catch (SocketException e) { - // Added to detect host unreachable - if (responseHandler != null) { - responseHandler.sendFailureMessage(e, "can't resolve host"); - } - return; - } catch (SocketTimeoutException e) { - if (responseHandler != null) { - responseHandler.sendFailureMessage(e, "socket time out"); - } - return; - } catch (IOException e) { - cause = e; - retry = retryHandler.retryRequest(cause, ++executionCount, context); - } catch (NullPointerException e) { - // there's a bug in HttpClient 4.0.x that on some occasions - // causes - // DefaultRequestExecutor to throw an NPE, see - // http://code.google.com/p/android/issues/detail?id=5255 - cause = new IOException("NPE in HttpClient" + e.getMessage()); - retry = retryHandler.retryRequest(cause, ++executionCount, context); - } - } - - // no retries left, crap out with exception - ConnectException ex = new ConnectException(); - ex.initCause(cause); - throw ex; - } -} diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpResponseHandler.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpResponseHandler.java deleted file mode 100644 index 77b164f..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/AsyncHttpResponseHandler.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpResponseException; -import org.apache.http.entity.BufferedHttpEntity; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; - -/** - * Used to intercept and handle the responses from requests made using - * {@link AsyncHttpClient}. The {@link #onSuccess(String)} method is - * designed to be anonymously overridden with your own response handling code. - *

- * Additionally, you can override the {@link #onFailure(Throwable, String)}, - * {@link #onStart()}, and {@link #onFinish()} methods as required. - *

- * For example: - *

- *

- * AsyncHttpClient client = new AsyncHttpClient();
- * client.get("http://www.google.com", new AsyncHttpResponseHandler() {
- *     @Override
- *     public void onStart() {
- *         // Initiated the request
- *     }
- *
- *     @Override
- *     public void onSuccess(String response) {
- *         // Successfully got a response
- *     }
- * 
- *     @Override
- *     public void onFailure(Throwable e, String response) {
- *         // Response failed :(
- *     }
- *
- *     @Override
- *     public void onFinish() {
- *         // Completed the request (either success or failure)
- *     }
- * });
- * 
- */ -public class AsyncHttpResponseHandler { - protected static final int SUCCESS_MESSAGE = 0; - protected static final int FAILURE_MESSAGE = 1; - protected static final int START_MESSAGE = 2; - protected static final int FINISH_MESSAGE = 3; - protected static final int PROGRESS_MESSAGE = 4; - - public AsyncHttpRequest context; - private Handler handler; - - /** - * Creates a new AsyncHttpResponseHandler - */ - public AsyncHttpResponseHandler() { - // Set up a handler to post events back to the correct thread if possible - if(Looper.myLooper() != null) { - handler = new Handler(){ - public void handleMessage(Message msg){ - AsyncHttpResponseHandler.this.handleMessage(msg); - } - }; - } - } - - - // - // Callbacks to be overridden, typically anonymously - // - - /** - * Fired when the request is started, override to handle in your own code - */ - public void onStart() {} - - - /** - * Fired in all cases when the request is finished, after both success and failure, override to handle in your own code - */ - public void onFinish() {} - - /** - * Fired when a request returns successfully, override to handle in your own code - * @param content the body of the HTTP response from the server - */ - public void onSuccess(String content, AsyncHttpRequest request) {} - - /** - * Fired when a request returns successfully, override to handle in your own code - * @param statusCode the status code of the response - * @param content the body of the HTTP response from the server - */ - public void onSuccess(int statusCode, String content) { - - context.responseString = content; - onSuccess(content, context); - } - - - /** - * fired when the request is on progress - * @param position - * @param total - */ - public void onProgress(long position, long total, AsyncHttpRequest request){} - public void onProgress(long position, long total) - { - onProgress(position,total, context); - } - - /** - * Fired when a request fails to complete, override to handle in your own code - * @param error the underlying cause of the failure - * @deprecated use {@link #onFailure(Throwable, String)} - */ - public void onFailure(Throwable error, AsyncHttpRequest request) {} - - public void onFailure(Throwable error, String content) { - - context.responseString = content; - onFailure(error, content, context); - } - - /** - * Fired when a request fails to complete, override to handle in your own code - * @param error the underlying cause of the failure - * @param content the response body, if any - */ - public void onFailure(Throwable error, String content, AsyncHttpRequest request) { - // By default, call the deprecated onFailure(Throwable) for compatibility - onFailure(error, request); - } - - // - // Pre-processing of messages (executes in background threadpool thread) - // - - protected void sendSuccessMessage(int statusCode, String responseBody) { - sendMessage(obtainMessage(SUCCESS_MESSAGE, new Object[]{new Integer(statusCode), responseBody})); - } - - protected void sendFailureMessage(Throwable e, String responseBody) { - sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[]{e, responseBody})); - } - - protected void sendFailureMessage(Throwable e, byte[] responseBody) { - sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[]{e, responseBody})); - } - - protected void sendStartMessage() { - sendMessage(obtainMessage(START_MESSAGE, null)); - } - - protected void sendFinishMessage() { - sendMessage(obtainMessage(FINISH_MESSAGE, null)); - } - - protected void sendProgressMessage(long position, long total) - { - sendMessage(obtainMessage(PROGRESS_MESSAGE, new Object[]{position,total})); - } - - - // - // Pre-processing of messages (in original calling thread, typically the UI thread) - // - - protected void handleSuccessMessage(int statusCode, String responseBody) { - onSuccess(statusCode, responseBody); - } - - protected void handleFailureMessage(Throwable e, String responseBody) { - onFailure(e, responseBody, context); - } - - - - // Methods which emulate android's Handler and Message methods - protected void handleMessage(Message msg) { - Object[] response; - - switch(msg.what) { - case SUCCESS_MESSAGE: - response = (Object[])msg.obj; - handleSuccessMessage(((Integer) response[0]).intValue(), (String) response[1]); - break; - case FAILURE_MESSAGE: - response = (Object[])msg.obj; - handleFailureMessage((Throwable)response[0], (String)response[1]); - break; - case START_MESSAGE: - onStart(); - break; - case FINISH_MESSAGE: - onFinish(); - break; - case PROGRESS_MESSAGE: - response = (Object[])msg.obj; - onProgress(((Long)response[0]).longValue(), ((Long)response[1]).longValue()); - break; - } - } - - protected void sendMessage(Message msg) { - if(handler != null){ - handler.sendMessage(msg); - } else { - handleMessage(msg); - } - } - - protected Message obtainMessage(int responseMessage, Object response) { - Message msg = null; - if(handler != null){ - msg = this.handler.obtainMessage(responseMessage, response); - }else{ - msg = Message.obtain(); - msg.what = responseMessage; - msg.obj = response; - } - return msg; - } - - // Interface to AsyncHttpRequest - void sendResponseMessage(HttpResponse response) { - StatusLine status = response.getStatusLine(); - String responseBody = null; - try { - HttpEntity entity = null; - HttpEntity temp = response.getEntity(); - if(temp != null) { - entity = new BufferedHttpEntity(temp); - responseBody = EntityUtils.toString(entity, "UTF-8"); - } - } catch(IOException e) { - sendFailureMessage(e, (String) null); - } - - if(status.getStatusCode() >= 300) { - sendFailureMessage(new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()), responseBody); - } else { - sendSuccessMessage(status.getStatusCode(), responseBody); - } - } -} \ No newline at end of file diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/BinaryHttpResponseHandler.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/BinaryHttpResponseHandler.java deleted file mode 100644 index 616465e..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/BinaryHttpResponseHandler.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -import android.os.Message; -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.StatusLine; -import org.apache.http.client.HttpResponseException; -import org.apache.http.entity.BufferedHttpEntity; -import org.apache.http.util.EntityUtils; - -import java.io.IOException; - -/** - * Used to intercept and handle the responses from requests made using - * {@link AsyncHttpClient}. Receives response body as byte array with a - * content-type whitelist. (e.g. checks Content-Type against allowed list, - * Content-length). - *

- * For example: - *

- *

- * AsyncHttpClient client = new AsyncHttpClient();
- * String[] allowedTypes = new String[] { "image/png" };
- * client.get("http://www.example.com/image.png", new BinaryHttpResponseHandler(allowedTypes) {
- *     @Override
- *     public void onSuccess(byte[] imageData) {
- *         // Successfully got a response
- *     }
- *
- *     @Override
- *     public void onFailure(Throwable e, byte[] imageData) {
- *         // Response failed :(
- *     }
- * });
- * 
- */ -public class BinaryHttpResponseHandler extends AsyncHttpResponseHandler { - // Allow images by default - private static String[] mAllowedContentTypes = new String[] { - "image/jpeg", - "image/png" - }; - - /** - * Creates a new BinaryHttpResponseHandler - */ - public BinaryHttpResponseHandler() { - super(); - } - - /** - * Creates a new BinaryHttpResponseHandler, and overrides the default allowed - * content types with passed String array (hopefully) of content types. - */ - public BinaryHttpResponseHandler(String[] allowedContentTypes) { - this(); - mAllowedContentTypes = allowedContentTypes; - } - - - // - // Callbacks to be overridden, typically anonymously - // - - /** - * Fired when a request returns successfully, override to handle in your own code - * @param binaryData the body of the HTTP response from the server - */ - public void onSuccess(byte[] binaryData) {} - - /** - * Fired when a request returns successfully, override to handle in your own code - * @param statusCode the status code of the response - * @param binaryData the body of the HTTP response from the server - */ - public void onSuccess(int statusCode, byte[] binaryData) { - context.responseData = binaryData; - onSuccess(binaryData); - } - - /** - * Fired when a request fails to complete, override to handle in your own code - * @param error the underlying cause of the failure - * @param binaryData the response body, if any - * @deprecated - */ - public void onFailure(Throwable error, byte[] binaryData) { - // By default, call the deprecated onFailure(Throwable) for compatibility - - context.responseData = binaryData; - onFailure(error, context); - } - - - // - // Pre-processing of messages (executes in background threadpool thread) - // - - protected void sendSuccessMessage(int statusCode, byte[] responseBody) { - sendMessage(obtainMessage(SUCCESS_MESSAGE, new Object[]{statusCode, responseBody})); - } - - protected void sendFailureMessage(Throwable e, byte[] responseBody) { - sendMessage(obtainMessage(FAILURE_MESSAGE, new Object[]{e, responseBody})); - } - - // - // Pre-processing of messages (in original calling thread, typically the UI thread) - // - - protected void handleSuccessMessage(int statusCode, byte[] responseBody) { - onSuccess(statusCode, responseBody); - } - - protected void handleFailureMessage(Throwable e, byte[] responseBody) { - onFailure(e, responseBody); - } - - // Methods which emulate android's Handler and Message methods - protected void handleMessage(Message msg) { - Object[] response; - switch(msg.what) { - case SUCCESS_MESSAGE: - response = (Object[])msg.obj; - handleSuccessMessage(((Integer) response[0]).intValue() , (byte[]) response[1]); - break; - case FAILURE_MESSAGE: - response = (Object[])msg.obj; - handleFailureMessage((Throwable)response[0], (byte[])response[1]); - break; - default: - super.handleMessage(msg); - break; - } - } - - // Interface to AsyncHttpRequest - void sendResponseMessage(HttpResponse response) { - StatusLine status = response.getStatusLine(); - Header[] contentTypeHeaders = response.getHeaders("Content-Type"); - byte[] responseBody = null; - if(contentTypeHeaders.length != 1) { - //malformed/ambiguous HTTP Header, ABORT! - sendFailureMessage(new HttpResponseException(status.getStatusCode(), "None, or more than one, Content-Type Header found!"), responseBody); - return; - } - Header contentTypeHeader = contentTypeHeaders[0]; - boolean foundAllowedContentType = false; - for(String anAllowedContentType : mAllowedContentTypes) { - if(anAllowedContentType.equals(contentTypeHeader.getValue())) { - foundAllowedContentType = true; - } - } - if(!foundAllowedContentType) { - //Content-Type not in allowed list, ABORT! - sendFailureMessage(new HttpResponseException(status.getStatusCode(), "Content-Type not allowed!"), responseBody); - return; - } - try { - HttpEntity entity = null; - HttpEntity temp = response.getEntity(); - if(temp != null) { - entity = new BufferedHttpEntity(temp); - } - responseBody = EntityUtils.toByteArray(entity); - } catch(IOException e) { - sendFailureMessage(e, (byte[]) null); - } - - if(status.getStatusCode() >= 300) { - sendFailureMessage(new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()), responseBody); - } else { - sendSuccessMessage(status.getStatusCode(), responseBody); - } - } -} \ No newline at end of file diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/JsonHttpResponseHandler.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/JsonHttpResponseHandler.java deleted file mode 100644 index 084bf33..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/JsonHttpResponseHandler.java +++ /dev/null @@ -1,169 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -import org.apache.http.HttpStatus; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; -import org.json.JSONTokener; - -import android.os.Message; - -/** - * Used to intercept and handle the responses from requests made using - * {@link AsyncHttpClient}, with automatic parsing into a {@link JSONObject} - * or {@link JSONArray}. - *

- * This class is designed to be passed to get, post, put and delete requests - * with the {@link #onSuccess(JSONObject)} or {@link #onSuccess(JSONArray)} - * methods anonymously overridden. - *

- * Additionally, you can override the other event methods from the - * parent class. - */ -public class JsonHttpResponseHandler extends AsyncHttpResponseHandler { - protected static final int SUCCESS_JSON_MESSAGE = 100; - - // - // Callbacks to be overridden, typically anonymously - // - - /** - * Fired when a request returns successfully and contains a json object - * at the base of the response string. Override to handle in your - * own code. - * @param response the parsed json object found in the server response (if any) - */ - public void onSuccess(JSONObject response) {} - - - /** - * Fired when a request returns successfully and contains a json array - * at the base of the response string. Override to handle in your - * own code. - * @param response the parsed json array found in the server response (if any) - */ - public void onSuccess(JSONArray response) {} - - /** - * Fired when a request returns successfully and contains a json object - * at the base of the response string. Override to handle in your - * own code. - * @param statusCode the status code of the response - * @param response the parsed json object found in the server response (if any) - */ - public void onSuccess(int statusCode, JSONObject response) { - onSuccess(response); - } - - - /** - * Fired when a request returns successfully and contains a json array - * at the base of the response string. Override to handle in your - * own code. - * @param statusCode the status code of the response - * @param response the parsed json array found in the server response (if any) - */ - public void onSuccess(int statusCode, JSONArray response) { - onSuccess(response); - } - - public void onFailure(Throwable e, JSONObject errorResponse) {} - public void onFailure(Throwable e, JSONArray errorResponse) {} - - - // - // Pre-processing of messages (executes in background threadpool thread) - // - - @Override - protected void sendSuccessMessage(int statusCode, String responseBody) { - if (statusCode != HttpStatus.SC_NO_CONTENT){ - try { - Object jsonResponse = parseResponse(responseBody); - sendMessage(obtainMessage(SUCCESS_JSON_MESSAGE, new Object[]{statusCode, jsonResponse})); - } catch(JSONException e) { - sendFailureMessage(e, responseBody); - } - }else{ - sendMessage(obtainMessage(SUCCESS_JSON_MESSAGE, new Object[]{statusCode, new JSONObject()})); - } - } - - - // - // Pre-processing of messages (in original calling thread, typically the UI thread) - // - - @Override - protected void handleMessage(Message msg) { - switch(msg.what){ - case SUCCESS_JSON_MESSAGE: - Object[] response = (Object[]) msg.obj; - handleSuccessJsonMessage(((Integer) response[0]).intValue(), response[1]); - break; - default: - super.handleMessage(msg); - } - } - - protected void handleSuccessJsonMessage(int statusCode, Object jsonResponse) { - if(jsonResponse instanceof JSONObject) { - onSuccess(statusCode, (JSONObject)jsonResponse); - } else if(jsonResponse instanceof JSONArray) { - onSuccess(statusCode, (JSONArray)jsonResponse); - } else { - onFailure(new JSONException("Unexpected type " + jsonResponse.getClass().getName()), (JSONObject)null); - } - } - - protected Object parseResponse(String responseBody) throws JSONException { - Object result = null; - //trim the string to prevent start with blank, and test if the string is valid JSON, because the parser don't do this :(. If Json is not valid this will return null - responseBody = responseBody.trim(); - if(responseBody.startsWith("{") || responseBody.startsWith("[")) { - result = new JSONTokener(responseBody).nextValue(); - } - if (result == null) { - result = responseBody; - } - return result; - } - - @Override - protected void handleFailureMessage(Throwable e, String responseBody) { - try { - if (responseBody != null) { - Object jsonResponse = parseResponse(responseBody); - if(jsonResponse instanceof JSONObject) { - onFailure(e, (JSONObject)jsonResponse); - } else if(jsonResponse instanceof JSONArray) { - onFailure(e, (JSONArray)jsonResponse); - } else { - onFailure(e, responseBody); - } - }else { - onFailure(e, ""); - } - }catch(JSONException ex) { - onFailure(e, responseBody); - } - } -} diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/PersistentCookieStore.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/PersistentCookieStore.java deleted file mode 100644 index 3f98a00..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/PersistentCookieStore.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.Date; -import java.util.List; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.http.client.CookieStore; -import org.apache.http.cookie.Cookie; - -import android.content.Context; -import android.content.SharedPreferences; -import android.text.TextUtils; - -/** - * A persistent cookie store which implements the Apache HttpClient - * {@link CookieStore} interface. Cookies are stored and will persist on the - * user's device between application sessions since they are serialized and - * stored in {@link SharedPreferences}. - *

- * Instances of this class are designed to be used with - * {@link AsyncHttpClient#setCookieStore}, but can also be used with a - * regular old apache HttpClient/HttpContext if you prefer. - */ -public class PersistentCookieStore implements CookieStore { - private static final String COOKIE_PREFS = "CookiePrefsFile"; - private static final String COOKIE_NAME_STORE = "names"; - private static final String COOKIE_NAME_PREFIX = "cookie_"; - - private final ConcurrentHashMap cookies; - private final SharedPreferences cookiePrefs; - - /** - * Construct a persistent cookie store. - */ - public PersistentCookieStore(Context context) { - cookiePrefs = context.getSharedPreferences(COOKIE_PREFS, 0); - cookies = new ConcurrentHashMap(); - - // Load any previously stored cookies into the store - String storedCookieNames = cookiePrefs.getString(COOKIE_NAME_STORE, null); - if(storedCookieNames != null) { - String[] cookieNames = TextUtils.split(storedCookieNames, ","); - for(String name : cookieNames) { - String encodedCookie = cookiePrefs.getString(COOKIE_NAME_PREFIX + name, null); - if(encodedCookie != null) { - Cookie decodedCookie = decodeCookie(encodedCookie); - if(decodedCookie != null) { - cookies.put(name, decodedCookie); - } - } - } - - // Clear out expired cookies - clearExpired(new Date()); - } - } - - @Override - public void addCookie(Cookie cookie) { - String name = cookie.getName() + cookie.getDomain(); - - // Save cookie into local store, or remove if expired - if(!cookie.isExpired(new Date())) { - cookies.put(name, cookie); - } else { - cookies.remove(name); - } - - // Save cookie into persistent store - SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); - prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); - prefsWriter.putString(COOKIE_NAME_PREFIX + name, encodeCookie(new SerializableCookie(cookie))); - prefsWriter.commit(); - } - - @Override - public void clear() { - // Clear cookies from local store - cookies.clear(); - - // Clear cookies from persistent store - SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); - for(String name : cookies.keySet()) { - prefsWriter.remove(COOKIE_NAME_PREFIX + name); - } - prefsWriter.remove(COOKIE_NAME_STORE); - prefsWriter.commit(); - } - - @Override - public boolean clearExpired(Date date) { - boolean clearedAny = false; - SharedPreferences.Editor prefsWriter = cookiePrefs.edit(); - - for(ConcurrentHashMap.Entry entry : cookies.entrySet()) { - String name = entry.getKey(); - Cookie cookie = entry.getValue(); - if(cookie.isExpired(date)) { - // Clear cookies from local store - cookies.remove(name); - - // Clear cookies from persistent store - prefsWriter.remove(COOKIE_NAME_PREFIX + name); - - // We've cleared at least one - clearedAny = true; - } - } - - // Update names in persistent store - if(clearedAny) { - prefsWriter.putString(COOKIE_NAME_STORE, TextUtils.join(",", cookies.keySet())); - } - prefsWriter.commit(); - - return clearedAny; - } - - @Override - public List getCookies() { - return new ArrayList(cookies.values()); - } - - - // - // Cookie serialization/deserialization - // - - protected String encodeCookie(SerializableCookie cookie) { - ByteArrayOutputStream os = new ByteArrayOutputStream(); - try { - ObjectOutputStream outputStream = new ObjectOutputStream(os); - outputStream.writeObject(cookie); - } catch (Exception e) { - return null; - } - - return byteArrayToHexString(os.toByteArray()); - } - - protected Cookie decodeCookie(String cookieStr) { - byte[] bytes = hexStringToByteArray(cookieStr); - ByteArrayInputStream is = new ByteArrayInputStream(bytes); - Cookie cookie = null; - try { - ObjectInputStream ois = new ObjectInputStream(is); - cookie = ((SerializableCookie)ois.readObject()).getCookie(); - } catch (Exception e) { - e.printStackTrace(); - } - - return cookie; - } - - // Using some super basic byte array <-> hex conversions so we don't have - // to rely on any large Base64 libraries. Can be overridden if you like! - protected String byteArrayToHexString(byte[] b) { - StringBuffer sb = new StringBuffer(b.length * 2); - for (byte element : b) { - int v = element & 0xff; - if(v < 16) { - sb.append('0'); - } - sb.append(Integer.toHexString(v)); - } - return sb.toString().toUpperCase(); - } - - protected byte[] hexStringToByteArray(String s) { - int len = s.length(); - byte[] data = new byte[len / 2]; - for(int i=0; i - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -import java.io.InputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.UnsupportedEncodingException; -import java.util.ArrayList; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.http.HttpEntity; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.utils.URLEncodedUtils; -import org.apache.http.message.BasicNameValuePair; - -/** - * A collection of string request parameters or files to send along with - * requests made from an {@link AsyncHttpClient} instance. - *

- * For example: - *

- *

- * RequestParams params = new RequestParams();
- * params.put("username", "james");
- * params.put("password", "123456");
- * params.put("email", "my@email.com");
- * params.put("profile_picture", new File("pic.jpg")); // Upload a File
- * params.put("profile_picture2", someInputStream); // Upload an InputStream
- * params.put("profile_picture3", new ByteArrayInputStream(someBytes)); // Upload some bytes
- *
- * AsyncHttpClient client = new AsyncHttpClient();
- * client.post("http://myendpoint.com", params, responseHandler);
- * 
- */ -public class RequestParams { - private static String ENCODING = "UTF-8"; - - protected ConcurrentHashMap urlParams; - protected ConcurrentHashMap fileParams; - protected ConcurrentHashMap> urlParamsWithArray; - - - /** - * Constructs a new empty RequestParams instance. - */ - public RequestParams() { - init(); - } - - public RequestParams(RequestProgressHandler progressHandler) { - super(); - } - - /** - * Constructs a new RequestParams instance containing the key/value - * string params from the specified map. - * @param source the source key/value string map to add. - */ - public RequestParams(Map source) { - init(); - - for(Map.Entry entry : source.entrySet()) { - put(entry.getKey(), entry.getValue()); - } - } - - /** - * Constructs a new RequestParams instance and populate it with a single - * initial key/value string param. - * @param key the key name for the intial param. - * @param value the value string for the initial param. - */ - public RequestParams(String key, String value) { - init(); - - put(key, value); - } - - /** - * Constructs a new RequestParams instance and populate it with multiple - * initial key/value string param. - * @param keysAndValues a sequence of keys and values. Objects are - * automatically converted to Strings (including the value {@code null}). - * @throws IllegalArgumentException if the number of arguments isn't even. - */ - public RequestParams(Object... keysAndValues) { - init(); - int len = keysAndValues.length; - if (len % 2 != 0) - throw new IllegalArgumentException("Supplied arguments must be even"); - for (int i = 0; i < len; i += 2) { - String key = String.valueOf(keysAndValues[i]); - String val = String.valueOf(keysAndValues[i + 1]); - put(key, val); - } - } - - /** - * Adds a key/value string pair to the request. - * @param key the key name for the new param. - * @param value the value string for the new param. - */ - public void put(String key, String value){ - if(key != null && value != null) { - urlParams.put(key, value); - } - } - - /** - * Adds a file to the request. - * @param key the key name for the new param. - * @param file the file to add. - */ - public void put(String key, File file) throws FileNotFoundException { - put(key, new FileInputStream(file), file.getName()); - } - - /** - * Adds param with more than one value. - * @param key the key name for the new param. - * @param values is the ArrayList with values for the param. - */ - public void put(String key, ArrayList values) { - if(key != null && values != null) { - urlParamsWithArray.put(key, values); - } - } - - /** - * Adds an input stream to the request. - * @param key the key name for the new param. - * @param stream the input stream to add. - */ - public void put(String key, InputStream stream) { - put(key, stream, null); - } - - /** - * Adds an input stream to the request. - * @param key the key name for the new param. - * @param stream the input stream to add. - * @param fileName the name of the file. - */ - public void put(String key, InputStream stream, String fileName) { - put(key, stream, fileName, null); - } - - /** - * Adds an input stream to the request. - * @param key the key name for the new param. - * @param stream the input stream to add. - * @param fileName the name of the file. - * @param contentType the content type of the file, eg. application/json - */ - public void put(String key, InputStream stream, String fileName, String contentType) { - if(key != null && stream != null) { - fileParams.put(key, new FileWrapper(stream, fileName, contentType)); - } - } - - /** - * Removes a parameter from the request. - * @param key the key name for the parameter to remove. - */ - public void remove(String key){ - urlParams.remove(key); - fileParams.remove(key); - urlParamsWithArray.remove(key); - } - - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - for(ConcurrentHashMap.Entry entry : urlParams.entrySet()) { - if(result.length() > 0) - result.append("&"); - - result.append(entry.getKey()); - result.append("="); - result.append(entry.getValue()); - } - - for(ConcurrentHashMap.Entry entry : fileParams.entrySet()) { - if(result.length() > 0) - result.append("&"); - - result.append(entry.getKey()); - result.append("="); - result.append("FILE"); - } - - for(ConcurrentHashMap.Entry> entry : urlParamsWithArray.entrySet()) { - if(result.length() > 0) - result.append("&"); - - ArrayList values = entry.getValue(); - for (String value : values) { - if (values.indexOf(value) != 0) - result.append("&"); - result.append(entry.getKey()); - result.append("="); - result.append(value); - } - } - - return result.toString(); - } - - /** - * Returns an HttpEntity containing all request parameters - */ - public HttpEntity getEntity(AsyncHttpResponseHandler progressHandler) { - HttpEntity entity = null; - - if(!fileParams.isEmpty()) { - -// SimpleMultipartEntity multipartEntity = new SimpleMultipartEntity(); - ProgressMultipartEntity multipartEntity = new ProgressMultipartEntity(progressHandler); - - // Add string params - for(ConcurrentHashMap.Entry entry : urlParams.entrySet()) { - multipartEntity.addPart(entry.getKey(), entry.getValue()); - } - - // Add dupe params - for(ConcurrentHashMap.Entry> entry : urlParamsWithArray.entrySet()) { - ArrayList values = entry.getValue(); - for (String value : values) { - multipartEntity.addPart(entry.getKey(), value); - } - } - - // Add file params - int currentIndex = 0; - int lastIndex = fileParams.entrySet().size() - 1; - for(ConcurrentHashMap.Entry entry : fileParams.entrySet()) { - FileWrapper file = entry.getValue(); - if(file.inputStream != null) { - boolean isLast = currentIndex == lastIndex; - if(file.contentType != null) { - multipartEntity.addPart(entry.getKey(), file.getFileName(), file.inputStream, file.contentType, isLast); - } else { - multipartEntity.addPart(entry.getKey(), file.getFileName(), file.inputStream, isLast); - } - } - currentIndex++; - } - - entity = multipartEntity; - } else { - try { - entity = new UrlEncodedFormEntity(getParamsList(), ENCODING); - } catch (UnsupportedEncodingException e) { - e.printStackTrace(); - } - } - - return entity; - } - - private void init(){ - urlParams = new ConcurrentHashMap(); - fileParams = new ConcurrentHashMap(); - urlParamsWithArray = new ConcurrentHashMap>(); - } - - protected List getParamsList() { - List lparams = new LinkedList(); - - for(ConcurrentHashMap.Entry entry : urlParams.entrySet()) { - lparams.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); - } - - for(ConcurrentHashMap.Entry> entry : urlParamsWithArray.entrySet()) { - ArrayList values = entry.getValue(); - for (String value : values) { - lparams.add(new BasicNameValuePair(entry.getKey(), value)); - } - } - - return lparams; - } - - protected String getParamString() { - return URLEncodedUtils.format(getParamsList(), ENCODING); - } - - private static class FileWrapper { - public InputStream inputStream; - public String fileName; - public String contentType; - - public FileWrapper(InputStream inputStream, String fileName, String contentType) { - this.inputStream = inputStream; - this.fileName = fileName; - this.contentType = contentType; - } - - public String getFileName() { - if(fileName != null) { - return fileName; - } else { - return "nofilename"; - } - } - } -} diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/RequestProgressHandler.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/RequestProgressHandler.java deleted file mode 100644 index 95e2a84..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/RequestProgressHandler.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.loopj.android.http; - -public interface RequestProgressHandler { - - public void updateProgress(long position, long total); -} diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/RetryHandler.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/RetryHandler.java deleted file mode 100644 index 715456f..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/RetryHandler.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - 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. -*/ - -/* - Some of the retry logic in this class is heavily borrowed from the - fantastic droid-fu project: https://github.com/donnfelker/droid-fu -*/ - -package com.loopj.android.http; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.SocketException; -import java.net.UnknownHostException; -import java.util.HashSet; -import java.util.Iterator; - -import javax.net.ssl.SSLException; - -import org.apache.http.NoHttpResponseException; -import org.apache.http.client.HttpRequestRetryHandler; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.protocol.ExecutionContext; -import org.apache.http.protocol.HttpContext; - -import android.os.SystemClock; - -class RetryHandler implements HttpRequestRetryHandler { - private static final int RETRY_SLEEP_TIME_MILLIS = 1500; - private static HashSet> exceptionWhitelist = new HashSet>(); - private static HashSet> exceptionBlacklist = new HashSet>(); - - static { - // Retry if the server dropped connection on us - exceptionWhitelist.add(NoHttpResponseException.class); - // retry-this, since it may happens as part of a Wi-Fi to 3G failover - exceptionWhitelist.add(UnknownHostException.class); - // retry-this, since it may happens as part of a Wi-Fi to 3G failover - exceptionWhitelist.add(SocketException.class); - - // never retry timeouts - exceptionBlacklist.add(InterruptedIOException.class); - // never retry SSL handshake failures - exceptionBlacklist.add(SSLException.class); - } - - private final int maxRetries; - - public RetryHandler(int maxRetries) { - this.maxRetries = maxRetries; - } - - public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { - boolean retry = true; - - Boolean b = (Boolean) context.getAttribute(ExecutionContext.HTTP_REQ_SENT); - boolean sent = (b != null && b.booleanValue()); - - if(executionCount > maxRetries) { - // Do not retry if over max retry count - retry = false; - } else if (isInList(exceptionBlacklist, exception)) { - // immediately cancel retry if the error is blacklisted - retry = false; - } else if (isInList(exceptionWhitelist, exception)) { - // immediately retry if error is whitelisted - retry = true; - } else if (!sent) { - // for most other errors, retry only if request hasn't been fully sent yet - retry = true; - } - - if(retry) { - // resend all idempotent requests - HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute( ExecutionContext.HTTP_REQUEST ); - String requestType = currentReq.getMethod(); - retry = !requestType.equals("POST"); - } - - if(retry) { - SystemClock.sleep(RETRY_SLEEP_TIME_MILLIS); - } else { - exception.printStackTrace(); - } - - return retry; - } - - protected boolean isInList(HashSet> list, Throwable error) { - Iterator> itr = list.iterator(); - while (itr.hasNext()) { - if (itr.next().isInstance(error)) { - return true; - } - } - return false; - } -} \ No newline at end of file diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/SerializableCookie.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/SerializableCookie.java deleted file mode 100644 index cc12993..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/SerializableCookie.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -package com.loopj.android.http; - -import java.io.Serializable; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.IOException; -import java.util.Date; - -import org.apache.http.cookie.Cookie; -import org.apache.http.impl.cookie.BasicClientCookie; - -/** - * A wrapper class around {@link Cookie} and/or {@link BasicClientCookie} - * designed for use in {@link PersistentCookieStore}. - */ -public class SerializableCookie implements Serializable { - private static final long serialVersionUID = 6374381828722046732L; - - private transient final Cookie cookie; - private transient BasicClientCookie clientCookie; - - public SerializableCookie(Cookie cookie) { - this.cookie = cookie; - } - - public Cookie getCookie() { - Cookie bestCookie = cookie; - if(clientCookie != null) { - bestCookie = clientCookie; - } - return bestCookie; - } - - private void writeObject(ObjectOutputStream out) throws IOException { - out.writeObject(cookie.getName()); - out.writeObject(cookie.getValue()); - out.writeObject(cookie.getComment()); - out.writeObject(cookie.getDomain()); - out.writeObject(cookie.getExpiryDate()); - out.writeObject(cookie.getPath()); - out.writeInt(cookie.getVersion()); - out.writeBoolean(cookie.isSecure()); - } - - private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { - String name = (String)in.readObject(); - String value = (String)in.readObject(); - clientCookie = new BasicClientCookie(name, value); - clientCookie.setComment((String)in.readObject()); - clientCookie.setDomain((String)in.readObject()); - clientCookie.setExpiryDate((Date)in.readObject()); - clientCookie.setPath((String)in.readObject()); - clientCookie.setVersion(in.readInt()); - clientCookie.setSecure(in.readBoolean()); - } -} \ No newline at end of file diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/SimpleMultipartEntity.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/SimpleMultipartEntity.java deleted file mode 100644 index bff0efc..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/SimpleMultipartEntity.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - Android Asynchronous Http Client - Copyright (c) 2011 James Smith - http://loopj.com - - 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. -*/ - -/* - This code is taken from Rafael Sanches' blog. - http://blog.rafaelsanches.com/2011/01/29/upload-using-multipart-post-using-httpclient-in-android/ -*/ - -package com.loopj.android.http; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.Random; - -import org.apache.http.Header; -import org.apache.http.HttpEntity; -import org.apache.http.message.BasicHeader; - -class SimpleMultipartEntity implements HttpEntity { - private final static char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); - - private String boundary = null; - - ByteArrayOutputStream out = new ByteArrayOutputStream(); - boolean isSetLast = false; - boolean isSetFirst = false; - - public SimpleMultipartEntity() { - final StringBuffer buf = new StringBuffer(); - final Random rand = new Random(); - for (int i = 0; i < 30; i++) { - buf.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]); - } - this.boundary = buf.toString(); - - } - - public void writeFirstBoundaryIfNeeds(){ - if(!isSetFirst){ - try { - out.write(("--" + boundary + "\r\n").getBytes()); - } catch (final IOException e) { - e.printStackTrace(); - } - } - - isSetFirst = true; - } - - public void writeLastBoundaryIfNeeds() { - if(isSetLast){ - return; - } - - try { - out.write(("\r\n--" + boundary + "--\r\n").getBytes()); - } catch (final IOException e) { - e.printStackTrace(); - } - - isSetLast = true; - } - - public void addPart(final String key, final String value) { - writeFirstBoundaryIfNeeds(); - try { - out.write(("Content-Disposition: form-data; name=\"" +key+"\"\r\n\r\n").getBytes()); - out.write(value.getBytes()); - out.write(("\r\n--" + boundary + "\r\n").getBytes()); - } catch (final IOException e) { - e.printStackTrace(); - } - } - - public void addPart(final String key, final String fileName, final InputStream fin, final boolean isLast){ - addPart(key, fileName, fin, "application/octet-stream", isLast); - } - - public void addPart(final String key, final String fileName, final InputStream fin, String type, final boolean isLast){ - writeFirstBoundaryIfNeeds(); - try { - type = "Content-Type: "+type+"\r\n"; - out.write(("Content-Disposition: form-data; name=\""+ key+"\"; filename=\"" + fileName + "\"\r\n").getBytes()); - out.write(type.getBytes()); - out.write("Content-Transfer-Encoding: binary\r\n\r\n".getBytes()); - - final byte[] tmp = new byte[4096]; - int l = 0; - while ((l = fin.read(tmp)) != -1) { - out.write(tmp, 0, l); - } - if(!isLast) - out.write(("\r\n--" + boundary + "\r\n").getBytes()); - out.flush(); - } catch (final IOException e) { - e.printStackTrace(); - } finally { - try { - fin.close(); - } catch (final IOException e) { - e.printStackTrace(); - } - } - } - - public void addPart(final String key, final File value, final boolean isLast) { - try { - addPart(key, value.getName(), new FileInputStream(value), isLast); - } catch (final FileNotFoundException e) { - e.printStackTrace(); - } - } - - @Override - public long getContentLength() { - writeLastBoundaryIfNeeds(); - return out.toByteArray().length; - } - - @Override - public Header getContentType() { - return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + boundary); - } - - @Override - public boolean isChunked() { - return false; - } - - @Override - public boolean isRepeatable() { - return false; - } - - @Override - public boolean isStreaming() { - return false; - } - - @Override - public void writeTo(final OutputStream outstream) throws IOException { - outstream.write(out.toByteArray()); - } - - @Override - public Header getContentEncoding() { - return null; - } - - @Override - public void consumeContent() throws IOException, - UnsupportedOperationException { - if (isStreaming()) { - throw new UnsupportedOperationException( - "Streaming entity does not implement #consumeContent()"); - } - } - - @Override - public InputStream getContent() throws IOException, - UnsupportedOperationException { - return new ByteArrayInputStream(out.toByteArray()); - } -} \ No newline at end of file diff --git a/sample-and-tests/libs/android-async-http/com/loopj/android/http/SyncHttpClient.java b/sample-and-tests/libs/android-async-http/com/loopj/android/http/SyncHttpClient.java deleted file mode 100644 index 764aa3c..0000000 --- a/sample-and-tests/libs/android-async-http/com/loopj/android/http/SyncHttpClient.java +++ /dev/null @@ -1,122 +0,0 @@ -package com.loopj.android.http; - -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.protocol.HttpContext; - -import android.content.Context; -import android.os.Message; - -public abstract class SyncHttpClient extends AsyncHttpClient { - private int responseCode; - /* - * as this is a synchronous request this is just a helping mechanism to pass - * the result back to this method. Therefore the result object has to be a - * field to be accessible - */ - protected String result; - protected AsyncHttpResponseHandler responseHandler = new AsyncHttpResponseHandler() { - - void sendResponseMessage(org.apache.http.HttpResponse response) { - responseCode = response.getStatusLine().getStatusCode(); - super.sendResponseMessage(response); - }; - - @Override - protected void sendMessage(Message msg) { - /* - * Dont use the handler and send it directly to the analysis - * (because its all the same thread) - */ - handleMessage(msg); - } - - @Override - public void onSuccess(String content, AsyncHttpRequest request) { - result = content; - } - - @Override - public void onFailure(Throwable error, String content) { - result = onRequestFailed(error, content); - } - }; - - /** - * @return the response code for the last request, might be usefull - * sometimes - */ - public int getResponseCode() { - return responseCode; - } - - // Private stuff - protected AsyncHttpRequest sendRequest(DefaultHttpClient client, - HttpContext httpContext, HttpUriRequest uriRequest, - String contentType, AsyncHttpResponseHandler responseHandler, - Context context) { - if (contentType != null) { - uriRequest.addHeader("Content-Type", contentType); - } - - /* - * will execute the request directly - */ - AsyncHttpRequest httpRequest = new AsyncHttpRequest(client, httpContext, uriRequest, responseHandler); - httpRequest.run(); - return httpRequest; - } - - public abstract String onRequestFailed(Throwable error, String content); - - public void delete(String url, RequestParams queryParams, - AsyncHttpResponseHandler responseHandler) { - // TODO what about query params?? - delete(url, responseHandler); - } - - public String get(String url, RequestParams params) { - this.get(url, params, responseHandler); - /* - * the response handler will have set the result when this line is - * reached - */ - return result; - } - - public String get(String url) { - this.get(url, null, responseHandler); - return result; - } - - public String put(String url, RequestParams params) { - this.put(url, params, responseHandler); - return result; - } - - public String put(String url) { - this.put(url, null, responseHandler); - return result; - } - - public String post(String url, RequestParams params) { - this.post(url, params, responseHandler); - return result; - } - - public String post(String url) { - this.post(url, null, responseHandler); - return result; - } - - public String delete(String url, RequestParams params) { - this.delete(url, params, responseHandler); - return result; - } - - public String delete(String url) { - this.delete(url, null, responseHandler); - return result; - } - -} diff --git a/sample-and-tests/libs/android-support-v4.jar b/sample-and-tests/libs/android-support-v4.jar deleted file mode 100644 index 96644ed..0000000 Binary files a/sample-and-tests/libs/android-support-v4.jar and /dev/null differ diff --git a/sample-and-tests/pom.xml b/sample-and-tests/pom.xml deleted file mode 100755 index 5ff502d..0000000 --- a/sample-and-tests/pom.xml +++ /dev/null @@ -1,224 +0,0 @@ - - - 4.0.0 - - - in.srain - parent - 1.1.0 - - - in.srain.cube - cube-sdk-demo - apk - CUBE DEMO - 1.0.13-SNAPSHOT - - - - in.srain.cube - cube-sdk - apklib - 1.0.34-SNAPSHOT - - - com.google.android - android - 4.4.0 - provided - - - com.google.android - support-v4 - r18 - - - - - 3.7.0 - 16 - - - - - oss-central - https://oss.sonatype.org/content/repositories/releases/ - - true - - - false - - - - oss-snapshots - https://oss.sonatype.org/content/repositories/snapshots - - false - always - - - true - always - - - - - - - - copy-lib - - - - maven-dependency-plugin - - - copyjars - validate - - copy-dependencies - - - true - provided - ${project.basedir}/libs - true - true - - - - copysources - validate - - copy-dependencies - - - sources - false - - ${project.basedir}/libs - true - provided - true - true - - - - - - - - - - release - - - - org.apache.maven.plugins - maven-jarsigner-plugin - - - signing - - sign - verify - - package - true - - true - - - ${project.build.directory}/${project.artifactId}.apk - - - ${sign.keystore} - ${sign.alias} - ${sign.storepass} - true - - - - - - com.jayway.maven.plugins.android.generation2 - android-maven-plugin - - - false - - - true - ${project.build.directory}/${project.artifactId}.apk - - ${project.build.directory}/天维网__${maven.build.timestamp}.apk - - - - false - true - - - ${env.ANDROID_HOME} - ${android.compile.apilevel} - - true - - false - ${project.basedir}/tools/proguard.jar - - - -Xms256m - -Xmx512m - - - - - true - - - alignApk - package - - zipalign - - - - - - org.codehaus.mojo - build-helper-maven-plugin - 1.7 - - - - ${project.build.directory}/天维网__${maven.build.timestamp}.apk - - apk - signed-aligned - - - ${project.build.directory}/proguard/mapping.txt - map - release - - - - - - attach-signed-aligned - package - - attach-artifact - - - - - - - - - diff --git a/sample-and-tests/proguard-project.txt b/sample-and-tests/proguard-project.txt deleted file mode 100644 index f2fe155..0000000 --- a/sample-and-tests/proguard-project.txt +++ /dev/null @@ -1,20 +0,0 @@ -# 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 *; -#} diff --git a/sample-and-tests/project.properties b/sample-and-tests/project.properties deleted file mode 100755 index 99b4254..0000000 --- a/sample-and-tests/project.properties +++ /dev/null @@ -1,15 +0,0 @@ -# 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-19 -android.library.reference.1=../core diff --git a/sample-and-tests/res/color/button_dark_text.xml b/sample-and-tests/res/color/button_dark_text.xml deleted file mode 100644 index 163d8cd..0000000 --- a/sample-and-tests/res/color/button_dark_text.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/sample-and-tests/res/drawable-hdpi/ic_launcher.png b/sample-and-tests/res/drawable-hdpi/ic_launcher.png deleted file mode 100644 index 288b665..0000000 Binary files a/sample-and-tests/res/drawable-hdpi/ic_launcher.png and /dev/null differ diff --git a/sample-and-tests/res/drawable-mdpi/ic_launcher.png b/sample-and-tests/res/drawable-mdpi/ic_launcher.png deleted file mode 100644 index 6ae570b..0000000 Binary files a/sample-and-tests/res/drawable-mdpi/ic_launcher.png and /dev/null differ diff --git a/sample-and-tests/res/drawable-nodpi/pic2.png b/sample-and-tests/res/drawable-nodpi/pic2.png deleted file mode 100644 index 29cb763..0000000 Binary files a/sample-and-tests/res/drawable-nodpi/pic2.png and /dev/null differ diff --git a/sample-and-tests/res/drawable-xhdpi/ic_launcher.png b/sample-and-tests/res/drawable-xhdpi/ic_launcher.png deleted file mode 100644 index d4fb7cd..0000000 Binary files a/sample-and-tests/res/drawable-xhdpi/ic_launcher.png and /dev/null differ diff --git a/sample-and-tests/res/drawable-xhdpi/ptr_pulltorefresh_arrow.png b/sample-and-tests/res/drawable-xhdpi/ptr_pulltorefresh_arrow.png deleted file mode 100644 index 4544edf..0000000 Binary files a/sample-and-tests/res/drawable-xhdpi/ptr_pulltorefresh_arrow.png and /dev/null differ diff --git a/sample-and-tests/res/drawable-xxhdpi/ic_launcher.png b/sample-and-tests/res/drawable-xxhdpi/ic_launcher.png deleted file mode 100644 index 85a6081..0000000 Binary files a/sample-and-tests/res/drawable-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/sample-and-tests/res/drawable/base_img_placeholder.png b/sample-and-tests/res/drawable/base_img_placeholder.png deleted file mode 100644 index 9171ca5..0000000 Binary files a/sample-and-tests/res/drawable/base_img_placeholder.png and /dev/null differ diff --git a/sample-and-tests/res/drawable/bg_border_normal.xml b/sample-and-tests/res/drawable/bg_border_normal.xml deleted file mode 100644 index afb88e7..0000000 --- a/sample-and-tests/res/drawable/bg_border_normal.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/drawable/request_demo_divider.xml b/sample-and-tests/res/drawable/request_demo_divider.xml deleted file mode 100644 index 73c7d8b..0000000 --- a/sample-and-tests/res/drawable/request_demo_divider.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/drawable/selector_border.xml b/sample-and-tests/res/drawable/selector_border.xml deleted file mode 100644 index ca94490..0000000 --- a/sample-and-tests/res/drawable/selector_border.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/drawable/selector_border_normal.xml b/sample-and-tests/res/drawable/selector_border_normal.xml deleted file mode 100644 index 80b1dea..0000000 --- a/sample-and-tests/res/drawable/selector_border_normal.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/drawable/selector_border_selected.xml b/sample-and-tests/res/drawable/selector_border_selected.xml deleted file mode 100755 index a3d7a8a..0000000 --- a/sample-and-tests/res/drawable/selector_border_selected.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/activity_main.xml b/sample-and-tests/res/layout/activity_main.xml deleted file mode 100755 index b9adaa1..0000000 --- a/sample-and-tests/res/layout/activity_main.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/activity_tabs.xml b/sample-and-tests/res/layout/activity_tabs.xml deleted file mode 100755 index 863a020..0000000 --- a/sample-and-tests/res/layout/activity_tabs.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/activity_title_base.xml b/sample-and-tests/res/layout/activity_title_base.xml deleted file mode 100755 index dedb5f0..0000000 --- a/sample-and-tests/res/layout/activity_title_base.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/activity_title_base_frame.xml b/sample-and-tests/res/layout/activity_title_base_frame.xml deleted file mode 100755 index dffea93..0000000 --- a/sample-and-tests/res/layout/activity_title_base_frame.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/base_header_bar_base.xml b/sample-and-tests/res/layout/base_header_bar_base.xml deleted file mode 100755 index 15fb9aa..0000000 --- a/sample-and-tests/res/layout/base_header_bar_base.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/base_header_bar_title.xml b/sample-and-tests/res/layout/base_header_bar_title.xml deleted file mode 100755 index 41ed56f..0000000 --- a/sample-and-tests/res/layout/base_header_bar_title.xml +++ /dev/null @@ -1,73 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/base_views_title_and_info.xml b/sample-and-tests/res/layout/base_views_title_and_info.xml deleted file mode 100755 index 79cf37d..0000000 --- a/sample-and-tests/res/layout/base_views_title_and_info.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - diff --git a/sample-and-tests/res/layout/fragment_bitmap.xml b/sample-and-tests/res/layout/fragment_bitmap.xml deleted file mode 100644 index b85dbc7..0000000 --- a/sample-and-tests/res/layout/fragment_bitmap.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - \ No newline at end of file diff --git a/sample-and-tests/res/layout/fragment_dotview.xml b/sample-and-tests/res/layout/fragment_dotview.xml deleted file mode 100644 index 1989305..0000000 --- a/sample-and-tests/res/layout/fragment_dotview.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - -