Android Bluetooth Scanner Not Running as a Service - java

I'm trying to run bluetooth beacon scanner as a service, so when the application is not active, when beacon is detected, a notification can.
The Service Code (Java) :
public class BtService extends Service {
public static final String TAG = BtService.class.getSimpleName();
private ScanCallback mScanCallback;
private BluetoothAdapter btAdapter;
private BluetoothLeScanner btScanner;
private boolean mIsScanning = false;
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "OnCreate Service");
final BluetoothManager btManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
btAdapter = btManager.getAdapter();
initBtCallBack();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "OnStartCommand Service");
btStartScanning();
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "Destroy");
btStopScanning();
}
/**
* BlueTooth CallBack
*/
private void initBtCallBack() {
Log.d(TAG, "InitBtCallBack");
try {
btScanner = btAdapter.getBluetoothLeScanner();
} catch (Exception e) {
e.printStackTrace();
}
mScanCallback = new ScanCallback() {
#Override
public void onScanResult(int callbackType, ScanResult result) {
Log.i(TAG, "Something found : " + result.getDevice().getAddress());
BluetoothDevice device = result.getDevice();
Log.i(TAG, "btDevice : " + device.toString());
Log.i(TAG, "result : " + result.toString());
btUseBeacon(result);
}
};
}
private void btStartScanning() {
if (btScanner != null) {
if(! mIsScanning) {
Log.i(TAG, "START scanning...");
myBeacons.clear();
loadMyBeaconList();
mIsScanning = true;
btScanner.startScan(mScanCallback);
}
} else {
Log.i(TAG, "CANNOT START Scanning");
}
}
private void btStopScanning() {
if(mIsScanning) {
Log.i(TAG, "STOP scanning");
mIsScanning = false;
btScanner.stopScan(mScanCallback);
saveMyBeaconList();
}
}
}
There also a BroadcastReceiver Class to start the Service
public class BtStartServiceReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent service = new Intent(context, BtService.class);
context.startService(service);
}
}
Déclaration in the Manifest.xml, between the . Permission for Boot_Completed as also been added.
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<service
android:name=".BtService"
android:icon="#mipmap/ic_launcher"
android:enabled="true">
</service>
<receiver android:name=".BtStartServiceReceiver" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
When the application is active or not, seems it does not work. In the logcat, I don't see any of the LOG i added in the code of the service.
When I kill the application, the logcat shows that the application is restarting, but nothing about Logs in code.
When I try to run this code adapted for an Activity, It works, beacon are detected and can make notification.
I don't wan't to use any beacon library or SDK, as I work with generic beacon.
Thank's for your help.

Related

Android SMS receiver call twice

I would like to notify the incoming sms message. I implemented the BroadcastReceiver for SMS receiver. And I also implemented the service for BOOT_COMPLETED action. Because the receiver cannot be registered if the device is reboot. When I launch the apps, that only call onReceiver once. But I reboot the device and start the BOOT_COMPLETED service. That will make the onReceive method call twice. But I don't know why. I confirm I only register the receiver once.
ps: When I reboot the device, I received the log order is enable receiver, register receiver, enable receive, onReceived, onReceived
Here is my code:
AutoStartService.java
public class AutoStartService extends Service {
private SmsReceiver smsReceiver;
public static boolean isStarted = false;
#Override
public void onCreate() {
super.onCreate();
isStarted = true;
if(!SmsReceiver.isEnableReceiver && smsReceiver == null) {
smsReceiver = new SmsReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.provider.Telephony.SMS_RECEIVED");
registerReceiver(smsReceiver, intentFilter);
Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
Log.e("AAA", "register receiver");
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
isStarted = false;
Toast.makeText(this, "Service Destroy", Toast.LENGTH_LONG).show();
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
BootCompleteReceiver.java
public class BootCompleteReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if(!AutoStartService.isStarted) {
new Handler().postDelayed(() -> {
Intent service = new Intent(context, AutoStartService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(service);
} else {
context.startService(service);
}
}, 500);
}
}
}
SmsReceiver.java
public class SmsReceiver extends BroadcastReceiver implements SmsHelper.SmsHelperDelegate {
private static final String SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED";
public static boolean isEnableReceiver = false;
public SmsReceiver() {
super();
isEnableReceiver = true;
Log.e("AAA", "enable receiver");
}
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(SMS_RECEIVED)) {
Bundle bundle = intent.getExtras();
if (bundle != null) {
Log.e("SmsReceiver", "onReceived");
}
}
}
AndroidManifest.xml
<receiver android:name=".receiver.SmsReceiver" android:enabled="true" android:exported="true">
<intent-filter android:priority="2147483647">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
<service android:name=".receiver.AutoStartService" android:exported="true"/>
<receiver android:name=".receiver.BootCompleteReceiver" android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>

