I'm trying to build an app that when receiving GCM message from Google's GCM server, then I can show a notification on the top of the screen like Facebook's app Messenger.
My problem is: The code
windowManager.addView(chatHead, params);
in function addView() showed below has no effect even it was called. Does anyone know what the problem is? Thanks for help!
The following is the detail that how I build my app:
First I follow How to make a Facebook Messenger-like notification like this in Android
I have tested the function "addView()" by creating a new service and call it in onCreate() and it did work. (It would appear an image on my HTC screen even when my activity is paused.)
public void addView(){
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.climia);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 0;
windowManager.addView(chatHead, params);
Log.i("addview","after windowManager.addView");
}
Second, I faced the problem that "GcmListenerService" doesn't have any looper to deal with UI update; thus I follow https://github.com/quakerntj/SendMesageToPhoneByGCM/blob/master/src/com/ntj/GcmTest/MyGcmListenerService.java to add handler and looper to handle WindowManager.
class MyThread extends Thread {
private Context mContext = null;
private Handler mHandler = null;
public MyThread(String s, Context context) {
super(s);
this.mContext = context;
}
public void setMessage(String message) {
Message msg = Message.obtain(mHandler, 0, message);
mHandler.sendMessage(msg);
}
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.i("Handler", "start handleMessage");
addView();
getLooper().quit();
}
};
Looper.loop();
}
}
Third, I use the thread created above to trigger addView whenever my app receives a GCM message:
@Override
public void onMessageReceived(String from, Bundle data) {
GCMData GCMdata = new GCMData();
GCMdata.title = data.getString("title");
GCMdata.body = data.getString("body");
GCMdata.detail = data.getString("detail");
GCMdata.type = data.getString("type");
/*
show a notification indicating to the user
*/ sendNotification(GCMdata);
mThread = new MyThread("nitamaGCM", this);
mThread.start();
synchronized (this) {
try {
// Wait the looper begin
wait(10);
} catch (InterruptedException e) {
}
}
mThread.setMessage(GCMdata.body);
}
PS: The whole source code is below:
public class MyGcmListenerService extends GcmListenerService {
public class GCMData{
String title;
String body;
String detail;
String type;
}
private static final String TAG = "MyGcmListenerService";
private WindowManager windowManager;
private ImageView chatHead;
private MyThread mThread = null;
/**
* Called when message is received.
*
* @param from SenderID of the sender.
* @param data Data bundle containing message data as key/value pairs.
* For Set of keys use data.keySet().
*/
// [START receive_message]
@Override
public void onMessageReceived(String from, Bundle data) {
GCMData GCMdata = new GCMData();
GCMdata.title = data.getString("title");
GCMdata.body = data.getString("body");
GCMdata.detail = data.getString("detail");
GCMdata.type = data.getString("type");
/*
show a notification indicating to the user
*/ sendNotification(GCMdata);
mThread = new MyThread("nitamaGCM", this);
mThread.start();
synchronized (this) {
try {
// Wait the looper begin
wait(10);
} catch (InterruptedException e) {
}
}
mThread.setMessage(GCMdata.body);
}
// [END receive_message]
/**
* Create and show a simple notification containing the received GCM message.
*
* @param message GCM message received.
*/
private void sendNotification(GCMData GCMdata) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(
this,
0 /* Request code */,
intent,
PendingIntent.FLAG_ONE_SHOT
);
Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.climia) //required, small icon in notification area
.setContentTitle(GCMdata.title) //required, notification title in notification drawer
.setContentText(GCMdata.body) //required, notification content in notification drawer
.setContentInfo(GCMdata.detail)
.setAutoCancel(true) //after clicking notification, dismiss notification
.setSound(defaultSoundUri)
.setVibrate(new long[]{0, 100, 100, 200}) //Vibrate format: stop, vibrate, stop, vibrate, ... unit: 1/1000 s
//.setDeleteIntent(pendingIntent) //trigger intent when the notification is cleared explicitly by the user
.setContentIntent(pendingIntent)
.setOnlyAlertOnce(true); //same notification ID will not Vibrate or Sound again
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(
Integer.parseInt(GCMdata.type) /* ID of notification */,
notificationBuilder.build());
}
public void addView(){
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
chatHead = new ImageView(this);
chatHead.setImageResource(R.drawable.climia);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.WRAP_CONTENT,
WindowManager.LayoutParams.TYPE_PHONE,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
PixelFormat.TRANSLUCENT);
params.gravity = Gravity.TOP | Gravity.LEFT;
params.x = 0;
params.y = 0;
windowManager.addView(chatHead, params);
Log.i("addview","after windowManager.addView");
}
class MyThread extends Thread {
private Context mContext = null;
private Handler mHandler = null;
public MyThread(String s, Context context) {
super(s);
this.mContext = context;
}
public void setMessage(String message) {
Message msg = Message.obtain(mHandler, 0, message);
mHandler.sendMessage(msg);
}
@Override
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
Log.i("Handler", "start handleMessage");
addView();
getLooper().quit();
}
};
Looper.loop();
}
}}