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.
Related
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
}
}
I am developing an application that must read a confirmation code by SMS exactly as on registration on Whatsapp. It works well for Android versions 5 and below, but from version 6 the application does not read the sms.
Below is the class called in the main function. It reads received SMS messages automatically:
public class SmsReceiver extends BroadcastReceiver {
private static SmsListener mListener;
//add...
private static final String
TAG = SmsReceiver.class.getSimpleName();
public static final String pdu_type = "pdus";
//add..
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onReceive(Context context, Intent intent) {
Bundle data = intent.getExtras();
Object[] pdus = (Object[]) data.get("pdus");
String format = data.getString("format");
//Toast.makeText(context,"coollll:" + pdus,Toast.LENGTH_LONG).show();
if (pdus!=null){
//
Toast.makeText(context,"noooooooo",Toast.LENGTH_LONG).show();
boolean isVersionM= (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.M);
for (int i=0; i<pdus.length; i++){
if (isVersionM){
SmsMessage smsMessage =
SmsMessage.createFromPdu((byte[]) pdus[i],format);
String sender = smsMessage.getDisplayOriginatingAddress();
if(sender.equals("myProjet")){
String messageBody = smsMessage.getMessageBody();
mListener.messageReceived(messageBody);
}
}else {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
String sender = smsMessage.getDisplayOriginatingAddress();
if(sender.equals("projet")){
String messageBody = smsMessage.getMessageBody();
mListener.messageReceived(messageBody);
}
}
}
}
}
public static void bindListerner(SmsListener listener){
mListener = listener;
}
}
Below is the SmsListener.java interface which listens for incoming messages:
public interface SmsListener {
public void messageReceived(String messageText);
}
And below is the activity that processes the received SMS:
public class CodeConfirmation extends Activity {
private String telephone;
private TextView tel, textcode, textCount, textSendAgainSms;
private RequestQueue requestQueue;
private StringRequest stringRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_code_confirmation);
final Pinview pin = (Pinview) findViewById(R.id.pinview);
pin.setPinBackgroundRes(R.drawable.sample_background);
countTime();
requestQueue= Volley.newRequestQueue(this);
Intent intent= getIntent();
final String codeGenere=
getIntent().getExtras().getString("code");
telephone= getIntent().getExtras().getString("telephone");
Toast.makeText(CodeConfirmation.this, codeGenere,
Toast.LENGTH_SHORT).show();
// on affiche le numéro de l'utilisateur dans la vue
tel =(TextView)findViewById(R.id.my_number);
textcode=(TextView)findViewById(R.id.text);
tel.setText(getString(R.string.your_tel)+ telephone);
textcode.setText(getString(R.string.code_confirmation));
textCount=(TextView)findViewById(R.id.textCount);
textSendAgainSms=(TextView)findViewById(R.id.send_code_agent);
textSendAgainSms.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
textSendAgainSms.setText(null);
countTime();
}
});
SmsReceiver.bindListerner(new SmsListener() {
#Override
public void messageReceived(String messageText) {
Toast.makeText(CodeConfirmation.this,"Message:" + messageText,Toast.LENGTH_LONG).show();
if (messageText.compareToIgnoreCase(codeGenere)==0){
pin.setValue(messageText);
Toast.makeText(CodeConfirmation.this, getString(R.string.succes_code), Toast.LENGTH_SHORT).show();
finish();
startActivity(new Intent(getApplicationContext(), LoginActivity.class));
}
}
});
/*
*Lorsque l'utilisateur entre le code à 5 chiffres
*/
pin.setPinViewEventListener(new
Pinview.PinViewEventListener() {
#Override
public void onDataEntered(Pinview pinview, boolean b) {
final String code= pinview.getValue();
//Toast.makeText(CodeConfirmation.this, code, Toast.LENGTH_SHORT).show();
if (code.compareToIgnoreCase(codeGenere)==0){
Toast.makeText(CodeConfirmation.this,getString(R.string.succes_code), Toast.LENGTH_SHORT).show();
finish();
startActivity(new Intent(getApplicationContext(),LoginActivity.class));
}
else{
Toast.makeText(CodeConfirmation.this,getString(R.string.wrong_code), Toast.LENGTH_SHORT).show();
}
}
});
}
public void countTime(){
new CountDownTimer(30000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
textCount.setText(getString(R.string.TimeCount)+":"+millisUntilFinished/1000);
}
#Override
public void onFinish() {
textSendAgainSms.setText(getString(R.string.send_code_agent));
}
}.start();
}
public void CheckNumber(final String telephone){
stringRequest= new StringRequest(Request.Method.POST, BuildConfig.server + "register", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
String objetJson= jsonObject.getString("success");
//Toast.makeText(getApplicationContext(),"response-> : "+jsonObject.getString("success"), Toast.LENGTH_SHORT).show();
if(objetJson.equals("true")){
/*Toast.makeText(getApplicationContext(), "code-> "+jsonObject.getString("code"), Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "telephone-> "+jsonObject.getString("telephone"), Toast.LENGTH_LONG).show();*/
//startActivity(new Intent(getApplicationContext(),CodeConfirmation.class));
}
else if(objetJson.equals("false")){
Toast.makeText(getApplicationContext(),"error", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),"Aucune connexion internet " ,Toast.LENGTH_SHORT).show();
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("telephone", telephone);
return hashMap;
}
};
requestQueue.add(stringRequest);
}
}
This is what my AndroidManifest.xml file looks like:
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<application
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=".connexion.LoginActivity"
android:label="#string/title_activity_login"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".connexion.CodeConfirmation"
android:label="#string/title_activity_code_confirmation" />
<receiver
android:name=".sms.SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action
android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
</manifest>
in the new android api, you need of course permission on Manifest, but you need implement runtime permissions, maybe you can put it in your first Activity.
Look this link
Examples to do runtime permission
I'm trying to use google's geofences and I follow the google docs
The problem is that when I call addGeofences() it should start the IntentService but it just stopped.
The addGeofences() result always shows success and my Log:
and then nothing happens,
my IntentService's onHandleIntent()'s Log shows nothing; I think it's not even activated.
I used Nexus5 API25 emulator and Target Android7.1.1(Google APIs)for testing.
I searched much but still can't figure out why; maybe I missed something.
here is my code:
private void startGeofenceMonitor()
{
Log.i("info", "Start geofence monitoring");
try
{
int permission = ActivityCompat.checkSelfPermission(MainActivity.this, android.Manifest.permission.ACCESS_FINE_LOCATION);
if (permission != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions( MainActivity.this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION} , PERMISSIONS_REQUEST_CODE);
Log.i("info", "Permission not available! ");
}
else
{
mGeofencingClient = LocationServices.getGeofencingClient(this);
geofenceList.add(new Geofence.Builder().setRequestId("point0")
.setCircularRegion(55, 55, 15)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setNotificationResponsiveness(1000)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT)
.build());
mGeofencingClient.addGeofences(getGeofencingRequest(), getGeofencePendingIntent())
.addOnSuccessListener(this, new OnSuccessListener<Void>()
{
#Override
public void onSuccess(Void aVoid)
{
Log.i("info", "geofence added!: ");
}
})
.addOnFailureListener(new OnFailureListener()
{
#Override
public void onFailure(#NonNull Exception e)
{
Log.i("info", "geofence failed! " + e.toString());
}
});
}
}
catch (Exception e)
{
Log.i("er", e.getMessage());
}
}
private GeofencingRequest getGeofencingRequest()
{
return new GeofencingRequest.Builder()
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER | GeofencingRequest.INITIAL_TRIGGER_DWELL)
.addGeofences(geofenceList)
.build();
}
private PendingIntent getGeofencePendingIntent()
{
if (mGeofencePendingIntent != null)
{
return mGeofencePendingIntent;
}
Intent intent = new Intent(this, GeofenceTransitionsIntentService.class);
mGeofencePendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
return mGeofencePendingIntent;
}
and my IntentSrvice
public GeofenceTransitionsIntentService()
{
super("GeofenceTransitionsIntentService");
Log.i("info", "IntentService is activated!");
}
#Override
protected void onHandleIntent(Intent intent)
{
String test = intent.getStringExtra("pls");
Log.i("info", "onHandleIntent is activated!");
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
Log.i("info", "geofencingEvent size: " + intent.toString());
if (geofencingEvent.hasError())
{
Log.e("er", "geofencingEvent has error!");
return;
}
else
{
}
int geofenceTransition = geofencingEvent.getGeofenceTransition();
Log.e("er", "geofenceTransition" + geofenceTransition);
if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_ENTER)
{
List<Geofence> triggeringGeofences = geofencingEvent.getTriggeringGeofences();
Geofence geofence = triggeringGeofences.get(0);
String requestID = geofence.getRequestId();
Log.i("geo", "Entering geofence : " + requestID);
}
else if (geofenceTransition == Geofence.GEOFENCE_TRANSITION_EXIT)
{
Log.i("geo", "Exiting geofence : ");
}
else
{
Log.i("geo", "geo not in range ");
}
}
manifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.hs.geofencestest">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"></uses-permission>
<meta-data
android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
<application
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=".GeofenceTransitionsIntentService" android:exported="true"/>
</application>
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>
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.