The problem with moving to the next track

I'm making a music player, and there was a problem when switching to the next song. When the phone is in working condition (the screen is on) the tracks switch smoothly, when the screen is off there is a long pause, the song starts only after a long time (very long!!!) or when the screen is turned on. Also, everything works well with a headset (Bluetooth), songs switch smoothly even when the screen is turned off. I use MediaPlayer.prepare to prepare the track (music files are taken from the SD card, so I don't see any point in using MediaPlayer.prepareAsync()). Songs are played using Service. Since the player works fine when the screen is turned on and poorly when it is turned off, then this is the problem. I tried everything, searched all the articles about media player in Russian and English, reviewed YouTube. Help is also accepted on Kotlin.
(here is the same question. but there is no answer. How to use wake lock for android mediaplayer?)
Below is the code:
public class MusicService extends Service implements MediaPlayer.OnCompletionListener,
MediaPlayer.OnPreparedListener {
IBinder mBinder = new MyBinder();
private MediaPlayer mediaPlayer = null;
private Uri uri;
private int position = POSITION_PLAY;
public static AudioManager audioManager;
int result;
private NotificationReceiver notificationReceiver;
#Override
public void onCreate() {
super.onCreate();
notificationReceiver = new NotificationReceiver();
audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
result = audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC,
AudioManager.AUDIOFOCUS_GAIN);
if (result != AudioManager.AUDIOFOCUS_REQUEST_GRANTED)
return;
IntentFilter intentFilter = new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
registerReceiver(notificationReceiver, intentFilter);
}
#Override
public void onDestroy() {
super.onDestroy();
releaseMP();
unregisterReceiver(notificationReceiver);
audioManager.abandonAudioFocus(this);
Log.e(TAG, "onDestroy()");
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public class MyBinder extends Binder {
MusicService getService() {
return MusicService.this;
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(myPosition != -1){
playMedia(myPosition);
}
return START_STICKY;
}
public void createMediaPlayer(int positionInner) {
position = positionInner;
uri = Uri.parse(musicFiles.get(position).getPath());
mediaPlayer = null;
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mediaPlayer.setDataSource(getApplicationContext(), uri);
} catch (IOException ioException) {
ioException.printStackTrace();
}
prepare();
}
private void playMedia(int position) {
if(mediaPlayer != null) {
mediaPlayer.stop();
releaseMP();
}
createMediaPlayer(position);
mediaPlayer.start();
}
public void prepare() {
try {
mediaPlayer.prepare();
} catch (IOException ioException) {
ioException.printStackTrace();
}
}
void showNotification(int playPauseBtn){
...
startForeground(2, notification);
if(!isGoing && IS_LIVE) {
stopForeground(false);
}
}
void OnCompleted(){
mediaPlayer.setOnCompletionListener(this);
}
void OnPrepared() { mediaPlayer.setOnPreparedListener(this);}
#Override
public void onCompletion(MediaPlayer mp) {
if(actionPlaying != null){
actionPlaying.nextBtnClicked();
if(mediaPlayer != null){
mediaPlayer.start();
OnCompleted();
}
}
}
private void releaseMP() {
if (mediaPlayer != null) {
try {
mediaPlayer.release();
mediaPlayer = null;
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
public void start() {
mediaPlayer.start();
}
public boolean isPlaying() {
return mediaPlayer.isPlaying();
}
public void stop() {
mediaPlayer.stop();
}
public void pause() {
mediaPlayer.pause();
}
public void release() {
releaseMP();
}
public int getDuration() {
return mediaPlayer.getDuration();
}
public void seekTo(int position) {
mediaPlayer.seekTo(position);
}
public int getCurrentPosition() {
return mediaPlayer.getCurrentPosition();
}
}
Code for the method:
public void nextBtnClicked() {
if(musicService.isPlaying()) {
musicService.stop();
musicService.release();
if(SHUFFLE && !REPEAT){
POSITION_PLAY = getRandom(ListSongs.size() - 1);
}
else if(!SHUFFLE && !REPEAT){
POSITION_PLAY = ((POSITION_PLAY + 1) % ListSongs.size());
}
uri = Uri.parse(ListSongs.get(POSITION_PLAY).getPath());
musicService.createMediaPlayer(POSITION_PLAY);
if(is_live_player_activity) {
metaData(uri);
}
musicService.OnCompleted();
musicService.showNotification(R.drawable.ic_pause);
playPauseBtn.setBackgroundResource(R.drawable.ic_pause);
musicService.start();
}
else {
musicService.stop();
musicService.release();
if(SHUFFLE && !REPEAT){
POSITION_PLAY = getRandom(ListSongs.size() - 1);
}
else if(!SHUFFLE && !REPEAT){
POSITION_PLAY = ((POSITION_PLAY + 1) % ListSongs.size());
}
uri = Uri.parse(ListSongs.get(POSITION_PLAY).getPath());
musicService.createMediaPlayer(POSITION_PLAY);
if(is_live_player_activity) {
metaData(uri);
}
musicService.OnCompleted();
if(FLAG){
musicService.showNotification(R.drawable.ic_pause);
playPauseBtn.setBackgroundResource(R.drawable.ic_pause);
} else {
musicService.showNotification(R.drawable.ic_play);
playPauseBtn.setBackgroundResource(R.drawable.ic_play);
}
}
}
Manifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.music">
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:name=".ApplicationClass"
android:screenOrientation="portrait"
android:theme="#style/Theme.Music">
<activity android:name=".MusicActivity"
android:screenOrientation="portrait"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
...
<service android:name=".MusicService" android:enabled="true"/>
<receiver android:name=".NotificationReceiver" android:enabled="true">
<intent-filter>
<action android:name="android.intent.action.MEDIA_BUTTON" />
<action android:name="android.media.AUDIO_BECOMING_NOISY" />
<action android:name="actionprevious" />
<action android:name="actionnext" />
<action android:name="actionplay" />
</intent-filter>
</receiver>
</application>
</manifest>
I found a problem. It was necessary to call MediaPlayer.setwakemode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);

Internet connection listener not working in android studio

I'm trying to create an Internet connection listener. But not working. I'm not getting any mistakes.I think the NetworkStateChangeReceiver does not work at all. Because Log.e does not appear in logcat. I'm new to Android and it's complicated for me.
Android manifest
<receiver
android:name=".NetworkStateChangeReceiver">
<intent-filter >
<action android:name="com.gdm.retailalfageek.NetworkAvailable" />
</intent-filter>
</receiver>
NetworkStateChangeReceiver.java
public class NetworkStateChangeReceiver extends BroadcastReceiver {
public static final String NETWORK_AVAILABLE_ACTION = "com.gdm.retailalfageek.NetworkAvailable";
public static final String IS_NETWORK_AVAILABLE = "isNetworkAvailable";
#Override
public void onReceive(Context context, Intent intent) {
Intent networkStateIntent = new Intent(NETWORK_AVAILABLE_ACTION);
networkStateIntent.putExtra(IS_NETWORK_AVAILABLE, getConnectionType(context));
LocalBroadcastManager.getInstance(context).sendBroadcast(networkStateIntent);
Log.e("Network Available ", "On receive called");
}
#IntRange(from = 0, to = 2)
public static int getConnectionType(Context context) {
int result = 0; // Returns connection type. 0: none; 1: mobile data; 2: wifi
ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (cm != null) {
NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());
Log.e("Network Available ", "On receive called");
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.e("Network Available ", "On receive called");
result = 2;
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
Log.e("Network Available ", "On receive called");
result = 1;
}
}
}
} else {
if (cm != null) {
NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
if (activeNetwork != null) {
Log.e("Network Available ", "On receive called");
// connected to the internet
if (activeNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
Log.e("Network Available ", "On receive called");
result = 2;
} else if (activeNetwork.getType() == ConnectivityManager.TYPE_MOBILE) {
Log.e("Network Available ", "On receive called");
result = 1;
}
}
}
}
return result;
}}
Application class
#Override
public void onCreate() {
super.onCreate();
IntentFilter filter = new IntentFilter();
filter.addAction("isNetworkAvailable");
registerReceiver(new NetworkStateChangeReceiver(), filter);
}
Hope the code given below help you.
Register a BroadcastReceiver in Manifest.file
<receiver android:name=".MyBroadcastReceiver" >
<intent-filter>
<action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
</intent-filter>
</receiver>
Set internet permissions in Manifest
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
Implement receiving class.
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// This will execute upon receiving event
}
}

