All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avos.avoscloud.AVNotificationManager Maven / Gradle / Ivy

The newest version!
package com.avos.avoscloud;

import android.annotation.TargetApi;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.alibaba.fastjson.JSON;
import com.avos.avoscloud.utils.StringUtils;
import com.avos.avospush.session.StaleMessageDepot;

import org.json.JSONException;
import org.json.JSONObject;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by wli on 2017/6/16.
 * 用来处理所有和 notification 相关的逻辑
 */

class AVNotificationManager {
  private static final String PUSH_INTENT_KEY = "com.avoscloud.push";
  private static final String PUSH_MESSAGE_DEPOT = "com.avos.push.message";
  private static final String LOGTAG = "AVNotificationManager";
  private static final String AV_PUSH_SERVICE_APP_DATA = "AV_PUSH_SERVICE_APP_DATA";
  private static final String ICON_KEY = "_notification_icon";

  private static final Random random = new Random();
  private final ConcurrentHashMap defaultPushCallback =
    new ConcurrentHashMap();
  private int notificationIcon;
  private final StaleMessageDepot depot;
  private Context context;

  private static AVNotificationManager notificationManager;

  public synchronized static AVNotificationManager getInstance() {
    if (null == notificationManager) {
      notificationManager = new AVNotificationManager(AVOSCloud.applicationContext);
    }
    return notificationManager;
  }

  private AVNotificationManager(Context context) {
    this.context = context;
    // Use application small icon by default.
    this.notificationIcon = context.getApplicationInfo().icon;

    depot = new StaleMessageDepot(PUSH_MESSAGE_DEPOT);
    readDataFromCache();
    if (AVOSCloud.isDebugLogEnabled()) {
      Log.d(LOGTAG, "Init AppManager Done, read data from cache: " + defaultPushCallback.size());
    }
  }

  @SuppressWarnings("unchecked")
  private void sendNotification(String from, String msg) throws IllegalArgumentException {
    Intent resultIntent = buildUpdateIntent(from, msg, null);
    sendNotification(from, msg, resultIntent);
  }

  private Intent buildUpdateIntent(String channel, String msg, String action) {
    Intent updateIntent = new Intent();
    if (action != null) {
      updateIntent.setAction(action);
    }
    updateIntent.putExtra(PUSH_INTENT_KEY, 1);
    updateIntent.putExtra("com.avos.avoscloud.Channel", channel);
    updateIntent.putExtra("com.avoscloud.Channel", channel);
    updateIntent.putExtra("com.avos.avoscloud.Data", msg);
    updateIntent.putExtra("com.avoscloud.Data", msg);
    updateIntent.setPackage(context.getPackageName());
    return updateIntent;
  }

  private void sendBroadcast(String channel, String msg, String action) {
    Intent updateIntent = buildUpdateIntent(channel, msg, action);
    if (AVOSCloud.showInternalDebugLog()) {
      LogUtil.avlog.d("action: " + updateIntent.getAction());
    }
    context.sendBroadcast(updateIntent);
    if (AVOSCloud.showInternalDebugLog()) {
      LogUtil.avlog.d("sent broadcast");
    }
  }

  /**
   * 给订阅了小米 action 的 broadcastreciver 发 broadcast
   * @param channel
   * @param msg
   */
  private void sendNotificationBroadcast(String channel, String msg, String action) {
    Intent updateIntent = buildUpdateIntent(channel, msg, action);
    if (AVOSCloud.showInternalDebugLog()) {
      LogUtil.avlog.d("action: " + updateIntent.getAction());
    }
    context.sendBroadcast(updateIntent);
    if (AVOSCloud.showInternalDebugLog()) {
      LogUtil.avlog.d("sent broadcast");
    }
  }

  private String getChannel(String msg) {
    return AVUtils.getJSONValue(msg, "_channel");
  }

  private String getAction(String msg) {
    return AVUtils.getJSONValue(msg, "action");
  }

  /**
   * 是否为静默推送
   * 默认值为 false,及如果 server 并没有传 silent 字段,则默认为通知栏推送
   * @param message
   * @return
   */
  private boolean getSilent(String message) {
    if (!AVUtils.isBlankString(message)) {
      try {
        JSONObject object = new JSONObject(message);
        return (object.optBoolean("silent", false));
      } catch (JSONException e) {
        if (AVOSCloud.isDebugLogEnabled()) {
          LogUtil.avlog.e("getSilent failed.", e);
        }
      }
    }
    return false;
  }

