├── README.md
├── app
├── andfix.jks
├── build.gradle
├── libs
│ ├── jpush-android-2.1.0.jar
│ └── umeng-onlineconfig_v1.0.0.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── zhw
│ │ └── andfix
│ │ └── ApplicationTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── java
│ │ └── com
│ │ │ └── zhw
│ │ │ └── andfix
│ │ │ ├── BaseApplication.java
│ │ │ ├── MainActivity.java
│ │ │ ├── MyReceiver.java
│ │ │ ├── TestActivity.java
│ │ │ ├── consts
│ │ │ └── SPConst.java
│ │ │ ├── model
│ │ │ └── PatchBean.java
│ │ │ └── util
│ │ │ ├── GsonUtils.java
│ │ │ ├── LocalPreferencesHelper.java
│ │ │ ├── RepairBugUtil.java
│ │ │ └── WeakHandler.java
│ ├── jniLibs
│ │ ├── arm64-v8a
│ │ │ ├── libandfix.so
│ │ │ └── libjpush210.so
│ │ ├── armeabi-v7a
│ │ │ ├── libandfix.so
│ │ │ └── libjpush210.so
│ │ ├── armeabi
│ │ │ └── libjpush210.so
│ │ ├── mips
│ │ │ ├── libandfix.so
│ │ │ └── libjpush210.so
│ │ ├── mips64
│ │ │ ├── libandfix.so
│ │ │ └── libjpush210.so
│ │ ├── x86
│ │ │ └── libjpush210.so
│ │ └── x86_64
│ │ │ ├── libandfix.so
│ │ │ └── libjpush210.so
│ └── res
│ │ ├── drawable-hdpi
│ │ ├── border_bg.9.png
│ │ ├── bottom_bg.9.png
│ │ ├── corners_bg.xml
│ │ ├── ic_launcher.png
│ │ ├── ic_richpush_actionbar_back.png
│ │ ├── ic_richpush_actionbar_divider.png
│ │ ├── jpush_notification_icon.png
│ │ ├── richpush_btn_selector.xml
│ │ ├── stripes.png
│ │ ├── tiledstripes.xml
│ │ └── top_bg.9.png
│ │ ├── drawable-ldpi
│ │ └── ic_launcher.png
│ │ ├── drawable-mdpi
│ │ └── ic_launcher.png
│ │ ├── drawable-xhdpi
│ │ └── ic_launcher.png
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ ├── activity_test.xml
│ │ ├── customer_notitfication_layout.xml
│ │ ├── customer_notitfication_layout_one.xml
│ │ ├── jpush_popwin_layout.xml
│ │ ├── jpush_webview_layout.xml
│ │ ├── main.xml
│ │ ├── push_set_dialog.xml
│ │ └── set_push_time.xml
│ │ ├── mipmap-hdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ └── ic_launcher.png
│ │ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ │ ├── values-w820dp
│ │ └── dimens.xml
│ │ ├── values-zh
│ │ ├── strings.xml
│ │ └── style.xml
│ │ └── values
│ │ ├── colors.xml
│ │ ├── dimens.xml
│ │ ├── jpush_style.xml
│ │ ├── strings.xml
│ │ ├── style.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── zhw
│ └── andfix
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
└── settings.gradle
/README.md:
--------------------------------------------------------------------------------
1 | # AndFix-Bad-Practices
2 | AndFix应用到项目的一个小栗子。个人技术水平只能写写这些没有技术的Demo了,请大家不要吐槽~
3 |
4 | # How To Work
5 | 1. 应用启动的时候,在 onCreate() 方法中获取友盟的在线参数来判断当前的应用版本是否有补丁需要下载,有则通过ThinDonloadManager来下载到SD下并且通过使用AndFix来加载到应用中。
6 | 2. 使用极光推送消息到该应用的版本需要下载补丁,如果应用收到了消息后,应用判断当前的版本是否需要下载补丁。如果应用没有收到消息的通知,则下次启动App的时候,获取友盟在线参数来判断是否需要下载补丁。
7 |
8 | # Part Code
9 |
10 | 通过ThinDownloadManager下载补丁包,下载成功后使用AndFix加载补丁包的方法:
11 |
12 | public void downloadAndLoad(Context context, final PatchBean bean, String downloadUrl) {
13 | if (mLocalPreferencesHelper == null) {
14 | mLocalPreferencesHelper = new LocalPreferencesHelper(context, SPConst.SP_NAME);
15 | }
16 | Uri downloadUri = Uri.parse(downloadUrl);
17 | Uri destinationUri = Uri.parse(Environment.getExternalStorageDirectory()
18 | .getAbsolutePath() + bean.url);
19 | DownloadRequest downloadRequest = new DownloadRequest(downloadUri)
20 | .setDestinationURI(destinationUri)
21 | .setPriority(DownloadRequest.Priority.HIGH)
22 | .setDownloadListener(new DownloadStatusListener() {
23 | @Override
24 | public void onDownloadComplete(int id) {
25 | // add patch at runtime
26 | try {
27 | // .apatch file path
28 | String patchFileString = Environment.getExternalStorageDirectory()
29 | .getAbsolutePath() + bean.url;
30 | BaseApplication.mPatchManager.addPatch(patchFileString);
31 | Log.d(TAG, "apatch:" + patchFileString + " added.");
32 |
33 | //复制且加载补丁成功后,删除下载的补丁
34 | File f = new File(patchFileString);
35 | if (f.exists()) {
36 | boolean result = new File(patchFileString).delete();
37 | if (!result)
38 | Log.e(TAG, patchFileString + " delete fail");
39 | }
40 | // mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
41 | } catch (IOException e) {
42 | Log.e(TAG, "", e);
43 | } catch (Throwable throwable) {
44 |
45 | }
46 | }
47 |
48 | @Override
49 | public void onDownloadFailed(int id, int errorCode, String errorMessage) {
50 | //下载失败的时候,标注标记位,等下次重新打开应用的时候重新下载
51 | // mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, true);
52 | Log.e(TAG, "onDownloadFailed");
53 |
54 | }
55 |
56 | @Override
57 | public void onProgress(int id, long totalBytes, int progress) {
58 | Log.e(TAG, "progress:" + progress);
59 | }
60 | });
61 | mDownloadManager = new ThinDownloadManager(THREAD_COUNT);
62 | mDownloadManager.add(downloadRequest);
63 | }
64 |
65 | 判断是否有补丁包需要下载的方法:
66 |
67 | public void comparePath(Context context, PatchBean RemoteBean) throws Exception {
68 | String pathInfo = mLocalPreferencesHelper.getString(SPConst.PATH_INFO);
69 | final PatchBean localBean = GsonUtils.getInstance().parseIfNull(PatchBean.class, pathInfo);
70 | //远程的应用版本跟当前应用的版本比较
71 | if (BaseApplication.VERSION_NAME.equals(RemoteBean.app_v)) {
72 | //远程的应用版本跟本地保存的应用版本一样,但补丁不一样,则需要下载重新
73 | /**
74 | *第一种情况:当本地记录的Bean为空的时候(刚安装的时候可能为空)并且远程的Bean的path_v不为空的时候需要下载补丁。
75 | * 第二种情况:当本地记录的path_v和远程Bean的path_v不一样的时候需要下载补丁。
76 | */
77 | if (localBean == null && !TextUtils.isEmpty(RemoteBean.path_v)
78 | || localBean.app_v.equals(RemoteBean.app_v) &&
79 | !localBean.path_v.equals(RemoteBean.path_v)) {
80 | downloadAndLoad(context, RemoteBean,
81 | SPConst.URL_PREFIX + RemoteBean.url);
82 | String json = GsonUtils.getInstance().parse(RemoteBean);
83 | mLocalPreferencesHelper.saveOrUpdate(SPConst.PATH_INFO, json);
84 | } /*else {
85 | mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
86 | }*/
87 | }
88 | }
89 |
90 | # Platform Config
91 | * 友盟在线参数
92 | 
93 |
94 | * 极光推送自定义消息
95 | 
96 |
97 |
98 | # Note
99 | - 如果你在使用AndFix的时候遇到关于so问题的报错,可以看一下这个的,希望它能帮助你解决问题。
100 | [https://github.com/zhonghanwen/AndFix-Ndk-Build-ADT](https://github.com/zhonghanwen/AndFix-Ndk-Build-ADT)
101 |
102 | # Thanks
103 | * [AndFix](https://github.com/alibaba/AndFix)
104 | * [ThinDownloadManager](https://github.com/smanikandan14/ThinDownloadManager)
105 | * JPush
106 | * Umeng
107 |
108 | # License
109 |
110 | Copyright 2016 zhonghanwen
111 |
112 | Licensed under the Apache License, Version 2.0 (the "License");
113 | you may not use this file except in compliance with the License.
114 | You may obtain a copy of the License at
115 |
116 | http://www.apache.org/licenses/LICENSE-2.0
117 |
118 | Unless required by applicable law or agreed to in writing, software
119 | distributed under the License is distributed on an "AS IS" BASIS,
120 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121 | See the License for the specific language governing permissions and
122 | limitations under the License.
--------------------------------------------------------------------------------
/app/andfix.jks:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/andfix.jks
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.1"
6 |
7 | defaultConfig {
8 | applicationId "com.zhw.andfix"
9 | minSdkVersion 15
10 | targetSdkVersion 23
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 |
15 | //签名
16 | signingConfigs {
17 | debug {
18 | storeFile file(ANDROID_STORE_FILE)
19 | storePassword ANDROID_STORE_PASS
20 | keyAlias ANDROID_KEY_ALIAS
21 | keyPassword ANDROID_KEY_PASS
22 | }
23 |
24 | release {
25 | storeFile file(ANDROID_STORE_FILE)
26 | storePassword ANDROID_STORE_PASS
27 | keyAlias ANDROID_KEY_ALIAS
28 | keyPassword ANDROID_KEY_PASS
29 | }
30 | }
31 |
32 | buildTypes {
33 | release {
34 | minifyEnabled false
35 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
36 | signingConfig signingConfigs.debug
37 | }
38 | }
39 | }
40 |
41 | dependencies {
42 | compile fileTree(include: ['*.jar'], dir: 'libs')
43 | testCompile 'junit:junit:4.12'
44 | compile 'com.android.support:appcompat-v7:23.2.0'
45 | compile 'com.android.support:support-v4:23.0.1'
46 | //下载器相关
47 | compile 'com.mani:thindownloadmanager:1.0.0'
48 | compile 'com.alipay.euler:andfix:0.3.1@aar'
49 | compile 'com.google.code.gson:gson:+'
50 | compile files('libs/jpush-android-2.1.0.jar')
51 | compile files('libs/umeng-onlineconfig_v1.0.0.jar')
52 | }
53 |
--------------------------------------------------------------------------------
/app/libs/jpush-android-2.1.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/libs/jpush-android-2.1.0.jar
--------------------------------------------------------------------------------
/app/libs/umeng-onlineconfig_v1.0.0.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/libs/umeng-onlineconfig_v1.0.0.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in C:\Program Files\Android\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/zhw/andfix/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
39 |
40 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
59 |
60 |
61 |
62 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
78 |
79 |
80 |
81 |
82 |
83 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
143 |
144 |
145 |
146 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/BaseApplication.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix;
2 |
3 | import android.app.Application;
4 | import android.content.pm.PackageInfo;
5 | import android.content.pm.PackageManager;
6 | import android.util.Log;
7 |
8 | import com.alipay.euler.andfix.patch.PatchManager;
9 |
10 | import cn.jpush.android.api.JPushInterface;
11 |
12 | /**
13 | * Created by zhonghw on 2016/3/10.
14 | */
15 | public class BaseApplication extends Application {
16 |
17 | private static final String TAG = "AndFix";
18 | public static String VERSION_NAME = "";
19 | public static PatchManager mPatchManager;
20 |
21 | @Override
22 | public void onCreate() {
23 | super.onCreate();
24 | try {
25 | PackageInfo mPackageInfo = this.getPackageManager().getPackageInfo(
26 | this.getPackageName(), 0);
27 | VERSION_NAME = mPackageInfo.versionName;
28 | } catch (PackageManager.NameNotFoundException e) {
29 | e.printStackTrace();
30 | }
31 | JPushInterface.init(this);
32 | initAndFix();
33 | }
34 |
35 |
36 | private void initAndFix() {
37 | // initialize
38 |
39 | mPatchManager = new PatchManager(this);
40 | mPatchManager.init(VERSION_NAME);
41 | Log.d(TAG, "inited.");
42 |
43 | // load patch
44 | mPatchManager.loadPatch();
45 | // Log.d(TAG, "apatch loaded.");
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix;
2 |
3 | import android.app.Activity;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.os.Bundle;
9 | import android.os.Handler;
10 | import android.os.Message;
11 | import android.text.TextUtils;
12 | import android.view.View;
13 |
14 | import com.umeng.onlineconfig.OnlineConfigAgent;
15 | import com.zhw.andfix.model.PatchBean;
16 | import com.zhw.andfix.util.GsonUtils;
17 | import com.zhw.andfix.util.RepairBugUtil;
18 | import com.zhw.andfix.util.WeakHandler;
19 |
20 |
21 | public class MainActivity extends Activity {
22 |
23 | public static final int MSG_WHAT_DOWNLOAD = 0x111;
24 | public static final String UMENG_ONLINE_PARAM = "pathInfo"; //友盟后台定义的参数名称
25 |
26 |
27 | @Override
28 | protected void onCreate(Bundle savedInstanceState) {
29 | super.onCreate(savedInstanceState);
30 | setContentView(R.layout.activity_main);
31 | registerMessageReceiver(); // used for receive msg
32 | initUmeng(); //初始化友盟在线参数
33 | /*boolean haveDownload = mLocalPreferencesHelper.getBooleanDefaultFalse(
34 | getString(R.string.spp_app_have_download));
35 | if (haveDownload){
36 | RepairBugUtil.getInstance().fixBug(this);
37 | }*/
38 |
39 | getUmengParamAndFix();
40 |
41 | }
42 |
43 | private void getUmengParamAndFix() {
44 | //获取友盟在线参数对应key的values
45 | String pathInfo = OnlineConfigAgent.getInstance().getConfigParams(this, UMENG_ONLINE_PARAM);
46 | if (!TextUtils.isEmpty(pathInfo)){
47 | PatchBean onLineBean = GsonUtils.getInstance().parseIfNull(PatchBean.class , pathInfo);
48 | try {
49 | //进行判断当前版本是否有补丁需要下载更新
50 | RepairBugUtil.getInstance().comparePath(this, onLineBean);
51 | } catch (Exception e) {
52 | e.printStackTrace();
53 | }
54 | }
55 | }
56 |
57 | /**
58 | * 友盟在线的初始化工作
59 | */
60 | private void initUmeng() {
61 | OnlineConfigAgent.getInstance().updateOnlineConfig(this);
62 | OnlineConfigAgent.getInstance().setDebugMode(true); //设置在线参数的调试模式
63 | }
64 |
65 |
66 | public void onClick(View view) {
67 | TestActivity.launch(this);
68 | }
69 |
70 |
71 | @Override
72 | protected void onDestroy() {
73 | unregisterReceiver(mMessageReceiver);
74 | RepairBugUtil.getInstance().release();
75 | super.onDestroy();
76 | }
77 |
78 |
79 |
80 | private WeakHandler mHandler = new WeakHandler(new Handler.Callback() {
81 | @Override
82 | public boolean handleMessage(Message msg) {
83 | if (msg.what == MSG_WHAT_DOWNLOAD){
84 | String message = (String) msg.obj;
85 | if (TextUtils.isEmpty(message)) return false;
86 | try {
87 | PatchBean bean = GsonUtils.getInstance().parse(PatchBean.class, message);
88 | RepairBugUtil.getInstance().comparePath(MainActivity.this, bean);
89 | } catch (Exception e) {
90 | e.printStackTrace();
91 | }
92 | }
93 | return false;
94 | }
95 | });
96 |
97 |
98 |
99 | //for receive customer msg from jpush server
100 | private MessageReceiver mMessageReceiver;
101 | public static final String MESSAGE_RECEIVED_ACTION = "com.zhw.andfix.MESSAGE_RECEIVED_ACTION";
102 | public static final String KEY_MESSAGE = "message";
103 |
104 | public void registerMessageReceiver() {
105 | mMessageReceiver = new MessageReceiver();
106 | IntentFilter filter = new IntentFilter();
107 | filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
108 | filter.addAction(MESSAGE_RECEIVED_ACTION);
109 | registerReceiver(mMessageReceiver, filter);
110 | }
111 |
112 | public class MessageReceiver extends BroadcastReceiver {
113 |
114 | @Override
115 | public void onReceive(Context context, Intent intent) {
116 | if (MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {
117 | String message = intent.getStringExtra(KEY_MESSAGE);
118 | Message msg = new Message();
119 | msg.what = MSG_WHAT_DOWNLOAD;
120 | msg.obj = message;
121 | mHandler.sendMessage(msg);
122 | }
123 | }
124 | }
125 |
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/MyReceiver.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.os.Bundle;
7 | import android.speech.tts.TextToSpeech;
8 | import android.text.TextUtils;
9 | import android.util.Log;
10 |
11 | import com.google.gson.reflect.TypeToken;
12 | import com.zhw.andfix.consts.SPConst;
13 | import com.zhw.andfix.model.PatchBean;
14 | import com.zhw.andfix.util.GsonUtils;
15 | import com.zhw.andfix.util.LocalPreferencesHelper;
16 | import com.zhw.andfix.util.RepairBugUtil;
17 |
18 | import org.json.JSONException;
19 | import org.json.JSONObject;
20 |
21 | import java.util.Iterator;
22 |
23 | import cn.jpush.android.api.JPushInterface;
24 |
25 | /**
26 | * 自定义接收器
27 | *
28 | * 如果不定义这个 Receiver,则:
29 | * 1) 默认用户会打开主界面
30 | * 2) 接收不到自定义消息
31 | */
32 | public class MyReceiver extends BroadcastReceiver {
33 | private static final String TAG = "JPush";
34 | private LocalPreferencesHelper mLocalPreferencesHelper;
35 |
36 | @Override
37 | public void onReceive(Context context, Intent intent) {
38 | Bundle bundle = intent.getExtras();
39 | Log.d(TAG, "[MyReceiver] onReceive - " + intent.getAction() + ", extras: " + printBundle(bundle));
40 |
41 | if (JPushInterface.ACTION_REGISTRATION_ID.equals(intent.getAction())) {
42 | String regId = bundle.getString(JPushInterface.EXTRA_REGISTRATION_ID);
43 | Log.d(TAG, "[MyReceiver] 接收Registration Id : " + regId);
44 | //send the Registration Id to your server...
45 |
46 | } else if (JPushInterface.ACTION_MESSAGE_RECEIVED.equals(intent.getAction())) {
47 | Log.d(TAG, "[MyReceiver] 接收到推送下来的自定义消息: " + bundle.getString(JPushInterface.EXTRA_MESSAGE));
48 | processCustomMessage(context, bundle);
49 |
50 | } else if (JPushInterface.ACTION_NOTIFICATION_RECEIVED.equals(intent.getAction())) {
51 | Log.d(TAG, "[MyReceiver] 接收到推送下来的通知");
52 | int notifactionId = bundle.getInt(JPushInterface.EXTRA_NOTIFICATION_ID);
53 | Log.d(TAG, "[MyReceiver] 接收到推送下来的通知的ID: " + notifactionId);
54 |
55 | } else if (JPushInterface.ACTION_NOTIFICATION_OPENED.equals(intent.getAction())) {
56 | /* Log.d(TAG, "[MyReceiver] 用户点击打开了通知");
57 |
58 | //打开自定义的Activity
59 | Intent i = new Intent(context, TestActivity.class);
60 | i.putExtras(bundle);
61 | //i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
62 | i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP );
63 | context.startActivity(i);*/
64 |
65 | } else if (JPushInterface.ACTION_RICHPUSH_CALLBACK.equals(intent.getAction())) {
66 | Log.d(TAG, "[MyReceiver] 用户收到到RICH PUSH CALLBACK: " + bundle.getString(JPushInterface.EXTRA_EXTRA));
67 | //在这里根据 JPushInterface.EXTRA_EXTRA 的内容处理代码,比如打开新的Activity, 打开一个网页等..
68 |
69 | } else if(JPushInterface.ACTION_CONNECTION_CHANGE.equals(intent.getAction())) {
70 | boolean connected = intent.getBooleanExtra(JPushInterface.EXTRA_CONNECTION_CHANGE, false);
71 | Log.w(TAG, "[MyReceiver]" + intent.getAction() +" connected state change to "+connected);
72 | } else {
73 | Log.d(TAG, "[MyReceiver] Unhandled intent - " + intent.getAction());
74 | }
75 | }
76 |
77 | // 打印所有的 intent extra 数据
78 | private static String printBundle(Bundle bundle) {
79 | StringBuilder sb = new StringBuilder();
80 | for (String key : bundle.keySet()) {
81 | if (key.equals(JPushInterface.EXTRA_NOTIFICATION_ID)) {
82 | sb.append("\nkey:" + key + ", value:" + bundle.getInt(key));
83 | }else if(key.equals(JPushInterface.EXTRA_CONNECTION_CHANGE)){
84 | sb.append("\nkey:" + key + ", value:" + bundle.getBoolean(key));
85 | } else if (key.equals(JPushInterface.EXTRA_EXTRA)) {
86 | if (bundle.getString(JPushInterface.EXTRA_EXTRA).isEmpty()) {
87 | Log.i(TAG, "This message has no Extra data");
88 | continue;
89 | }
90 |
91 | try {
92 | JSONObject json = new JSONObject(bundle.getString(JPushInterface.EXTRA_EXTRA));
93 | Iterator it = json.keys();
94 |
95 | while (it.hasNext()) {
96 | String myKey = it.next().toString();
97 | sb.append("\nkey:" + key + ", value: [" +
98 | myKey + " - " +json.optString(myKey) + "]");
99 | }
100 | } catch (JSONException e) {
101 | Log.e(TAG, "Get message extra JSON error!");
102 | }
103 |
104 | } else {
105 | sb.append("\nkey:" + key + ", value:" + bundle.getString(key));
106 | }
107 | }
108 | return sb.toString();
109 | }
110 |
111 | //send msg to MainActivity
112 | /*
113 | private void processCustomMessage(Context context, Bundle bundle) {
114 | if (mLocalPreferencesHelper == null) {
115 | mLocalPreferencesHelper = new LocalPreferencesHelper(context, SPConst.SP_NAME);
116 | }
117 | String pathInfo = mLocalPreferencesHelper.getString(SPConst.PATH_INFO);
118 | final PatchBean localBean = GsonUtils.getInstance().parseIfNull(PatchBean.class , pathInfo);
119 | String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
120 | if (TextUtils.isEmpty(message)) return;
121 | try {
122 | PatchBean bean = GsonUtils.getInstance().parse(PatchBean.class, message);
123 | if (BaseApplication.VERSION_NAME.equals(bean.app_v)){ //远程的应用版本跟当前应用的版本比较
124 | if (localBean == null && !TextUtils.isEmpty(bean.path_v)
125 | || localBean.app_v.equals(bean.app_v) &&
126 | ! localBean.path_v.equals(bean.path_v)){ //远程的应用版本跟本地保存的应用版本一样,但补丁不一样,则需要下载重新
127 | RepairBugUtil.getInstance().downloadAndLoad(context, bean, SPConst.URL_PREFIX + bean.url);
128 | String json = GsonUtils.getInstance().parse(bean);
129 | mLocalPreferencesHelper.saveOrUpdate(SPConst.PATH_INFO, json);
130 | }else {
131 | mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
132 | }
133 | }
134 | } catch (Exception e) {
135 | e.printStackTrace();
136 | }
137 | Log.e(TAG,message);
138 | }
139 | */
140 |
141 |
142 | private void processCustomMessage(Context context, Bundle bundle) {
143 | String message = bundle.getString(JPushInterface.EXTRA_MESSAGE);
144 | Intent msgIntent = new Intent(MainActivity.MESSAGE_RECEIVED_ACTION);
145 | msgIntent.putExtra(MainActivity.KEY_MESSAGE, message);
146 | context.sendBroadcast(msgIntent);
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/TestActivity.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.widget.Toast;
7 |
8 | import com.zhw.andfix.model.PatchBean;
9 |
10 | /**
11 | * Created by zhonghw on 2016/3/11.
12 | */
13 | public class TestActivity extends Activity {
14 |
15 | PatchBean bean;
16 |
17 | public static void launch(Activity activity){
18 | Intent intent = new Intent(activity, TestActivity.class);
19 | activity.startActivity(intent);
20 | }
21 |
22 | @Override
23 | protected void onCreate(Bundle savedInstanceState) {
24 | super.onCreate(savedInstanceState);
25 | setContentView(R.layout.activity_test);
26 | /*bean = new PatchBean();
27 | bean.url = "repair the bug";*/
28 | /*tetBug();*/
29 |
30 | }
31 |
32 | private void tetBug() {
33 | Toast.makeText(this, "hello,world!!!", Toast.LENGTH_SHORT).show();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/consts/SPConst.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix.consts;
2 |
3 | /**
4 | * Created by zhonghw on 2016/3/11.
5 | */
6 | public class SPConst {
7 | public static final String SP_NAME = "app";
8 | public static final String IsHavePathDownLoad = "IsHavePathDownLoad";
9 | public static final String PATH_INFO = "pathInfo";
10 | public static final String URL_PREFIX = "http://7xrnko.com1.z0.glb.clouddn.com";
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/model/PatchBean.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix.model;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * Created by zhonghw on 2016/3/11.
7 | */
8 | public class PatchBean implements Serializable {
9 | public String app_v; //应用的版本
10 | public String path_v; //补丁的版本
11 | public String url; //补丁的下载地址
12 | }
13 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/util/GsonUtils.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix.util;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 | import com.google.gson.JsonSyntaxException;
6 |
7 | import java.io.InputStream;
8 | import java.io.InputStreamReader;
9 | import java.io.Reader;
10 | import java.lang.reflect.Type;
11 |
12 | public class GsonUtils {
13 |
14 | private Gson mGson;
15 |
16 | private GsonUtils() {
17 | mGson = new GsonBuilder()
18 | .serializeNulls().setPrettyPrinting() // 对json结果格式化.
19 | .create();
20 | }
21 |
22 | private static class SingletonHolder {
23 | public static final GsonUtils INSTANCE = new GsonUtils();
24 | }
25 |
26 | public static GsonUtils getInstance() {
27 | return SingletonHolder.INSTANCE;
28 | }
29 |
30 | public Gson getGson() {
31 | return mGson;
32 | }
33 |
34 | public T parseIfNull(Type typeOfT, InputStream is) {
35 | try {
36 | return mGson.fromJson(new InputStreamReader(is), typeOfT);
37 | } catch (JsonSyntaxException e) {
38 | e.printStackTrace();
39 | return null;
40 | }
41 | }
42 |
43 | public T parseIfNull(Type typeOfT, String json) {
44 | try {
45 | return mGson.fromJson(json, typeOfT);
46 | } catch (JsonSyntaxException e) {
47 | e.printStackTrace();
48 | return null;
49 | }
50 | }
51 |
52 | public T parse(Type typeOfT, String json) throws Exception {
53 | try {
54 | return mGson.fromJson(json, typeOfT);
55 | } catch (JsonSyntaxException e) {
56 | e.printStackTrace();
57 | throw new Exception(e);
58 | }
59 | }
60 |
61 | public T parseIfNull(Type typeOfT, Reader json) {
62 | try {
63 | return mGson.fromJson(json, typeOfT);
64 | } catch (JsonSyntaxException e) {
65 | e.printStackTrace();
66 | return null;
67 | }
68 | }
69 |
70 | public T parse(Type typeOfT, Reader json) throws Exception {
71 | try {
72 | return mGson.fromJson(json, typeOfT);
73 | } catch (JsonSyntaxException e) {
74 | e.printStackTrace();
75 | throw new Exception(e);
76 | }
77 | }
78 |
79 | public T parseIfNull(Class clazz, String json) {
80 | try {
81 | return mGson.fromJson(json, clazz);
82 | } catch (JsonSyntaxException e) {
83 | e.printStackTrace();
84 | return null;
85 | }
86 | }
87 |
88 | public T parse(Class clazz, String json) throws Exception {
89 | try {
90 | return mGson.fromJson(json, clazz);
91 | } catch (JsonSyntaxException e) {
92 | e.printStackTrace();
93 | throw new Exception(e);
94 | }
95 | }
96 |
97 | public String parseIfNull(T object) {
98 | try {
99 | return mGson.toJson(object);
100 | } catch (JsonSyntaxException e) {
101 | e.printStackTrace();
102 | return null;
103 | }
104 | }
105 |
106 | public String parse(T object) throws Exception {
107 | try {
108 | return mGson.toJson(object);
109 | } catch (JsonSyntaxException e) {
110 | e.printStackTrace();
111 | throw new Exception(e);
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/util/LocalPreferencesHelper.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix.util;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | public class LocalPreferencesHelper {
7 | private SharedPreferences mSharedPreferences;
8 |
9 | public LocalPreferencesHelper(Context context, String dbName) {
10 | mSharedPreferences = context.getSharedPreferences(dbName,
11 | Context.MODE_PRIVATE);
12 | }
13 |
14 | public void saveOrUpdate(String key, String value) {
15 | mSharedPreferences.edit().putString(key, value).commit();
16 | }
17 |
18 | public void saveOrUpdate(String key, int value) {
19 | mSharedPreferences.edit().putInt(key, value).commit();
20 | }
21 |
22 | public void saveOrUpdate(String key, float value) {
23 | mSharedPreferences.edit().putFloat(key, value).commit();
24 | }
25 |
26 | public void saveOrUpdate(String key, boolean value) {
27 | mSharedPreferences.edit().putBoolean(key, value).commit();
28 | }
29 |
30 | public void saveOrUpdate(String key, long value) {
31 | mSharedPreferences.edit().putLong(key, value).commit();
32 | }
33 |
34 | public void del(String key) {
35 | mSharedPreferences.edit().remove(key).commit();
36 | }
37 |
38 | public float getFloat(String key) {
39 | return mSharedPreferences.getFloat(key, -1);
40 | }
41 |
42 | public String getString(String key) {
43 | return mSharedPreferences.getString(key, "");
44 | }
45 |
46 | public boolean getBooleanDefaultFalse(String key) {
47 | return mSharedPreferences.getBoolean(key, false);
48 | }
49 |
50 | public boolean getBooleanDefaultTrue(String key) {
51 | return mSharedPreferences.getBoolean(key, true);
52 | }
53 |
54 | public int getInt(String key) {
55 | return mSharedPreferences.getInt(key, -1);
56 | }
57 |
58 | public int getInt(String key, int defValue) {
59 | return mSharedPreferences.getInt(key, defValue);
60 | }
61 |
62 | public long getLong(String key) {
63 | return mSharedPreferences.getLong(key, -1);
64 | }
65 |
66 | public long getLong(String key, long defValue) {
67 | return mSharedPreferences.getLong(key, defValue);
68 | }
69 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/util/RepairBugUtil.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix.util;
2 |
3 | import android.content.Context;
4 | import android.net.Uri;
5 | import android.os.Environment;
6 | import android.text.TextUtils;
7 | import android.util.Log;
8 |
9 | import com.google.gson.reflect.TypeToken;
10 | import com.thin.downloadmanager.DownloadRequest;
11 | import com.thin.downloadmanager.DownloadStatusListener;
12 | import com.thin.downloadmanager.ThinDownloadManager;
13 | import com.zhw.andfix.BaseApplication;
14 | import com.zhw.andfix.R;
15 | import com.zhw.andfix.consts.SPConst;
16 | import com.zhw.andfix.model.PatchBean;
17 |
18 | import java.io.File;
19 | import java.io.IOException;
20 |
21 | /**
22 | * Created by zhonghw on 2016/3/11.
23 | */
24 | public class RepairBugUtil {
25 |
26 | private static final String TAG = "AndFix";
27 | private static final int THREAD_COUNT = 3; //下载的线程数
28 | private ThinDownloadManager mDownloadManager;
29 | private LocalPreferencesHelper mLocalPreferencesHelper;
30 |
31 | private static class SingletonHolder {
32 | public static final RepairBugUtil INSTANCE = new RepairBugUtil();
33 | }
34 |
35 | public static RepairBugUtil getInstance() {
36 | return SingletonHolder.INSTANCE;
37 | }
38 |
39 | public void downloadAndLoad(Context context, final PatchBean bean, String downloadUrl) {
40 | if (mLocalPreferencesHelper == null) {
41 | mLocalPreferencesHelper = new LocalPreferencesHelper(context, SPConst.SP_NAME);
42 | }
43 | Uri downloadUri = Uri.parse(downloadUrl);
44 | Uri destinationUri = Uri.parse(Environment.getExternalStorageDirectory()
45 | .getAbsolutePath() + bean.url);
46 | DownloadRequest downloadRequest = new DownloadRequest(downloadUri)
47 | .setDestinationURI(destinationUri)
48 | .setPriority(DownloadRequest.Priority.HIGH)
49 | .setDownloadListener(new DownloadStatusListener() {
50 | @Override
51 | public void onDownloadComplete(int id) {
52 | // add patch at runtime
53 | try {
54 | // .apatch file path
55 | String patchFileString = Environment.getExternalStorageDirectory()
56 | .getAbsolutePath() + bean.url;
57 | BaseApplication.mPatchManager.addPatch(patchFileString);
58 | Log.d(TAG, "apatch:" + patchFileString + " added.");
59 |
60 | //复制且加载补丁成功后,删除下载的补丁
61 | File f = new File(patchFileString);
62 | if (f.exists()) {
63 | boolean result = new File(patchFileString).delete();
64 | if (!result)
65 | Log.e(TAG, patchFileString + " delete fail");
66 | }
67 | // mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
68 | } catch (IOException e) {
69 | Log.e(TAG, "", e);
70 | } catch (Throwable throwable) {
71 |
72 | }
73 | }
74 |
75 | @Override
76 | public void onDownloadFailed(int id, int errorCode, String errorMessage) {
77 | //下载失败的时候,标注标记位,等下次重新打开应用的时候重新下载
78 | // mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, true);
79 | Log.e(TAG, "onDownloadFailed");
80 |
81 | }
82 |
83 | @Override
84 | public void onProgress(int id, long totalBytes, int progress) {
85 | Log.e(TAG, "progress:" + progress);
86 | }
87 | });
88 | mDownloadManager = new ThinDownloadManager(THREAD_COUNT);
89 | mDownloadManager.add(downloadRequest);
90 | }
91 |
92 |
93 | public void comparePath(Context context, PatchBean RemoteBean) throws Exception {
94 | String pathInfo = mLocalPreferencesHelper.getString(SPConst.PATH_INFO);
95 | final PatchBean localBean = GsonUtils.getInstance().parseIfNull(PatchBean.class, pathInfo);
96 | //远程的应用版本跟当前应用的版本比较
97 | if (BaseApplication.VERSION_NAME.equals(RemoteBean.app_v)) {
98 | //远程的应用版本跟本地保存的应用版本一样,但补丁不一样,则需要下载重新
99 | /**
100 | *第一种情况:当本地记录的Bean为空的时候(刚安装的时候可能为空)并且远程的Bean的path_v不为空的时候需要下载补丁。
101 | * 第二种情况:当本地记录的path_v和远程Bean的path_v不一样的时候需要下载补丁。
102 | */
103 | if (localBean == null && !TextUtils.isEmpty(RemoteBean.path_v)
104 | || localBean.app_v.equals(RemoteBean.app_v) &&
105 | !localBean.path_v.equals(RemoteBean.path_v)) {
106 | downloadAndLoad(context, RemoteBean,
107 | SPConst.URL_PREFIX + RemoteBean.url);
108 | String json = GsonUtils.getInstance().parse(RemoteBean);
109 | mLocalPreferencesHelper.saveOrUpdate(SPConst.PATH_INFO, json);
110 | } /*else {
111 | mLocalPreferencesHelper.saveOrUpdate(SPConst.IsHavePathDownLoad, false);
112 | }*/
113 | }
114 | }
115 |
116 | public void release() {
117 | if (mDownloadManager != null) {
118 | mDownloadManager.release();
119 | }
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/app/src/main/java/com/zhw/andfix/util/WeakHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2014 Badoo Trading Limited
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy
4 | * of this software and associated documentation files (the "Software"), to deal
5 | * in the Software without restriction, including without limitation the rights
6 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | * copies of the Software, and to permit persons to whom the Software is
8 | * furnished to do so, subject to the following conditions:
9 | *
10 | * The above copyright notice and this permission notice shall be included in
11 | * all copies or substantial portions of the Software.
12 | *
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | * THE SOFTWARE.
20 | *
21 | * Portions of documentation in this code are modifications based on work created and
22 | * shared by Android Open Source Project and used according to terms described in the
23 | * Apache License, Version 2.0
24 | */
25 | package com.zhw.andfix.util;
26 |
27 | import android.os.Handler;
28 | import android.os.Looper;
29 | import android.os.Message;
30 | import android.support.annotation.NonNull;
31 | import android.support.annotation.Nullable;
32 | import android.support.annotation.VisibleForTesting;
33 |
34 | import java.lang.ref.WeakReference;
35 | import java.util.concurrent.locks.Lock;
36 | import java.util.concurrent.locks.ReentrantLock;
37 |
38 | /**
39 | * Memory safer implementation of android.os.Handler
40 | *
41 | * Original implementation of Handlers always keeps hard reference to handler in queue of execution.
42 | * If you create anonymous handler and post delayed message into it, it will keep all parent class
43 | * for that time in memory even if it could be cleaned.
44 | *
45 | * This implementation is trickier, it will keep WeakReferences to runnables and messages,
46 | * and GC could collect them once WeakHandler instance is not referenced any more
47 | *
48 | *
49 | * @see android.os.Handler
50 | *
51 | * Created by Dmytro Voronkevych on 17/06/2014.
52 | */
53 | @SuppressWarnings("unused")
54 | public class WeakHandler {
55 | private final Handler.Callback mCallback; // hard reference to Callback. We need to keep callback in memory
56 | private final ExecHandler mExec;
57 | private Lock mLock = new ReentrantLock();
58 | @SuppressWarnings("ConstantConditions")
59 | @VisibleForTesting
60 | final ChainedRef mRunnables = new ChainedRef(mLock, null);
61 |
62 | /**
63 | * Default constructor associates this handler with the {@link Looper} for the
64 | * current thread.
65 | *
66 | * If this thread does not have a looper, this handler won't be able to receive messages
67 | * so an exception is thrown.
68 | */
69 | public WeakHandler() {
70 | mCallback = null;
71 | mExec = new ExecHandler();
72 | }
73 |
74 | /**
75 | * Constructor associates this handler with the {@link Looper} for the
76 | * current thread and takes a callback interface in which you can handle
77 | * messages.
78 | *
79 | * If this thread does not have a looper, this handler won't be able to receive messages
80 | * so an exception is thrown.
81 | *
82 | * @param callback The callback interface in which to handle messages, or null.
83 | */
84 | public WeakHandler(@Nullable Handler.Callback callback) {
85 | mCallback = callback; // Hard referencing body
86 | mExec = new ExecHandler(new WeakReference<>(callback)); // Weak referencing inside ExecHandler
87 | }
88 |
89 | /**
90 | * Use the provided {@link Looper} instead of the default one.
91 | *
92 | * @param looper The looper, must not be null.
93 | */
94 | public WeakHandler(@NonNull Looper looper) {
95 | mCallback = null;
96 | mExec = new ExecHandler(looper);
97 | }
98 |
99 | /**
100 | * Use the provided {@link Looper} instead of the default one and take a callback
101 | * interface in which to handle messages.
102 | *
103 | * @param looper The looper, must not be null.
104 | * @param callback The callback interface in which to handle messages, or null.
105 | */
106 | public WeakHandler(@NonNull Looper looper, @NonNull Handler.Callback callback) {
107 | mCallback = callback;
108 | mExec = new ExecHandler(looper, new WeakReference<>(callback));
109 | }
110 |
111 | /**
112 | * Causes the Runnable r to be added to the message queue.
113 | * The runnable will be run on the thread to which this handler is
114 | * attached.
115 | *
116 | * @param r The Runnable that will be executed.
117 | *
118 | * @return Returns true if the Runnable was successfully placed in to the
119 | * message queue. Returns false on failure, usually because the
120 | * looper processing the message queue is exiting.
121 | */
122 | public final boolean post(@NonNull Runnable r) {
123 | return mExec.post(wrapRunnable(r));
124 | }
125 |
126 | /**
127 | * Causes the Runnable r to be added to the message queue, to be run
128 | * at a specific time given by uptimeMillis.
129 | * The time-base is {@link android.os.SystemClock#uptimeMillis}.
130 | * The runnable will be run on the thread to which this handler is attached.
131 | *
132 | * @param r The Runnable that will be executed.
133 | * @param uptimeMillis The absolute time at which the callback should run,
134 | * using the {@link android.os.SystemClock#uptimeMillis} time-base.
135 | *
136 | * @return Returns true if the Runnable was successfully placed in to the
137 | * message queue. Returns false on failure, usually because the
138 | * looper processing the message queue is exiting. Note that a
139 | * result of true does not mean the Runnable will be processed -- if
140 | * the looper is quit before the delivery time of the message
141 | * occurs then the message will be dropped.
142 | */
143 | public final boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
144 | return mExec.postAtTime(wrapRunnable(r), uptimeMillis);
145 | }
146 |
147 | /**
148 | * Causes the Runnable r to be added to the message queue, to be run
149 | * at a specific time given by uptimeMillis.
150 | * The time-base is {@link android.os.SystemClock#uptimeMillis}.
151 | * The runnable will be run on the thread to which this handler is attached.
152 | *
153 | * @param r The Runnable that will be executed.
154 | * @param uptimeMillis The absolute time at which the callback should run,
155 | * using the {@link android.os.SystemClock#uptimeMillis} time-base.
156 | *
157 | * @return Returns true if the Runnable was successfully placed in to the
158 | * message queue. Returns false on failure, usually because the
159 | * looper processing the message queue is exiting. Note that a
160 | * result of true does not mean the Runnable will be processed -- if
161 | * the looper is quit before the delivery time of the message
162 | * occurs then the message will be dropped.
163 | *
164 | * @see android.os.SystemClock#uptimeMillis
165 | */
166 | public final boolean postAtTime(Runnable r, Object token, long uptimeMillis) {
167 | return mExec.postAtTime(wrapRunnable(r), token, uptimeMillis);
168 | }
169 |
170 | /**
171 | * Causes the Runnable r to be added to the message queue, to be run
172 | * after the specified amount of time elapses.
173 | * The runnable will be run on the thread to which this handler
174 | * is attached.
175 | *
176 | * @param r The Runnable that will be executed.
177 | * @param delayMillis The delay (in milliseconds) until the Runnable
178 | * will be executed.
179 | *
180 | * @return Returns true if the Runnable was successfully placed in to the
181 | * message queue. Returns false on failure, usually because the
182 | * looper processing the message queue is exiting. Note that a
183 | * result of true does not mean the Runnable will be processed --
184 | * if the looper is quit before the delivery time of the message
185 | * occurs then the message will be dropped.
186 | */
187 | public final boolean postDelayed(Runnable r, long delayMillis) {
188 | return mExec.postDelayed(wrapRunnable(r), delayMillis);
189 | }
190 |
191 | /**
192 | * Posts a message to an object that implements Runnable.
193 | * Causes the Runnable r to executed on the next iteration through the
194 | * message queue. The runnable will be run on the thread to which this
195 | * handler is attached.
196 | * This method is only for use in very special circumstances -- it
197 | * can easily starve the message queue, cause ordering problems, or have
198 | * other unexpected side-effects.
199 | *
200 | * @param r The Runnable that will be executed.
201 | *
202 | * @return Returns true if the message was successfully placed in to the
203 | * message queue. Returns false on failure, usually because the
204 | * looper processing the message queue is exiting.
205 | */
206 | public final boolean postAtFrontOfQueue(Runnable r) {
207 | return mExec.postAtFrontOfQueue(wrapRunnable(r));
208 | }
209 |
210 | /**
211 | * Remove any pending posts of Runnable r that are in the message queue.
212 | */
213 | public final void removeCallbacks(Runnable r) {
214 | final WeakRunnable runnable = mRunnables.remove(r);
215 | if (runnable != null) {
216 | mExec.removeCallbacks(runnable);
217 | }
218 | }
219 |
220 | /**
221 | * Remove any pending posts of Runnable r with Object
222 | * token that are in the message queue. If token is null,
223 | * all callbacks will be removed.
224 | */
225 | public final void removeCallbacks(Runnable r, Object token) {
226 | final WeakRunnable runnable = mRunnables.remove(r);
227 | if (runnable != null) {
228 | mExec.removeCallbacks(runnable, token);
229 | }
230 | }
231 |
232 | /**
233 | * Pushes a message onto the end of the message queue after all pending messages
234 | * before the current time. It will be received in callback,
235 | * in the thread attached to this handler.
236 | *
237 | * @return Returns true if the message was successfully placed in to the
238 | * message queue. Returns false on failure, usually because the
239 | * looper processing the message queue is exiting.
240 | */
241 | public final boolean sendMessage(Message msg) {
242 | return mExec.sendMessage(msg);
243 | }
244 |
245 | /**
246 | * Sends a Message containing only the what value.
247 | *
248 | * @return Returns true if the message was successfully placed in to the
249 | * message queue. Returns false on failure, usually because the
250 | * looper processing the message queue is exiting.
251 | */
252 | public final boolean sendEmptyMessage(int what) {
253 | return mExec.sendEmptyMessage(what);
254 | }
255 |
256 | /**
257 | * Sends a Message containing only the what value, to be delivered
258 | * after the specified amount of time elapses.
259 | * @see #sendMessageDelayed(android.os.Message, long)
260 | *
261 | * @return Returns true if the message was successfully placed in to the
262 | * message queue. Returns false on failure, usually because the
263 | * looper processing the message queue is exiting.
264 | */
265 | public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {
266 | return mExec.sendEmptyMessageDelayed(what, delayMillis);
267 | }
268 |
269 | /**
270 | * Sends a Message containing only the what value, to be delivered
271 | * at a specific time.
272 | * @see #sendMessageAtTime(android.os.Message, long)
273 | *
274 | * @return Returns true if the message was successfully placed in to the
275 | * message queue. Returns false on failure, usually because the
276 | * looper processing the message queue is exiting.
277 | */
278 | public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
279 | return mExec.sendEmptyMessageAtTime(what, uptimeMillis);
280 | }
281 |
282 | /**
283 | * Enqueue a message into the message queue after all pending messages
284 | * before (current time + delayMillis). You will receive it in
285 | * callback, in the thread attached to this handler.
286 | *
287 | * @return Returns true if the message was successfully placed in to the
288 | * message queue. Returns false on failure, usually because the
289 | * looper processing the message queue is exiting. Note that a
290 | * result of true does not mean the message will be processed -- if
291 | * the looper is quit before the delivery time of the message
292 | * occurs then the message will be dropped.
293 | */
294 | public final boolean sendMessageDelayed(Message msg, long delayMillis) {
295 | return mExec.sendMessageDelayed(msg, delayMillis);
296 | }
297 |
298 | /**
299 | * Enqueue a message into the message queue after all pending messages
300 | * before the absolute time (in milliseconds) uptimeMillis.
301 | * The time-base is {@link android.os.SystemClock#uptimeMillis}.
302 | * You will receive it in callback, in the thread attached
303 | * to this handler.
304 | *
305 | * @param uptimeMillis The absolute time at which the message should be
306 | * delivered, using the
307 | * {@link android.os.SystemClock#uptimeMillis} time-base.
308 | *
309 | * @return Returns true if the message was successfully placed in to the
310 | * message queue. Returns false on failure, usually because the
311 | * looper processing the message queue is exiting. Note that a
312 | * result of true does not mean the message will be processed -- if
313 | * the looper is quit before the delivery time of the message
314 | * occurs then the message will be dropped.
315 | */
316 | public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
317 | return mExec.sendMessageAtTime(msg, uptimeMillis);
318 | }
319 |
320 | /**
321 | * Enqueue a message at the front of the message queue, to be processed on
322 | * the next iteration of the message loop. You will receive it in
323 | * callback, in the thread attached to this handler.
324 | * This method is only for use in very special circumstances -- it
325 | * can easily starve the message queue, cause ordering problems, or have
326 | * other unexpected side-effects.
327 | *
328 | * @return Returns true if the message was successfully placed in to the
329 | * message queue. Returns false on failure, usually because the
330 | * looper processing the message queue is exiting.
331 | */
332 | public final boolean sendMessageAtFrontOfQueue(Message msg) {
333 | return mExec.sendMessageAtFrontOfQueue(msg);
334 | }
335 |
336 | /**
337 | * Remove any pending posts of messages with code 'what' that are in the
338 | * message queue.
339 | */
340 | public final void removeMessages(int what) {
341 | mExec.removeMessages(what);
342 | }
343 |
344 | /**
345 | * Remove any pending posts of messages with code 'what' and whose obj is
346 | * 'object' that are in the message queue. If object is null,
347 | * all messages will be removed.
348 | */
349 | public final void removeMessages(int what, Object object) {
350 | mExec.removeMessages(what, object);
351 | }
352 |
353 | /**
354 | * Remove any pending posts of callbacks and sent messages whose
355 | * obj is token. If token is null,
356 | * all callbacks and messages will be removed.
357 | */
358 | public final void removeCallbacksAndMessages(Object token) {
359 | mExec.removeCallbacksAndMessages(token);
360 | }
361 |
362 | /**
363 | * Check if there are any pending posts of messages with code 'what' in
364 | * the message queue.
365 | */
366 | public final boolean hasMessages(int what) {
367 | return mExec.hasMessages(what);
368 | }
369 |
370 | /**
371 | * Check if there are any pending posts of messages with code 'what' and
372 | * whose obj is 'object' in the message queue.
373 | */
374 | public final boolean hasMessages(int what, Object object) {
375 | return mExec.hasMessages(what, object);
376 | }
377 |
378 | public final Looper getLooper() {
379 | return mExec.getLooper();
380 | }
381 |
382 | private WeakRunnable wrapRunnable(@NonNull Runnable r) {
383 | //noinspection ConstantConditions
384 | if (r == null) {
385 | throw new NullPointerException("Runnable can't be null");
386 | }
387 | final ChainedRef hardRef = new ChainedRef(mLock, r);
388 | mRunnables.insertAfter(hardRef);
389 | return hardRef.wrapper;
390 | }
391 |
392 | private static class ExecHandler extends Handler {
393 | private final WeakReference mCallback;
394 |
395 | ExecHandler() {
396 | mCallback = null;
397 | }
398 |
399 | ExecHandler(WeakReference callback) {
400 | mCallback = callback;
401 | }
402 |
403 | ExecHandler(Looper looper) {
404 | super(looper);
405 | mCallback = null;
406 | }
407 |
408 | ExecHandler(Looper looper, WeakReference callback) {
409 | super(looper);
410 | mCallback = callback;
411 | }
412 |
413 | @Override
414 | public void handleMessage(@NonNull Message msg) {
415 | if (mCallback == null) {
416 | return;
417 | }
418 | final Handler.Callback callback = mCallback.get();
419 | if (callback == null) { // Already disposed
420 | return;
421 | }
422 | callback.handleMessage(msg);
423 | }
424 | }
425 |
426 | static class WeakRunnable implements Runnable {
427 | private final WeakReference mDelegate;
428 | private final WeakReference mReference;
429 |
430 | WeakRunnable(WeakReference delegate, WeakReference reference) {
431 | mDelegate = delegate;
432 | mReference = reference;
433 | }
434 |
435 | @Override
436 | public void run() {
437 | final Runnable delegate = mDelegate.get();
438 | final ChainedRef reference = mReference.get();
439 | if (reference != null) {
440 | reference.remove();
441 | }
442 | if (delegate != null) {
443 | delegate.run();
444 | }
445 | }
446 | }
447 |
448 | static class ChainedRef {
449 | @Nullable
450 | ChainedRef next;
451 | @Nullable
452 | ChainedRef prev;
453 | @NonNull
454 | final Runnable runnable;
455 | @NonNull
456 | final WeakRunnable wrapper;
457 |
458 | @NonNull
459 | Lock lock;
460 |
461 | public ChainedRef(@NonNull Lock lock, @NonNull Runnable r) {
462 | this.runnable = r;
463 | this.lock = lock;
464 | this.wrapper = new WeakRunnable(new WeakReference<>(r), new WeakReference<>(this));
465 | }
466 |
467 | public WeakRunnable remove() {
468 | lock.lock();
469 | try {
470 | if (prev != null) {
471 | prev.next = next;
472 | }
473 | if (next != null) {
474 | next.prev = prev;
475 | }
476 | prev = null;
477 | next = null;
478 | } finally {
479 | lock.unlock();
480 | }
481 | return wrapper;
482 | }
483 |
484 | public void insertAfter(@NonNull ChainedRef candidate) {
485 | lock.lock();
486 | try {
487 | if (this.next != null) {
488 | this.next.prev = candidate;
489 | }
490 |
491 | candidate.next = this.next;
492 | this.next = candidate;
493 | candidate.prev = this;
494 | } finally {
495 | lock.unlock();
496 | }
497 | }
498 |
499 | @Nullable
500 | public WeakRunnable remove(Runnable obj) {
501 | lock.lock();
502 | try {
503 | ChainedRef curr = this.next; // Skipping head
504 | while (curr != null) {
505 | if (curr.runnable == obj) { // We do comparison exactly how Handler does inside
506 | return curr.remove();
507 | }
508 | curr = curr.next;
509 | }
510 | } finally {
511 | lock.unlock();
512 | }
513 | return null;
514 | }
515 | }
516 | }
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libandfix.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/arm64-v8a/libandfix.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/arm64-v8a/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/arm64-v8a/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libandfix.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/armeabi-v7a/libandfix.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi-v7a/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/armeabi-v7a/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/armeabi/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/armeabi/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips/libandfix.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/mips/libandfix.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/mips/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips64/libandfix.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/mips64/libandfix.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/mips64/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/mips64/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/x86/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86_64/libandfix.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/x86_64/libandfix.so
--------------------------------------------------------------------------------
/app/src/main/jniLibs/x86_64/libjpush210.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/jniLibs/x86_64/libjpush210.so
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/border_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/border_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/bottom_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/bottom_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/corners_bg.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 |
9 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_richpush_actionbar_back.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/ic_richpush_actionbar_back.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/ic_richpush_actionbar_divider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/ic_richpush_actionbar_divider.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/jpush_notification_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/jpush_notification_icon.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/richpush_btn_selector.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
10 |
14 |
15 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/stripes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/stripes.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/tiledstripes.xml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/app/src/main/res/drawable-hdpi/top_bg.9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-hdpi/top_bg.9.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-ldpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-ldpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
17 |
18 |
19 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_test.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/customer_notitfication_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
15 |
21 |
22 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/customer_notitfication_layout_one.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
10 |
15 |
21 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/jpush_popwin_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
14 |
15 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/jpush_webview_layout.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
13 |
14 |
20 |
21 |
29 |
30 |
40 |
41 |
42 |
47 |
48 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
16 |
22 |
28 |
34 |
39 |
40 |
46 |
47 |
53 |
54 |
60 |
66 |
67 |
73 |
74 |
75 |
76 |
83 |
84 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/push_set_dialog.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
13 |
14 |
20 |
21 |
26 |
27 |
28 |
36 |
37 |
41 |
42 |
46 |
47 |
56 |
57 |
63 |
64 |
65 |
69 |
70 |
74 |
75 |
84 |
85 |
91 |
92 |
93 |
94 |
101 |
102 |
107 |
108 |
109 |
117 |
118 |
123 |
124 |
129 |
130 |
131 |
139 |
144 |
145 |
146 |
154 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/set_push_time.xml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
14 |
15 |
23 |
24 |
29 |
30 |
31 |
39 |
40 |
44 |
45 |
50 |
51 |
52 |
53 |
57 |
58 |
62 |
63 |
67 |
68 |
73 |
74 |
79 |
80 |
81 |
85 |
86 |
91 |
92 |
97 |
98 |
99 |
103 |
104 |
110 |
111 |
116 |
117 |
118 |
122 |
123 |
128 |
129 |
134 |
135 |
136 |
137 |
141 |
142 |
146 |
147 |
152 |
153 |
158 |
159 |
160 |
164 |
165 |
170 |
171 |
176 |
177 |
178 |
182 |
183 |
188 |
189 |
194 |
195 |
196 |
197 |
198 |
202 |
203 |
208 |
209 |
210 |
215 |
216 |
220 |
221 |
226 |
227 |
231 |
232 |
238 |
239 |
240 |
241 |
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zhonghanwen/AndFix-Bad-Practices/5471ea037fe0512608e93ff61a632c32e6bf9986/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, JPush!
4 | AndFix-Best-Practices
5 | Tag can be number, alphabet, underscore, Chinese. Use , to split many tags.
6 | Alias can be number, alphabet, underscore, Chinese.
7 | style should be number
8 | style cannot be empty
9 | alias cannot be empty
10 | tag cannot be empty
11 | Invalid format
12 | Failed to init due to network exception.
13 | Running in background. Please see log.
14 | Succeed to set
15 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values-zh/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
12 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #3F51B5
4 | #303F9F
5 | #FF4081
6 |
7 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/jpush_style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Hello World, JPush!
4 | AndFix-Best-Practices
5 | Tag为大小写字母,数字,下划线,中文, 多个用以逗号分隔
6 | Alias为大小写字母,数字,下划线
7 | style为数字
8 | style不能为空
9 | alias不能为空
10 | tag不能为空
11 | 格式不对
12 | 网络连接异常,初始化失败 请检查网络!
13 | 程序在后台执行, 请查看日志!
14 | 设置成功
15 | app
16 | IsHavePathDownLoad
17 |
18 |
--------------------------------------------------------------------------------
/app/src/main/res/values/style.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
12 |
16 |
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/app/src/test/java/com/zhw/andfix/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.zhw.andfix;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 |
3 | buildscript {
4 | repositories {
5 | jcenter()
6 | }
7 | dependencies {
8 | classpath 'com.android.tools.build:gradle:2.1.0-alpha1'
9 |
10 | // NOTE: Do not place your application dependencies here; they belong
11 | // in the individual module build.gradle files
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | jcenter()
18 | }
19 | }
20 |
21 | task clean(type: Delete) {
22 | delete rootProject.buildDir
23 | }
24 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 | aaptOptions.cruncherEnabled = false
20 |
21 | # The Gradle daemon aims to improve the startup and execution time of Gradle.
22 | # When set to true the Gradle daemon is to run the build.
23 | # TODO: disable daemon on CI, since builds should be clean and reliable on servers
24 | org.gradle.daemon=true
25 |
26 | # Specifies the JVM arguments used for the daemon process.
27 | # The setting is particularly useful for tweaking memory settings.
28 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
29 | org.gradle.jvmargs=-Xmx4096m -XX:MaxPermSize=1024m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
30 |
31 | # When configured, Gradle will run in incubating parallel mode.
32 | # This option should only be used with decoupled projects. More details, visit
33 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
34 | org.gradle.parallel=true
35 |
36 | # Enables new incubating mode that makes Gradle selective when configuring projects.
37 | # Only relevant projects are configured which results in faster builds for large multi-projects.
38 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:configuration_on_demand
39 | org.gradle.configureondemand=true
40 |
41 | ANDROID_STORE_FILE = andfix.jks
42 | ANDROID_STORE_PASS = 123456
43 | ANDROID_KEY_ALIAS = andfix
44 | ANDROID_KEY_PASS = 123456
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app'
2 |
--------------------------------------------------------------------------------