How to update a service running in a separate process when the Android app is updated?

When I update the app to a new version, the service that was installed with the previous app version is still running. When I update the app the second time, the updated service is running properly.
However, after first update, whenever i close the app or restart the phone the service from the previous version is running.
How can i force the new service to run as soon as the app is updated.
Here is my code
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.djuro.updateservicewithappupdate">
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:process=":myService" />
<receiver android:name=".PackageReplacedReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" android:path="com.djuro.updateservicewithappupdate"/>
</intent-filter>
</receiver>
</application>
</manifest>
App.java
public class App extends Application {
private static final String TAG = App.class.getName();
private static App mInstance;
private Messenger myServiceMessenger;
private boolean isBound;
private Messenger replyMessenger = new Messenger(new IncomingHandler());
#Override
public void onCreate() {
super.onCreate();
if (mInstance == null) {
mInstance = this;
startMyService();
}
isBound = false;
// start the chore service (if it is not running) and bind to it
}
public void startMyService() {
startService(new Intent(mInstance, MyService.class));
doBindService();
}
public void stopMyService() {
doUnBindService(true);
stopService(new Intent(mInstance, MyService.class));
}
public static App getInstance() {
return mInstance;
}
public static Context getContext() {
return mInstance.getApplicationContext();
}
public static Messenger getChoreMessenger() {return mInstance.myServiceMessenger;}
#Override
public void onTerminate() {
doUnBindService(false);
super.onTerminate();
}
private void doBindService() {
if (!isBound) {
Log.d(TAG, "Binding ChoreService.");
bindService(new Intent(this, MyService.class), myServiceConnection, Context.BIND_AUTO_CREATE);
isBound = true;
}
}
private void doUnBindService(boolean restartService) {
if (isBound) {
Log.d(TAG, "Unbinding ChoreService.");
if (myServiceMessenger != null) {
try {
Message msg = Message.obtain(null, MyService.UNREGISTER_CLIENT);
msg.replyTo = replyMessenger;
replyMessenger.send(msg);
}
catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
if (restartService) {
try {
Message msg = Message.obtain(null, MyService.STOP_SERVICE_ON_UNBIND);
msg.replyTo = replyMessenger;
replyMessenger.send(msg);
}
catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
unbindService(myServiceConnection);
isBound = false;
} else if (restartService) {
stopService(new Intent(mInstance, MyService.class));
}
}
private ServiceConnection myServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
myServiceMessenger = new Messenger(service);
Log.d(TAG, "connected to service");
try {
Message msg = Message.obtain(null, MyService.REGISTER_CLIENT);
msg.replyTo = replyMessenger;
myServiceMessenger.send(msg);
}
catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
myServiceMessenger = null;
Log.d(TAG, "disconnected from ChoreService");
}
};
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
}
}
}
MyService.java
public class MyService extends Service {
private static final String TAG = MyService.class.getName();
public static final int UNREGISTER_CLIENT = 1;
public static final int REGISTER_CLIENT = 2;
public static final int STOP_SERVICE_ON_UNBIND = 3;
final Messenger messenger = new Messenger(new IncomingHandler());
private String appVersion;
private boolean stopOnUnbind;
private int boundCount = 0;
// called when the intent starts the Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand()");
getVersion();
return START_STICKY;
}
// called once at creation (before onStartCommand)
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
// used to bind intent to service
#Nullable
#Override
public IBinder onBind(Intent intent) {
//doStopForeground();
boundCount ++;
Log.d(TAG, "bound count: " + boundCount);
return messenger.getBinder();
}
#Override
public boolean onUnbind(Intent intent) {
boundCount --;
Log.d(TAG, "bound count: " + boundCount);
boolean result = super.onUnbind(intent);
if (stopOnUnbind) {
Log.d(TAG, "stopSelf()");
stopSelf();
}
return result;
}
// called when the service is destroyed
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
super.onDestroy();
}
public void getVersion() {
try {
PackageInfo pInfo = this.getPackageManager().getPackageInfo(getPackageName(), 0);
appVersion = pInfo.versionName;
Log.d(TAG, "appVersion: " + appVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Log.d(TAG, "IncomingHandler handling message. msg.what= " + msg.what);
switch (msg.what) {
case STOP_SERVICE_ON_UNBIND:
stopOnUnbind = true;
break;
default:
super.handleMessage(msg);
break;
}
}
}
}
PackageReplacedReceiver.java
public class PackageReplacedReceiver extends BroadcastReceiver {
private static final String TAG = PackageReplacedReceiver.class.getName();
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "package updated");
App.getInstance().stopMyService();
}
}
Use android.intent.action.MY_PACKAGE_REPLACED action in your intent filer and stop your service from broadcast receiver.
<receiver android:name=".PackageReplacedReceiver" android:enabled="#bool/is_at_least_api_12" > <intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>