  private Date getExpiration(String msg) {
    String result = "";
    try {
      JSONObject object = new JSONObject(msg);
      result = object.getString("_expiration_time");
    } catch (JSONException e) {
      // LogUtil.avlog.i(e);
      // 不应该当做一个Error发出来,既然expire仅仅是一个option的数据
      // Log.e(LOGTAG, "Get expiration date error.", e);
    }
    if (AVUtils.isBlankString(result)) {
      return null;
    }
    Date date = AVUtils.dateFromString(result);
    return date;
  }

  /**
   * 处理 GCM 的透传消息
   * @param channel
   * @param action
   * @param message
   */
  void processGcmMessage(String channel, String action, String message) {
    if (channel == null || !containsDefaultPushCallback(channel)) {
      channel = AVOSCloud.applicationId;
      if (action != null) {
        sendBroadcast(channel, message, action);
      } else {
        sendNotification(channel, message);
      }
    }
  }

  /**
   * 处理透传消息(华为只有透传)
   * @param message
   */
  void processMixPushMessage(String message) {
    if (!AVUtils.isBlankString(message)) {
      String channel = getChannel(message);
      if (channel == null || !containsDefaultPushCallback(channel)) {
        channel = AVOSCloud.applicationId;
      }

      String action = getAction(message);
      boolean slient = getSilent(message);
      if (action != null) {
        sendBroadcast(channel, message, action);
      } else if (!slient) {
        sendNotification(channel, message);
      } else {
        LogUtil.avlog.e("ignore push silent message: " + message);
      }
    }
  }

  /**
   * 处理混合推送通知栏消息点击后的事件(现在支持小米、魅族,华为不支持)
   * 处理逻辑:如果是自定义 action 的消息点击事件,则发送 broadcast,否则按照 sdk 自有逻辑打开相应的 activity
   * @param message
   */
  void processMixNotification(String message, String defaultAction) {
    if (StringUtils.isBlankString(message)) {
      LogUtil.log.e(LOGTAG, "message is empty, ignore.");
    } else {
      String channel = getChannel(message);
      if (channel == null || !containsDefaultPushCallback(channel)) {
        channel = AVOSCloud.applicationId;
      }

      String action = getAction(message);
      if (null != action) {
        sendNotificationBroadcast(channel, message, defaultAction);
      } else {
        String clsName = getDefaultPushCallback(channel);
        if (StringUtils.isBlankString(clsName)) {
          LogUtil.log.e(LOGTAG, "className is empty, ignore.");
        } else {
          Intent intent = buildUpdateIntent(channel, message, null);
          ComponentName cn = new ComponentName(context, clsName);
          intent.setComponent(cn);
          intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
          PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
          try {
            pendingIntent.send();
          } catch (PendingIntent.CanceledException e) {
            LogUtil.log.e(LOGTAG,"Ocurred PendingIntent.CanceledException", e);
          }
        }
      }
    }
  }

  /**
   * 处理 LeanCloud 自有 socket 传过来的推送消息
   * @param message
   * @param messageId
   */
  void processPushMessage(String message, String messageId) {
    try {
      String channel = getChannel(message);
      if (channel == null || !containsDefaultPushCallback(channel)) {
        channel = AVOSCloud.applicationId;
      }

      Date expiration = getExpiration(message);
      if (expiration != null) {
        if (expiration.before(new Date())) {
          LogUtil.avlog.d("message expired:" + message);
          return;
        }
      }

      if (depot.putStableMessage(messageId)) {
        String action = getAction(message);
        if (action != null) {
          sendBroadcast(channel, message, action);
        } else {
          sendNotification(channel, message);
        }
      }
    } catch (Exception e) {
      LogUtil.avlog.e("Process notification failed.", e);
    }
  }

  /**
   * 处理混合推送到达事件(暂只支持小米)
   * @param message
   * @param action
   */
  void porcessMixNotificationArrived(String message, String action) {
    if (!AVUtils.isBlankString(message) && !AVUtils.isBlankString(action)) {
      String channel = getChannel(message);
      if (channel == null || !containsDefaultPushCallback(channel)) {
        channel = AVOSCloud.applicationId;
      }

      sendNotificationBroadcast(channel, message, action);
    }
  }

  private void readDataFromCache() {
    SharedPreferences appData = context.getSharedPreferences(AV_PUSH_SERVICE_APP_DATA, Context.MODE_PRIVATE);
    for (Map.Entry entry : appData.getAll().entrySet()) {
      String channel = (String) entry.getKey();
      if (channel.equals(ICON_KEY)) {
        try {
          notificationIcon = Integer.valueOf((String) entry.getValue());
        } catch (Exception e) {
          // ignore;
        }
      } else {
        String defaultCls = String.valueOf(entry.getValue());
        defaultPushCallback.put(channel, defaultCls);
      }
    }
  }

  private int getNotificationIcon() {
    return notificationIcon;
  }

