Repository: way1989/WayHoo Branch: master Commit: 2198b8d28a28 Files: 333 Total size: 1.4 MB Directory structure: gitextract_c4ix2knx/ ├── .gitignore ├── LICENSE ├── README.md ├── Upgrade-lib/ │ ├── .settings/ │ │ └── org.eclipse.jdt.core.prefs │ ├── AndroidManifest.xml │ ├── proguard-project.txt │ ├── project.properties │ └── src/ │ └── com/ │ └── way/ │ └── upgrade/ │ ├── .MainActivity.java.swp │ ├── MainActivity.java │ ├── bean/ │ │ └── UpgradeInfo.java │ ├── core/ │ │ ├── CheckNewVersionListener.java │ │ ├── UpgradeInterface.java │ │ └── UpgradeManager.java │ ├── job/ │ │ ├── AbstractCheckNewVersionJob.java │ │ ├── CheckNewVersionJobWithoutClientUrl.java │ │ └── DownloadNewVersionJob.java │ ├── locale/ │ │ ├── LocaleChina.java │ │ ├── LocaleChinaTW.java │ │ ├── LocaleChinese.java │ │ ├── LocaleEnglish.java │ │ ├── LocaleHandler.java │ │ └── LocaleUS.java │ ├── parser/ │ │ └── json/ │ │ ├── AbstractJsonParsing.java │ │ └── FirVersionJsonParsing.java │ ├── receiver/ │ │ └── DownloadCompleteReveiver.java │ └── utils/ │ ├── Constants.java │ ├── ContextUtils.java │ ├── FileUtils.java │ ├── Log.java │ ├── NetUtils.java │ ├── Preferences.java │ ├── Utils.java │ └── thread/ │ ├── Future.java │ ├── FutureListener.java │ ├── PriorityThreadFactory.java │ └── ThreadPool.java └── WayHoo/ ├── .settings/ │ └── org.eclipse.jdt.core.prefs ├── AndroidManifest.xml ├── Upgrade-lib/ │ └── com/ │ └── way/ │ └── upgrade/ │ ├── .MainActivity.java.swp │ ├── MainActivity.java │ ├── bean/ │ │ └── UpgradeInfo.java │ ├── core/ │ │ ├── CheckNewVersionListener.java │ │ ├── UpgradeInterface.java │ │ └── UpgradeManager.java │ ├── job/ │ │ ├── AbstractCheckNewVersionJob.java │ │ ├── CheckNewVersionJobWithoutClientUrl.java │ │ └── DownloadNewVersionJob.java │ ├── locale/ │ │ ├── LocaleChina.java │ │ ├── LocaleChinaTW.java │ │ ├── LocaleChinese.java │ │ ├── LocaleEnglish.java │ │ ├── LocaleHandler.java │ │ └── LocaleUS.java │ ├── parser/ │ │ └── json/ │ │ ├── AbstractJsonParsing.java │ │ └── FirVersionJsonParsing.java │ ├── receiver/ │ │ └── DownloadCompleteReveiver.java │ └── utils/ │ ├── Constants.java │ ├── ContextUtils.java │ ├── FileUtils.java │ ├── Log.java │ ├── NetUtils.java │ ├── Preferences.java │ ├── Utils.java │ └── thread/ │ ├── Future.java │ ├── FutureListener.java │ ├── PriorityThreadFactory.java │ └── ThreadPool.java ├── jni/ │ ├── Android.mk │ ├── Application.mk │ ├── bitmapPort.c │ ├── bitmapPort.h │ ├── com_way_util_blur_jni_FrostedGlassUtil.h │ ├── constants.h │ ├── frostedGlass.c │ ├── imageProcess.c │ └── imageProcess.h ├── libs/ │ ├── Bughd_android_sdk_v1.2.6.jar │ ├── android-support-v13.jar │ └── locSDK_5.3.jar ├── proguard-project.txt ├── project.properties ├── res/ │ ├── anim/ │ │ ├── count_down_exit.xml │ │ ├── fade_out.xml │ │ ├── in_from_bottom.xml │ │ ├── in_from_top.xml │ │ ├── out_from_bottom.xml │ │ ├── out_from_top.xml │ │ ├── push_right_out.xml │ │ ├── slide_in_from_bottom.xml │ │ ├── slide_in_from_top.xml │ │ ├── slide_out_to_bottom.xml │ │ └── slide_out_to_top.xml │ ├── color/ │ │ ├── vpi__dark_theme.xml │ │ └── vpi__light_theme.xml │ ├── drawable/ │ │ ├── city_edit_prs.xml │ │ ├── city_query_delete.xml │ │ ├── cityselector_locate_btn_bg.xml │ │ ├── home_setting_selector.xml │ │ ├── indicator_bg_bottom.xml │ │ ├── indicator_bg_top.xml │ │ ├── item_background.xml │ │ ├── item_prs.xml │ │ ├── listview_background.xml │ │ ├── main_city_name_bg.xml │ │ ├── main_life_complete_selector.xml │ │ ├── main_life_edit.xml │ │ ├── module_bg.xml │ │ ├── refresh_icon_anim.xml │ │ ├── resource_circle_progressbar_indeterminate.xml │ │ ├── setting_top_back.xml │ │ ├── settings_bg_city_item_down.xml │ │ ├── settings_bg_city_item_up.xml │ │ ├── shape_bg.xml │ │ ├── sidebar_item_background_dark_selector.xml │ │ ├── sidebar_item_background_light_selector.xml │ │ ├── sidebar_item_selected_layerlist_dark.xml │ │ ├── slidingmenu_shadow.xml │ │ ├── topbar_icon_share_selector.xml │ │ ├── topbar_icon_side_selector.xml │ │ ├── update_forecast_selector.xml │ │ ├── vpi__tab_indicator.xml │ │ ├── weather_detail_activity_btn_bg.xml │ │ └── white_border.xml │ ├── layout/ │ │ ├── about.xml │ │ ├── activity_main.xml │ │ ├── activity_main_actionbar.xml │ │ ├── base_fragment.xml │ │ ├── city_manager_actionbar.xml │ │ ├── city_manager_layout.xml │ │ ├── city_manger_grid_item_add.xml │ │ ├── city_manger_grid_item_normal.xml │ │ ├── city_query_actionbar.xml │ │ ├── city_query_hotcity_grid_item.xml │ │ ├── city_query_layout.xml │ │ ├── city_query_list_item.xml │ │ ├── comm_lay_emptyview.xml │ │ ├── comm_lay_loadfailed.xml │ │ ├── comm_lay_loading.xml │ │ ├── count_down_to_location.xml │ │ ├── custom_progress_dialog.xml │ │ ├── feed_back_view.xml │ │ ├── loading_empty_container.xml │ │ ├── no_results_message.xml │ │ ├── notification_weather_multi.xml │ │ ├── sidemenu_list_item_category.xml │ │ ├── sidemenu_list_item_item.xml │ │ ├── sidemenu_listview.xml │ │ ├── splash_activity_layout.xml │ │ ├── swipeback_layout.xml │ │ ├── weather_aqi.xml │ │ ├── weather_current_condition.xml │ │ ├── weather_details.xml │ │ ├── weather_forecast.xml │ │ ├── weather_forecast_item.xml │ │ ├── weather_fragment.xml │ │ ├── weather_index.xml │ │ ├── weather_index_item.xml │ │ ├── weather_info_error.xml │ │ ├── weather_provider_layout_rigo_2x2.xml │ │ ├── weather_provider_layout_rigo_4x1.xml │ │ └── weather_provider_layout_rigo_4x2.xml │ ├── values/ │ │ ├── arrays.xml │ │ ├── attrs.xml │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── drawables.xml │ │ ├── ids.xml │ │ ├── integers.xml │ │ ├── menudrawer_attrs.xml │ │ ├── menudrawer_colors.xml │ │ ├── menudrawer_ids.xml │ │ ├── menudrawer_strings.xml │ │ ├── menudrawer_styles.xml │ │ ├── strings.xml │ │ ├── styles.xml │ │ ├── swipeback_attrs.xml │ │ ├── swipeback_styles.xml │ │ ├── vpi__attrs.xml │ │ ├── vpi__colors.xml │ │ ├── vpi__defaults.xml │ │ └── vpi__styles.xml │ ├── values-hdpi/ │ │ └── dimens.xml │ ├── values-xhdpi/ │ │ └── dimens.xml │ ├── values-zh-rCN/ │ │ └── strings.xml │ └── xml/ │ ├── weather_appwidget_info_rigo_2x2.xml │ ├── weather_appwidget_info_rigo_4x1.xml │ └── weather_appwidget_info_rigo_4x2.xml └── src/ ├── com/ │ ├── android/ │ │ └── volley/ │ │ ├── AuthFailureError.java │ │ ├── Cache.java │ │ ├── CacheDispatcher.java │ │ ├── DefaultRetryPolicy.java │ │ ├── ExecutorDelivery.java │ │ ├── Network.java │ │ ├── NetworkDispatcher.java │ │ ├── NetworkError.java │ │ ├── NetworkResponse.java │ │ ├── NoConnectionError.java │ │ ├── ParseError.java │ │ ├── Request.java │ │ ├── RequestQueue.java │ │ ├── Response.java │ │ ├── ResponseDelivery.java │ │ ├── RetryPolicy.java │ │ ├── ServerError.java │ │ ├── TimeoutError.java │ │ ├── VolleyError.java │ │ ├── VolleyLog.java │ │ └── toolbox/ │ │ ├── AndroidAuthenticator.java │ │ ├── Authenticator.java │ │ ├── BasicNetwork.java │ │ ├── ByteArrayPool.java │ │ ├── ClearCacheRequest.java │ │ ├── DiskBasedCache.java │ │ ├── HttpClientStack.java │ │ ├── HttpHeaderParser.java │ │ ├── HttpStack.java │ │ ├── HurlStack.java │ │ ├── ImageLoader.java │ │ ├── ImageRequest.java │ │ ├── JsonArrayRequest.java │ │ ├── JsonObjectRequest.java │ │ ├── JsonRequest.java │ │ ├── NetworkImageView.java │ │ ├── NoCache.java │ │ ├── PoolingByteArrayOutputStream.java │ │ ├── RequestFuture.java │ │ ├── StringRequest.java │ │ └── Volley.java │ ├── viewpagerindicator/ │ │ ├── CirclePageIndicator.java │ │ ├── IconPageIndicator.java │ │ ├── IconPagerAdapter.java │ │ ├── IcsLinearLayout.java │ │ ├── LinePageIndicator.java │ │ ├── PageIndicator.java │ │ ├── TabPageIndicator.java │ │ ├── TitlePageIndicator.java │ │ └── UnderlinePageIndicator.java │ └── way/ │ ├── adapter/ │ │ ├── FragmentPagerAdapter.java │ │ ├── ParallaxPagerTransformer.java │ │ ├── QueryCityAdapter.java │ │ ├── SideMenuAdapter.java │ │ ├── WeatherListAdapter.java │ │ └── WeatherPagerAdapter.java │ ├── beans/ │ │ ├── Category.java │ │ ├── City.java │ │ ├── Item.java │ │ └── MainItem.java │ ├── common/ │ │ └── util/ │ │ ├── L.java │ │ ├── LocationUtils.java │ │ ├── LunarCalendar.java │ │ ├── LunarCalendarConvertUtil.java │ │ ├── NetUtil.java │ │ ├── PreferenceUtils.java │ │ ├── SystemUtils.java │ │ ├── T.java │ │ ├── TimeUtils.java │ │ └── WeatherIconUtils.java │ ├── db/ │ │ └── CityProvider.java │ ├── fragment/ │ │ ├── BaseFragment.java │ │ ├── IExceptionDeclare.java │ │ ├── ITaskManager.java │ │ ├── TaskException.java │ │ ├── TaskManager.java │ │ ├── WeatherFragment.java │ │ └── WorkTask.java │ ├── observablescrollview/ │ │ ├── CacheFragmentStatePagerAdapter.java │ │ ├── ObservableGridView.java │ │ ├── ObservableListView.java │ │ ├── ObservableScrollView.java │ │ ├── ObservableScrollViewCallbacks.java │ │ ├── ObservableWebView.java │ │ ├── ScrollState.java │ │ ├── ScrollUtils.java │ │ ├── Scrollable.java │ │ └── TouchInterceptionFrameLayout.java │ ├── ui/ │ │ ├── swipeback/ │ │ │ ├── SwipeBackActivity.java │ │ │ ├── SwipeBackActivityBase.java │ │ │ ├── SwipeBackActivityHelper.java │ │ │ ├── SwipeBackLayout.java │ │ │ └── ViewDragHelper.java │ │ └── view/ │ │ ├── CountDownView.java │ │ ├── DragSortGridView.java │ │ ├── LoadingEmptyContainer.java │ │ ├── NoResultsContainer.java │ │ ├── TouchDispatchView.java │ │ ├── WeatherAqiView.java │ │ ├── WeatherBaseView.java │ │ ├── WeatherDetailsView.java │ │ ├── WeatherForecastView.java │ │ ├── WeatherIndexView.java │ │ └── WeatherTypefacedTextView.java │ ├── util/ │ │ └── blur/ │ │ └── jni/ │ │ ├── BitmapUtils.java │ │ └── FrostedGlassUtil.java │ ├── weather/ │ │ └── plugin/ │ │ ├── bean/ │ │ │ ├── AQI.java │ │ │ ├── Alerts.java │ │ │ ├── Forecast.java │ │ │ ├── Index.java │ │ │ ├── IndexDetail.java │ │ │ ├── RealTime.java │ │ │ └── WeatherInfo.java │ │ ├── spider/ │ │ │ ├── WeatherConstants.java │ │ │ ├── WeatherController.java │ │ │ ├── WeatherSpider.java │ │ │ └── WeatherUtilities.java │ │ └── util/ │ │ ├── Constants.java │ │ └── NetUtil.java │ └── yahoo/ │ ├── AboutActivity.java │ ├── App.java │ ├── BaseActivity.java │ ├── FeedBackActivity.java │ ├── MainActivity.java │ ├── ManagerCityActivity.java │ ├── QueryCityActivity.java │ └── SplashActivity.java └── net/ └── simonvt/ └── menudrawer/ ├── BuildLayerFrameLayout.java ├── ColorDrawable.java ├── DraggableDrawer.java ├── FloatScroller.java ├── MenuDrawer.java ├── NoClickThroughFrameLayout.java ├── OverlayDrawer.java ├── PeekInterpolator.java ├── Position.java ├── Scroller.java ├── SinusoidalInterpolator.java ├── SlideDrawable.java ├── SlidingDrawer.java ├── SmoothInterpolator.java ├── StaticDrawer.java ├── ViewHelper.java └── compat/ ├── ActionBarHelper.java ├── ActionBarHelperCompat.java └── ActionBarHelperNative.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Built application files *.apk *.ap_ .DS_Store # files for the dex VM *.dex # Java class files *.class # generated files bin/ gen/ # Local configuration file (sdk path, etc) local.properties # Eclipse project files .classpath .project # Proguard folder generated by Eclipse proguard/ # Intellij project files *.iml *.ipr *.iws .idea/ # Gradle files .gradle/ build/ # Local configuration file (sdk path, etc) local.properties # Proguard folder generated by Eclipse proguard/ ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2014 way 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. ================================================ FILE: README.md ================================================ 威震天气 ====== 本应用是以变形金刚作为主题元素的实用型Android天气软件,界面高仿雅虎天气,数据来自中国天气网! ##下载apk [腾讯应用市场](http://sj.qq.com/myapp/detail.htm?apkName=com.way.yahoo) [百度应用市场](http://shouji.baidu.com/soft/item?docid=6930651&from=as&f=search_app_%E5%A8%81%E9%9C%87%E5%A4%A9%E6%B0%94%40list_1_title%401%40header_all_input) # **威震天气 Android 客户端项目简析** # *注:本文假设你已经有Android开发环境* ①.启动Eclipse,将名为WayHoo导入作为主工程,并确保你当前的Android SDK是最新版。
②.将libs目录下相应的库导入Eclipse,并作为主工程的库工程,以免缺少一些必要的资源或类。
③.如果编译出错,请修改项目根目录下的 project.properties 文件。
④.请使用Android 4.0 以上版本的SDK,JDK1.6编译: > target=android-19 **本项目采用 GPL 授权协议,欢迎大家在这个基础上进行改进,并与大家分享。** ## 联系我 way: * [邮箱](mailto:way.ping.li@gmail.com "给我发邮件") * [博客](http://blog.csdn.net/way_ping_li "CSDN博客") ## 测试截图 ###高斯模糊效果图 ![Screenshot 0](https://raw.githubusercontent.com/way1989/WayHoo/master/screenshots/0.png "Screenshot 0") ![Screenshot 1](http://git.oschina.net/way/WayHoo/raw/master/screenshots/1.png "Screenshot 1") ![Screenshot 2](http://git.oschina.net/way/WayHoo/raw/master/screenshots/2.png "Screenshot 2") ![Screenshot 3](http://git.oschina.net/way/WayHoo/raw/master/screenshots/3.png "Screenshot 3") ![Screenshot 4](http://git.oschina.net/way/WayHoo/raw/master/screenshots/4.png "Screenshot 4") ![Screenshot 5](http://git.oschina.net/way/WayHoo/raw/master/screenshots/5.png "Screenshot 5") ![Screenshot 6](http://git.oschina.net/way/WayHoo/raw/master/screenshots/6.png "Screenshot 6") ================================================ FILE: Upgrade-lib/.settings/org.eclipse.jdt.core.prefs ================================================ 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 ================================================ FILE: Upgrade-lib/AndroidManifest.xml ================================================ ================================================ FILE: Upgrade-lib/proguard-project.txt ================================================ # To enable ProGuard in your project, edit project.properties # to define the proguard.config property as described in that file. # # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the ProGuard # include property in project.properties. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: Upgrade-lib/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-22 android.library=true ================================================ FILE: Upgrade-lib/src/com/way/upgrade/MainActivity.java ================================================ package com.way.upgrade; import android.app.Activity; import android.os.Bundle; import com.way.upgrade.core.UpgradeManager; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final UpgradeManager upgradeMangeer = UpgradeManager.newInstance(this); upgradeMangeer.askForNewVersion(); } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/bean/UpgradeInfo.java ================================================ package com.way.upgrade.bean; import android.os.Parcel; import android.os.Parcelable; /** * 版本更新信息 * * @author way * @since 2014/4/28 */ public class UpgradeInfo implements Parcelable{ private int id; /**唯一标识apk*/ private String key; /** 版本信息 */ private String version; /** 版本名称 */ private String versionName; /** 是否有更新 */ private String result; /** 新版本地址 */ private String url; /** 版本描述 */ private String description; /** 已下载的大小 */ private long downloadSize; private String mustUpdate; private String changeLog; private String errorCode; public static final Parcelable.Creator CREATOR = new Creator() { @Override public UpgradeInfo[] newArray(int size) { return new UpgradeInfo[size]; } @Override public UpgradeInfo createFromParcel(Parcel source) { return new UpgradeInfo(source); } }; public UpgradeInfo() { } public UpgradeInfo(Parcel in) { id = in.readInt(); key = in.readString(); version = in.readString(); versionName = in.readString(); result = in.readString(); url = in.readString(); description = in.readString(); downloadSize = in.readLong(); result = in.readString(); mustUpdate = in.readString(); changeLog = in.readString(); errorCode = in.readString(); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(key); dest.writeString(version); dest.writeString(versionName); dest.writeString(result); dest.writeString(url); dest.writeString(description); dest.writeLong(downloadSize); dest.writeString(result); dest.writeString(mustUpdate); dest.writeString(changeLog); dest.writeString(errorCode); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public long getDownloadSize() { return downloadSize; } public void setDownloadSize(long downloadSize) { this.downloadSize = downloadSize; } public String getVersionName() { return versionName; } public void setVersionName(String versionName) { this.versionName = versionName; } public String isResult() { return result; } public void setResult(String result) { this.result = result; } public String getMustUpdate() { return mustUpdate; } public void setMustUpdate(String mustUpdate) { this.mustUpdate = mustUpdate; } public String getChangeLog() { return changeLog; } public void setChangeLog(String changeLog) { this.changeLog = changeLog; } public String getResult() { return result; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } @Override public String toString() { return "UpgradeInfo [id=" + id + ", key=" + key + ", version=" + version + ", versionName=" + versionName + ", result=" + result + ", url=" + url + ", description=" + description + ", downloadSize=" + downloadSize + ", mustUpdate=" + mustUpdate + ", changeLog=" + changeLog + ", errorCode=" + errorCode + "]"; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/core/CheckNewVersionListener.java ================================================ package com.way.upgrade.core; /** * * @author way * @sine 2014/10/29 */ public interface CheckNewVersionListener { public void checkNewVersion(boolean result); } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/core/UpgradeInterface.java ================================================ package com.way.upgrade.core; import com.way.upgrade.bean.UpgradeInfo; /** * * @author way * @since 2014/4/28 */ public interface UpgradeInterface { /** * 请求服务器是否有新版本,并弹出对话框 * * @return */ public void askForNewVersion(); /** * 请求服务器是否有新版本 * * @return */ public void askForNewVersionFlag( CheckNewVersionListener checkversionListener); /** * 下载新版本 * * @return */ public void downloadNewVersion(UpgradeInfo upgradeInfo); } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/core/UpgradeManager.java ================================================ package com.way.upgrade.core; import java.util.HashMap; import java.util.Locale; import java.util.Map; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.Toast; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.job.CheckNewVersionJobWithoutClientUrl; import com.way.upgrade.job.DownloadNewVersionJob; import com.way.upgrade.locale.LocaleChina; import com.way.upgrade.locale.LocaleChinaTW; import com.way.upgrade.locale.LocaleChinese; import com.way.upgrade.locale.LocaleEnglish; import com.way.upgrade.locale.LocaleHandler; import com.way.upgrade.locale.LocaleUS; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.ContextUtils; import com.way.upgrade.utils.thread.Future; import com.way.upgrade.utils.thread.FutureListener; import com.way.upgrade.utils.thread.ThreadPool; /** * * @author way * @since 2014/4/28 */ public class UpgradeManager extends LocaleHandler implements UpgradeInterface { private Context mContext; private static ThreadPool mThreadPool; private Handler mHandler; private AlertDialog alertDialog; private AlertDialog alertDialogForMustUpdate; private ProgressDialog mProgressDialog; private Map handlers; private static Future mFuture; private CheckNewVersionListener mAskForNewVersionFlagListener; private FutureListener mAskForNewVersionListener = new FutureListener() { public void onFutureDone(Future future) { UpgradeInfo upgradeInfo = future.get(); Message msg = mHandler.obtainMessage(); if (upgradeInfo != null) { if (upgradeInfo.getErrorCode() != null) { if (upgradeInfo.getErrorCode().equals( Constants.ERROR_CODE_NET)) { msg.what = Constants.MSG_NET_ERROR; } } else if (Boolean.parseBoolean(upgradeInfo.getResult())) { mFuture = future; msg.what = Constants.MSG_HAVA_NEW_VERSION; msg.obj = upgradeInfo; } else if (!Boolean.parseBoolean(upgradeInfo.getResult())) { msg.what = Constants.MSG_NO_NEW_VERSION; } } else { msg.what = Constants.MSG_NO_NEW_VERSION; } mHandler.sendMessage(msg); }; }; public class AskForNewVersionFlag implements FutureListener { @Override public void onFutureDone(Future future) { UpgradeInfo upgradeInfo = future.get(); boolean result = false; if (upgradeInfo != null) { result = Boolean.parseBoolean(upgradeInfo.getResult()); } Message msg = mHandler.obtainMessage(); msg.what = Constants.MSG_VERSION_RESULT; msg.obj = result; mHandler.sendMessage(msg); } } public UpgradeManager(Context context) { createHandlers(); mContext = context; init(); } private void init() { if (mThreadPool == null) { mThreadPool = new ThreadPool(); } mHandler = new Handler(mContext.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case Constants.MSG_HAVA_NEW_VERSION: try { ContextUtils.closeProgressDialog(mProgressDialog); UpgradeInfo description = (UpgradeInfo) msg.obj; showDialog(description); } catch (Exception e1) { e1.printStackTrace(); } break; case Constants.MSG_NO_NEW_VERSION: try { ContextUtils.closeProgressDialog(mProgressDialog); ContextUtils.showToast(mContext, getToastMessage(), Toast.LENGTH_SHORT); } catch (Exception e) { e.printStackTrace(); } break; case Constants.MSG_START_DOWNLOAD: UpgradeInfo description1 = (UpgradeInfo) msg.obj; downloadNewVersion(description1); break; case Constants.MSG_VERSION_RESULT: Boolean result = (Boolean) msg.obj; mAskForNewVersionFlagListener.checkNewVersion(result); break; case Constants.MSG_NET_ERROR: try { ContextUtils.closeProgressDialog(mProgressDialog); } catch (Exception e) { e.printStackTrace(); } ContextUtils.showToast(mContext, getToastNetErrorMessage(), Toast.LENGTH_SHORT); default: break; } } }; alertDialog = ContextUtils.showAlertDialog(mContext, getDialogTitle(), "", new int[] { android.R.string.ok, android.R.string.cancel }, new DialogInterface.OnClickListener[] { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { if (mFuture != null) { Message msg = mHandler.obtainMessage(); msg.what = Constants.MSG_START_DOWNLOAD; msg.obj = mFuture.get(); mHandler.sendMessage(msg); } } }, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } } }); alertDialogForMustUpdate = ContextUtils .showAlertDialog( mContext, getDialogTitle(), "", new int[] { android.R.string.ok }, new DialogInterface.OnClickListener[] { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { if (mFuture != null) { Message msg = mHandler.obtainMessage(); msg.what = Constants.MSG_START_DOWNLOAD; msg.obj = mFuture.get(); mHandler.sendMessage(msg); } } } }); alertDialogForMustUpdate.setCancelable(false); mProgressDialog = ContextUtils.createProgressDialog(mContext); mProgressDialog.setTitle(getProgressDialogTitle()); mProgressDialog.setMessage(getProgressDialogMessage()); } public static UpgradeManager newInstance(Context context) { return new UpgradeManager(context); } private void showProgressDialog() { if (mProgressDialog != null) { try { mProgressDialog.show(); } catch (Exception e) { e.printStackTrace(); } } } @Override public void askForNewVersion() { showProgressDialog(); mThreadPool.submit(new CheckNewVersionJobWithoutClientUrl(mContext), mAskForNewVersionListener, ThreadPool.MODE_NETWORK); } @Override public void askForNewVersionFlag( CheckNewVersionListener checkversionListener) { if (checkversionListener == null) { return; } mAskForNewVersionFlagListener = checkversionListener; AskForNewVersionFlag mAskForNewVersionFlagListener = new AskForNewVersionFlag(); mThreadPool.submit(new CheckNewVersionJobWithoutClientUrl(mContext), mAskForNewVersionFlagListener, ThreadPool.MODE_NETWORK); } @Override public void downloadNewVersion(UpgradeInfo upgradeInfo) { mThreadPool.submit(new DownloadNewVersionJob(mContext, upgradeInfo), null, ThreadPool.MODE_CPU); } private void createHandlers() { handlers = new HashMap(); handlers.put(LocaleChinese.defaultLocale, new LocaleChinese()); handlers.put(LocaleChinaTW.defaultLocale, new LocaleChinaTW()); handlers.put(LocaleEnglish.defaultLocale, new LocaleEnglish()); handlers.put(Locale.CHINA.toString(), new LocaleChina()); handlers.put(Locale.US.toString(), new LocaleUS()); } private LocaleHandler lookupHandlerBy(String handlerName) { LocaleHandler handler = handlers.get(handlerName); if (handler == null) return handlers.get(Locale.ENGLISH.getLanguage()); return handlers.get(handlerName); } private void showDialog(UpgradeInfo description) { int mustUpdate = Integer.valueOf(description.getMustUpdate()); boolean result = Boolean.parseBoolean(description.isResult()); String descriptionStr = description.getChangeLog(); Log.i("liweiping", "mustUpdate = " + mustUpdate + ", result = " + result + ", alertDialog = " + alertDialog + ", alertDialogForMustUpdate = " + alertDialogForMustUpdate); if (mustUpdate == Constants.NOT_MUST_UPDATE) { if (alertDialog != null && result) { alertDialog.setTitle(getDialogTitle()); alertDialog.setMessage(descriptionStr); alertDialog.show(); } } else { if (alertDialogForMustUpdate != null && result) { alertDialogForMustUpdate.setTitle(getDialogTitle()); alertDialogForMustUpdate.setMessage(descriptionStr); alertDialogForMustUpdate.show(); } } } private String getLocaleLanguage() { return Locale.getDefault().toString(); } @Override public String getDialogTitle() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getDialogTitle(); } @Override public String getProgressDialogTitle() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getProgressDialogTitle(); } @Override public String getProgressDialogMessage() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getProgressDialogMessage(); } @Override public String getToastMessage() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getToastMessage(); } @Override public String getToastNetErrorMessage() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getToastNetErrorMessage(); } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/job/AbstractCheckNewVersionJob.java ================================================ package com.way.upgrade.job; import java.io.IOException; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.parser.json.FirVersionJsonParsing; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.NetUtils; import com.way.upgrade.utils.NetUtils.NETWORK_STATUS; import com.way.upgrade.utils.thread.ThreadPool; import com.way.upgrade.utils.thread.ThreadPool.JobContext; /** * * @author way * @since 2014/4/28 */ public abstract class AbstractCheckNewVersionJob implements ThreadPool.Job { protected Context mContext; protected String bundle_id; protected String api_token; public AbstractCheckNewVersionJob(Context context) { this.mContext = context; try { ApplicationInfo appInfo = mContext.getPackageManager() .getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA); bundle_id = appInfo.metaData.getString("bundle_id"); api_token = appInfo.metaData.getString("api_token"); } catch (NameNotFoundException e) { throw new NullPointerException( "app_id and token must not null in AndroidManifest.xml " + e); } Log.i("liweiping", "AbstractCheckNewVersionJob app_id = " + bundle_id + ", api_token = " + api_token); } @Override public UpgradeInfo run(JobContext jc) { UpgradeInfo upgradeInfo = null; if (NetUtils.getNetworkType(mContext) == NETWORK_STATUS.STATE_NONE_NETWORK) { Log.i("liweiping", "NETWORK_STATUS.STATE_NONE_NETWORK"); upgradeInfo = new UpgradeInfo(); upgradeInfo.setErrorCode(Constants.ERROR_CODE_NET); return upgradeInfo; } try { String checkUpdateUrl = String.format(getCheckVersionUrl(), bundle_id, api_token); Log.i("liweiping", "checkUpdateUrl = " + checkUpdateUrl); JSONObject jo = NetUtils.getJSONArrayByGet(checkUpdateUrl); FirVersionJsonParsing firVersionJsonParsing = new FirVersionJsonParsing( mContext); Log.i("liweiping", "upgradeInfo = " + upgradeInfo + ", checkUpdateUrl = " + checkUpdateUrl + ", jo = " + jo.toString()); upgradeInfo = firVersionJsonParsing.readJsonItem(jo); } catch (Exception e) { upgradeInfo = new UpgradeInfo(); upgradeInfo.setErrorCode(Constants.ERROR_CODE_NET); Log.i("liweiping",e.getMessage()); e.printStackTrace(); } return upgradeInfo; } public abstract String getCheckVersionUrl(); } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/job/CheckNewVersionJobWithoutClientUrl.java ================================================ package com.way.upgrade.job; import android.content.Context; import com.way.upgrade.utils.Constants; /** * * @author way * @since 2014/4/28 */ public class CheckNewVersionJobWithoutClientUrl extends AbstractCheckNewVersionJob { public CheckNewVersionJobWithoutClientUrl(Context context) { super(context); } @Override public String getCheckVersionUrl() { return Constants.BASE_URL; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/job/DownloadNewVersionJob.java ================================================ package com.way.upgrade.job; import java.io.File; import android.app.DownloadManager; import android.app.DownloadManager.Request; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.util.Log; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.Preferences; import com.way.upgrade.utils.thread.ThreadPool; import com.way.upgrade.utils.thread.ThreadPool.JobContext; public class DownloadNewVersionJob implements ThreadPool.Job { private Context mContext; private UpgradeInfo mUpgradeInfo; private boolean allowMobileDownload = false; private static final long MAX_ALLOWED_DOWNLOAD_BYTES_BY_MOBILE = 3145725; public DownloadNewVersionJob(Context context, UpgradeInfo upgradeInfo) { this.mContext = context; this.mUpgradeInfo = upgradeInfo; } @Override public Void run(JobContext jc) { try { if (checkDownloadRunning()) return null; if (checkApkExist()) { Intent installApkIntent = new Intent(); installApkIntent.setAction(Intent.ACTION_VIEW); installApkIntent.setDataAndType( Uri.parse(Preferences.getDownloadPath(mContext)), "application/vnd.android.package-archive"); installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); mContext.startActivity(installApkIntent); } else { String apkName = mContext.getPackageName() + System.currentTimeMillis() + Constants.APK_SUFFIX; // 系统下载程序 final DownloadManager downloadManager = (DownloadManager) mContext .getSystemService(mContext.DOWNLOAD_SERVICE); Long recommendedMaxBytes = DownloadManager .getRecommendedMaxBytesOverMobile(mContext); // 可以在移动网络下下载 if (recommendedMaxBytes == null || recommendedMaxBytes.longValue() > MAX_ALLOWED_DOWNLOAD_BYTES_BY_MOBILE) { allowMobileDownload = true; } Uri uri = Uri.parse(mUpgradeInfo.getUrl()); final Request request = new Request(uri); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); int NETWORK_TYPE = DownloadManager.Request.NETWORK_WIFI; if (allowMobileDownload) { NETWORK_TYPE |= DownloadManager.Request.NETWORK_MOBILE; } request.setAllowedNetworkTypes(NETWORK_TYPE); request.allowScanningByMediaScanner(); request.setShowRunningNotification(true); request.setVisibleInDownloadsUi(true); request.setDestinationInExternalPublicDir( Environment.DIRECTORY_DOWNLOADS, apkName); PackageManager packageManager = mContext.getPackageManager(); ApplicationInfo applicationInfo = packageManager .getApplicationInfo(mContext.getPackageName(), 0); Log.i("liweiping", "appName = " + packageManager .getApplicationLabel(applicationInfo)); request.setTitle(packageManager .getApplicationLabel(applicationInfo)); request.setMimeType("application/vnd.android.package-archive"); // id 保存起来跟之后的广播接收器作对比 long id = downloadManager.enqueue(request); long oldId = Preferences.getDownloadId(mContext); if (oldId != -1) { downloadManager.remove(oldId); } Preferences.removeAll(mContext); Preferences.setDownloadId(mContext, id); Preferences.setUpgradeInfo(mContext, mUpgradeInfo); Preferences.setDownloadStatus(mContext, Constants.DOWNLOAD_STATUS_RUNNING); } } catch (Exception e) { e.printStackTrace(); } return null; } private boolean checkApkExist() { UpgradeInfo prefUpgradeInfo = Preferences.getUpgradeInfo(mContext); String version = prefUpgradeInfo.getVersion(); String downloadPath = Preferences.getDownloadPath(mContext); if (version != null && version.trim().length() != 0 && version.equals(mUpgradeInfo.getVersion()) && downloadPath != null && downloadPath.trim().length() != 0) { String path = Uri.parse(downloadPath).getPath(); if (path != null && path.endsWith(Constants.APK_SUFFIX)) { File file = new File(path); if (file.exists()) { return true; } } } return false; } @SuppressWarnings("static-access") private boolean checkDownloadRunning() { UpgradeInfo prefUpgradeInfo = Preferences.getUpgradeInfo(mContext); String version = prefUpgradeInfo.getVersion(); int downloadStatus = Preferences.getDownloadStatus(mContext); if (version != null && version.trim().length() != 0 && version.equals(mUpgradeInfo.getVersion())) { long downloadId = Preferences.getDownloadId(mContext); if (downloadId != -1) { final DownloadManager downloadManager = (DownloadManager) mContext .getSystemService(mContext.DOWNLOAD_SERVICE); DownloadManager.Query mDownloadQuery = new DownloadManager.Query(); mDownloadQuery.setFilterById(downloadId); Cursor cursor = downloadManager.query(mDownloadQuery); if (cursor != null && cursor.moveToFirst()) { int status = cursor.getInt(cursor .getColumnIndex(DownloadManager.COLUMN_STATUS)); if (status == DownloadManager.STATUS_RUNNING || downloadStatus == Constants.DOWNLOAD_STATUS_RUNNING) { return true; } } } } return false; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/locale/LocaleChina.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public class LocaleChina extends LocaleChinese { } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/locale/LocaleChinaTW.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public class LocaleChinaTW extends LocaleChinese { public static final String defaultLocale = "zh_TW"; @Override public String getDialogTitle() { return "發現新版本,是否升級?"; } @Override public String getProgressDialogTitle() { return "檢查更新"; } @Override public String getProgressDialogMessage() { return "正在檢查..."; } @Override public String getToastMessage() { return "已是最新版本"; } @Override public String getToastNetErrorMessage() { return "網路異常"; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/locale/LocaleChinese.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public class LocaleChinese extends LocaleHandler { public static final String defaultLocale = "zh"; @Override public String getDialogTitle() { return "发现新版本,是否升级?"; } @Override public String getProgressDialogTitle() { return "检查更新"; } @Override public String getProgressDialogMessage() { return "正在检查..."; } @Override public String getToastMessage() { return "已是最新版本"; } @Override public String getToastNetErrorMessage() { return "网络异常"; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/locale/LocaleEnglish.java ================================================ package com.way.upgrade.locale; public class LocaleEnglish extends LocaleHandler { public static final String defaultLocale = "en"; @Override public String getDialogTitle() { return "Find New Version,Update Now?"; } @Override public String getProgressDialogTitle() { return "Check Update"; } @Override public String getProgressDialogMessage() { return "Checking"; } @Override public String getToastMessage() { return "Is the latest version"; } @Override public String getToastNetErrorMessage() { return "Net Error"; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/locale/LocaleHandler.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public abstract class LocaleHandler { protected String value; public abstract String getDialogTitle(); public abstract String getProgressDialogTitle(); public abstract String getProgressDialogMessage(); public abstract String getToastMessage(); public abstract String getToastNetErrorMessage(); public void setUpgradeDescription(String value) { this.value = value; } public String getUpgradeDescription() { return value; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/locale/LocaleUS.java ================================================ package com.way.upgrade.locale; public class LocaleUS extends LocaleEnglish { } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/parser/json/AbstractJsonParsing.java ================================================ package com.way.upgrade.parser.json; import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public abstract class AbstractJsonParsing { public abstract T readJsonItem(JSONObject jsonItem) throws JSONException; /** * 输入InputStream * * @param inStream * @return * @throws Exception */ public ArrayList readJsonArray(JSONArray jsonArray) { try { ArrayList listOperating = new ArrayList(); for (int i = 0; i < jsonArray.length(); i++) { JSONObject item = jsonArray.getJSONObject(i); T itemBean = readJsonItem(item); listOperating.add(itemBean); } return listOperating; } catch (JSONException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/parser/json/FirVersionJsonParsing.java ================================================ package com.way.upgrade.parser.json; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.ContextUtils; public class FirVersionJsonParsing extends AbstractJsonParsing { private Context mContext; public FirVersionJsonParsing(Context context) { mContext = context; } @Override public UpgradeInfo readJsonItem(JSONObject versionJsonObj) throws JSONException { UpgradeInfo upgradeInfo = new UpgradeInfo(); String url = versionJsonObj.getString("installUrl"); String firVersionCode = versionJsonObj.getString("version"); String firVersionName = versionJsonObj.getString("versionShort"); String changeLog = versionJsonObj.getString("changelog"); upgradeInfo.setUrl(url); upgradeInfo.setVersion(firVersionCode); boolean result = ContextUtils.getVersionCode(mContext) < Integer .parseInt(firVersionCode) || (ContextUtils.getVersionCode(mContext) == Integer .parseInt(firVersionCode) && !ContextUtils .getVersionName(mContext).equals(firVersionName)); upgradeInfo.setResult(String.valueOf(result)); upgradeInfo.setVersionName(firVersionName); upgradeInfo.setMustUpdate(Constants.NOT_MUST_UPDATE + ""); upgradeInfo.setChangeLog(changeLog); return upgradeInfo; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/receiver/DownloadCompleteReveiver.java ================================================ package com.way.upgrade.receiver; import android.app.DownloadManager; import android.app.DownloadManager.Query; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import com.way.upgrade.utils.Preferences; /** * 下载完成通知接收器 * * @author way * */ public class DownloadCompleteReveiver extends BroadcastReceiver { private DownloadManager downloadManager; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); if (id == Preferences.getDownloadId(context)) { Query query = new Query(); query.setFilterById(id); downloadManager = (DownloadManager) context .getSystemService(Context.DOWNLOAD_SERVICE); Cursor cursor = downloadManager.query(query); int columnCount = cursor.getColumnCount(); String path = null; while (cursor.moveToNext()) { for (int j = 0; j < columnCount; j++) { String columnName = cursor.getColumnName(j); String string = cursor.getString(j); if ("local_uri".equals(columnName)) { path = string; } } } cursor.close(); if (path != null) { Preferences.setDownloadPath(context, path); Preferences.setDownloadStatus(context, -1); Intent installApkIntent = new Intent(); installApkIntent.setAction(Intent.ACTION_VIEW); installApkIntent.setDataAndType(Uri.parse(path), "application/vnd.android.package-archive"); installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); context.startActivity(installApkIntent); } } } else if (action.equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) { long[] ids = intent .getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); if (ids.length > 0 && ids[0] == Preferences.getDownloadId(context)) { Intent downloadIntent = new Intent(); downloadIntent.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS); downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); context.startActivity(downloadIntent); } } } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/Constants.java ================================================ package com.way.upgrade.utils; /** * * @author way 2014/4/28 */ public class Constants { //public static final String BASE_URL = "http://fir.im/api/v2/app/version/%s?token=%s"; public static final String BASE_URL = "http://api.fir.im/apps/latest/%s?api_token=%s"; public static final String DOWNLOAD_FILE_PATH = "/upgrade"; public static final int MSG_HAVA_NEW_VERSION = 1; public static final int MSG_NO_NEW_VERSION = 2; public static final int MSG_START_DOWNLOAD = 3; public static final int MSG_VERSION_RESULT = 4; public static final int MSG_NET_ERROR = 5; public static final int MUST_UPDATE = 1; public static final int NOT_MUST_UPDATE = 0; public static final String APK_SUFFIX = ".apk"; public static final Integer DOWNLOAD_STATUS_RUNNING = 1; public static final String ERROR_CODE_NET = "net_error"; } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/ContextUtils.java ================================================ package com.way.upgrade.utils; import java.lang.reflect.Method; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.os.Build; import android.util.Log; import android.widget.Toast; /** * 上下文操作,如创建对话框,进度条,版本信息... * * @author way 2013/12/6 */ public class ContextUtils { private static final String TAG = "ContextUtils"; /** * Show a Toast(Toast.LENGTH_SHORT). * * @param text * the content shown on the Toast. */ public static void showToast(Context context, String text, int length) { Toast.makeText(context, text, length).show(); } /** * Show a Toast(Toast.LENGTH_SHORT). * * @param text * the content shown on the Toast. */ public static void showToast(Context context, int resId, int length) { Toast.makeText(context, resId, length).show(); } public static ProgressDialog createProgressDialog(Context context) { ProgressDialog dialog = new ProgressDialog(context); dialog.setIndeterminate(true); dialog.setCancelable(true); return dialog; } /** * show progress dialog * * @param context * @param title * Dialog title * @param message * Dialog message * @return */ public static ProgressDialog showProgressDialog(Context context, int title, int message) { ProgressDialog dialog = new ProgressDialog(context); dialog.setTitle(title); dialog.setMessage(context.getResources().getString(message)); dialog.setIndeterminate(true); dialog.setCancelable(true); dialog.show(); return dialog; } /** * close progress dialog * * @param progressDialog */ public static void closeProgressDialog(Dialog progressDialog) { if (progressDialog != null && progressDialog.isShowing()) { progressDialog.cancel(); } } /** * * @param context * @param title * @param message * @param buttonTexts * @param listeners * @return */ public static AlertDialog.Builder showDialog(Context context, int title, int message, int[] buttonTexts, OnClickListener[] listeners) { AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(title); dialog.setMessage(message); if (buttonTexts.length == 1) { dialog.setNeutralButton(buttonTexts[0], listeners[0]); } else if (buttonTexts.length == 2) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNegativeButton(buttonTexts[1], listeners[1]); } else if (buttonTexts.length == 3) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNeutralButton(buttonTexts[1], listeners[1]); dialog.setNegativeButton(buttonTexts[2], listeners[2]); } dialog.show(); return dialog; } /** * * @param context * @param title * @param message * @param buttonTexts * @param listeners * @return */ public static AlertDialog.Builder showDialog(Context context, String title, String message, int[] buttonTexts, OnClickListener[] listeners) { AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(title); dialog.setMessage(message); if (buttonTexts.length == 1) { dialog.setNeutralButton(buttonTexts[0], listeners[0]); } else if (buttonTexts.length == 2) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNegativeButton(buttonTexts[1], listeners[1]); } else if (buttonTexts.length == 3) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNeutralButton(buttonTexts[1], listeners[1]); dialog.setNegativeButton(buttonTexts[2], listeners[2]); } dialog.show(); return dialog; } /** * * @param context * @param title * @param message * @param buttonTexts * @param listeners * @return */ public static AlertDialog showAlertDialog(Context context, String title, String message, int[] buttonTexts, OnClickListener[] listeners) { AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(title); dialog.setMessage(message); if (buttonTexts.length == 1) { dialog.setNeutralButton(buttonTexts[0], listeners[0]); } else if (buttonTexts.length == 2) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNegativeButton(buttonTexts[1], listeners[1]); } else if (buttonTexts.length == 3) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNeutralButton(buttonTexts[1], listeners[1]); dialog.setNegativeButton(buttonTexts[2], listeners[2]); } return dialog.create(); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static String getCustomVersion() { try { String className = "android.os.SystemProperties"; String methodName = "get"; String key = "ro.custom.build.version"; Class clazz = Class.forName(className); // Constructor con = clazz.getEnclosingConstructor(); Method method = clazz.getDeclaredMethod(methodName, String.class); return (String) method.invoke(clazz, key); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 获取版本号 * * @param context * @return */ public static int getVersionCode(Context context) { int versionCode = -1; try { PackageInfo info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); versionCode = info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); Log.e(TAG, e.getMessage()); } return versionCode; } /** * 获取版本信息 * * @param mContext * @return */ public static String getVersionName(Context context) { String versionName = null; try { PackageInfo info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); versionName = info.versionName; // int versionCode = info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); Log.e(TAG, e.getMessage()); } return versionName; } public static String getUserAgent(Context context) { PackageInfo packageInfo; try { packageInfo = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); } catch (NameNotFoundException e) { throw new IllegalStateException("getPackageInfo failed"); } return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s", packageInfo.packageName, packageInfo.versionName, Build.BRAND, Build.DEVICE, Build.MODEL, Build.ID, Build.VERSION.SDK_INT, Build.VERSION.RELEASE, Build.VERSION.INCREMENTAL); } public static Intent getActivityIntent(Context context, String packageName, String className) { PackageManager pm = context.getPackageManager(); Intent intent = new Intent(); ComponentName compoentName = new ComponentName(packageName, className); intent.setComponent(compoentName); ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); if (ri != null) { return intent; } return null; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/FileUtils.java ================================================ package com.way.upgrade.utils; import java.io.File; /** * @author way 2013/12/6 */ public class FileUtils { private static final String TAG = "FileUtils"; /** * @param f * @throws Exception */ public static void createNewFile(File f) throws Exception { Log.i(TAG, "create file:" + f, Log.APP); if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } if (!f.exists()) { f.createNewFile(); } } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/Log.java ================================================ package com.way.upgrade.utils; public class Log { public static final boolean DEBUG = true; public static final boolean DATA_DEBUG = true; public static final boolean APP_DEBUG = true; public static final boolean DISPLAY_DEBUG = false; public static final int DATA = 0; public static final int DISPLAY = 1; public static final int APP = 2; public static final String TAG = "zhujianwen"; public static void v(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.v(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.v(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.v(tag, msg); } } public static void v(String msg, int mod) { v(TAG, msg, mod); } public static void d(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.d(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.d(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.d(tag, msg); } } public static void d(String msg, int mod) { d(TAG, msg, mod); } public static void i(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.i(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.i(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.i(tag, msg); } } public static void i(String msg, int mod) { i(TAG, msg, mod); } public static void w(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.w(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.w(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.w(tag, msg); } } public static void w(String msg, int mod) { w(TAG, msg, mod); } public static void e(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.e(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.e(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.e(tag, msg); } } public static void e(String msg, int mod) { e(TAG, msg, mod); } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/NetUtils.java ================================================ package com.way.upgrade.utils; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; /** * 网络操作 * * @author way 2013/12/6 */ public class NetUtils { private static final String TAG = "NetUtils"; private static final String NETTYPE_WIFI = "WIFI"; private static String multipart_form_data = "multipart/form-data"; private static String twoHyphens = "--"; private static String boundary = java.util.UUID.randomUUID().toString(); // 数据分隔 private static String lineEnd = "\r\n"; // The value is "\r\n" in Windows. public enum NETWORK_STATUS { STATE_WIFI, STATE_GPRS, STATE_NONE_NETWORK } private NetUtils() { } public static NETWORK_STATUS getNetworkType(Context context) { NETWORK_STATUS ret = NETWORK_STATUS.STATE_NONE_NETWORK; ConnectivityManager connetManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); if (connetManager == null) { Log.e(TAG, "isNetWorkAvailable connetManager = null", Log.APP); return ret; } NetworkInfo[] infos = connetManager.getAllNetworkInfo(); if (infos == null) { return ret; } for (int i = 0; i < infos.length && infos[i] != null; i++) { if (infos[i].isConnected() && infos[i].isAvailable()) { if (infos[i].getTypeName().equalsIgnoreCase(NETTYPE_WIFI)) { ret = NETWORK_STATUS.STATE_WIFI; } else { ret = NETWORK_STATUS.STATE_GPRS; } break; } } Log.i(TAG, "get network stype is : " + ret, Log.APP); return ret; } /** * * @param context * @param typeName * ("",WIFI,MOBILE) * @return */ public static boolean isNetWorkAvailable(Context context, String typeName) { Log.i(TAG, ">>> isNetWorkAvailable context = " + context + "typeName = " + typeName, Log.APP); boolean ret = false; ConnectivityManager connetManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); if (connetManager == null) { Log.e(TAG, "isNetWorkAvailable connetManager = null", Log.APP); return ret; } NetworkInfo[] infos = connetManager.getAllNetworkInfo(); if (infos == null) { return ret; } if ((typeName == null) || (typeName.length() <= 0)) { for (int i = 0; i < infos.length && infos[i] != null; i++) { if (infos[i].isConnected() && infos[i].isAvailable()) { ret = true; break; } } } else { for (int i = 0; i < infos.length && infos[i] != null; i++) { if (infos[i].getTypeName().equalsIgnoreCase(typeName) && infos[i].isConnected() && infos[i].isAvailable()) { Log.i(TAG, "isNetWorkAvailable name is : " + infos[i].getTypeName(), Log.APP); ret = true; break; } } } Log.i(TAG, "isNetWorkAvailable >>> result is : " + ret, Log.APP); return ret; } /** * * @param url * @return * @throws IOException */ public static synchronized InputStream getInputStreamByGet(String url) throws IOException { Log.i(TAG, " url:" + url, Log.APP); HttpURLConnection httpConnection = null; int currentSize = 0; if (url == null) { return null; } URL uri = new URL(url); httpConnection = (HttpURLConnection) uri.openConnection(); httpConnection.setRequestProperty("User-Agent", "PacificHttpClient"); if (currentSize > 0) { httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-"); } // 设置超时时间 httpConnection.setConnectTimeout(10000);// 限制连接超时5秒钟 httpConnection.setReadTimeout(2 * 10000); httpConnection.setRequestProperty("Content-type", "text/html;charset=UTF-8"); httpConnection.setDoOutput(true); httpConnection.setRequestMethod("GET"); httpConnection.setUseCaches(false); int requestCode = httpConnection.getResponseCode(); if (requestCode == 200) { InputStream in = httpConnection.getInputStream(); return in; } return null; } /** * post方式从服务器获取json数组 * * @return * @throws IOException * @throws ClientProtocolException * @throws JSONException */ public static JSONArray getJSONArrayByPost(String uri) throws ClientProtocolException, IOException, JSONException { Log.i(TAG, " uri:" + uri, Log.APP); StringBuilder builder = new StringBuilder(); HttpParams httpParameters = new BasicHttpParams(); // Set the default socket timeout (SO_TIMEOUT) in milliseconds which is // the timeout for waiting for data. HttpConnectionParams.setConnectionTimeout(httpParameters, 5000); HttpConnectionParams.setSoTimeout(httpParameters, 10000); HttpClient client = new DefaultHttpClient(httpParameters); HttpPost post = new HttpPost(uri); HttpResponse response = client.execute(post); BufferedReader reader = new BufferedReader(new InputStreamReader( response.getEntity().getContent())); for (String s = reader.readLine(); s != null; s = reader.readLine()) { builder.append(s); } String jsonString = new String(builder.toString()); if ("{}".equals(jsonString)) { return null; } Log.i(TAG, " jsonString:" + jsonString, Log.DATA); return new JSONArray(jsonString); } /** * get方式从服务器获取json数组 * * @return * @throws IOException * @throws ClientProtocolException * @throws JSONException */ public static JSONObject getJSONArrayByGet(String uri) throws ClientProtocolException, IOException, JSONException { Log.i(TAG, " uri:" + uri, Log.APP); StringBuilder builder = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(uri); HttpResponse response = client.execute(get); BufferedReader reader = new BufferedReader(new InputStreamReader( response.getEntity().getContent())); for (String s = reader.readLine(); s != null; s = reader.readLine()) { builder.append(s); } String jsonString = new String(builder.toString()); if ("{}".equals(jsonString)) { return null; } Log.i(TAG, " jsonString:" + jsonString, Log.DATA); return new JSONObject(jsonString); } /** * 使用post的方式,提交表单,不包括文件上传(新服务器) * * @param actionUrl * @param params * @param files * @return * @throws IOException */ public static boolean uploadParamsByPost(String actionUrl, Map params) throws IOException { Log.i(TAG, " actionUrl:" + actionUrl + " params:" + params, Log.APP); String BOUNDARY = java.util.UUID.randomUUID().toString(); String PREFIX = "--", LINEND = "\r\n"; String MULTIPART_FROM_DATA = "multipart/form-data"; String CHARSET = "UTF-8"; URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(10 * 1000); conn.setConnectTimeout(10 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); // Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); // 首先组拼文本类型的参数 StringBuilder sb = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINEND); sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND); sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND); sb.append("Content-Transfer-Encoding: 8bit" + LINEND); sb.append(LINEND); sb.append(entry.getValue()); sb.append(LINEND); } DataOutputStream outStream = new DataOutputStream( conn.getOutputStream()); outStream.write(sb.toString().getBytes()); // 请求结束标志 byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); outStream.write(end_data); outStream.flush(); outStream.close(); // 得到响应号 int res = conn.getResponseCode(); if (res == 200) { return true; } conn.disconnect(); return false; } /** * 使用post的方式,提交表单,不包括文件上传(老服务器写的代码使用这种方式) * * @param actionUrl * :http://xxx/xxx.json * @param query * :Helpers.combinaStr("login_name=#&password=#&email=#&name=", * listParams); * @return */ public static JSONObject uploadParamsByPost(String actionUrl, String query) { Log.i(TAG, " actionUrl:" + actionUrl + " query:" + query, Log.APP); try { URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(10 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); // Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); // query is your body conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// 请求�? // 必须设置 conn.setRequestProperty("Content-Length", query.toString() .getBytes("UTF-8").length + "");// 注意是字节长�? // 不是字符长度 conn.getOutputStream().write(query.toString().getBytes("UTF-8")); // 得到响应�? int res = conn.getResponseCode(); if (res == HttpURLConnection.HTTP_OK) { StringBuffer stringBuffer = new StringBuffer(); String readLine; BufferedReader responseReader; // 处理响应流,必须与服务器响应流输出的编码�?�� responseReader = new BufferedReader(new InputStreamReader( conn.getInputStream(), "UTF-8")); while ((readLine = responseReader.readLine()) != null) { stringBuffer.append(readLine).append("/n"); } responseReader.close(); return new JSONObject(stringBuffer.toString()); } } catch (Exception e) { e.printStackTrace(); } return null; } public int uploadFilesByPost(String actionUrl, String fileName, File file) { Log.i(TAG, " actionUrl:" + actionUrl + " fileName:" + fileName, Log.APP); String CHARSET = "UTF-8"; // 得到响应�? int res = 0; try { URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(10 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); // Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); conn.setRequestProperty("Content-Type", multipart_form_data + ";boundary=" + boundary); // 输出�? DataOutputStream outStream = new DataOutputStream( conn.getOutputStream()); // 发�?文件数据 if (file != null) { StringBuilder sb1 = new StringBuilder(); sb1.append(twoHyphens); sb1.append(boundary); sb1.append(lineEnd); // actionData 是自己定义的 sb1.append("Content-Disposition: form-data; name=\"actionData\"; filename=\"" + fileName + "\"" + lineEnd); sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + lineEnd); sb1.append(lineEnd); outStream.write(sb1.toString().getBytes()); InputStream is = new FileInputStream(file); byte[] buffer = new byte[1024]; int len = 0; while ((len = is.read(buffer)) != -1) { outStream.write(buffer, 0, len); } is.close(); outStream.write(lineEnd.getBytes()); } // 请求结束标志 byte[] end_data = (twoHyphens + boundary + twoHyphens + lineEnd) .getBytes(); outStream.write(end_data); outStream.flush(); res = conn.getResponseCode(); outStream.close(); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); } return res; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/Preferences.java ================================================ package com.way.upgrade.utils; import android.content.Context; import android.content.SharedPreferences; import com.way.upgrade.bean.UpgradeInfo; /** * * @author way 2014/11/3 */ public class Preferences { public static final String PREFERENCES_NAME = "com_upgrade_manager"; public static final String KEY_DOWNLOAD_ID = "downloadId"; protected static final String KEY_APPKEY = "key"; protected static final String KEY_VERSION = "version"; protected static final String KEY_URL = "url"; protected static final String KEY_DESCRIPTION = "description"; protected static final String KEY_DOWNLOAD_SIZE = "downloadSize"; protected static final String KEY_DOWNLOAD_PATH = "download_path"; protected static final String KEY_DOWNLOAD_STATUS = "download_status"; public static void setDownloadId(Context context, long downloadId) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putLong(KEY_DOWNLOAD_ID, downloadId); editor.commit(); } public static long getDownloadId(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); return pref.getLong(KEY_DOWNLOAD_ID, -1); } public static void setUpgradeInfo(Context context, UpgradeInfo upgrade) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putString(KEY_APPKEY, upgrade.getKey()); editor.putString(KEY_VERSION, upgrade.getVersion()); editor.putString(KEY_URL, upgrade.getUrl()); editor.putString(KEY_DESCRIPTION, upgrade.getDescription()); editor.putLong(KEY_DOWNLOAD_SIZE, upgrade.getDownloadSize()); editor.commit(); } public static UpgradeInfo getUpgradeInfo(Context context) { UpgradeInfo upgradeInfo = new UpgradeInfo(); SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); upgradeInfo.setKey(pref.getString(KEY_APPKEY, "")); upgradeInfo.setVersion(pref.getString(KEY_VERSION, "")); upgradeInfo.setUrl(pref.getString(KEY_URL, "")); upgradeInfo.setDescription(pref.getString(KEY_DESCRIPTION, "")); upgradeInfo.setDownloadSize(pref.getLong(KEY_DOWNLOAD_SIZE, -1)); return upgradeInfo; } public static void setDownloadPath(Context context, String downloadPath) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putString(KEY_DOWNLOAD_PATH, downloadPath); editor.commit(); } public static String getDownloadPath(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); return pref.getString(KEY_DOWNLOAD_PATH, ""); } public static void removeAll(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.clear(); editor.commit(); } public static void setDownloadStatus(Context context, int downloadId) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putInt(KEY_DOWNLOAD_STATUS, downloadId); editor.commit(); } public static int getDownloadStatus(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); return pref.getInt(KEY_DOWNLOAD_STATUS, -1); } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/Utils.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils; import java.io.Closeable; import java.io.InterruptedIOException; import java.util.List; import android.database.Cursor; import android.os.Build; import android.os.ParcelFileDescriptor; import android.text.TextUtils; public class Utils { private static final String TAG = "Utils"; private static final String DEBUG_TAG = "GalleryDebug"; private static final long POLY64REV = 0x95AC9329AC4BC9B5L; private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL; private static long[] sCrcTable = new long[256]; private static final boolean IS_DEBUG_BUILD = Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug"); private static final String MASK_STRING = "********************************"; // Throws AssertionError if the input is false. public static void assertTrue(boolean cond) { if (!cond) { throw new AssertionError(); } } // Throws AssertionError with the message. We had a method having the form // assertTrue(boolean cond, String message, Object ... args); // However a call to that method will cause memory allocation even if the // condition is false (due to autoboxing generated by "Object ... args"), // so we don't use that anymore. public static void fail(String message, Object... args) { throw new AssertionError(args.length == 0 ? message : String.format( message, args)); } // Throws NullPointerException if the input is null. public static T checkNotNull(T object) { if (object == null) throw new NullPointerException(); return object; } // Returns true if two input Object are both null or equal // to each other. public static boolean equals(Object a, Object b) { return (a == b) || (a == null ? false : a.equals(b)); } // Returns the next power of two. // Returns the input if it is already power of 2. // Throws IllegalArgumentException if the input is <= 0 or // the answer overflows. public static int nextPowerOf2(int n) { if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n); n -= 1; n |= n >> 16; n |= n >> 8; n |= n >> 4; n |= n >> 2; n |= n >> 1; return n + 1; } // Returns the previous power of two. // Returns the input if it is already power of 2. // Throws IllegalArgumentException if the input is <= 0 public static int prevPowerOf2(int n) { if (n <= 0) throw new IllegalArgumentException(); return Integer.highestOneBit(n); } // Returns the input value x clamped to the range [min, max]. public static int clamp(int x, int min, int max) { if (x > max) return max; if (x < min) return min; return x; } // Returns the input value x clamped to the range [min, max]. public static float clamp(float x, float min, float max) { if (x > max) return max; if (x < min) return min; return x; } // Returns the input value x clamped to the range [min, max]. public static long clamp(long x, long min, long max) { if (x > max) return max; if (x < min) return min; return x; } public static boolean isOpaque(int color) { return color >>> 24 == 0xFF; } public static void swap(int[] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } /** * A function thats returns a 64-bit crc for string * * @param in * input string * @return a 64-bit crc value */ public static final long crc64Long(String in) { if (in == null || in.length() == 0) { return 0; } return crc64Long(getBytes(in)); } static { // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c long part; for (int i = 0; i < 256; i++) { part = i; for (int j = 0; j < 8; j++) { long x = ((int) part & 1) != 0 ? POLY64REV : 0; part = (part >> 1) ^ x; } sCrcTable[i] = part; } } public static final long crc64Long(byte[] buffer) { long crc = INITIALCRC; for (int k = 0, n = buffer.length; k < n; ++k) { crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8); } return crc; } public static byte[] getBytes(String in) { byte[] result = new byte[in.length() * 2]; int output = 0; for (char ch : in.toCharArray()) { result[output++] = (byte) (ch & 0xFF); result[output++] = (byte) (ch >> 8); } return result; } public static void closeSilently(Closeable c) { if (c == null) return; try { c.close(); } catch (Throwable t) { Log.w(TAG, "close fail", Log.APP); } } public static int compare(long a, long b) { return a < b ? -1 : a == b ? 0 : 1; } public static int ceilLog2(float value) { int i; for (i = 0; i < 31; i++) { if ((1 << i) >= value) break; } return i; } public static int floorLog2(float value) { int i; for (i = 0; i < 31; i++) { if ((1 << i) > value) break; } return i - 1; } public static void closeSilently(ParcelFileDescriptor fd) { try { if (fd != null) fd.close(); } catch (Throwable t) { Log.w(TAG, "fail to close", Log.APP); } } public static void closeSilently(Cursor cursor) { try { if (cursor != null) cursor.close(); } catch (Throwable t) { Log.w(TAG, "fail to close", Log.APP); } } public static float interpolateAngle(float source, float target, float progress) { // interpolate the angle from source to target // We make the difference in the range of [-179, 180], this is the // shortest path to change source to target. float diff = target - source; if (diff < 0) diff += 360f; if (diff > 180) diff -= 360f; float result = source + diff * progress; return result < 0 ? result + 360f : result; } public static float interpolateScale(float source, float target, float progress) { return source + progress * (target - source); } public static String ensureNotNull(String value) { return value == null ? "" : value; } public static String ensureNotNull(Object obj) { return obj == null ? "" : obj.toString(); } public static float parseFloatSafely(String content, float defaultValue) { if (content == null) return defaultValue; try { return Float.parseFloat(content); } catch (NumberFormatException e) { return defaultValue; } } public static int parseIntSafely(String content, int defaultValue) { if (content == null) return defaultValue; try { return Integer.parseInt(content); } catch (NumberFormatException e) { return defaultValue; } } public static boolean isNullOrEmpty(String exifMake) { return TextUtils.isEmpty(exifMake); } public static void waitWithoutInterrupt(Object object) { try { object.wait(); } catch (InterruptedException e) { Log.w(TAG, "unexpected interrupt: " + object, Log.APP); } } public static boolean handleInterrruptedException(Throwable e) { // A helper to deal with the interrupt exception // If an interrupt detected, we will setup the bit again. if (e instanceof InterruptedIOException || e instanceof InterruptedException) { Thread.currentThread().interrupt(); return true; } return false; } /** * @return String with special XML characters escaped. */ public static String escapeXml(String s) { StringBuilder sb = new StringBuilder(); for (int i = 0, len = s.length(); i < len; ++i) { char c = s.charAt(i); switch (c) { case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '\"': sb.append("""); break; case '\'': sb.append("'"); break; case '&': sb.append("&"); break; default: sb.append(c); } } return sb.toString(); } public static String[] copyOf(String[] source, int newSize) { String[] result = new String[newSize]; newSize = Math.min(source.length, newSize); System.arraycopy(source, 0, result, 0, newSize); return result; } // Mask information for debugging only. It returns // info.toString() directly // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask // ("****") // in release build to protect the information (e.g. for privacy issue). public static String maskDebugInfo(Object info) { if (info == null) return null; String s = info.toString(); int length = Math.min(s.length(), MASK_STRING.length()); return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length); } // This method should be ONLY used for debugging. public static void debug(String message, Object... args) { Log.v(DEBUG_TAG, String.format(message, args), Log.APP); } /** * combina the url. usr the param list repleace the [#] in the url. * * @param str * @param params * @return * @exception RuntimeException * May throw the runtime exception while the method was done. * @author MichaelHuang */ public static String combinaStr(String str, List params) throws RuntimeException { try { String[] strs = str.split("[#]"); String newStr = ""; for (int i = 0; i < strs.length; i++) { String itemUrl = strs[i]; newStr += itemUrl; if (i >= 0 && i < params.size()) newStr += params.get(i); } Log.i(TAG, " newStr:" + newStr, Log.DATA); return newStr; } catch (Exception e) { throw new RuntimeException(); } } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/thread/Future.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; // This Future differs from the java.util.concurrent.Future in these aspects: // // - Once cancel() is called, isCancelled() always returns true. It is a sticky // flag used to communicate to the implementation. The implmentation may // ignore that flag. Regardless whether the Future is cancelled, a return // value will be provided to get(). The implementation may choose to return // null if it finds the Future is cancelled. // // - get() does not throw exceptions. // public interface Future { public void cancel(); public boolean isCancelled(); public boolean isDone(); public T get(); public void waitDone(); } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/thread/FutureListener.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; /** * * @author way * * @param */ public interface FutureListener { public void onFutureDone(Future future); } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/thread/PriorityThreadFactory.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; import android.os.Process; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * A thread factory that creates threads with a given thread priority. */ public class PriorityThreadFactory implements ThreadFactory { private final int mPriority; private final AtomicInteger mNumber = new AtomicInteger(); private final String mName; public PriorityThreadFactory(String name, int priority) { mName = name; mPriority = priority; } @Override public Thread newThread(Runnable r) { return new Thread(r, mName + '-' + mNumber.getAndIncrement()) { @Override public void run() { Process.setThreadPriority(mPriority); super.run(); } }; } } ================================================ FILE: Upgrade-lib/src/com/way/upgrade/utils/thread/ThreadPool.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import com.way.upgrade.utils.Log; /** * * @author way * */ public class ThreadPool { private static final String TAG = "ThreadPool"; private static final int CORE_POOL_SIZE = 4; private static final int MAX_POOL_SIZE = 8; private static final int KEEP_ALIVE_TIME = 20; // 10 seconds // Resource type public static final int MODE_NONE = 0; public static final int MODE_CPU = 1; public static final int MODE_NETWORK = 2; public static final JobContext JOB_CONTEXT_STUB = new JobContextStub(); // M: in order to take full advantage of MT6589 CPU Core, change cpuCounter // to 4 from 2 ResourceCounter mCpuCounter = new ResourceCounter(4); ResourceCounter mNetworkCounter = new ResourceCounter(6); // A Job is like a Callable, but it has an addition JobContext parameter. public interface Job { public T run(JobContext jc); } public interface JobContext { boolean isCancelled(); void setCancelListener(CancelListener listener); boolean setMode(int mode); } private static class JobContextStub implements JobContext { @Override public boolean isCancelled() { return false; } @Override public void setCancelListener(CancelListener listener) { } @Override public boolean setMode(int mode) { return true; } } public interface CancelListener { public void onCancel(); } private static class ResourceCounter { public int value; public ResourceCounter(int v) { value = v; } } private final Executor mExecutor; public ThreadPool() { this(CORE_POOL_SIZE, MAX_POOL_SIZE); } public ThreadPool(int initPoolSize, int maxPoolSize) { mExecutor = new ThreadPoolExecutor(initPoolSize, maxPoolSize, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue(), new PriorityThreadFactory( "thread-pool", android.os.Process.THREAD_PRIORITY_BACKGROUND)); } // Submit a job to the thread pool. The listener will be called when the // job is finished (or cancelled). public Future submit(Job job, FutureListener listener, int threadMode) { Log.i(TAG, " Job:" + job, Log.APP); Worker w = new Worker(job, listener, threadMode); mExecutor.execute(w); return w; } public Future submit(Job job) { return submit(job, null, MODE_CPU); } private class Worker implements Runnable, Future, JobContext { private static final String TAG = "Worker"; private Job mJob; private FutureListener mListener; private CancelListener mCancelListener; private ResourceCounter mWaitOnResource; private volatile boolean mIsCancelled; private boolean mIsDone; private T mResult; private int mMode; private int mTargetMode; public Worker(Job job, FutureListener listener, int threadMode) { mJob = job; mListener = listener; mTargetMode = threadMode; } // This is called by a thread in the thread pool. @Override public void run() { Log.i(TAG, " start", Log.APP); T result = null; // A job is in CPU mode by default. setMode returns false // if the job is cancelled. if (setMode(mTargetMode)) { try { result = mJob.run(this); } catch (Throwable ex) { } } synchronized (this) { setMode(MODE_NONE); mResult = result; mIsDone = true; notifyAll(); } if (mListener != null) mListener.onFutureDone(this); Log.i(TAG, " end", Log.APP); } // Below are the methods for Future. @Override public synchronized void cancel() { if (mIsCancelled) return; mIsCancelled = true; if (mWaitOnResource != null) { synchronized (mWaitOnResource) { mWaitOnResource.notifyAll(); } } if (mCancelListener != null) { mCancelListener.onCancel(); } } @Override public boolean isCancelled() { return mIsCancelled; } @Override public synchronized boolean isDone() { return mIsDone; } @Override public synchronized T get() { while (!mIsDone) { try { wait(); } catch (Exception ex) { } } return mResult; } @Override public void waitDone() { get(); } // Below are the methods for JobContext (only called from the // thread running the job) @Override public synchronized void setCancelListener(CancelListener listener) { mCancelListener = listener; if (mIsCancelled && mCancelListener != null) { mCancelListener.onCancel(); } } @Override public boolean setMode(int mode) { // Release old resource Log.i(TAG, " start mode:" + mode, Log.APP); ResourceCounter rc = modeToCounter(mMode); if (rc != null) releaseResource(rc); mMode = MODE_NONE; // Acquire new resource rc = modeToCounter(mode); if (rc != null) { if (!acquireResource(rc)) { return false; } mMode = mode; } Log.i(TAG, " end", Log.APP); return true; } private ResourceCounter modeToCounter(int mode) { if (mode == MODE_CPU) { Log.i(TAG, " MODE_CPU", Log.APP); return mCpuCounter; } else if (mode == MODE_NETWORK) { Log.i(TAG, " MODE_NETWORK", Log.APP); return mNetworkCounter; } else { return null; } } private boolean acquireResource(ResourceCounter counter) { Log.i(TAG, " start", Log.APP); while (true) { synchronized (this) { if (mIsCancelled) { mWaitOnResource = null; return false; } mWaitOnResource = counter; } synchronized (counter) { if (counter.value > 0) { counter.value--; break; } else { try { counter.wait(); } catch (InterruptedException ex) { // ignore. } } } } synchronized (this) { mWaitOnResource = null; } Log.i(TAG, " end", Log.APP); return true; } private void releaseResource(ResourceCounter counter) { Log.i(TAG, " start", Log.APP); synchronized (counter) { counter.value++; counter.notifyAll(); } Log.i(TAG, " end", Log.APP); } } } ================================================ FILE: WayHoo/.settings/org.eclipse.jdt.core.prefs ================================================ 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 ================================================ FILE: WayHoo/AndroidManifest.xml ================================================ android:windowSoftInputMode="stateHidden|adjustResize" ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/MainActivity.java ================================================ package com.way.upgrade; import android.app.Activity; import android.os.Bundle; import com.way.upgrade.core.UpgradeManager; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); final UpgradeManager upgradeMangeer = UpgradeManager.newInstance(this); upgradeMangeer.askForNewVersion(); } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/bean/UpgradeInfo.java ================================================ package com.way.upgrade.bean; import android.os.Parcel; import android.os.Parcelable; /** * 版本更新信息 * * @author way * @since 2014/4/28 */ public class UpgradeInfo implements Parcelable{ private int id; /**唯一标识apk*/ private String key; /** 版本信息 */ private String version; /** 版本名称 */ private String versionName; /** 是否有更新 */ private String result; /** 新版本地址 */ private String url; /** 版本描述 */ private String description; /** 已下载的大小 */ private long downloadSize; private String mustUpdate; private String changeLog; private String errorCode; public static final Parcelable.Creator CREATOR = new Creator() { @Override public UpgradeInfo[] newArray(int size) { return new UpgradeInfo[size]; } @Override public UpgradeInfo createFromParcel(Parcel source) { return new UpgradeInfo(source); } }; public UpgradeInfo() { } public UpgradeInfo(Parcel in) { id = in.readInt(); key = in.readString(); version = in.readString(); versionName = in.readString(); result = in.readString(); url = in.readString(); description = in.readString(); downloadSize = in.readLong(); result = in.readString(); mustUpdate = in.readString(); changeLog = in.readString(); errorCode = in.readString(); } @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(id); dest.writeString(key); dest.writeString(version); dest.writeString(versionName); dest.writeString(result); dest.writeString(url); dest.writeString(description); dest.writeLong(downloadSize); dest.writeString(result); dest.writeString(mustUpdate); dest.writeString(changeLog); dest.writeString(errorCode); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getVersion() { return version; } public void setVersion(String version) { this.version = version; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } public long getDownloadSize() { return downloadSize; } public void setDownloadSize(long downloadSize) { this.downloadSize = downloadSize; } public String getVersionName() { return versionName; } public void setVersionName(String versionName) { this.versionName = versionName; } public String isResult() { return result; } public void setResult(String result) { this.result = result; } public String getMustUpdate() { return mustUpdate; } public void setMustUpdate(String mustUpdate) { this.mustUpdate = mustUpdate; } public String getChangeLog() { return changeLog; } public void setChangeLog(String changeLog) { this.changeLog = changeLog; } public String getResult() { return result; } public String getErrorCode() { return errorCode; } public void setErrorCode(String errorCode) { this.errorCode = errorCode; } @Override public String toString() { return "UpgradeInfo [id=" + id + ", key=" + key + ", version=" + version + ", versionName=" + versionName + ", result=" + result + ", url=" + url + ", description=" + description + ", downloadSize=" + downloadSize + ", mustUpdate=" + mustUpdate + ", changeLog=" + changeLog + ", errorCode=" + errorCode + "]"; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/core/CheckNewVersionListener.java ================================================ package com.way.upgrade.core; /** * * @author way * @sine 2014/10/29 */ public interface CheckNewVersionListener { public void checkNewVersion(boolean result); } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/core/UpgradeInterface.java ================================================ package com.way.upgrade.core; import com.way.upgrade.bean.UpgradeInfo; /** * * @author way * @since 2014/4/28 */ public interface UpgradeInterface { /** * 请求服务器是否有新版本,并弹出对话框 * * @return */ public void askForNewVersion(); /** * 请求服务器是否有新版本 * * @return */ public void askForNewVersionFlag( CheckNewVersionListener checkversionListener); /** * 下载新版本 * * @return */ public void downloadNewVersion(UpgradeInfo upgradeInfo); } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/core/UpgradeManager.java ================================================ package com.way.upgrade.core; import java.util.HashMap; import java.util.Locale; import java.util.Map; import android.app.AlertDialog; import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.os.Handler; import android.os.Message; import android.util.Log; import android.widget.Toast; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.job.CheckNewVersionJobWithoutClientUrl; import com.way.upgrade.job.DownloadNewVersionJob; import com.way.upgrade.locale.LocaleChina; import com.way.upgrade.locale.LocaleChinaTW; import com.way.upgrade.locale.LocaleChinese; import com.way.upgrade.locale.LocaleEnglish; import com.way.upgrade.locale.LocaleHandler; import com.way.upgrade.locale.LocaleUS; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.ContextUtils; import com.way.upgrade.utils.thread.Future; import com.way.upgrade.utils.thread.FutureListener; import com.way.upgrade.utils.thread.ThreadPool; /** * * @author way * @since 2014/4/28 */ public class UpgradeManager extends LocaleHandler implements UpgradeInterface { private Context mContext; private static ThreadPool mThreadPool; private Handler mHandler; private AlertDialog alertDialog; private AlertDialog alertDialogForMustUpdate; private ProgressDialog mProgressDialog; private Map handlers; private static Future mFuture; private CheckNewVersionListener mAskForNewVersionFlagListener; private FutureListener mAskForNewVersionListener = new FutureListener() { public void onFutureDone(Future future) { UpgradeInfo upgradeInfo = future.get(); Message msg = mHandler.obtainMessage(); if (upgradeInfo != null) { if (upgradeInfo.getErrorCode() != null) { if (upgradeInfo.getErrorCode().equals( Constants.ERROR_CODE_NET)) { msg.what = Constants.MSG_NET_ERROR; } } else if (Boolean.parseBoolean(upgradeInfo.getResult())) { mFuture = future; msg.what = Constants.MSG_HAVA_NEW_VERSION; msg.obj = upgradeInfo; } else if (!Boolean.parseBoolean(upgradeInfo.getResult())) { msg.what = Constants.MSG_NO_NEW_VERSION; } } else { msg.what = Constants.MSG_NO_NEW_VERSION; } mHandler.sendMessage(msg); }; }; public class AskForNewVersionFlag implements FutureListener { @Override public void onFutureDone(Future future) { UpgradeInfo upgradeInfo = future.get(); boolean result = false; if (upgradeInfo != null) { result = Boolean.parseBoolean(upgradeInfo.getResult()); } Message msg = mHandler.obtainMessage(); msg.what = Constants.MSG_VERSION_RESULT; msg.obj = result; mHandler.sendMessage(msg); } } public UpgradeManager(Context context) { createHandlers(); mContext = context; init(); } private void init() { if (mThreadPool == null) { mThreadPool = new ThreadPool(); } mHandler = new Handler(mContext.getMainLooper()) { @Override public void handleMessage(Message msg) { switch (msg.what) { case Constants.MSG_HAVA_NEW_VERSION: try { ContextUtils.closeProgressDialog(mProgressDialog); UpgradeInfo description = (UpgradeInfo) msg.obj; showDialog(description); } catch (Exception e1) { e1.printStackTrace(); } break; case Constants.MSG_NO_NEW_VERSION: try { ContextUtils.closeProgressDialog(mProgressDialog); ContextUtils.showToast(mContext, getToastMessage(), Toast.LENGTH_SHORT); } catch (Exception e) { e.printStackTrace(); } break; case Constants.MSG_START_DOWNLOAD: UpgradeInfo description1 = (UpgradeInfo) msg.obj; downloadNewVersion(description1); break; case Constants.MSG_VERSION_RESULT: Boolean result = (Boolean) msg.obj; mAskForNewVersionFlagListener.checkNewVersion(result); break; case Constants.MSG_NET_ERROR: try { ContextUtils.closeProgressDialog(mProgressDialog); } catch (Exception e) { e.printStackTrace(); } ContextUtils.showToast(mContext, getToastNetErrorMessage(), Toast.LENGTH_SHORT); default: break; } } }; alertDialog = ContextUtils.showAlertDialog(mContext, getDialogTitle(), "", new int[] { android.R.string.ok, android.R.string.cancel }, new DialogInterface.OnClickListener[] { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { if (mFuture != null) { Message msg = mHandler.obtainMessage(); msg.what = Constants.MSG_START_DOWNLOAD; msg.obj = mFuture.get(); mHandler.sendMessage(msg); } } }, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { dialog.dismiss(); } } }); alertDialogForMustUpdate = ContextUtils .showAlertDialog( mContext, getDialogTitle(), "", new int[] { android.R.string.ok }, new DialogInterface.OnClickListener[] { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface arg0, int arg1) { if (mFuture != null) { Message msg = mHandler.obtainMessage(); msg.what = Constants.MSG_START_DOWNLOAD; msg.obj = mFuture.get(); mHandler.sendMessage(msg); } } } }); alertDialogForMustUpdate.setCancelable(false); mProgressDialog = ContextUtils.createProgressDialog(mContext); mProgressDialog.setTitle(getProgressDialogTitle()); mProgressDialog.setMessage(getProgressDialogMessage()); } public static UpgradeManager newInstance(Context context) { return new UpgradeManager(context); } private void showProgressDialog() { if (mProgressDialog != null) { try { mProgressDialog.show(); } catch (Exception e) { e.printStackTrace(); } } } @Override public void askForNewVersion() { showProgressDialog(); mThreadPool.submit(new CheckNewVersionJobWithoutClientUrl(mContext), mAskForNewVersionListener, ThreadPool.MODE_NETWORK); } @Override public void askForNewVersionFlag( CheckNewVersionListener checkversionListener) { if (checkversionListener == null) { return; } mAskForNewVersionFlagListener = checkversionListener; AskForNewVersionFlag mAskForNewVersionFlagListener = new AskForNewVersionFlag(); mThreadPool.submit(new CheckNewVersionJobWithoutClientUrl(mContext), mAskForNewVersionFlagListener, ThreadPool.MODE_NETWORK); } @Override public void downloadNewVersion(UpgradeInfo upgradeInfo) { mThreadPool.submit(new DownloadNewVersionJob(mContext, upgradeInfo), null, ThreadPool.MODE_CPU); } private void createHandlers() { handlers = new HashMap(); handlers.put(LocaleChinese.defaultLocale, new LocaleChinese()); handlers.put(LocaleChinaTW.defaultLocale, new LocaleChinaTW()); handlers.put(LocaleEnglish.defaultLocale, new LocaleEnglish()); handlers.put(Locale.CHINA.toString(), new LocaleChina()); handlers.put(Locale.US.toString(), new LocaleUS()); } private LocaleHandler lookupHandlerBy(String handlerName) { LocaleHandler handler = handlers.get(handlerName); if (handler == null) return handlers.get(Locale.ENGLISH.getLanguage()); return handlers.get(handlerName); } private void showDialog(UpgradeInfo description) { int mustUpdate = Integer.valueOf(description.getMustUpdate()); boolean result = Boolean.parseBoolean(description.isResult()); String descriptionStr = description.getChangeLog(); Log.i("liweiping", "mustUpdate = " + mustUpdate + ", result = " + result + ", alertDialog = " + alertDialog + ", alertDialogForMustUpdate = " + alertDialogForMustUpdate); if (mustUpdate == Constants.NOT_MUST_UPDATE) { if (alertDialog != null && result) { alertDialog.setTitle(getDialogTitle()); alertDialog.setMessage(descriptionStr); alertDialog.show(); } } else { if (alertDialogForMustUpdate != null && result) { alertDialogForMustUpdate.setTitle(getDialogTitle()); alertDialogForMustUpdate.setMessage(descriptionStr); alertDialogForMustUpdate.show(); } } } private String getLocaleLanguage() { return Locale.getDefault().toString(); } @Override public String getDialogTitle() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getDialogTitle(); } @Override public String getProgressDialogTitle() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getProgressDialogTitle(); } @Override public String getProgressDialogMessage() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getProgressDialogMessage(); } @Override public String getToastMessage() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getToastMessage(); } @Override public String getToastNetErrorMessage() { LocaleHandler handler = lookupHandlerBy(getLocaleLanguage()); return handler.getToastNetErrorMessage(); } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/job/AbstractCheckNewVersionJob.java ================================================ package com.way.upgrade.job; import java.io.IOException; import org.apache.http.client.ClientProtocolException; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.parser.json.FirVersionJsonParsing; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.NetUtils; import com.way.upgrade.utils.NetUtils.NETWORK_STATUS; import com.way.upgrade.utils.thread.ThreadPool; import com.way.upgrade.utils.thread.ThreadPool.JobContext; /** * * @author way * @since 2014/4/28 */ public abstract class AbstractCheckNewVersionJob implements ThreadPool.Job { protected Context mContext; protected String bundle_id; protected String api_token; public AbstractCheckNewVersionJob(Context context) { this.mContext = context; try { ApplicationInfo appInfo = mContext.getPackageManager() .getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA); bundle_id = appInfo.metaData.getString("bundle_id"); api_token = appInfo.metaData.getString("api_token"); } catch (NameNotFoundException e) { throw new NullPointerException( "app_id and token must not null in AndroidManifest.xml " + e); } Log.i("liweiping", "AbstractCheckNewVersionJob app_id = " + bundle_id + ", api_token = " + api_token); } @Override public UpgradeInfo run(JobContext jc) { UpgradeInfo upgradeInfo = null; if (NetUtils.getNetworkType(mContext) == NETWORK_STATUS.STATE_NONE_NETWORK) { Log.i("liweiping", "NETWORK_STATUS.STATE_NONE_NETWORK"); upgradeInfo = new UpgradeInfo(); upgradeInfo.setErrorCode(Constants.ERROR_CODE_NET); return upgradeInfo; } try { String checkUpdateUrl = String.format(getCheckVersionUrl(), bundle_id, api_token); Log.i("liweiping", "checkUpdateUrl = " + checkUpdateUrl); JSONObject jo = NetUtils.getJSONArrayByGet(checkUpdateUrl); FirVersionJsonParsing firVersionJsonParsing = new FirVersionJsonParsing( mContext); Log.i("liweiping", "upgradeInfo = " + upgradeInfo + ", checkUpdateUrl = " + checkUpdateUrl + ", jo = " + jo.toString()); upgradeInfo = firVersionJsonParsing.readJsonItem(jo); } catch (Exception e) { upgradeInfo = new UpgradeInfo(); upgradeInfo.setErrorCode(Constants.ERROR_CODE_NET); Log.i("liweiping",e.getMessage()); e.printStackTrace(); } return upgradeInfo; } public abstract String getCheckVersionUrl(); } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/job/CheckNewVersionJobWithoutClientUrl.java ================================================ package com.way.upgrade.job; import android.content.Context; import com.way.upgrade.utils.Constants; /** * * @author way * @since 2014/4/28 */ public class CheckNewVersionJobWithoutClientUrl extends AbstractCheckNewVersionJob { public CheckNewVersionJobWithoutClientUrl(Context context) { super(context); } @Override public String getCheckVersionUrl() { return Constants.BASE_URL; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/job/DownloadNewVersionJob.java ================================================ package com.way.upgrade.job; import java.io.File; import android.app.DownloadManager; import android.app.DownloadManager.Request; import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Environment; import android.util.Log; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.Preferences; import com.way.upgrade.utils.thread.ThreadPool; import com.way.upgrade.utils.thread.ThreadPool.JobContext; public class DownloadNewVersionJob implements ThreadPool.Job { private Context mContext; private UpgradeInfo mUpgradeInfo; private boolean allowMobileDownload = false; private static final long MAX_ALLOWED_DOWNLOAD_BYTES_BY_MOBILE = 3145725; public DownloadNewVersionJob(Context context, UpgradeInfo upgradeInfo) { this.mContext = context; this.mUpgradeInfo = upgradeInfo; } @Override public Void run(JobContext jc) { try { if (checkDownloadRunning()) return null; if (checkApkExist()) { Intent installApkIntent = new Intent(); installApkIntent.setAction(Intent.ACTION_VIEW); installApkIntent.setDataAndType( Uri.parse(Preferences.getDownloadPath(mContext)), "application/vnd.android.package-archive"); installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); mContext.startActivity(installApkIntent); } else { String apkName = mContext.getPackageName() + System.currentTimeMillis() + Constants.APK_SUFFIX; // 系统下载程序 final DownloadManager downloadManager = (DownloadManager) mContext .getSystemService(mContext.DOWNLOAD_SERVICE); Long recommendedMaxBytes = DownloadManager .getRecommendedMaxBytesOverMobile(mContext); // 可以在移动网络下下载 if (recommendedMaxBytes == null || recommendedMaxBytes.longValue() > MAX_ALLOWED_DOWNLOAD_BYTES_BY_MOBILE) { allowMobileDownload = true; } Uri uri = Uri.parse(mUpgradeInfo.getUrl()); final Request request = new Request(uri); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); int NETWORK_TYPE = DownloadManager.Request.NETWORK_WIFI; if (allowMobileDownload) { NETWORK_TYPE |= DownloadManager.Request.NETWORK_MOBILE; } request.setAllowedNetworkTypes(NETWORK_TYPE); request.allowScanningByMediaScanner(); request.setShowRunningNotification(true); request.setVisibleInDownloadsUi(true); request.setDestinationInExternalPublicDir( Environment.DIRECTORY_DOWNLOADS, apkName); PackageManager packageManager = mContext.getPackageManager(); ApplicationInfo applicationInfo = packageManager .getApplicationInfo(mContext.getPackageName(), 0); Log.i("liweiping", "appName = " + packageManager .getApplicationLabel(applicationInfo)); request.setTitle(packageManager .getApplicationLabel(applicationInfo)); request.setMimeType("application/vnd.android.package-archive"); // id 保存起来跟之后的广播接收器作对比 long id = downloadManager.enqueue(request); long oldId = Preferences.getDownloadId(mContext); if (oldId != -1) { downloadManager.remove(oldId); } Preferences.removeAll(mContext); Preferences.setDownloadId(mContext, id); Preferences.setUpgradeInfo(mContext, mUpgradeInfo); Preferences.setDownloadStatus(mContext, Constants.DOWNLOAD_STATUS_RUNNING); } } catch (Exception e) { e.printStackTrace(); } return null; } private boolean checkApkExist() { UpgradeInfo prefUpgradeInfo = Preferences.getUpgradeInfo(mContext); String version = prefUpgradeInfo.getVersion(); String downloadPath = Preferences.getDownloadPath(mContext); if (version != null && version.trim().length() != 0 && version.equals(mUpgradeInfo.getVersion()) && downloadPath != null && downloadPath.trim().length() != 0) { String path = Uri.parse(downloadPath).getPath(); if (path != null && path.endsWith(Constants.APK_SUFFIX)) { File file = new File(path); if (file.exists()) { return true; } } } return false; } @SuppressWarnings("static-access") private boolean checkDownloadRunning() { UpgradeInfo prefUpgradeInfo = Preferences.getUpgradeInfo(mContext); String version = prefUpgradeInfo.getVersion(); int downloadStatus = Preferences.getDownloadStatus(mContext); if (version != null && version.trim().length() != 0 && version.equals(mUpgradeInfo.getVersion())) { long downloadId = Preferences.getDownloadId(mContext); if (downloadId != -1) { final DownloadManager downloadManager = (DownloadManager) mContext .getSystemService(mContext.DOWNLOAD_SERVICE); DownloadManager.Query mDownloadQuery = new DownloadManager.Query(); mDownloadQuery.setFilterById(downloadId); Cursor cursor = downloadManager.query(mDownloadQuery); if (cursor != null && cursor.moveToFirst()) { int status = cursor.getInt(cursor .getColumnIndex(DownloadManager.COLUMN_STATUS)); if (status == DownloadManager.STATUS_RUNNING || downloadStatus == Constants.DOWNLOAD_STATUS_RUNNING) { return true; } } } } return false; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/locale/LocaleChina.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public class LocaleChina extends LocaleChinese { } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/locale/LocaleChinaTW.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public class LocaleChinaTW extends LocaleChinese { public static final String defaultLocale = "zh_TW"; @Override public String getDialogTitle() { return "發現新版本,是否升級?"; } @Override public String getProgressDialogTitle() { return "檢查更新"; } @Override public String getProgressDialogMessage() { return "正在檢查..."; } @Override public String getToastMessage() { return "已是最新版本"; } @Override public String getToastNetErrorMessage() { return "網路異常"; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/locale/LocaleChinese.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public class LocaleChinese extends LocaleHandler { public static final String defaultLocale = "zh"; @Override public String getDialogTitle() { return "发现新版本,是否升级?"; } @Override public String getProgressDialogTitle() { return "检查更新"; } @Override public String getProgressDialogMessage() { return "正在检查..."; } @Override public String getToastMessage() { return "已是最新版本"; } @Override public String getToastNetErrorMessage() { return "网络异常"; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/locale/LocaleEnglish.java ================================================ package com.way.upgrade.locale; public class LocaleEnglish extends LocaleHandler { public static final String defaultLocale = "en"; @Override public String getDialogTitle() { return "Find New Version,Update Now?"; } @Override public String getProgressDialogTitle() { return "Check Update"; } @Override public String getProgressDialogMessage() { return "Checking"; } @Override public String getToastMessage() { return "Is the latest version"; } @Override public String getToastNetErrorMessage() { return "Net Error"; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/locale/LocaleHandler.java ================================================ package com.way.upgrade.locale; /** * * @author way * @since 2014/10/29 */ public abstract class LocaleHandler { protected String value; public abstract String getDialogTitle(); public abstract String getProgressDialogTitle(); public abstract String getProgressDialogMessage(); public abstract String getToastMessage(); public abstract String getToastNetErrorMessage(); public void setUpgradeDescription(String value) { this.value = value; } public String getUpgradeDescription() { return value; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/locale/LocaleUS.java ================================================ package com.way.upgrade.locale; public class LocaleUS extends LocaleEnglish { } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/parser/json/AbstractJsonParsing.java ================================================ package com.way.upgrade.parser.json; import java.util.ArrayList; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; public abstract class AbstractJsonParsing { public abstract T readJsonItem(JSONObject jsonItem) throws JSONException; /** * 输入InputStream * * @param inStream * @return * @throws Exception */ public ArrayList readJsonArray(JSONArray jsonArray) { try { ArrayList listOperating = new ArrayList(); for (int i = 0; i < jsonArray.length(); i++) { JSONObject item = jsonArray.getJSONObject(i); T itemBean = readJsonItem(item); listOperating.add(itemBean); } return listOperating; } catch (JSONException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } return null; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/parser/json/FirVersionJsonParsing.java ================================================ package com.way.upgrade.parser.json; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import com.way.upgrade.bean.UpgradeInfo; import com.way.upgrade.utils.Constants; import com.way.upgrade.utils.ContextUtils; public class FirVersionJsonParsing extends AbstractJsonParsing { private Context mContext; public FirVersionJsonParsing(Context context) { mContext = context; } @Override public UpgradeInfo readJsonItem(JSONObject versionJsonObj) throws JSONException { UpgradeInfo upgradeInfo = new UpgradeInfo(); String url = versionJsonObj.getString("installUrl"); String firVersionCode = versionJsonObj.getString("version"); String firVersionName = versionJsonObj.getString("versionShort"); String changeLog = versionJsonObj.getString("changelog"); upgradeInfo.setUrl(url); upgradeInfo.setVersion(firVersionCode); boolean result = ContextUtils.getVersionCode(mContext) < Integer .parseInt(firVersionCode) || (ContextUtils.getVersionCode(mContext) == Integer .parseInt(firVersionCode) && !ContextUtils .getVersionName(mContext).equals(firVersionName)); upgradeInfo.setResult(String.valueOf(result)); upgradeInfo.setVersionName(firVersionName); upgradeInfo.setMustUpdate(Constants.NOT_MUST_UPDATE + ""); upgradeInfo.setChangeLog(changeLog); return upgradeInfo; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/receiver/DownloadCompleteReveiver.java ================================================ package com.way.upgrade.receiver; import android.app.DownloadManager; import android.app.DownloadManager.Query; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.net.Uri; import com.way.upgrade.utils.Preferences; /** * 下载完成通知接收器 * * @author way * */ public class DownloadCompleteReveiver extends BroadcastReceiver { private DownloadManager downloadManager; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (action.equals(DownloadManager.ACTION_DOWNLOAD_COMPLETE)) { long id = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, 0); if (id == Preferences.getDownloadId(context)) { Query query = new Query(); query.setFilterById(id); downloadManager = (DownloadManager) context .getSystemService(Context.DOWNLOAD_SERVICE); Cursor cursor = downloadManager.query(query); int columnCount = cursor.getColumnCount(); String path = null; while (cursor.moveToNext()) { for (int j = 0; j < columnCount; j++) { String columnName = cursor.getColumnName(j); String string = cursor.getString(j); if ("local_uri".equals(columnName)) { path = string; } } } cursor.close(); if (path != null) { Preferences.setDownloadPath(context, path); Preferences.setDownloadStatus(context, -1); Intent installApkIntent = new Intent(); installApkIntent.setAction(Intent.ACTION_VIEW); installApkIntent.setDataAndType(Uri.parse(path), "application/vnd.android.package-archive"); installApkIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); context.startActivity(installApkIntent); } } } else if (action.equals(DownloadManager.ACTION_NOTIFICATION_CLICKED)) { long[] ids = intent .getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS); if (ids.length > 0 && ids[0] == Preferences.getDownloadId(context)) { Intent downloadIntent = new Intent(); downloadIntent.setAction(DownloadManager.ACTION_VIEW_DOWNLOADS); downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); context.startActivity(downloadIntent); } } } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/Constants.java ================================================ package com.way.upgrade.utils; /** * * @author way 2014/4/28 */ public class Constants { //public static final String BASE_URL = "http://fir.im/api/v2/app/version/%s?token=%s"; public static final String BASE_URL = "http://api.fir.im/apps/latest/%s?api_token=%s"; public static final String DOWNLOAD_FILE_PATH = "/upgrade"; public static final int MSG_HAVA_NEW_VERSION = 1; public static final int MSG_NO_NEW_VERSION = 2; public static final int MSG_START_DOWNLOAD = 3; public static final int MSG_VERSION_RESULT = 4; public static final int MSG_NET_ERROR = 5; public static final int MUST_UPDATE = 1; public static final int NOT_MUST_UPDATE = 0; public static final String APK_SUFFIX = ".apk"; public static final Integer DOWNLOAD_STATUS_RUNNING = 1; public static final String ERROR_CODE_NET = "net_error"; } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/ContextUtils.java ================================================ package com.way.upgrade.utils; import java.lang.reflect.Method; import android.app.AlertDialog; import android.app.Dialog; import android.app.ProgressDialog; import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.os.Build; import android.util.Log; import android.widget.Toast; /** * 上下文操作,如创建对话框,进度条,版本信息... * * @author way 2013/12/6 */ public class ContextUtils { private static final String TAG = "ContextUtils"; /** * Show a Toast(Toast.LENGTH_SHORT). * * @param text * the content shown on the Toast. */ public static void showToast(Context context, String text, int length) { Toast.makeText(context, text, length).show(); } /** * Show a Toast(Toast.LENGTH_SHORT). * * @param text * the content shown on the Toast. */ public static void showToast(Context context, int resId, int length) { Toast.makeText(context, resId, length).show(); } public static ProgressDialog createProgressDialog(Context context) { ProgressDialog dialog = new ProgressDialog(context); dialog.setIndeterminate(true); dialog.setCancelable(true); return dialog; } /** * show progress dialog * * @param context * @param title * Dialog title * @param message * Dialog message * @return */ public static ProgressDialog showProgressDialog(Context context, int title, int message) { ProgressDialog dialog = new ProgressDialog(context); dialog.setTitle(title); dialog.setMessage(context.getResources().getString(message)); dialog.setIndeterminate(true); dialog.setCancelable(true); dialog.show(); return dialog; } /** * close progress dialog * * @param progressDialog */ public static void closeProgressDialog(Dialog progressDialog) { if (progressDialog != null && progressDialog.isShowing()) { progressDialog.cancel(); } } /** * * @param context * @param title * @param message * @param buttonTexts * @param listeners * @return */ public static AlertDialog.Builder showDialog(Context context, int title, int message, int[] buttonTexts, OnClickListener[] listeners) { AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(title); dialog.setMessage(message); if (buttonTexts.length == 1) { dialog.setNeutralButton(buttonTexts[0], listeners[0]); } else if (buttonTexts.length == 2) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNegativeButton(buttonTexts[1], listeners[1]); } else if (buttonTexts.length == 3) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNeutralButton(buttonTexts[1], listeners[1]); dialog.setNegativeButton(buttonTexts[2], listeners[2]); } dialog.show(); return dialog; } /** * * @param context * @param title * @param message * @param buttonTexts * @param listeners * @return */ public static AlertDialog.Builder showDialog(Context context, String title, String message, int[] buttonTexts, OnClickListener[] listeners) { AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(title); dialog.setMessage(message); if (buttonTexts.length == 1) { dialog.setNeutralButton(buttonTexts[0], listeners[0]); } else if (buttonTexts.length == 2) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNegativeButton(buttonTexts[1], listeners[1]); } else if (buttonTexts.length == 3) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNeutralButton(buttonTexts[1], listeners[1]); dialog.setNegativeButton(buttonTexts[2], listeners[2]); } dialog.show(); return dialog; } /** * * @param context * @param title * @param message * @param buttonTexts * @param listeners * @return */ public static AlertDialog showAlertDialog(Context context, String title, String message, int[] buttonTexts, OnClickListener[] listeners) { AlertDialog.Builder dialog = new AlertDialog.Builder(context); dialog.setTitle(title); dialog.setMessage(message); if (buttonTexts.length == 1) { dialog.setNeutralButton(buttonTexts[0], listeners[0]); } else if (buttonTexts.length == 2) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNegativeButton(buttonTexts[1], listeners[1]); } else if (buttonTexts.length == 3) { dialog.setPositiveButton(buttonTexts[0], listeners[0]); dialog.setNeutralButton(buttonTexts[1], listeners[1]); dialog.setNegativeButton(buttonTexts[2], listeners[2]); } return dialog.create(); } @SuppressWarnings({ "unchecked", "rawtypes" }) public static String getCustomVersion() { try { String className = "android.os.SystemProperties"; String methodName = "get"; String key = "ro.custom.build.version"; Class clazz = Class.forName(className); // Constructor con = clazz.getEnclosingConstructor(); Method method = clazz.getDeclaredMethod(methodName, String.class); return (String) method.invoke(clazz, key); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * 获取版本号 * * @param context * @return */ public static int getVersionCode(Context context) { int versionCode = -1; try { PackageInfo info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); versionCode = info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); Log.e(TAG, e.getMessage()); } return versionCode; } /** * 获取版本信息 * * @param mContext * @return */ public static String getVersionName(Context context) { String versionName = null; try { PackageInfo info = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); versionName = info.versionName; // int versionCode = info.versionCode; } catch (NameNotFoundException e) { e.printStackTrace(); Log.e(TAG, e.getMessage()); } return versionName; } public static String getUserAgent(Context context) { PackageInfo packageInfo; try { packageInfo = context.getPackageManager().getPackageInfo( context.getPackageName(), 0); } catch (NameNotFoundException e) { throw new IllegalStateException("getPackageInfo failed"); } return String.format("%s/%s; %s/%s/%s/%s; %s/%s/%s", packageInfo.packageName, packageInfo.versionName, Build.BRAND, Build.DEVICE, Build.MODEL, Build.ID, Build.VERSION.SDK_INT, Build.VERSION.RELEASE, Build.VERSION.INCREMENTAL); } public static Intent getActivityIntent(Context context, String packageName, String className) { PackageManager pm = context.getPackageManager(); Intent intent = new Intent(); ComponentName compoentName = new ComponentName(packageName, className); intent.setComponent(compoentName); ResolveInfo ri = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); if (ri != null) { return intent; } return null; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/FileUtils.java ================================================ package com.way.upgrade.utils; import java.io.File; /** * @author way 2013/12/6 */ public class FileUtils { private static final String TAG = "FileUtils"; /** * @param f * @throws Exception */ public static void createNewFile(File f) throws Exception { Log.i(TAG, "create file:" + f, Log.APP); if (!f.getParentFile().exists()) { f.getParentFile().mkdirs(); } if (!f.exists()) { f.createNewFile(); } } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/Log.java ================================================ package com.way.upgrade.utils; public class Log { public static final boolean DEBUG = true; public static final boolean DATA_DEBUG = true; public static final boolean APP_DEBUG = true; public static final boolean DISPLAY_DEBUG = false; public static final int DATA = 0; public static final int DISPLAY = 1; public static final int APP = 2; public static final String TAG = "zhujianwen"; public static void v(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.v(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.v(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.v(tag, msg); } } public static void v(String msg, int mod) { v(TAG, msg, mod); } public static void d(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.d(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.d(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.d(tag, msg); } } public static void d(String msg, int mod) { d(TAG, msg, mod); } public static void i(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.i(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.i(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.i(tag, msg); } } public static void i(String msg, int mod) { i(TAG, msg, mod); } public static void w(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.w(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.w(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.w(tag, msg); } } public static void w(String msg, int mod) { w(TAG, msg, mod); } public static void e(String tag, String msg, int mod) { if (!DEBUG) { return; } if (mod == DATA && DATA_DEBUG) { android.util.Log.e(tag, msg); } else if (mod == DISPLAY && DISPLAY_DEBUG) { android.util.Log.e(tag, msg); } else if (mod == APP && APP_DEBUG) { android.util.Log.e(tag, msg); } } public static void e(String msg, int mod) { e(TAG, msg, mod); } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/NetUtils.java ================================================ package com.way.upgrade.utils; import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.net.URL; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; /** * 网络操作 * * @author way 2013/12/6 */ public class NetUtils { private static final String TAG = "NetUtils"; private static final String NETTYPE_WIFI = "WIFI"; private static String multipart_form_data = "multipart/form-data"; private static String twoHyphens = "--"; private static String boundary = java.util.UUID.randomUUID().toString(); // 数据分隔 private static String lineEnd = "\r\n"; // The value is "\r\n" in Windows. public enum NETWORK_STATUS { STATE_WIFI, STATE_GPRS, STATE_NONE_NETWORK } private NetUtils() { } public static NETWORK_STATUS getNetworkType(Context context) { NETWORK_STATUS ret = NETWORK_STATUS.STATE_NONE_NETWORK; ConnectivityManager connetManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); if (connetManager == null) { Log.e(TAG, "isNetWorkAvailable connetManager = null", Log.APP); return ret; } NetworkInfo[] infos = connetManager.getAllNetworkInfo(); if (infos == null) { return ret; } for (int i = 0; i < infos.length && infos[i] != null; i++) { if (infos[i].isConnected() && infos[i].isAvailable()) { if (infos[i].getTypeName().equalsIgnoreCase(NETTYPE_WIFI)) { ret = NETWORK_STATUS.STATE_WIFI; } else { ret = NETWORK_STATUS.STATE_GPRS; } break; } } Log.i(TAG, "get network stype is : " + ret, Log.APP); return ret; } /** * * @param context * @param typeName * ("",WIFI,MOBILE) * @return */ public static boolean isNetWorkAvailable(Context context, String typeName) { Log.i(TAG, ">>> isNetWorkAvailable context = " + context + "typeName = " + typeName, Log.APP); boolean ret = false; ConnectivityManager connetManager = (ConnectivityManager) context .getSystemService(Context.CONNECTIVITY_SERVICE); if (connetManager == null) { Log.e(TAG, "isNetWorkAvailable connetManager = null", Log.APP); return ret; } NetworkInfo[] infos = connetManager.getAllNetworkInfo(); if (infos == null) { return ret; } if ((typeName == null) || (typeName.length() <= 0)) { for (int i = 0; i < infos.length && infos[i] != null; i++) { if (infos[i].isConnected() && infos[i].isAvailable()) { ret = true; break; } } } else { for (int i = 0; i < infos.length && infos[i] != null; i++) { if (infos[i].getTypeName().equalsIgnoreCase(typeName) && infos[i].isConnected() && infos[i].isAvailable()) { Log.i(TAG, "isNetWorkAvailable name is : " + infos[i].getTypeName(), Log.APP); ret = true; break; } } } Log.i(TAG, "isNetWorkAvailable >>> result is : " + ret, Log.APP); return ret; } /** * * @param url * @return * @throws IOException */ public static synchronized InputStream getInputStreamByGet(String url) throws IOException { Log.i(TAG, " url:" + url, Log.APP); HttpURLConnection httpConnection = null; int currentSize = 0; if (url == null) { return null; } URL uri = new URL(url); httpConnection = (HttpURLConnection) uri.openConnection(); httpConnection.setRequestProperty("User-Agent", "PacificHttpClient"); if (currentSize > 0) { httpConnection.setRequestProperty("RANGE", "bytes=" + currentSize + "-"); } // 设置超时时间 httpConnection.setConnectTimeout(10000);// 限制连接超时5秒钟 httpConnection.setReadTimeout(2 * 10000); httpConnection.setRequestProperty("Content-type", "text/html;charset=UTF-8"); httpConnection.setDoOutput(true); httpConnection.setRequestMethod("GET"); httpConnection.setUseCaches(false); int requestCode = httpConnection.getResponseCode(); if (requestCode == 200) { InputStream in = httpConnection.getInputStream(); return in; } return null; } /** * post方式从服务器获取json数组 * * @return * @throws IOException * @throws ClientProtocolException * @throws JSONException */ public static JSONArray getJSONArrayByPost(String uri) throws ClientProtocolException, IOException, JSONException { Log.i(TAG, " uri:" + uri, Log.APP); StringBuilder builder = new StringBuilder(); HttpParams httpParameters = new BasicHttpParams(); // Set the default socket timeout (SO_TIMEOUT) in milliseconds which is // the timeout for waiting for data. HttpConnectionParams.setConnectionTimeout(httpParameters, 5000); HttpConnectionParams.setSoTimeout(httpParameters, 10000); HttpClient client = new DefaultHttpClient(httpParameters); HttpPost post = new HttpPost(uri); HttpResponse response = client.execute(post); BufferedReader reader = new BufferedReader(new InputStreamReader( response.getEntity().getContent())); for (String s = reader.readLine(); s != null; s = reader.readLine()) { builder.append(s); } String jsonString = new String(builder.toString()); if ("{}".equals(jsonString)) { return null; } Log.i(TAG, " jsonString:" + jsonString, Log.DATA); return new JSONArray(jsonString); } /** * get方式从服务器获取json数组 * * @return * @throws IOException * @throws ClientProtocolException * @throws JSONException */ public static JSONObject getJSONArrayByGet(String uri) throws ClientProtocolException, IOException, JSONException { Log.i(TAG, " uri:" + uri, Log.APP); StringBuilder builder = new StringBuilder(); HttpClient client = new DefaultHttpClient(); HttpGet get = new HttpGet(uri); HttpResponse response = client.execute(get); BufferedReader reader = new BufferedReader(new InputStreamReader( response.getEntity().getContent())); for (String s = reader.readLine(); s != null; s = reader.readLine()) { builder.append(s); } String jsonString = new String(builder.toString()); if ("{}".equals(jsonString)) { return null; } Log.i(TAG, " jsonString:" + jsonString, Log.DATA); return new JSONObject(jsonString); } /** * 使用post的方式,提交表单,不包括文件上传(新服务器) * * @param actionUrl * @param params * @param files * @return * @throws IOException */ public static boolean uploadParamsByPost(String actionUrl, Map params) throws IOException { Log.i(TAG, " actionUrl:" + actionUrl + " params:" + params, Log.APP); String BOUNDARY = java.util.UUID.randomUUID().toString(); String PREFIX = "--", LINEND = "\r\n"; String MULTIPART_FROM_DATA = "multipart/form-data"; String CHARSET = "UTF-8"; URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(10 * 1000); conn.setConnectTimeout(10 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); // Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); conn.setRequestProperty("Content-Type", MULTIPART_FROM_DATA + ";boundary=" + BOUNDARY); // 首先组拼文本类型的参数 StringBuilder sb = new StringBuilder(); for (Map.Entry entry : params.entrySet()) { sb.append(PREFIX); sb.append(BOUNDARY); sb.append(LINEND); sb.append("Content-Disposition: form-data; name=\"" + entry.getKey() + "\"" + LINEND); sb.append("Content-Type: text/plain; charset=" + CHARSET + LINEND); sb.append("Content-Transfer-Encoding: 8bit" + LINEND); sb.append(LINEND); sb.append(entry.getValue()); sb.append(LINEND); } DataOutputStream outStream = new DataOutputStream( conn.getOutputStream()); outStream.write(sb.toString().getBytes()); // 请求结束标志 byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINEND).getBytes(); outStream.write(end_data); outStream.flush(); outStream.close(); // 得到响应号 int res = conn.getResponseCode(); if (res == 200) { return true; } conn.disconnect(); return false; } /** * 使用post的方式,提交表单,不包括文件上传(老服务器写的代码使用这种方式) * * @param actionUrl * :http://xxx/xxx.json * @param query * :Helpers.combinaStr("login_name=#&password=#&email=#&name=", * listParams); * @return */ public static JSONObject uploadParamsByPost(String actionUrl, String query) { Log.i(TAG, " actionUrl:" + actionUrl + " query:" + query, Log.APP); try { URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(10 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); // Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); // query is your body conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");// 请求�? // 必须设置 conn.setRequestProperty("Content-Length", query.toString() .getBytes("UTF-8").length + "");// 注意是字节长�? // 不是字符长度 conn.getOutputStream().write(query.toString().getBytes("UTF-8")); // 得到响应�? int res = conn.getResponseCode(); if (res == HttpURLConnection.HTTP_OK) { StringBuffer stringBuffer = new StringBuffer(); String readLine; BufferedReader responseReader; // 处理响应流,必须与服务器响应流输出的编码�?�� responseReader = new BufferedReader(new InputStreamReader( conn.getInputStream(), "UTF-8")); while ((readLine = responseReader.readLine()) != null) { stringBuffer.append(readLine).append("/n"); } responseReader.close(); return new JSONObject(stringBuffer.toString()); } } catch (Exception e) { e.printStackTrace(); } return null; } public int uploadFilesByPost(String actionUrl, String fileName, File file) { Log.i(TAG, " actionUrl:" + actionUrl + " fileName:" + fileName, Log.APP); String CHARSET = "UTF-8"; // 得到响应�? int res = 0; try { URL uri = new URL(actionUrl); HttpURLConnection conn = (HttpURLConnection) uri.openConnection(); conn.setReadTimeout(10 * 1000); conn.setDoInput(true);// 允许输入 conn.setDoOutput(true);// 允许输出 conn.setUseCaches(false); conn.setRequestMethod("POST"); // Post方式 conn.setRequestProperty("connection", "keep-alive"); conn.setRequestProperty("Charsert", "UTF-8"); conn.setRequestProperty("Content-Type", multipart_form_data + ";boundary=" + boundary); // 输出�? DataOutputStream outStream = new DataOutputStream( conn.getOutputStream()); // 发�?文件数据 if (file != null) { StringBuilder sb1 = new StringBuilder(); sb1.append(twoHyphens); sb1.append(boundary); sb1.append(lineEnd); // actionData 是自己定义的 sb1.append("Content-Disposition: form-data; name=\"actionData\"; filename=\"" + fileName + "\"" + lineEnd); sb1.append("Content-Type: application/octet-stream; charset=" + CHARSET + lineEnd); sb1.append(lineEnd); outStream.write(sb1.toString().getBytes()); InputStream is = new FileInputStream(file); byte[] buffer = new byte[1024]; int len = 0; while ((len = is.read(buffer)) != -1) { outStream.write(buffer, 0, len); } is.close(); outStream.write(lineEnd.getBytes()); } // 请求结束标志 byte[] end_data = (twoHyphens + boundary + twoHyphens + lineEnd) .getBytes(); outStream.write(end_data); outStream.flush(); res = conn.getResponseCode(); outStream.close(); conn.disconnect(); } catch (IOException e) { e.printStackTrace(); } return res; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/Preferences.java ================================================ package com.way.upgrade.utils; import android.content.Context; import android.content.SharedPreferences; import com.way.upgrade.bean.UpgradeInfo; /** * * @author way 2014/11/3 */ public class Preferences { public static final String PREFERENCES_NAME = "com_upgrade_manager"; public static final String KEY_DOWNLOAD_ID = "downloadId"; protected static final String KEY_APPKEY = "key"; protected static final String KEY_VERSION = "version"; protected static final String KEY_URL = "url"; protected static final String KEY_DESCRIPTION = "description"; protected static final String KEY_DOWNLOAD_SIZE = "downloadSize"; protected static final String KEY_DOWNLOAD_PATH = "download_path"; protected static final String KEY_DOWNLOAD_STATUS = "download_status"; public static void setDownloadId(Context context, long downloadId) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putLong(KEY_DOWNLOAD_ID, downloadId); editor.commit(); } public static long getDownloadId(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); return pref.getLong(KEY_DOWNLOAD_ID, -1); } public static void setUpgradeInfo(Context context, UpgradeInfo upgrade) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putString(KEY_APPKEY, upgrade.getKey()); editor.putString(KEY_VERSION, upgrade.getVersion()); editor.putString(KEY_URL, upgrade.getUrl()); editor.putString(KEY_DESCRIPTION, upgrade.getDescription()); editor.putLong(KEY_DOWNLOAD_SIZE, upgrade.getDownloadSize()); editor.commit(); } public static UpgradeInfo getUpgradeInfo(Context context) { UpgradeInfo upgradeInfo = new UpgradeInfo(); SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); upgradeInfo.setKey(pref.getString(KEY_APPKEY, "")); upgradeInfo.setVersion(pref.getString(KEY_VERSION, "")); upgradeInfo.setUrl(pref.getString(KEY_URL, "")); upgradeInfo.setDescription(pref.getString(KEY_DESCRIPTION, "")); upgradeInfo.setDownloadSize(pref.getLong(KEY_DOWNLOAD_SIZE, -1)); return upgradeInfo; } public static void setDownloadPath(Context context, String downloadPath) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putString(KEY_DOWNLOAD_PATH, downloadPath); editor.commit(); } public static String getDownloadPath(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); return pref.getString(KEY_DOWNLOAD_PATH, ""); } public static void removeAll(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.clear(); editor.commit(); } public static void setDownloadStatus(Context context, int downloadId) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); SharedPreferences.Editor editor = pref.edit(); editor.putInt(KEY_DOWNLOAD_STATUS, downloadId); editor.commit(); } public static int getDownloadStatus(Context context) { SharedPreferences pref = context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_APPEND); return pref.getInt(KEY_DOWNLOAD_STATUS, -1); } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/Utils.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils; import java.io.Closeable; import java.io.InterruptedIOException; import java.util.List; import android.database.Cursor; import android.os.Build; import android.os.ParcelFileDescriptor; import android.text.TextUtils; public class Utils { private static final String TAG = "Utils"; private static final String DEBUG_TAG = "GalleryDebug"; private static final long POLY64REV = 0x95AC9329AC4BC9B5L; private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL; private static long[] sCrcTable = new long[256]; private static final boolean IS_DEBUG_BUILD = Build.TYPE.equals("eng") || Build.TYPE.equals("userdebug"); private static final String MASK_STRING = "********************************"; // Throws AssertionError if the input is false. public static void assertTrue(boolean cond) { if (!cond) { throw new AssertionError(); } } // Throws AssertionError with the message. We had a method having the form // assertTrue(boolean cond, String message, Object ... args); // However a call to that method will cause memory allocation even if the // condition is false (due to autoboxing generated by "Object ... args"), // so we don't use that anymore. public static void fail(String message, Object... args) { throw new AssertionError(args.length == 0 ? message : String.format( message, args)); } // Throws NullPointerException if the input is null. public static T checkNotNull(T object) { if (object == null) throw new NullPointerException(); return object; } // Returns true if two input Object are both null or equal // to each other. public static boolean equals(Object a, Object b) { return (a == b) || (a == null ? false : a.equals(b)); } // Returns the next power of two. // Returns the input if it is already power of 2. // Throws IllegalArgumentException if the input is <= 0 or // the answer overflows. public static int nextPowerOf2(int n) { if (n <= 0 || n > (1 << 30)) throw new IllegalArgumentException("n is invalid: " + n); n -= 1; n |= n >> 16; n |= n >> 8; n |= n >> 4; n |= n >> 2; n |= n >> 1; return n + 1; } // Returns the previous power of two. // Returns the input if it is already power of 2. // Throws IllegalArgumentException if the input is <= 0 public static int prevPowerOf2(int n) { if (n <= 0) throw new IllegalArgumentException(); return Integer.highestOneBit(n); } // Returns the input value x clamped to the range [min, max]. public static int clamp(int x, int min, int max) { if (x > max) return max; if (x < min) return min; return x; } // Returns the input value x clamped to the range [min, max]. public static float clamp(float x, float min, float max) { if (x > max) return max; if (x < min) return min; return x; } // Returns the input value x clamped to the range [min, max]. public static long clamp(long x, long min, long max) { if (x > max) return max; if (x < min) return min; return x; } public static boolean isOpaque(int color) { return color >>> 24 == 0xFF; } public static void swap(int[] array, int i, int j) { int temp = array[i]; array[i] = array[j]; array[j] = temp; } /** * A function thats returns a 64-bit crc for string * * @param in * input string * @return a 64-bit crc value */ public static final long crc64Long(String in) { if (in == null || in.length() == 0) { return 0; } return crc64Long(getBytes(in)); } static { // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c long part; for (int i = 0; i < 256; i++) { part = i; for (int j = 0; j < 8; j++) { long x = ((int) part & 1) != 0 ? POLY64REV : 0; part = (part >> 1) ^ x; } sCrcTable[i] = part; } } public static final long crc64Long(byte[] buffer) { long crc = INITIALCRC; for (int k = 0, n = buffer.length; k < n; ++k) { crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8); } return crc; } public static byte[] getBytes(String in) { byte[] result = new byte[in.length() * 2]; int output = 0; for (char ch : in.toCharArray()) { result[output++] = (byte) (ch & 0xFF); result[output++] = (byte) (ch >> 8); } return result; } public static void closeSilently(Closeable c) { if (c == null) return; try { c.close(); } catch (Throwable t) { Log.w(TAG, "close fail", Log.APP); } } public static int compare(long a, long b) { return a < b ? -1 : a == b ? 0 : 1; } public static int ceilLog2(float value) { int i; for (i = 0; i < 31; i++) { if ((1 << i) >= value) break; } return i; } public static int floorLog2(float value) { int i; for (i = 0; i < 31; i++) { if ((1 << i) > value) break; } return i - 1; } public static void closeSilently(ParcelFileDescriptor fd) { try { if (fd != null) fd.close(); } catch (Throwable t) { Log.w(TAG, "fail to close", Log.APP); } } public static void closeSilently(Cursor cursor) { try { if (cursor != null) cursor.close(); } catch (Throwable t) { Log.w(TAG, "fail to close", Log.APP); } } public static float interpolateAngle(float source, float target, float progress) { // interpolate the angle from source to target // We make the difference in the range of [-179, 180], this is the // shortest path to change source to target. float diff = target - source; if (diff < 0) diff += 360f; if (diff > 180) diff -= 360f; float result = source + diff * progress; return result < 0 ? result + 360f : result; } public static float interpolateScale(float source, float target, float progress) { return source + progress * (target - source); } public static String ensureNotNull(String value) { return value == null ? "" : value; } public static String ensureNotNull(Object obj) { return obj == null ? "" : obj.toString(); } public static float parseFloatSafely(String content, float defaultValue) { if (content == null) return defaultValue; try { return Float.parseFloat(content); } catch (NumberFormatException e) { return defaultValue; } } public static int parseIntSafely(String content, int defaultValue) { if (content == null) return defaultValue; try { return Integer.parseInt(content); } catch (NumberFormatException e) { return defaultValue; } } public static boolean isNullOrEmpty(String exifMake) { return TextUtils.isEmpty(exifMake); } public static void waitWithoutInterrupt(Object object) { try { object.wait(); } catch (InterruptedException e) { Log.w(TAG, "unexpected interrupt: " + object, Log.APP); } } public static boolean handleInterrruptedException(Throwable e) { // A helper to deal with the interrupt exception // If an interrupt detected, we will setup the bit again. if (e instanceof InterruptedIOException || e instanceof InterruptedException) { Thread.currentThread().interrupt(); return true; } return false; } /** * @return String with special XML characters escaped. */ public static String escapeXml(String s) { StringBuilder sb = new StringBuilder(); for (int i = 0, len = s.length(); i < len; ++i) { char c = s.charAt(i); switch (c) { case '<': sb.append("<"); break; case '>': sb.append(">"); break; case '\"': sb.append("""); break; case '\'': sb.append("'"); break; case '&': sb.append("&"); break; default: sb.append(c); } } return sb.toString(); } public static String[] copyOf(String[] source, int newSize) { String[] result = new String[newSize]; newSize = Math.min(source.length, newSize); System.arraycopy(source, 0, result, 0, newSize); return result; } // Mask information for debugging only. It returns // info.toString() directly // for debugging build (i.e., 'eng' and 'userdebug') and returns a mask // ("****") // in release build to protect the information (e.g. for privacy issue). public static String maskDebugInfo(Object info) { if (info == null) return null; String s = info.toString(); int length = Math.min(s.length(), MASK_STRING.length()); return IS_DEBUG_BUILD ? s : MASK_STRING.substring(0, length); } // This method should be ONLY used for debugging. public static void debug(String message, Object... args) { Log.v(DEBUG_TAG, String.format(message, args), Log.APP); } /** * combina the url. usr the param list repleace the [#] in the url. * * @param str * @param params * @return * @exception RuntimeException * May throw the runtime exception while the method was done. * @author MichaelHuang */ public static String combinaStr(String str, List params) throws RuntimeException { try { String[] strs = str.split("[#]"); String newStr = ""; for (int i = 0; i < strs.length; i++) { String itemUrl = strs[i]; newStr += itemUrl; if (i >= 0 && i < params.size()) newStr += params.get(i); } Log.i(TAG, " newStr:" + newStr, Log.DATA); return newStr; } catch (Exception e) { throw new RuntimeException(); } } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/thread/Future.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; // This Future differs from the java.util.concurrent.Future in these aspects: // // - Once cancel() is called, isCancelled() always returns true. It is a sticky // flag used to communicate to the implementation. The implmentation may // ignore that flag. Regardless whether the Future is cancelled, a return // value will be provided to get(). The implementation may choose to return // null if it finds the Future is cancelled. // // - get() does not throw exceptions. // public interface Future { public void cancel(); public boolean isCancelled(); public boolean isDone(); public T get(); public void waitDone(); } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/thread/FutureListener.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; /** * * @author way * * @param */ public interface FutureListener { public void onFutureDone(Future future); } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/thread/PriorityThreadFactory.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; import android.os.Process; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; /** * A thread factory that creates threads with a given thread priority. */ public class PriorityThreadFactory implements ThreadFactory { private final int mPriority; private final AtomicInteger mNumber = new AtomicInteger(); private final String mName; public PriorityThreadFactory(String name, int priority) { mName = name; mPriority = priority; } @Override public Thread newThread(Runnable r) { return new Thread(r, mName + '-' + mNumber.getAndIncrement()) { @Override public void run() { Process.setThreadPriority(mPriority); super.run(); } }; } } ================================================ FILE: WayHoo/Upgrade-lib/com/way/upgrade/utils/thread/ThreadPool.java ================================================ /* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.way.upgrade.utils.thread; import java.util.concurrent.Executor; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import com.way.upgrade.utils.Log; /** * * @author way * */ public class ThreadPool { private static final String TAG = "ThreadPool"; private static final int CORE_POOL_SIZE = 4; private static final int MAX_POOL_SIZE = 8; private static final int KEEP_ALIVE_TIME = 20; // 10 seconds // Resource type public static final int MODE_NONE = 0; public static final int MODE_CPU = 1; public static final int MODE_NETWORK = 2; public static final JobContext JOB_CONTEXT_STUB = new JobContextStub(); // M: in order to take full advantage of MT6589 CPU Core, change cpuCounter // to 4 from 2 ResourceCounter mCpuCounter = new ResourceCounter(4); ResourceCounter mNetworkCounter = new ResourceCounter(6); // A Job is like a Callable, but it has an addition JobContext parameter. public interface Job { public T run(JobContext jc); } public interface JobContext { boolean isCancelled(); void setCancelListener(CancelListener listener); boolean setMode(int mode); } private static class JobContextStub implements JobContext { @Override public boolean isCancelled() { return false; } @Override public void setCancelListener(CancelListener listener) { } @Override public boolean setMode(int mode) { return true; } } public interface CancelListener { public void onCancel(); } private static class ResourceCounter { public int value; public ResourceCounter(int v) { value = v; } } private final Executor mExecutor; public ThreadPool() { this(CORE_POOL_SIZE, MAX_POOL_SIZE); } public ThreadPool(int initPoolSize, int maxPoolSize) { mExecutor = new ThreadPoolExecutor(initPoolSize, maxPoolSize, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue(), new PriorityThreadFactory( "thread-pool", android.os.Process.THREAD_PRIORITY_BACKGROUND)); } // Submit a job to the thread pool. The listener will be called when the // job is finished (or cancelled). public Future submit(Job job, FutureListener listener, int threadMode) { Log.i(TAG, " Job:" + job, Log.APP); Worker w = new Worker(job, listener, threadMode); mExecutor.execute(w); return w; } public Future submit(Job job) { return submit(job, null, MODE_CPU); } private class Worker implements Runnable, Future, JobContext { private static final String TAG = "Worker"; private Job mJob; private FutureListener mListener; private CancelListener mCancelListener; private ResourceCounter mWaitOnResource; private volatile boolean mIsCancelled; private boolean mIsDone; private T mResult; private int mMode; private int mTargetMode; public Worker(Job job, FutureListener listener, int threadMode) { mJob = job; mListener = listener; mTargetMode = threadMode; } // This is called by a thread in the thread pool. @Override public void run() { Log.i(TAG, " start", Log.APP); T result = null; // A job is in CPU mode by default. setMode returns false // if the job is cancelled. if (setMode(mTargetMode)) { try { result = mJob.run(this); } catch (Throwable ex) { } } synchronized (this) { setMode(MODE_NONE); mResult = result; mIsDone = true; notifyAll(); } if (mListener != null) mListener.onFutureDone(this); Log.i(TAG, " end", Log.APP); } // Below are the methods for Future. @Override public synchronized void cancel() { if (mIsCancelled) return; mIsCancelled = true; if (mWaitOnResource != null) { synchronized (mWaitOnResource) { mWaitOnResource.notifyAll(); } } if (mCancelListener != null) { mCancelListener.onCancel(); } } @Override public boolean isCancelled() { return mIsCancelled; } @Override public synchronized boolean isDone() { return mIsDone; } @Override public synchronized T get() { while (!mIsDone) { try { wait(); } catch (Exception ex) { } } return mResult; } @Override public void waitDone() { get(); } // Below are the methods for JobContext (only called from the // thread running the job) @Override public synchronized void setCancelListener(CancelListener listener) { mCancelListener = listener; if (mIsCancelled && mCancelListener != null) { mCancelListener.onCancel(); } } @Override public boolean setMode(int mode) { // Release old resource Log.i(TAG, " start mode:" + mode, Log.APP); ResourceCounter rc = modeToCounter(mMode); if (rc != null) releaseResource(rc); mMode = MODE_NONE; // Acquire new resource rc = modeToCounter(mode); if (rc != null) { if (!acquireResource(rc)) { return false; } mMode = mode; } Log.i(TAG, " end", Log.APP); return true; } private ResourceCounter modeToCounter(int mode) { if (mode == MODE_CPU) { Log.i(TAG, " MODE_CPU", Log.APP); return mCpuCounter; } else if (mode == MODE_NETWORK) { Log.i(TAG, " MODE_NETWORK", Log.APP); return mNetworkCounter; } else { return null; } } private boolean acquireResource(ResourceCounter counter) { Log.i(TAG, " start", Log.APP); while (true) { synchronized (this) { if (mIsCancelled) { mWaitOnResource = null; return false; } mWaitOnResource = counter; } synchronized (counter) { if (counter.value > 0) { counter.value--; break; } else { try { counter.wait(); } catch (InterruptedException ex) { // ignore. } } } } synchronized (this) { mWaitOnResource = null; } Log.i(TAG, " end", Log.APP); return true; } private void releaseResource(ResourceCounter counter) { Log.i(TAG, " start", Log.APP); synchronized (counter) { counter.value++; counter.notifyAll(); } Log.i(TAG, " end", Log.APP); } } } ================================================ FILE: WayHoo/jni/Android.mk ================================================ # Copyright (C) 2009 The Android Open Source Project # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := libfrostedGlass LOCAL_SRC_FILES := frostedGlass.c bitmapPort.c imageProcess.c LOCAL_LDLIBS := -llog -ljnigraphics #LOCAL_SHARED_LIBRARIES += \ #liblog libjnigraphics include $(BUILD_SHARED_LIBRARY) ================================================ FILE: WayHoo/jni/Application.mk ================================================ APP_ABI := armeabi armeabi-v7a APP_PLATFORM:= android-21 APP_OPTIM := release ================================================ FILE: WayHoo/jni/bitmapPort.c ================================================ #include #include #include #include #include "constants.h" #include "bitmapPort.h" static AndroidBitmapInfo imageInfo; static uint8_t* imageData; // int allocateMemory() { int ret = 0; size_t size = 4*imageInfo.width*imageInfo.height;//color-int imageData = (uint8_t*)malloc(size); if (imageData == NULL) { ret = -1; } return ret; } void freeMemory(){ if(imageData != NULL){ free(imageData); imageData = NULL; } } void getUnifiedImageData(jobject bitmap, JNIEnv *env) { if (imageData == NULL) return; switch (imageInfo.format) { case ANDROID_BITMAP_FORMAT_RGBA_8888: LOGE("get ARGB 8888"); getARGB8888Data(bitmap, env); break; case ANDROID_BITMAP_FORMAT_RGBA_4444: LOGE("get ARGB 4444"); getARGB4444Data(bitmap, env); break; case ANDROID_BITMAP_FORMAT_RGB_565: LOGE("get rgb 565"); getRGB565Data(bitmap, env); break; case ANDROID_BITMAP_FORMAT_A_8: LOGE("get alpha 8"); getAlpha8Data(bitmap, env); break; default: break; } } void getARGB8888Data(jobject bitmap, JNIEnv *env) { int ret, row, col; void *pixelscolor; if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } uint8_t *pData = imageData; uint32_t colorValue = 0; for (row = 0; row < imageInfo.height; row++) { uint32_t * line = (uint32_t *) pixelscolor; for (col = 0; col < imageInfo.width; col++) { colorValue = line[col]; *pData++ = colorValue & ARGB8888_MASK_BLUE; *pData++ = (colorValue & ARGB8888_MASK_GREEN) >> 8; *pData++ = (colorValue & ARGB8888_MASK_RED) >> 16; *pData++ = (colorValue & ARGB8888_MASK_ALPHA)>>24; } //stride pixelscolor = (uint8_t*)pixelscolor + imageInfo.stride; } AndroidBitmap_unlockPixels(env, bitmap); } void getARGB4444Data(jobject bitmap, JNIEnv *env) { int ret, row, col; void *pixelscolor; if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } uint8_t *pData = imageData; for (row = 0; row < imageInfo.height; row++) { uint16_t *line = (uint16_t *) pixelscolor; for (col = 0; col < imageInfo.width; col++) { //*pData++ = (line[col] & ARGB4444_MASK_RED) << 4; //*pData++ = (line[col] & ARGB4444_MASK_GREEN) << 4; //*pData++ = (line[col] & ARGB4444_MASK_BLUE) << 4; } pixelscolor = (uint8_t*)pixelscolor + imageInfo.stride; } AndroidBitmap_unlockPixels(env, bitmap); } void getRGB565Data(jobject bitmap, JNIEnv *env) { int ret, row, col; void *pixelscolor; if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } uint8_t *pData = imageData; for (row = 0; row < imageInfo.height; row++) { uint16_t *line = (uint16_t *) pixelscolor; for (col = 0; col < imageInfo.width; col++) { *pData++ = ((line[col] & RGB565_MASK_RED) >> 11) << 3; *pData++ = ((line[col] & RGB565_MASK_GREEN) >> 5) << 2; *pData++ = (line[col] & RGB565_MASK_BLUE) << 3; } pixelscolor = (uint8_t*)pixelscolor + imageInfo.stride; } AndroidBitmap_unlockPixels(env, bitmap); } void getAlpha8Data(jobject bitmap, JNIEnv *env) { int ret, row, col; void *pixelscolor; if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } uint8_t *pData = imageData; for (row = 0; row < imageInfo.height; row++) { uint8_t *line = (uint8_t *) pixelscolor; for (col = 0; col < imageInfo.width; col++) { *pData++ = line[col]; *pData++ = line[col]; *pData++ = line[col]; } pixelscolor = (uint8_t*)pixelscolor + imageInfo.stride; } AndroidBitmap_unlockPixels(env, bitmap); } void setUnifiedImageData(jobject bitmap, JNIEnv *env) { switch (imageInfo.format) { case ANDROID_BITMAP_FORMAT_RGBA_8888: LOGE("set ARGB 8888"); setARGB8888Data(bitmap, env); break; case ANDROID_BITMAP_FORMAT_RGBA_4444: LOGE("set ARGB 4444"); setARGB4444Data(bitmap, env); break; case ANDROID_BITMAP_FORMAT_RGB_565: LOGE("set rgb 565"); setRGB565Data(bitmap, env); break; case ANDROID_BITMAP_FORMAT_A_8: LOGE("set alpha 8"); setAlpha8Data(bitmap, env); break; default: break; } } void setARGB8888Data(jobject bitmap, JNIEnv *env) { int ret, row, col; uint32_t red, green, blue, alpha; void *pixelscolor; if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } uint8_t *pData = imageData; for (row = 0; row < imageInfo.height; row++) { uint32_t *line = (uint32_t *) pixelscolor; for (col = 0; col < imageInfo.width; col++) { blue = *pData++; green = *pData++; red = *pData++; alpha = *pData++; line[col] = ((alpha<<24) & ARGB8888_MASK_ALPHA)//(line[col] & ARGB8888_MASK_ALPHA) | ((red << 16) & ARGB8888_MASK_RED) | ((green << 8) & ARGB8888_MASK_GREEN) | (blue & ARGB8888_MASK_BLUE); } pixelscolor = (uint8_t*)pixelscolor + imageInfo.stride; } AndroidBitmap_unlockPixels(env, bitmap); } void setARGB4444Data(jobject bitmap, JNIEnv *env) {} void setRGB565Data(jobject bitmap, JNIEnv *env) { int ret, row, col; uint16_t red, green, blue; void *pixelscolor; if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixelscolor)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } uint8_t *pData = imageData; for (row = 0; row < imageInfo.height; row++) { uint16_t *line = (uint16_t *) pixelscolor; for (col = 0; col < imageInfo.width; col++) { red = *pData++; green = *pData++; blue = *pData++; line[col] = ((red << 8) & RGB565_MASK_RED) | ((green << 3) & RGB565_MASK_GREEN) | (blue >> 3); } pixelscolor = (uint8_t*)pixelscolor + imageInfo.stride; } AndroidBitmap_unlockPixels(env, bitmap); LOGE("set RGB 565 Data finished"); } void setAlpha8Data(jobject bitmap, JNIEnv *env) {} //warp int AndroidBitmap_getInfo_warp(JNIEnv* env, jobject jbitmap) { return AndroidBitmap_getInfo(env, jbitmap, &imageInfo); } void blur(){ gaussBlurProcess(imageData, imageInfo.width, imageInfo.height); } void logBitmapPort(){ LOGI("color image :: width is %d; height is %d; stride is %d; format is %d;flags is%d", imageInfo.width,imageInfo.height,imageInfo.stride,imageInfo.format,imageInfo.flags); } void clearColorPort(int color){ clearColorProcess(imageData, imageInfo.width, imageInfo.height, color); } void boxBlurPort(int radius){ boxBlurProcess(imageData, imageInfo.width, imageInfo.height, imageInfo.stride, radius); } void stackBlurPort(int radius){ stackBlurProcess(imageData, imageInfo.width, imageInfo.height, imageInfo.stride, radius); } void oilPaintPort(int radius){ oilPaintProcess(imageData, imageInfo.width, imageInfo.height, imageInfo.stride, radius); } void colorWaterPaintPort(int radius){ colorWaterPaint(imageData, imageInfo.width, imageInfo.height, imageInfo.stride, radius); } ================================================ FILE: WayHoo/jni/bitmapPort.h ================================================ #include #include #include #include #include "constants.h" #ifndef _BITMAP_PORT_H_ #define _BITMAP_PORT_H_ //declare int allocateMemory(); void getUnifiedImageData(jobject bitmap, JNIEnv *env); void getARGB8888Data(jobject bitmap, JNIEnv *env); void getARGB4444Data(jobject bitmap, JNIEnv *env); void getRGB565Data(jobject bitmap, JNIEnv *env); void getAlpha8Data(jobject bitmap, JNIEnv *env); void setUnifiedImageData(jobject bitmap, JNIEnv *env); void setARGB8888Data(jobject bitmap, JNIEnv *env); void setARGB4444Data(jobject bitmap, JNIEnv *env); void setRGB565Data(jobject bitmap, JNIEnv *env); void setAlpha8Data(jobject bitmap, JNIEnv *env); void blurPort(); void logBitmapPort(); void clearColorPort(int color); void boxBlurPort(int radius); void stackBlurPort(int radius); #endif ================================================ FILE: WayHoo/jni/com_way_util_blur_jni_FrostedGlassUtil.h ================================================ /* DO NOT EDIT THIS FILE - it is machine generated */ #include /* Header for class com_way_util_blur_jni_FrostedGlassUtil */ #ifndef _Included_com_way_util_blur_jni_FrostedGlassUtil #define _Included_com_way_util_blur_jni_FrostedGlassUtil #ifdef __cplusplus extern "C" { #endif /* * Class: com_way_util_blur_jni_FrostedGlassUtil * Method: boxBlur * Signature: (Landroid/graphics/Bitmap;I)V */ JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_boxBlur (JNIEnv *, jobject, jobject, jint); /* * Class: com_way_util_blur_jni_FrostedGlassUtil * Method: stackBlur * Signature: (Landroid/graphics/Bitmap;I)V */ JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_stackBlur (JNIEnv *, jobject, jobject, jint); /* * Class: com_way_util_blur_jni_FrostedGlassUtil * Method: oilPaint * Signature: (Landroid/graphics/Bitmap;I)V */ JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_oilPaint (JNIEnv *, jobject, jobject, jint); /* * Class: com_way_util_blur_jni_FrostedGlassUtil * Method: colorWaterPaint * Signature: (Landroid/graphics/Bitmap;I)V */ JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_colorWaterPaint (JNIEnv *, jobject, jobject, jint); #ifdef __cplusplus } #endif #endif ================================================ FILE: WayHoo/jni/constants.h ================================================ #ifndef _CONSTANTS_H_ #define _CONSTANTS_H_ #include #include #include #include "com_way_util_blur_jni_FrostedGlassUtil.h" #define RGB565_MASK_RED 0xF800 #define RGB565_MASK_GREEN 0x07E0 #define RGB565_MASK_BLUE 0x001F #define ARGB8888_MASK_ALPHA 0xFF000000 #define ARGB8888_MASK_RED 0x00FF0000 #define ARGB8888_MASK_GREEN 0x0000FF00 #define ARGB8888_MASK_BLUE 0x000000FF #define ARGB4444_MASK_RED 0x0F00; #define ARGB4444_MASK_GREEN 0x00F0; #define ARGB4444_MASK_BLUE 0x000F; #define ARGB8888_2_COLOR(a,r,g,b) (((a)<<24)|((r)<<16)|((g)<<8)|(b)) #define LOG_TAG "FrostedGlass" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__) #endif ================================================ FILE: WayHoo/jni/frostedGlass.c ================================================ /* * Copyright (C) 2009 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #include #include #include #include #include "constants.h" #include "bitmapPort.h" //#include "ImageProcessor.h" //#include "Lomo.h" /* This is a trivial JNI example where we use a native method * to return a new VM String. See the corresponding Java source * file located at: * * apps/samples/hello-jni/project/src/com/example/hellojni/HelloJni.java */ JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_boxBlur(JNIEnv *env, jclass obj, jobject srcBitmap, jint radius) { void* pixelscolor; int ret, row, col; if ((ret = AndroidBitmap_getInfo_warp(env, srcBitmap)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } logBitmapPort(); if (-1 == allocateMemory()) { LOGE("allocate memory failed !"); return; } getUnifiedImageData(srcBitmap, env); LOGE("get unified image data "); boxBlurPort(radius); LOGE("conver image data"); setUnifiedImageData(srcBitmap, env); LOGE("set unified image data"); freeMemory(); } JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_stackBlur(JNIEnv *env, jclass obj, jobject srcBitmap, jint radius) { void* pixelscolor; int ret, row, col; if ((ret = AndroidBitmap_getInfo_warp(env, srcBitmap)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } logBitmapPort(); if (-1 == allocateMemory()) { LOGE("allocate memory failed !"); return; } getUnifiedImageData(srcBitmap, env); LOGE("get unified image data "); stackBlurPort(radius); LOGE("conver image data"); setUnifiedImageData(srcBitmap, env); LOGE("set unified image data"); freeMemory(); } JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_oilPaint(JNIEnv *env, jclass obj, jobject srcBitmap, jint radius) { void* pixelscolor; int ret, row, col; if ((ret = AndroidBitmap_getInfo_warp(env, srcBitmap)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } logBitmapPort(); if (-1 == allocateMemory()) { LOGE("allocate memory failed !"); return; } getUnifiedImageData(srcBitmap, env); LOGE("get unified image data "); oilPaintPort(radius); LOGE("conver image data"); setUnifiedImageData(srcBitmap, env); LOGE("set unified image data"); freeMemory(); } JNIEXPORT void JNICALL Java_com_way_util_blur_jni_FrostedGlassUtil_colorWaterPaint(JNIEnv *env, jclass obj, jobject srcBitmap, jint radius) { void* pixelscolor; int ret, row, col; if ((ret = AndroidBitmap_getInfo_warp(env, srcBitmap)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } logBitmapPort(); if (-1 == allocateMemory()) { LOGE("allocate memory failed !"); return; } getUnifiedImageData(srcBitmap, env); LOGE("get unified image data "); colorWaterPaintPort(radius); LOGE("conver image data"); setUnifiedImageData(srcBitmap, env); LOGE("set unified image data"); freeMemory(); } ================================================ FILE: WayHoo/jni/imageProcess.c ================================================ #include "stdlib.h" #include "stdio.h" #include "math.h" #include "imageProcess.h" #include "constants.h" static void iblurV(int *pDataSave, int * pData, int *divTable, int width, int height, int radius); static void iblurH(int *pDataSave, int * pData, int *divTable, int width, int height, int radius); static void iStackBlur(int *pData, int width, int height, int radius); static void iQSort(uint8_t a[],int low,int high); static void iColorWaterFilter( int * pSrcImage, int * pDstImage, int width, int height ); void gaussBlurProcess(uint8_t *image, int width, int height) { // 高斯矩阵 int gauss[16] = { 1, 2, 1, 2, 4, 2, 1, 2, 1 }; int pixR = 0; int pixG = 0; int pixB = 0; int pixColor = 0; int newR = 0; int newG = 0; int newB = 0; int idx = 0; int * pixels = 0; int * pData = (int *)image; int value = 0; pixels = (int *)malloc(width * height*sizeof(int)); if(pixels == NULL){ return; } memset((unsigned char *)pixels, 0, sizeof(int)*width * height); int i = 0; int j = 0; int v = 0; int h = height - 1; int m; int n; for (j = 1; j < h; j++){ v = width - 1; for (i = 1; i < v; i++){ idx = 0; //initial newR = 0; newG = 0; newB = 0; //add for (m = -1; m <= 1; m++) { for (n = -1; n <= 1; n++) { pixColor = pData[(j + m) * width + i + n]; pixR = (pixColor>>16)&0xFF; pixG = (pixColor>>8)&0xFF; pixB = (pixColor)&0xFF; value = gauss[idx]; newR = newR + pixR * value; newG = newG + pixG * value; newB = newB + pixB * value; idx++; } } //divide newR /= 16; newG /= 16; newB /= 16; //newR = Math.min(255, Math.max(0, newR)); //newG = Math.min(255, Math.max(0, newG)); //newB = Math.min(255, Math.max(0, newB)); //setColor pixels[j * width + i] = 0xFF000000|(newR<<16)|(newG<<8)|(newB);//Color.argb(255, newR, newG, newB); } } //copy memcpy(image, pixels, width*height); } void clearColorProcess(uint8_t *image, int width, int height, int color) { memset(image, 0xFF, width*height*4); //image[0] = 0; int * pData = (int *)image; int i = 0; int j = 0; for (j = 0; j < height; j++){ for (i = 0; i < width; i++){ pData[j * width + i] = color;//Color.argb(255, newR, newG, newB); } } } void blurH(uint8_t * image, int width, int height, int radius) { int i = 0; int j = 0; uint32_t color; int32_t addR; int32_t addG; int32_t addB; int32_t addA; //copy data uint8_t * pDataSave = NULL; int * pData = (int *)image; int widthMinus1 = 0; int * divTable = NULL; //save length j = 2*radius + 1; divTable = (int *)malloc(256*j*sizeof(int)); if(divTable == NULL){ return; } //clear data memset(divTable, 0, 256*j*sizeof(int)); pDataSave = (uint8_t *)malloc(width*height*sizeof(int)); if(pDataSave == NULL){ return; } //clear data memset(pDataSave, 0, width*height*sizeof(int)); j = 256*(2*radius + 1); //change div int inIndex = 0; widthMinus1 = (2*radius + 1); if(j < (1<<15)){ //GFIXED inIndex = (1<<15)/widthMinus1; //计算灰度均值表 for ( i = 0; i < j; i++ ){ //divide[i] = i/tableSize; divTable[i] = (i*inIndex)>>15; } }else{ for ( i = 0; i < j; i++ ){ divTable[i] = i/widthMinus1; } } //set data widthMinus1 = width - 1; for (j = 0; j < height; j++ ) { int outIndex = j; int Plx = 0; //记录像素的灰度累加值 addR = 0; addG = 0; addB = 0; addA = 0; for ( i = - radius; i <= radius; i++ ) { i = (i < 0)?1:0; i = (i > width - 1)?i:(width - 1); color = pData[inIndex+i]; // Plx += pData[inIndex+i]; addA += ((color&ARGB8888_MASK_ALPHA)>>24); addR += (color&ARGB8888_MASK_RED)>>16; addG += (color&ARGB8888_MASK_GREEN)>>8; addB += (color&ARGB8888_MASK_BLUE); } for ( i = 0; i < width; i++ ) { int i1 = i + radius + 1; if ( i1 > widthMinus1 ){ i1 = widthMinus1; } int i2 = i - radius; if ( i2 < 0 ){ i2 = 0; } int cTail = pData[inIndex+i1]; int cHead = pData[inIndex+i2]; //Plx += (r1 - r2); addA += ((cTail&ARGB8888_MASK_ALPHA)>>24) - ((cHead&ARGB8888_MASK_ALPHA)>>24); addR += ((cTail&ARGB8888_MASK_RED)>>16) - ((cHead&ARGB8888_MASK_RED)>>16); addG += ((cTail&ARGB8888_MASK_GREEN)>>8) - ((cHead&ARGB8888_MASK_GREEN)>>8); addB += (cTail&ARGB8888_MASK_BLUE) - (cHead&ARGB8888_MASK_BLUE); //colorAdd/(radius*1+1) color = ARGB8888_2_COLOR((divTable[addA]), divTable[addR], divTable[addG], divTable[addB]); pDataSave[inIndex + i] = color; } //next line inIndex += width; } memcpy(pData, pDataSave, width*height*sizeof(int)); if(pDataSave != NULL){ free(pDataSave); pDataSave = NULL; } if(divTable != NULL){ free(divTable); divTable = NULL; } } void boxBlurProcess(uint8_t *image, int width, int height, int stride, int radius){ int * divTable = NULL; int * pDataSave; int * pData = (int *)image; int len; int widthMinus1 = (2*radius + 1); //save length len = 2*radius + 1; //LOGI("00"); divTable = (int *)malloc(256*len*sizeof(int)); if(divTable == NULL){ return; } //clear data memset(divTable, 0, 256*len*sizeof(int)); len = 256*(2*radius + 1); //change div int inIndex = 0; int i; //LOGI("0"); /* if(len < (1<<15)){ //GFIXED inIndex = (1<<15)/widthMinus1; //计算灰度均值表 for ( i = 0; i < len; i++ ){ //divide[i] = i/tableSize; divTable[i] = (i*inIndex)>>15; } }else */ { for ( i = 0; i < len; i++ ){ divTable[i] = i/widthMinus1; } } //LOGI("2"); pDataSave = (int *)malloc(width*height*sizeof(int)); if(pDataSave == NULL){ return; } iblurH(pDataSave, pData, divTable, width, height, radius); //LOGI("3"); iblurV(pData, pDataSave, divTable, width, height, radius); //memcpy(pData, pDataSave, width*height*sizeof(int)); //memset(pData, 0xFF, width*height*sizeof(int)); //clearColorProcess((uint8_t *)image, width, height, 0xFFFFFF00); //LOGI("4"); if(divTable != NULL){ free(divTable); divTable = NULL; } if(pDataSave != NULL){ free(pDataSave); pDataSave = NULL; } } static void iblurH(int *pDataSave, int * pData, int *divTable, int width, int height, int radius) { int i = 0; int j = 0; int color; int addR; int addG; int addB; int addA; int R; int G; int B; int A; int widthMinus1 = 0; int lineHead; //set data widthMinus1 = width - 1; lineHead = 0; int x; for (j = 0; j < height; j++ ) { //set zero addA = 0; addR = 0; addG = 0; addB = 0; //add color for ( i = - (radius + 1); i < radius; i++ ) { x = (i < 0)?0:i; x = (x > (width - 1))?(width - 1):x; color = pData[lineHead + x]; // Plx += pData[inIndex+i]; A = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; R = (color&ARGB8888_MASK_RED)>>16&0xFF; G = (color&ARGB8888_MASK_GREEN)>>8&0xFF; B = (color&ARGB8888_MASK_BLUE)&0xFF; addA += A; addR += R; addG += G; addB += B; } for ( i = 0; i < width; i++ ) { x = i + radius; if ( x > widthMinus1 ){ x = widthMinus1; } color = pData[lineHead + x]; A = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; R = (color&ARGB8888_MASK_RED)>>16&0xFF; G = (color&ARGB8888_MASK_GREEN)>>8&0xFF; B = (color&ARGB8888_MASK_BLUE)&0xFF; addA += A; addR += R; addG += G; addB += B; x = i - (radius + 1); if ( x < 0 ){ x = 0; } color = pData[lineHead + x]; A = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; R = (color&ARGB8888_MASK_RED)>>16&0xFF; G = (color&ARGB8888_MASK_GREEN)>>8&0xFF; B = (color&ARGB8888_MASK_BLUE)&0xFF; addA -= A; addR -= R; addG -= G; addB -= B; //div A = divTable[addA];//addA/(radius*2+1); R = divTable[addR];//addR/(radius*2+1); G = divTable[addG];//addG/(radius*2+1); B = divTable[addB];//addB/(radius*2+1); color = ARGB8888_2_COLOR(A,R,G,B);//(((A))<<24) | (((R))<<16) | (((G))<<8)|(B); pDataSave[lineHead + i] = color; } //next line lineHead += width; } } static void iblurV(int *pDataSave, int * pData, int *divTable, int width, int height, int radius) { int i = 0; int j = 0; int color; int addR; int addG; int addB; int addA; int R; int G; int B; int A; int heightMinus1 = 0; int lineHead; //set data heightMinus1 = height - 1; lineHead = 0; int y; char name[100]; for (i = 0; i < width; i++ ) { //set zero addA = 0; addR = 0; addG = 0; addB = 0; //add color for ( j = - (radius + 1); j < radius; j++ ) { y = (j < 0)?0:j; y = (y > (height - 1))?(height - 1):y; color = pData[lineHead + y*width]; // Plx += pData[inIndex+i]; A = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; R = (color&ARGB8888_MASK_RED)>>16&0xFF; G = (color&ARGB8888_MASK_GREEN)>>8&0xFF; B = (color&ARGB8888_MASK_BLUE)&0xFF; addA += A; addR += R; addG += G; addB += B; } for ( j = 0; j < height; j++ ) { y = j + radius; if ( y > heightMinus1 ){ y = heightMinus1; } color = pData[lineHead + y*width]; A = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; R = (color&ARGB8888_MASK_RED)>>16&0xFF; G = (color&ARGB8888_MASK_GREEN)>>8&0xFF; B = (color&ARGB8888_MASK_BLUE)&0xFF; addA += A; addR += R; addG += G; addB += B; y = j - (radius + 1); if ( y < 0 ){ y = 0; } color = pData[lineHead + y*width]; sprintf(name,"offset=%d,w=%d,h=%d,total=%d",lineHead + y*width,width, height,width*height); if(lineHead + y*width<0||lineHead + y*width>=height*width){ //LOGI(name); } A = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; R = (color&ARGB8888_MASK_RED)>>16&0xFF; G = (color&ARGB8888_MASK_GREEN)>>8&0xFF; B = (color&ARGB8888_MASK_BLUE)&0xFF; addA -= A; addR -= R; addG -= G; addB -= B; //div A = divTable[addA];//addA/(radius*2+1); R = divTable[addR];//addR/(radius*2+1); G = divTable[addG];//addG/(radius*2+1); B = divTable[addB];//addB/(radius*2+1); color = ARGB8888_2_COLOR(A,R,G,B);//(((A))<<24) | (((R))<<16) | (((G))<<8)|(B); pDataSave[lineHead + j*width] = color; } //next line lineHead ++; } } ////////////////////////////////////////////////////////////////////////////////////////////// void stackBlurProcess(uint8_t *image, int width, int height, int stride, int radius){ int * pData = (int *)image; int len; //LOGI("2"); //LOGI("3"); iStackBlur(pData, width, height, radius); //LOGI("4"); } int Math_max(int x, int y){ return (x>y)?x:y; } int Math_min(int x, int y){ return (x0)?x:(-x); } static void iStackBlur(int *pData, int width, int height, int radius){ if (radius < 1) { return; } int w = width; int h = height; int* pix = pData; //Log.e("pix", w + " " + h + " " + pix.length); //bitmap.getPixels(pix, 0, w, 0, 0, w, h); int wm = w - 1; int hm = h - 1; int wh = w * h; int div = radius + radius + 1; int *r = (int*)malloc(wh*sizeof(int)); int *g = (int*)malloc(wh*sizeof(int)); int *b = (int*)malloc(wh*sizeof(int)); int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; int * vmin = (int*)malloc(Math_max(w, h)*sizeof(int)); int divsum = (div + 1) >> 1; divsum *= divsum; int *dv = (int*)malloc(256 * divsum*sizeof(int)); for (i = 0; i < 256 * divsum; i++) { dv[i] = (i / divsum); } yw = yi = 0; //int[][] stack = new int[div][3]; int **stack = (int **)malloc(div*sizeof(int*)); for (x = 0; x < div; ++x){ stack[x] = (int *)malloc(3*sizeof(int)); } int stackpointer; int stackstart; int* sir; int rbs; int r1 = radius + 1; int routsum, goutsum, boutsum; int rinsum, ginsum, binsum; //char name[128]; //sprintf(name,"start%d", radius); //LOGI(name); for (y = 0; y < h; y++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; for (i = -radius; i <= radius; i++) { p = pix[yi + Math_min(wm, Math_max(i, 0))]; sir = stack[i + radius]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rbs = r1 - Math_abs(i); rsum += sir[0] * rbs; gsum += sir[1] * rbs; bsum += sir[2] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } } stackpointer = radius; for (x = 0; x < w; x++) { r[yi] = dv[rsum]; g[yi] = dv[gsum]; b[yi] = dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (y == 0) { vmin[x] = Math_min(x + radius + 1, wm); } p = pix[yw + vmin[x]]; sir[0] = (p & 0xff0000) >> 16; sir[1] = (p & 0x00ff00) >> 8; sir[2] = (p & 0x0000ff); rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[(stackpointer) % div]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi++; } yw += w; } //LOGI("Next"); for (x = 0; x < w; x++) { rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; yp = -radius * w; for (i = -radius; i <= radius; i++) { yi = Math_max(0, yp) + x; sir = stack[i + radius]; sir[0] = r[yi]; sir[1] = g[yi]; sir[2] = b[yi]; rbs = r1 - Math_abs(i); rsum += r[yi] * rbs; gsum += g[yi] * rbs; bsum += b[yi] * rbs; if (i > 0) { rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; } else { routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; } if (i < hm) { yp += w; } } yi = x; stackpointer = radius; for (y = 0; y < h; y++) { // Preserve alpha channel: ( 0xff000000 & pix[yi] ) //force to set alpha 255 modified by chao.lc pix[yi] = ( 0xff000000 /*& pix[yi]*/ ) | ( dv[rsum] << 16 ) | ( dv[gsum] << 8 ) | dv[bsum]; rsum -= routsum; gsum -= goutsum; bsum -= boutsum; stackstart = stackpointer - radius + div; sir = stack[stackstart % div]; routsum -= sir[0]; goutsum -= sir[1]; boutsum -= sir[2]; if (x == 0) { vmin[y] = Math_min(y + r1, hm) * w; } p = x + vmin[y]; sir[0] = r[p]; sir[1] = g[p]; sir[2] = b[p]; rinsum += sir[0]; ginsum += sir[1]; binsum += sir[2]; rsum += rinsum; gsum += ginsum; bsum += binsum; stackpointer = (stackpointer + 1) % div; sir = stack[stackpointer]; routsum += sir[0]; goutsum += sir[1]; boutsum += sir[2]; rinsum -= sir[0]; ginsum -= sir[1]; binsum -= sir[2]; yi += w; } } if(vmin != NULL){ free(vmin); vmin = NULL; } if(dv != NULL){ free(dv); dv = NULL; } for (x = 0; x < div; ++x){ if(stack[x] != NULL){ free(stack[x]); stack[x] = NULL; } } if(stack != NULL){ free( stack ); } if(r!=NULL){ free(r); r = NULL; } if(g != NULL){ free(g); g = NULL; } if(b != NULL){ free(b); b = NULL; } } static int iOilPaint( int * pDstData, int * pSrcData, int width, int height, int radius) { int dx; int dy; int i = 0; int j = 0; int r = 0; int g = 0; int b = 0; int rTemp = 0; int gTemp = 0; int bTemp = 0; int rIndex = 0; int gIndex = 0; int bIndex = 0; int histo[256+256+256]; int * histoR = histo; int * histoG = histo + 256; int * histoB = histo + 256 + 256; int color; int N = 2; int offset = width - (2*N+1); int * pSrcTempData; if( 2*N+1 > width || 2*N + 1 > height ) { return -1; } //copy pix memcpy( pDstData, pSrcData, sizeof(int)*width*height); int *pDstTempData = pDstData + N*width; for( j = N; j < height - N; j++ ) { for( i = 0; i < width; i++ ) { pSrcTempData = pSrcData; memset( histo, 0, sizeof( int )*768 );// rTemp = 0; gTemp = 0; bTemp = 0; for( dy = - N; dy <= N; dy++ ) { for( dx = - N; dx <= N; dx++) { //color = *(pSrcImage->p + dx + dy*pSrcImage->w); color = *pSrcTempData; //r = (color&0xF800)>>11; //g = (color&0x7E0)>>5; //b = (color&0x1F); //a = ((color&ARGB8888_MASK_ALPHA)>>24)&0xFF; r = (color&ARGB8888_MASK_RED)>>16&0xFF; g = (color&ARGB8888_MASK_GREEN)>>8&0xFF; b = (color&ARGB8888_MASK_BLUE)&0xFF; histoR[r]++; histoG[g]++; histoB[b]++; if ( histoR[r] > rTemp ) { rTemp = histoR[r]; rIndex = r; } if ( histoG[g] > gTemp ) { gTemp = histoG[g]; gIndex = g; } if ( histoB[b] > bTemp ) { bTemp = histoB[b]; bIndex = b; } pSrcTempData++; } pSrcTempData += offset; } *(pDstTempData++) = ARGB8888_2_COLOR(255,rIndex,gIndex,bIndex);//(rIndex<<11) | (gIndex<<5) | (bIndex); pSrcData++; } } return 0; } void oilPaintProcess(uint8_t *image, int width, int height, int stride, int radius){ //LOGI("2"); int *pDataSave = (int *)malloc(width*height*sizeof(int)); if(pDataSave == NULL){ return; } iOilPaint(pDataSave, (int *)image, width, height, radius); memcpy( image, pDataSave, sizeof(int)*width*height); //LOGI("4"); if(pDataSave != NULL){ free(pDataSave); pDataSave = NULL; } } //////////////////// static int iPartions(uint8_t a[],int low,int high) { int pivotkey=a[low]; a[0]=a[low]; while(low=pivotkey) --high; a[low]=a[high]; while(low>16&0xFF; g[m] = (color&ARGB8888_MASK_GREEN)>>8&0xFF; b[m] = (color&ARGB8888_MASK_BLUE)&0xFF; pSrcDataTemp++; m++; } pSrcDataTemp += offset; } /* //Sort( r, SortArray, num2 ); qsort( r, num2 ); rColor = SortArray[num22]; qsort( g, num2 ); //Sort( g, SortArray, num2 ); gColor = SortArray[num22]; //Sort( b, SortArray, num2 ); qsort( b, num2 ); bColor = SortArray[num22]; */ iQuickSort( r, num2 ); rColor = r[num22]; iQuickSort( g, num2 ); gColor = g[num22]; iQuickSort( b, num2 ); bColor = b[num22]; *pDstData = ARGB8888_2_COLOR( 255, rColor, gColor, bColor ); pDstData++; pSrcData++; //LOGI("SSSS"); } } //LOGI("SSSS ssussusuu"); return; } static void iColorWaterFilter( int * pDstImage, int * pSrcImage, int width, int height ) { int i = 0; int j = 0; int rColor; int gColor; int bColor; int color; int * pDesData = pDstImage; int * pSrcData = pSrcImage; int * pSrcDataTemp = pSrcData; //int colorAdd; //int colorSub; int colorSubLow; int colorSubHigh; int colorAddLow; int colorAddHigh; // filterCoef[0]=0; filterCoef[1]=-(1<<15); filterCoef[2]=0; // filterCoef[3]=-(1<<15); filterCoef[4]=5<<15; filterCoef[5]=-(1<<15); // filterCoef[6]=0; filterCoef[7]=-(1<<15); filterCoef[8]=0; memcpy( pDesData, pSrcData, sizeof(int)*width*height ); pDesData += width; char name[128]; for ( j = 1; j < height - 1; j++ ) { for ( i = 0; i < width; i++ ) { // pSrcDataTemp = pSrcData; color = *(pSrcDataTemp+1); //colorSub = (( color | (color << 16) ) & 0x07E0F81F); colorSubLow = color&0x00FF00FF; colorSubHigh = (color&0xFF00FF00)>>8; pSrcDataTemp += width; color = *(pSrcDataTemp); //colorSub += (( color | (color << 16) ) & 0x07E0F81F); colorSubLow += color&0x00FF00FF; colorSubHigh += (color&0xFF00FF00)>>8; //x5 color = *(pSrcDataTemp+1); //colorAdd = (( color | (color << 16) ) & 0x07E0F81F); //colorAdd = (colorAdd<<2) + colorAdd; //sprintf(name, "color =%x",color); //LOGI(name); colorAddLow = ((color&0x00FF00FF)<<2) + (color&0x00FF00FF); colorAddHigh = (((color&0xFF00FF00)>>8)<<2) + ((color&0xFF00FF00)>>8); //sprintf(name, "spit:%x,%x",colorAddLow,colorAddHigh); //LOGI(name); //colorAddLow = ((color&0x00FF00FF))*5; //colorAddHigh = (((color>>8)&0x00FF00FF))*5; color = *(pSrcDataTemp+2); //colorSub += (( color | (color << 16) ) & 0x07E0F81F); colorSubLow += color&0x00FF00FF; colorSubHigh += (color&0xFF00FF00)>>8; pSrcDataTemp += width; color = *(pSrcDataTemp+1); //colorSub += (( color | (color << 16) ) & 0x07E0F81F); colorSubLow += color&0x00FF00FF; colorSubHigh += (color&0xFF00FF00)>>8; rColor = ((colorAddLow)>>16); gColor = (colorAddHigh&0xFFFF); bColor = (colorAddLow&0xFFFF); //sprintf(name, "rcolor =%x,%x,%x",rColor,gColor,bColor); //LOGI(name); rColor -= (colorSubLow>>16); gColor -= (colorSubHigh&0xFFFF); bColor -= (colorSubLow)&0xFFFF; if ( rColor > 255 ) { rColor = 255; } else if ( rColor < 0 ) { rColor = 0; } if ( gColor > 255 ) { gColor = 255; } else if ( gColor < 0 ) { gColor = 0; } if ( bColor > 255 ) { bColor = 255; } else if ( bColor < 0 ) { bColor = 0; } color = ARGB8888_2_COLOR(255, rColor, gColor, bColor);//*(pSrcDataTemp+1);//ARGB8888_2_COLOR(255, rColor, gColor, bColor);//ARGB8888_2_COLOR(255, rColor, gColor, bColor ); //sprintf(name, "last color =%x",color); //LOGI(name); *pDesData = color; pDesData++; pSrcData++; } } return; } void colorWaterPaint( int * pSrcImage, int width, int height, int stride, int radius ){ // //LOGI("start colorWaterPaint mmmmm"); int *pDstData = (int *)malloc( sizeof(int)*width*height ); if ( pDstData == NULL ) { return; } imMedian( pDstData, pSrcImage, width, height, radius ); //memcpy(pSrcImage,pDstData,sizeof(int)*width*height); //CommonFilter( &DesImageCpy, pDesImage, 3, filterCoef ); iColorWaterFilter( pSrcImage, pDstData, width, height ); if ( pDstData != NULL ){ free( pDstData ); pDstData = 0; } } ================================================ FILE: WayHoo/jni/imageProcess.h ================================================ #ifndef _IMAGE_PROCESS_H_ #define _IMAGE_PROCESS_H_ void gaussBlurProcess( uint8_t *colorImg, int width, int height ); void clearColorProcess(uint8_t *image, int width, int height, int color); void boxBlurProcess(uint8_t *image, int width, int height, int stride, int radius); void stackBlurProcess(uint8_t *image, int width, int height, int stride, int radius); void oilPaintProcess(uint8_t *image, int width, int height, int stride, int radius); void colorWaterPaint( int * pSrcImage, int width, int heiht, int stride, int radius ); #endif ================================================ FILE: WayHoo/proguard-project.txt ================================================ # To enable ProGuard in your project, edit project.properties # to define the proguard.config property as described in that file. # # Add project specific ProGuard rules here. # By default, the flags in this file are appended to flags specified # in ${sdk.dir}/tools/proguard/proguard-android.txt # You can edit the include path and order by changing the ProGuard # include property in project.properties. # # For more details, see # http://developer.android.com/guide/developing/tools/proguard.html # Add any project specific keep options here: # If your project uses WebView with JS, uncomment the following # and specify the fully qualified class name to the JavaScript interface # class: #-keepclassmembers class fqcn.of.javascript.interface.for.webview { # public *; #} ================================================ FILE: WayHoo/project.properties ================================================ # This file is automatically generated by Android Tools. # Do not modify this file -- YOUR CHANGES WILL BE ERASED! # # This file must be checked in Version Control Systems. # # To customize properties used by the Ant build system edit # "ant.properties", and override values to adapt the script to your # project structure. # # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt # Project target. target=android-21 ================================================ FILE: WayHoo/res/anim/count_down_exit.xml ================================================ ================================================ FILE: WayHoo/res/anim/fade_out.xml ================================================ ================================================ FILE: WayHoo/res/anim/in_from_bottom.xml ================================================ ================================================ FILE: WayHoo/res/anim/in_from_top.xml ================================================ ================================================ FILE: WayHoo/res/anim/out_from_bottom.xml ================================================ ================================================ FILE: WayHoo/res/anim/out_from_top.xml ================================================ ================================================ FILE: WayHoo/res/anim/push_right_out.xml ================================================ ================================================ FILE: WayHoo/res/anim/slide_in_from_bottom.xml ================================================ ================================================ FILE: WayHoo/res/anim/slide_in_from_top.xml ================================================ ================================================ FILE: WayHoo/res/anim/slide_out_to_bottom.xml ================================================ ================================================ FILE: WayHoo/res/anim/slide_out_to_top.xml ================================================ ================================================ FILE: WayHoo/res/color/vpi__dark_theme.xml ================================================ ================================================ FILE: WayHoo/res/color/vpi__light_theme.xml ================================================ ================================================ FILE: WayHoo/res/drawable/city_edit_prs.xml ================================================ ================================================ FILE: WayHoo/res/drawable/city_query_delete.xml ================================================ ================================================ FILE: WayHoo/res/drawable/cityselector_locate_btn_bg.xml ================================================ ================================================ FILE: WayHoo/res/drawable/home_setting_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/indicator_bg_bottom.xml ================================================ ================================================ FILE: WayHoo/res/drawable/indicator_bg_top.xml ================================================ ================================================ FILE: WayHoo/res/drawable/item_background.xml ================================================ ================================================ FILE: WayHoo/res/drawable/item_prs.xml ================================================ ================================================ FILE: WayHoo/res/drawable/listview_background.xml ================================================ ================================================ FILE: WayHoo/res/drawable/main_city_name_bg.xml ================================================ ================================================ FILE: WayHoo/res/drawable/main_life_complete_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/main_life_edit.xml ================================================ ================================================ FILE: WayHoo/res/drawable/module_bg.xml ================================================ ================================================ FILE: WayHoo/res/drawable/refresh_icon_anim.xml ================================================ ================================================ FILE: WayHoo/res/drawable/resource_circle_progressbar_indeterminate.xml ================================================ ================================================ FILE: WayHoo/res/drawable/setting_top_back.xml ================================================ ================================================ FILE: WayHoo/res/drawable/settings_bg_city_item_down.xml ================================================ ================================================ FILE: WayHoo/res/drawable/settings_bg_city_item_up.xml ================================================ ================================================ FILE: WayHoo/res/drawable/shape_bg.xml ================================================ ================================================ FILE: WayHoo/res/drawable/sidebar_item_background_dark_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/sidebar_item_background_light_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/sidebar_item_selected_layerlist_dark.xml ================================================ ================================================ FILE: WayHoo/res/drawable/slidingmenu_shadow.xml ================================================ ================================================ FILE: WayHoo/res/drawable/topbar_icon_share_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/topbar_icon_side_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/update_forecast_selector.xml ================================================ ================================================ FILE: WayHoo/res/drawable/vpi__tab_indicator.xml ================================================ ================================================ FILE: WayHoo/res/drawable/weather_detail_activity_btn_bg.xml ================================================ ================================================ FILE: WayHoo/res/drawable/white_border.xml ================================================ ================================================ FILE: WayHoo/res/layout/about.xml ================================================ ================================================ FILE: WayHoo/res/layout/activity_main.xml ================================================