この条件が Google Play Services のバージョンによって異なり、7.8.0 から 8.4.0 に変更したときにはまったので調べた結果をまとめておきます。
(調べたのは 7.8.0 と 8.4.0 で、この間の他のバージョンは調べていません。)
7.8.0
7.8.0 では、送信する JSON に "notification" payload があり、その中の "icon" の値が null じゃない場合は onMessageReceived() が呼ばれずに GcmListenerService が Notification を出します。このときの Notification には "notification" payload で指定された "title" や "body" が使われます。"title" の値が空のときはアプリ名が利用されます。
notification payload の形式については https://developers.google.com/cloud-messaging/http-server-ref#notification-payload-support 参照
つまり
"notification" の "icon" == null → onMessageReceived()
"notification" の "icon" != null → GcmListenerService が Notification 発行
8.4.0
8.4.0 では条件が大きく変わります。
"content_available" が false (指定がない場合も false)かつ "notification" の "icon" == null の場合 onMessageReceived() が呼ばれます。そうでない場合、アプリが foreground にあれば onMessageReceived() が呼ばれ、background なら GcmListenerService が Notification を出します。
つまり
"content_available" == false && "notification" の "icon" == null → onMessageReceived()
"content_available" == true || "notification" の "icon" != null →
アプリが foreground → onMessageReceived()
アプリが background → GcmListenerService が Notification 発行
"content_available" を true にしていると、7.8.0 から 8.4.0 に変更したときに今まで background でも onMessageReceived() が呼ばれていたのに呼ばれなくなります。全然ドキュメントにも書いてないしはまりました。。。
7.8.0 のコード
GcmListenerService
private void zzt(Bundle var1) {
var1.remove("message_type");
var1.remove("android.support.content.wakelockid");
if(zza.zzu(var1)) {
zza.zzay(this).zzv(var1); // "notification" のデータを使って Notification を発行している
} else {
String var2 = var1.getString("from");
var1.remove("from");
this.onMessageReceived(var2, var1);
}
}
zza
static boolean zzu(Bundle var0) {
return zzb(var0, "gcm.n.icon") != null;
}
"gcm.n.icon" は "notification" payload の "icon" に対応している。
8.4.0 のコード
GcmListenerService
private void zzq(Intent var1) {
Bundle var2 = var1.getExtras();
var2.remove("message_type");
var2.remove("android.support.content.wakelockid");
if(zzb.zzy(var2)) {
if(!zzb.zzaI(this)) { // 同じプロセスの Activity が foreground かチェック、foreground じゃない場合 if の中に入る
zzb.zzc(this, this.getClass()).zzA(var2); // "notification" のデータを使って Notification を発行している
return;
}
if(zzx(var1.getExtras())) {
zza.zzh(this, var1);
}
zzb.zzz(var2);
}
String var3 = var2.getString("from");
var2.remove("from");
zzw(var2);
this.onMessageReceived(var3, var2);
}
zzb
static boolean zzy(Bundle var0) {
return "1".equals(zze(var0, "gcm.n.e")) || zze(var0, "gcm.n.icon") != null;
}
"gcm.n.e" は "content_available" に対応している。
"gcm.n.icon" は "notification" payload の "icon" に対応している。
zzb
static boolean zzaI(Context var0) {
KeyguardManager var1 = (KeyguardManager)var0.getSystemService("keyguard");
if(var1.inKeyguardRestrictedInputMode()) {
return false;
} else {
int var2 = Process.myPid();
ActivityManager var3 = (ActivityManager)var0.getSystemService("activity");
List var4 = var3.getRunningAppProcesses();
if(var4 != null) {
Iterator var5 = var4.iterator();
while(var5.hasNext()) {
RunningAppProcessInfo var6 = (RunningAppProcessInfo)var5.next();
if(var6.pid == var2) {
return var6.importance == 100;
}
}
}
return false;
}
}