Cant receive notifications from GCM

Im trying to add notifications to my android app. So I decided to implement GCM.
I have used the sample code from the official documentation
https://developer.android.com/google/gcm/client.html
and the sample application
https://code.google.com/p/gcm/source/browse/samples/gcm-demo-client/src/com/google/android/gcm/demo/app/
Here is my implementation
public class RegisterActivity extends Activity implements SurfaceHolder.Callback{
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
String SENDER_ID = "210822831159";
GoogleCloudMessaging gcm;
AtomicInteger msgId = new AtomicInteger();
Context context;
String regid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
context = getApplicationContext();
if (checkPlayServices())
{
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty())
{
registerInBackground();
}
else
{
//"No valid Google Play Services APK found."
}
}
//...
}
#Override
protected void onResume() {
super.onResume();
// Check device for Play Services APK.
checkPlayServices();
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
finish();
}
return false;
}
return true;
}
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = getGcmPreferences(context);
int appVersion = getAppVersion(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.putInt(PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGcmPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
return "";
}
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
return "";
}
return registrationId;
}
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
sendRegistrationIdToBackend();
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
//...
}
}.execute(null, null, null);
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
private SharedPreferences getGcmPreferences(Context context) {
return getSharedPreferences(RegisterActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
private void sendRegistrationIdToBackend() {
// TODO
}
//...
}
The Broadcaster:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Intent Service:
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
* Filter messages based on message type. Since it is likely that GCM
* will be extended in the future with new message types, just ignore
* any message types you're not interested in, or that you don't
* recognize.
*/
if (GoogleCloudMessaging.
MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification("Deleted messages on server: " +
extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// This loop represents the service doing some work.
for (int i=0; i<5; i++) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
// Post notification of received message.
sendNotification("Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, HomeActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.HBM.sample" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.HBM.sample.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.HBM.sample.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.HBM.sample" />
</intent-filter>
</receiver>
<service
android:name=".GcmIntentService"
android:enabled="true" />
<activity
android:name=".RegisterActivity"
android:windowSoftInputMode="stateHidden|adjustResize" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".HomeActivity"
android:windowSoftInputMode="stateHidden|adjustResize" >
android:label="#string/title_activity_home" >
</activity>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
The app compiles fine and when I set a breakpoint in registerInBackground after:
regid = gcm.register(SENDER_ID);
the client registers fine and I get the registration id that looks something like this:
APA91bEdxx0UyqtX6qoVuhYNSeJkuAITIpdkbCkBCCsOyX5-lpbtNAJBvvGqIGKqxGhW24-y-tWbj2EDKJAiyvzVhP7jhMevZBr-o-Y6Eli0uG24oWXjFOWa1Sj9vjNXaO5wbWs7WodC4Oq4QOFaPQscF_v44Z_kyg
After that I created a GCM Server application and send a notification to the registrationId
Here is the json response:
{"multicast_id":5827029040432755439,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1407451852374547%913f6fe1f9fd7ecd"}]}
It looks like the app registers fine and the notifications are pushed successfully. But onReceive never fires and I dont get any notifications o_O
I have tried the app on two different phones and different networks. But Im not sure what Im doing wrong. I hope someone can help me. I would really appreciate it.

Categories

Resources