map, @NonNull String keyValue){
248 | if (!keyValue.contains("=")) {
249 | return;
250 | }
251 |
252 | String[] params = keyValue.split("=");
253 | if (params.length == 2) {
254 | map.put(params[0].trim(), URLDecoder.decode(params[1].trim()));
255 | }
256 | }
257 |
258 | private static String getVersionName(@NonNull Context context) {
259 | try {
260 | PackageManager packageManager = context.getPackageManager();
261 | PackageInfo packInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
262 | return packInfo.versionName;
263 | } catch (PackageManager.NameNotFoundException e) {
264 | Log.e(AppLink.TAG, "getVersionName() error: " + e.getMessage());
265 | return "";
266 | }
267 | }
268 | }
269 |
--------------------------------------------------------------------------------
/library/src/main/java/com/feizhang/applink/PushContentReceiver.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import android.arch.lifecycle.Lifecycle;
4 | import android.arch.lifecycle.LifecycleObserver;
5 | import android.arch.lifecycle.OnLifecycleEvent;
6 | import android.content.Context;
7 | import android.content.IntentFilter;
8 | import android.support.annotation.NonNull;
9 | import android.support.v4.app.Fragment;
10 | import android.support.v7.app.AppCompatActivity;
11 | import android.text.TextUtils;
12 | import android.util.Pair;
13 |
14 | import java.util.List;
15 | import java.util.Map;
16 |
17 | /**
18 | * Created by zhangfei on 2015/9/8.
19 | *
20 | * It's designed to register in Activity, Fragment or CustomView
21 | * to receive push message and do work which should only be done in them,
22 | * like refresh page and so on.
23 | */
24 | public abstract class PushContentReceiver extends PushReceiver {
25 |
26 | /**
27 | * remember to register in onCreate(), it'll automatically unregister when onDestroy()
28 | */
29 | public static void register(@NonNull final AppCompatActivity activity,
30 | @NonNull final PushContentReceiver receiver,
31 | boolean highPriority) {
32 | register(activity, activity.getLifecycle(), receiver, highPriority);
33 | }
34 |
35 | /**
36 | * remember to register it in construct method, it'll automatically unregister when onDestroy()
37 | */
38 | public static void register(@NonNull final Fragment fragment,
39 | @NonNull final PushContentReceiver receiver,
40 | boolean highPriority) {
41 | Context context = fragment.getContext();
42 | if (context != null) {
43 | register(context, fragment.getLifecycle(), receiver, highPriority);
44 | }
45 | }
46 |
47 | private static void register(@NonNull final Context context,
48 | @NonNull final Lifecycle lifecycle,
49 | @NonNull final PushContentReceiver receiver,
50 | final boolean highPriority) {
51 | lifecycle.addObserver(new LifecycleObserver() {
52 |
53 | @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
54 | void onCreate() {
55 | IntentFilter intentFilter = new IntentFilter();
56 | intentFilter.addAction(PushNotificationReceiver.buildPushAction(context));
57 |
58 | if (highPriority) {
59 | intentFilter.setPriority(100);
60 | }
61 |
62 | context.registerReceiver(receiver,
63 | intentFilter,
64 | PushNotificationReceiver.buildPermission(context),
65 | null);
66 | }
67 |
68 | @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
69 | void onDestroy() {
70 | context.unregisterReceiver(receiver);
71 | }
72 | });
73 | }
74 |
75 | /**
76 | * same as {@link #register(AppCompatActivity, PushContentReceiver, boolean)} but suggest to use in custom view
77 | */
78 | public static void register(@NonNull Context context, @NonNull PushContentReceiver receiver, boolean highPriority) {
79 | IntentFilter intentFilter = new IntentFilter();
80 | intentFilter.addAction(PushNotificationReceiver.buildPushAction(context));
81 | if (highPriority) {
82 | intentFilter.setPriority(100);
83 | }
84 | context.registerReceiver(receiver, intentFilter, PushNotificationReceiver.buildPermission(context), null);
85 | }
86 |
87 | public static void unregister(@NonNull Context context, @NonNull PushContentReceiver receiver) {
88 | context.unregisterReceiver(receiver);
89 | }
90 |
91 | /**
92 | * Specify appLink to receive or to handle.
93 | */
94 | public abstract List getAppLinks();
95 |
96 | /**
97 | * Return true to indicate that the push message has been handled and will not deliver it to other receiver.
98 | */
99 | public abstract boolean onReceive(@NonNull Context context, @NonNull AppLink appLink);
100 |
101 | /**
102 | * since different order detail page or product page may have only one activity, so here need to provide its key and value,
103 | * and they'll be used to check if same order detail page or same product page
104 | *
105 | * @return target key and value
106 | */
107 | public Pair getTargetKeyValue() {
108 | return null;
109 | }
110 |
111 | @Override
112 | public final void onAppLinkReceive(@NonNull Context context, @NonNull AppLink appLink) {
113 | String appLinkUrl = appLink.getAppLink();
114 |
115 | // check if target appLink can receive by current receiver
116 | boolean matched = false;
117 | List appLinks = getAppLinks();
118 | for (String item : appLinks) {
119 | // check if configured appLink was included in received appLink
120 | // configured appLinks aways have no params and received appLinks may have params
121 | if (appLinkUrl.startsWith(item)) {
122 | matched = true;
123 | break;
124 | }
125 | }
126 | if (!matched) {
127 | return;
128 | }
129 |
130 | Map params = appLink.getParams();
131 | Pair targetKeyValue = getTargetKeyValue();
132 | if (targetKeyValue == null) {
133 | // abort broadcast if already handled
134 | boolean handled = onReceive(context, appLink);
135 | if (handled) {
136 | abortBroadcast();
137 | }
138 | } else {
139 | // check if empty
140 | if (TextUtils.isEmpty(targetKeyValue.first) || TextUtils.isEmpty(targetKeyValue.second)) {
141 | return;
142 | }
143 |
144 | // the target page is current page
145 | String param = params.get(targetKeyValue.first);
146 | if (TextUtils.equals(targetKeyValue.second, param)) {
147 | // abort if already handled
148 | boolean handled = onReceive(context, appLink);
149 | if (handled) {
150 | abortBroadcast();
151 | }
152 | }
153 | }
154 | }
155 | }
--------------------------------------------------------------------------------
/library/src/main/java/com/feizhang/applink/PushMessageDbHelper.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 | import android.database.sqlite.SQLiteOpenHelper;
6 | import android.support.annotation.NonNull;
7 |
8 | /**
9 | * Created by zhangfei on 2015/9/8.
10 | */
11 | public class PushMessageDbHelper extends SQLiteOpenHelper {
12 | private Context mContext;
13 |
14 | PushMessageDbHelper(@NonNull Context context) {
15 | super(context, "push_message.db", null, 1);
16 | mContext = context.getApplicationContext();
17 | }
18 |
19 | @Override
20 | public void onCreate(SQLiteDatabase db) {
21 | db.execSQL("CREATE TABLE IF NOT EXISTS push_message (" +
22 | "_id INTEGER PRIMARY KEY AUTOINCREMENT," +
23 | "title TEXT," +
24 | "sub_title TEXT," +
25 | "pic_url TEXT," +
26 | "app_link TEXT," +
27 | "account TEXT," +
28 | "update_dt TEXT," +
29 | "read INTEGER)");
30 | }
31 |
32 | @Override
33 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
34 |
35 | }
36 |
37 | @NonNull
38 | Context getContext() {
39 | return mContext;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/library/src/main/java/com/feizhang/applink/PushMessageService.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import android.content.ContentValues;
4 | import android.content.Context;
5 | import android.database.Cursor;
6 | import android.database.sqlite.SQLiteDatabase;
7 | import android.support.annotation.NonNull;
8 | import android.text.TextUtils;
9 |
10 | import java.util.Collections;
11 | import java.util.List;
12 | import java.util.Locale;
13 |
14 | public class PushMessageService {
15 | private PushMessageDbHelper dbHelper;
16 | private static PushMessageService instance = null;
17 |
18 | private PushMessageService(Context context) {
19 | this.dbHelper = new PushMessageDbHelper(context);
20 | }
21 |
22 | public synchronized static PushMessageService getInstance(Context context) {
23 | if (instance == null) {
24 | synchronized (PushMessageService.class) {
25 | instance = new PushMessageService(context);
26 | }
27 | }
28 |
29 | return instance;
30 | }
31 |
32 | public void delete(long messageId) {
33 | if (messageId > 0) {
34 | return;
35 | }
36 |
37 | dbHelper.getWritableDatabase().delete("push_message", "_id=?",
38 | new String[]{String.valueOf(messageId)});
39 | }
40 |
41 | public void delete(@NonNull String appLink, @NonNull String account) {
42 | if (TextUtils.isEmpty(appLink)) {
43 | return;
44 | }
45 |
46 | AppLink pushMessage = AppLinkUtils.parseAppLink(dbHelper.getContext(), appLink);
47 | if (pushMessage == null) {
48 | return;
49 | }
50 |
51 | if (pushMessage.isPrivate() && !TextUtils.isEmpty(account)) {
52 | dbHelper.getWritableDatabase().delete("push_message", "app_link like ? and account=?",
53 | new String[]{appLink + "%", account});
54 | } else {
55 | dbHelper.getWritableDatabase().delete("push_message", "app_link like ?",
56 | new String[]{appLink + "%"});
57 | }
58 | }
59 |
60 | public int count(@NonNull String linkUrl, @NonNull String account) {
61 | AppLink pushMessage = AppLinkUtils.parseAppLink(dbHelper.getContext(), linkUrl);
62 | if (pushMessage == null) {
63 | return 0;
64 | }
65 |
66 | if (pushMessage.isPrivate() && TextUtils.isEmpty(account)) {
67 | return 0;
68 | }
69 |
70 | Cursor cursor;
71 | if (pushMessage.isPrivate()) {
72 | cursor = dbHelper.getReadableDatabase().rawQuery(
73 | "select count(*) from push_message where app_link like ?",
74 | new String[]{pushMessage.getAppLink() + "%"});
75 | } else {
76 | cursor = dbHelper.getReadableDatabase().rawQuery(
77 | "select count(*) from push_message where app_link like ? and account=?",
78 | new String[]{pushMessage.getAppLink() + "%", account});
79 | }
80 |
81 | try {
82 | cursor.moveToFirst();
83 | return cursor.getInt(0);
84 | } finally {
85 | cursor.close();
86 | }
87 | }
88 |
89 | public boolean haveUnread(@NonNull String appLink, @NonNull String account) {
90 | return haveUnread(Collections.singletonList(appLink), account);
91 | }
92 |
93 | public boolean haveUnread(@NonNull List appLinks, @NonNull String account) {
94 | for (String appLink : appLinks) {
95 | AppLink pushMessage = AppLinkUtils.parseAppLink(dbHelper.getContext(), appLink);
96 | if (pushMessage == null) {
97 | continue;
98 | }
99 |
100 | if (pushMessage.isPrivate() && TextUtils.isEmpty(account)) {
101 | continue;
102 | }
103 |
104 | Cursor cursor;
105 | if (pushMessage.isPrivate()) {
106 | String sql = "select count(*) from push_message where app_link like ? and account=? and read=?";
107 | cursor = dbHelper.getReadableDatabase().rawQuery(sql, new String[]{appLink + "%", account, "0"});
108 | } else {
109 | String sql = "select count(*) from push_message where app_link like ? and read=?";
110 | cursor = dbHelper.getReadableDatabase().rawQuery(sql, new String[]{appLink + "%", "0"});
111 | }
112 |
113 | try {
114 | cursor.moveToFirst();
115 | return cursor.getInt(0) > 0;
116 | } finally {
117 | cursor.close();
118 | }
119 | }
120 |
121 | return false;
122 | }
123 |
124 | public void save(@NonNull AppLink pushMessage) {
125 | SQLiteDatabase database = dbHelper.getWritableDatabase();
126 | try {
127 | // delete exist appLink and add new one
128 | database.beginTransaction();
129 | database.execSQL("DELETE FROM push_message WHERE lower(app_link) = ?",
130 | new String[]{pushMessage.getAppLink().toLowerCase(Locale.SIMPLIFIED_CHINESE)});
131 | database.execSQL("INSERT INTO push_message(title, sub_title, pic_url, app_link, account, update_dt, read) " +
132 | "VALUES(?, ?, ?, ?, ?, ?, ?)", new Object[]{
133 | pushMessage.getTitle(),
134 | pushMessage.getSubTitle(),
135 | pushMessage.getPicUrl(),
136 | pushMessage.getAppLink(),
137 | pushMessage.getAccount(),
138 | pushMessage.getReceiveDt(),
139 | pushMessage.isRead()});
140 | database.setTransactionSuccessful();
141 | } finally {
142 | database.endTransaction();
143 | }
144 | }
145 |
146 | public void setAsRead(@NonNull String appLink, @NonNull String account) {
147 | AppLink pushMessage = AppLinkUtils.parseAppLink(dbHelper.getContext(), appLink);
148 | if (pushMessage == null) {
149 | return;
150 | }
151 |
152 | if (pushMessage.isPrivate() && TextUtils.isEmpty(account)) {
153 | return;
154 | }
155 |
156 | ContentValues values = new ContentValues();
157 | values.put("read", true);
158 | values.put("update_dt", System.currentTimeMillis());
159 |
160 | if (pushMessage.isPrivate()) {
161 | dbHelper.getWritableDatabase().update("push_message", values, "app_link like ? and account=?",
162 | new String[]{appLink + "%", account});
163 | } else {
164 | dbHelper.getWritableDatabase().update("push_message", values, "app_link like ?",
165 | new String[]{appLink + "%"});
166 | }
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/library/src/main/java/com/feizhang/applink/PushNotificationReceiver.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import android.app.Notification;
4 | import android.app.NotificationChannel;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.content.Context;
8 | import android.content.Intent;
9 | import android.content.IntentFilter;
10 | import android.content.pm.ApplicationInfo;
11 | import android.content.pm.PackageManager;
12 | import android.graphics.Bitmap;
13 | import android.graphics.BitmapFactory;
14 | import android.graphics.Canvas;
15 | import android.graphics.Color;
16 | import android.graphics.PixelFormat;
17 | import android.graphics.drawable.Drawable;
18 | import android.os.Build;
19 | import android.support.annotation.NonNull;
20 | import android.support.annotation.Nullable;
21 | import android.support.annotation.RequiresApi;
22 | import android.support.v4.app.NotificationCompat;
23 | import android.support.v4.app.TaskStackBuilder;
24 | import android.text.TextUtils;
25 | import android.util.Log;
26 | import android.view.View;
27 |
28 | import java.net.URL;
29 |
30 | /**
31 | * It's designed to register in application to work as a global push message receiver.
32 | */
33 | public abstract class PushNotificationReceiver extends PushReceiver {
34 |
35 | public static void register(@NonNull Context context, @NonNull PushNotificationReceiver receiver) {
36 | if (isMainProcess(context)) {
37 | IntentFilter intentFilter = new IntentFilter();
38 | intentFilter.addAction(PushNotificationReceiver.buildPushAction(context));
39 | context.registerReceiver(receiver, intentFilter,
40 | PushNotificationReceiver.buildPermission(context), null);
41 | }
42 | }
43 |
44 | /**
45 | * Override to provider small icon in push notification
46 | */
47 | public abstract int getSmallIcon(@NonNull Context context);
48 |
49 | @Override
50 | public void onAppLinkReceive(@NonNull Context context, @NonNull final AppLink appLink) {
51 | if (!appLink.showNotification(context)) {
52 | return;
53 | }
54 |
55 | // do any work but don't open activity
56 | appLink.onExecute(context);
57 |
58 | // build intent for starting activity
59 | Intent intent = appLink.onStartActivity(context);
60 |
61 | // not all appLinks have a target activity,
62 | // appLinks without target activity may do other works like send broadcast.
63 | if (intent == null) {
64 | return;
65 | }
66 |
67 | // no title cannot show notification
68 | if (TextUtils.isEmpty(appLink.getTitle())) {
69 | Log.d(AppLink.TAG, "no title cannot show notification for " + appLink.getAppLink());
70 | return;
71 | }
72 |
73 | // create notification builder
74 | TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
75 | stackBuilder.addParentStack(intent.getComponent());
76 | stackBuilder.addNextIntent(intent);
77 |
78 | intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
79 | PendingIntent pendingIntent = stackBuilder.getPendingIntent(0,
80 | PendingIntent.FLAG_UPDATE_CURRENT);
81 | final NotificationCompat.Builder builder = appLink.getBuilder(
82 | context,
83 | appLink.getTitle(),
84 | appLink.getSubTitle());
85 | builder.setSmallIcon(getSmallIcon(context));
86 | builder.setLargeIcon(getAppIcon(context));
87 | builder.setContentIntent(pendingIntent);
88 | builder.setDefaults(Notification.DEFAULT_ALL);
89 |
90 | final NotificationManager manager = (NotificationManager) context.getApplicationContext()
91 | .getSystemService(Context.NOTIFICATION_SERVICE);
92 | if (manager != null) {
93 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
94 | NotificationChannel channel = getNotificationChannel(context);
95 | manager.createNotificationChannel(channel);
96 | builder.setChannelId(channel.getId());
97 | }
98 |
99 | // notification with large picture
100 | if (!TextUtils.isEmpty(appLink.getPicUrl())) {
101 | new Thread() {
102 | @Override
103 | public void run() {
104 | try {
105 | URL url = new URL(appLink.getPicUrl());
106 | Bitmap bitmap = BitmapFactory.decodeStream(url.openStream());
107 | builder.setLargeIcon(bitmap);
108 | builder.setStyle(new NotificationCompat
109 | .BigPictureStyle()
110 | .bigPicture(bitmap)
111 | .bigLargeIcon(null));
112 | manager.notify(appLink.getId(), builder.build());
113 | } catch (Exception ignored) {
114 | }
115 | }
116 | }.start();
117 | } else {
118 | manager.notify(appLink.getId(), builder.build());
119 | }
120 | }
121 | }
122 |
123 | @RequiresApi(api = Build.VERSION_CODES.O)
124 | public static NotificationChannel getNotificationChannel(@NonNull Context context) {
125 | NotificationChannel channel = new NotificationChannel(context.getPackageName(),
126 | getAppName(context), NotificationManager.IMPORTANCE_HIGH);
127 | channel.enableLights(true);
128 | channel.setLightColor(Color.GREEN);
129 | channel.setShowBadge(true);
130 | channel.enableLights(true);
131 | channel.enableVibration(true);
132 | channel.setLockscreenVisibility(View.VISIBLE);
133 | return channel;
134 | }
135 |
136 | @Nullable
137 | private static CharSequence getAppName(@NonNull Context context) {
138 | try {
139 | PackageManager packageManager = context.getApplicationContext().getPackageManager();
140 | ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
141 | return packageManager.getApplicationLabel(applicationInfo);
142 | } catch (PackageManager.NameNotFoundException e) {
143 | return "";
144 | }
145 | }
146 |
147 | @Nullable
148 | static Bitmap getAppIcon(@NonNull Context context) {
149 | PackageManager manager;
150 | ApplicationInfo info;
151 |
152 | try {
153 | manager = context.getApplicationContext().getPackageManager();
154 | info = manager.getApplicationInfo(context.getPackageName(), 0);
155 | Drawable drawable = manager.getApplicationIcon(info);
156 | return drawableToBitmap(drawable);
157 | } catch (PackageManager.NameNotFoundException ignored) {
158 | return null;
159 | }
160 | }
161 |
162 | private static Bitmap drawableToBitmap(Drawable drawable) {
163 | int w = drawable.getIntrinsicWidth();
164 | int h = drawable.getIntrinsicHeight();
165 |
166 | Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ?
167 | Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
168 | Bitmap bitmap = Bitmap.createBitmap(w, h, config);
169 | Canvas canvas = new Canvas(bitmap);
170 | drawable.setBounds(0, 0, w, h);
171 | drawable.draw(canvas);
172 | return bitmap;
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/library/src/main/java/com/feizhang/applink/PushReceiver.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import android.app.ActivityManager;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.support.annotation.NonNull;
8 | import android.text.TextUtils;
9 | import android.util.Log;
10 |
11 | import java.util.List;
12 |
13 | /**
14 | * It's a base push receiver, it main work is to save appLink into db if need,
15 | * after that it delivers push message to sub-receiver.
16 | */
17 | public abstract class PushReceiver extends BroadcastReceiver {
18 | public static final String EXTRA_APP_LINK = "appLink";
19 | public static final String EXTRA_TITLE = "title";
20 | public static final String EXTRA_SUB_TITLE = "subTitle";
21 | public static final String EXTRA_PIC_URL = "picUrl";
22 | public static final String EXTRA_REFRESH_ONLY = "refreshOnly";
23 |
24 | public static String buildPushAction(@NonNull Context context) {
25 | return context.getPackageName() + ".appLink.intent.action.PUSH";
26 | }
27 |
28 | public static String buildPermission(@NonNull Context context) {
29 | return context.getPackageName() + ".appLink.PERMISSION";
30 | }
31 |
32 | public abstract void onAppLinkReceive(@NonNull Context context, @NonNull AppLink appLink);
33 |
34 | public abstract String getAccount(@NonNull Context context);
35 |
36 | @Override
37 | public final void onReceive(Context context, Intent intent) {
38 | String action = intent.getAction();
39 | if (TextUtils.isEmpty(action)) {
40 | Log.e(AppLink.TAG, "no action in intent");
41 | return;
42 | }
43 |
44 | // check received message should be handled by current receiver
45 | if (TextUtils.equals(buildPushAction(context), action)) {
46 | String appLink = intent.getStringExtra(EXTRA_APP_LINK);
47 | String title = intent.getStringExtra(EXTRA_TITLE);
48 | String subTitle = intent.getStringExtra(EXTRA_SUB_TITLE);
49 | String picUrl = intent.getStringExtra(EXTRA_PIC_URL);
50 | boolean refresh = intent.getBooleanExtra(EXTRA_REFRESH_ONLY, false);
51 |
52 | AppLink link = AppLinkUtils.parseAppLink(context, appLink);
53 | if (link == null) {
54 | Log.e(AppLink.TAG, appLink + " cannot be resolved");
55 | return;
56 | }
57 |
58 | // try save it into db
59 | link.setId((int) (System.currentTimeMillis() / 1000));
60 | link.setTitle(title);
61 | link.setSubTitle(subTitle);
62 | link.setPicUrl(picUrl);
63 | link.setAccount(getAccount(context));
64 |
65 | if (link.shouldSave() && !refresh) {
66 | PushMessageService.getInstance(context).save(link);
67 | }
68 |
69 | // deliver message to sub-receiver
70 | onAppLinkReceive(context, link);
71 | }
72 | }
73 |
74 | protected static boolean isMainProcess(@NonNull Context context) {
75 | ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE));
76 | List processes = am.getRunningAppProcesses();
77 | String mainProcessName = context.getPackageName();
78 | int myPid = android.os.Process.myPid();
79 | for (ActivityManager.RunningAppProcessInfo info : processes) {
80 | if (info.pid == myPid && mainProcessName.equals(info.processName)) {
81 | return true;
82 | }
83 | }
84 |
85 | return false;
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/library/src/main/java/com/feizhang/applink/RedDotView.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import android.content.Context;
4 | import android.support.annotation.NonNull;
5 | import android.support.v7.widget.AppCompatImageView;
6 | import android.util.AttributeSet;
7 | import android.util.Log;
8 | import android.view.View;
9 |
10 | import java.util.ArrayList;
11 | import java.util.Arrays;
12 | import java.util.List;
13 |
14 | /**
15 | * Created by zhangfei on 2016/1/19.
16 | */
17 | public class RedDotView extends AppCompatImageView {
18 | private String mAccount = "no-account";
19 |
20 | private List mAppLinks = new ArrayList<>();
21 |
22 | private PushContentReceiver mContentReceiver = new PushContentReceiver() {
23 |
24 | @Override
25 | public String getAccount(@NonNull Context context) {
26 | return mAccount;
27 | }
28 |
29 | @Override
30 | public List getAppLinks() {
31 | return mAppLinks;
32 | }
33 |
34 | @Override
35 | public boolean onReceive(@NonNull Context context, @NonNull AppLink appLink) {
36 | Log.d("DotView", "onReceive appLink: " + appLink);
37 |
38 | if (mAppLinks == null || mAppLinks.size() == 0) {
39 | return false;
40 | }
41 |
42 | boolean haveUnReadMsg = false;
43 | for (String item : mAppLinks) {
44 | if (PushMessageService.getInstance(getContext()).haveUnread(item, getAccount(context))) {
45 | haveUnReadMsg = true;
46 | break;
47 | }
48 | }
49 |
50 | setVisibility(haveUnReadMsg ? VISIBLE : GONE);
51 | return false;
52 | }
53 | };
54 |
55 | public RedDotView(@NonNull Context context) {
56 | this(context, null);
57 | }
58 |
59 | public RedDotView(@NonNull Context context, AttributeSet attrs) {
60 | this(context, attrs, 0);
61 | }
62 |
63 | public RedDotView(@NonNull Context context, AttributeSet attrs, int defStyleAttr) {
64 | super(context, attrs, defStyleAttr);
65 | setImageResource(R.drawable.red_dot_view);
66 | }
67 |
68 | @Override
69 | protected void onAttachedToWindow() {
70 | super.onAttachedToWindow();
71 | PushContentReceiver.register(getContext(), mContentReceiver, false);
72 | checkVisible();
73 | }
74 |
75 | @Override
76 | protected void onDetachedFromWindow() {
77 | super.onDetachedFromWindow();
78 | PushContentReceiver.unregister(getContext(), mContentReceiver);
79 | }
80 |
81 | /**
82 | * For some case, push message is private, so need to provide account.
83 | *
84 | * @param account account maybe phone number or account id
85 | */
86 | public void setAccount(String account) {
87 | mAccount = account;
88 | }
89 |
90 | /**
91 | * Bind push appLink with red dot view, so that it can receive push message automatically.
92 | */
93 | public void setAppLinks(String... appLinks) {
94 | mAppLinks.clear();
95 | mAppLinks.addAll(Arrays.asList(appLinks));
96 | }
97 |
98 | /**
99 | * Remove red dot
100 | */
101 | public void remove() {
102 | if (mAppLinks == null || mAppLinks.size() == 0) {
103 | return;
104 | }
105 |
106 | // remove message when clicked
107 | for (String appLink : mAppLinks) {
108 | PushMessageService.getInstance(getContext()).delete(appLink, mAccount);
109 | AppLinkUtils.refreshAppLink(getContext(), appLink);
110 | }
111 | }
112 |
113 | private void checkVisible() {
114 | if (mAppLinks == null || mAppLinks.size() == 0) {
115 | return;
116 | }
117 |
118 | boolean exist = PushMessageService.getInstance(getContext()).haveUnread(
119 | mAppLinks, mAccount);
120 | setVisibility(exist ? View.VISIBLE : GONE);
121 | }
122 | }
--------------------------------------------------------------------------------
/library/src/main/res/drawable/red_dot_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
9 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | library
3 |
4 |
--------------------------------------------------------------------------------
/library/src/test/java/com/feizhang/applink/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.feizhang.applink;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':app', ':library'
2 |
--------------------------------------------------------------------------------