  void setNotificationIcon(int icon) {
    notificationIcon = icon;
    AVPersistenceUtils.sharedInstance().savePersistentSettingString(AV_PUSH_SERVICE_APP_DATA,
      ICON_KEY, String.valueOf(icon));
  }

  void addDefaultPushCallback(String channel, String clsName) {
    defaultPushCallback.put(channel, clsName);
    AVPersistenceUtils.sharedInstance().savePersistentSettingString(AV_PUSH_SERVICE_APP_DATA,
      channel, String.valueOf(clsName));
  }

  void removeDefaultPushCallback(String channel) {
    defaultPushCallback.remove(channel);
    AVPersistenceUtils.sharedInstance().removePersistentSettingString(AV_PUSH_SERVICE_APP_DATA,
      channel);
  }

  private boolean containsDefaultPushCallback(String channel) {
    return defaultPushCallback.containsKey(channel);
  }

  String getDefaultPushCallback(String channel) {
    return AVUtils.isBlankString(channel) ? null : defaultPushCallback.get(channel);
  }

  public int size() {
    return defaultPushCallback.size();
  }

  @TargetApi(Build.VERSION_CODES.O)
  private void sendNotification(String from, String msg, Intent resultIntent) {
    String clsName = getDefaultPushCallback(from);
    if (AVUtils.isBlankString(clsName)) {
      throw new IllegalArgumentException(
        "No default callback found, did you forget to invoke setDefaultPushCallback?");
    }
    int lastIndex = clsName.lastIndexOf(".");
    if (lastIndex != -1) {
      // String packageName = clsName.substring(0, lastIndex);
      // Log.d(LOGTAG, "packageName: " + packageName);
      int notificationId = random.nextInt();
      ComponentName cn = new ComponentName(context, clsName);
      resultIntent.setComponent(cn);
      PendingIntent contentIntent =
        PendingIntent.getActivity(context, notificationId, resultIntent, 0);
      String sound = getSound(msg);
      Notification notification = null;
      if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
        NotificationCompat.Builder mBuilder =
            new NotificationCompat.Builder(context)
                .setSmallIcon(getNotificationIcon())
                .setContentTitle(getTitle(msg)).setAutoCancel(true).setContentIntent(contentIntent)
                .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
                .setContentText(getText(msg));
        notification = mBuilder.build();
      } else {
        Notification.Builder builder = new Notification.Builder(context)
            .setSmallIcon(getNotificationIcon())
            .setContentTitle(getTitle(msg))
            .setAutoCancel(true).setContentIntent(contentIntent)
            .setDefaults(Notification.DEFAULT_VIBRATE | Notification.DEFAULT_SOUND)
            .setContentText(getText(msg))
            .setChannelId(PushService.DefaultChannelId);

        notification = builder.build();
      }
      if (sound != null && sound.trim().length() > 0) {
        notification.sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + sound);
      }
      NotificationManager manager =
          (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
      manager.notify(notificationId, notification);
    } else {
      Log.e(LOGTAG, "Class name is invalid, which must contain '.': " + clsName);
    }
  }

  private String getTitle(String msg) {
    return getValue(msg, "title");
  }

  private String getSound(String msg) {
    return getValue(msg, "sound");
  }

  private String getValue(String msg, String key) {
    String title = AVUtils.getJSONValue(msg, key);
    if (title != null && title.trim().length() > 0) {
      return title;
    } else {
      Map jsonMap = JSON.parseObject(msg, HashMap.class);
      if (jsonMap == null || jsonMap.isEmpty()) return getApplicationName();

      Map data = (Map) jsonMap.get("data");
      if (data == null || data.isEmpty()) {
        return getApplicationName();
      }
      Object val = data.get(key);
      if (val != null) {
        return val.toString();
      } else {
        return getApplicationName();
      }
    }
  }

  private String getApplicationName() {
    final PackageManager pm = context.getPackageManager();
    ApplicationInfo ai;
    try {
      ai = pm.getApplicationInfo(context.getPackageName(), 0);
    } catch (final PackageManager.NameNotFoundException e) {
      ai = null;
    }
    final String applicationName =
      (String) (ai != null ? pm.getApplicationLabel(ai) : "Notification");
    return applicationName;
  }

  @SuppressWarnings("unchecked")
  private String getText(String msg) {
    String text = AVUtils.getJSONValue(msg, "alert");
    if (text != null && text.trim().length() > 0) {
      return text;
    } else {
      Map jsonMap = JSON.parseObject(msg, HashMap.class);
      if (jsonMap == null || jsonMap.isEmpty()) return null;

      Map data = (Map) jsonMap.get("data");
      if (data == null || data.isEmpty()) {
        return null;
      }
      Object val = data.get("message");
      if (val != null) {
        return val.toString();
      } else {
        return null;
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy