I encountered a strange problem - I've been using GCM in my application for quite a long time and everything works perfectly. However, before a release to Google Play I changed my application package name from com.android.testapp to com.android.recognition and after this GCM stopped working. At first I got en error GCM sender id not set on constructor and fixed it by overriding getSenderIds(Context context), but now I can't get a registration ID. Here are the messages from logcat:
How can I fix this? When I switched to a new package I changed everything in the manifest file to the new package:
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="com.android.recognition" />
</intent-filter>
</receiver>
So what is the problem behind this? Can renaming the application package cause this or is there another reason?
The problem is answered, in my case it was little more complicated.
Check you have an active internet connection
Check that you have Internet permission in your manifest
Make sure the package name is correct as Eran mentioned
The device time is correctly setup. Even if everything is perfect, it will fail if device clock is not set correctly.
Wrong clock caused problem for me. :)
This SERVICE_NOT_AVAILABLE error says that GCM Service is not available in current. Wait and try after some time.
This happens many time (As my experience), so don't worry about it.
See the GCMConstants class of GCM Lib.
/**
* The device can't read the response, or there was a 500/503 from the
* server that can be retried later. The application should use exponential
* back off and retry.
*/
public static final String ERROR_SERVICE_NOT_AVAILABLE =
"SERVICE_NOT_AVAILABLE";
For more investigation see handleRegistration() of GCMBaseIntentService
private void handleRegistration(final Context context, Intent intent) {
String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
String error = intent.getStringExtra(EXTRA_ERROR);
String unregistered = intent.getStringExtra(EXTRA_UNREGISTERED);
Log.d(TAG, "handleRegistration: registrationId = " + registrationId +
", error = " + error + ", unregistered = " + unregistered);
// registration succeeded
if (registrationId != null) {
GCMRegistrar.resetBackoff(context);
GCMRegistrar.setRegistrationId(context, registrationId);
onRegistered(context, registrationId);
return;
}
// unregistration succeeded
if (unregistered != null) {
// Remember we are unregistered
GCMRegistrar.resetBackoff(context);
String oldRegistrationId =
GCMRegistrar.clearRegistrationId(context);
onUnregistered(context, oldRegistrationId);
return;
}
// last operation (registration or unregistration) returned an error;
Log.d(TAG, "Registration error: " + error);
// Registration failed
if (ERROR_SERVICE_NOT_AVAILABLE.equals(error)) {
boolean retry = onRecoverableError(context, error);
if (retry) {
int backoffTimeMs = GCMRegistrar.getBackoff(context);
int nextAttempt = backoffTimeMs / 2 +
sRandom.nextInt(backoffTimeMs);
Log.d(TAG, "Scheduling registration retry, backoff = " +
nextAttempt + " (" + backoffTimeMs + ")");
Intent retryIntent =
new Intent(INTENT_FROM_GCM_LIBRARY_RETRY);
retryIntent.putExtra(EXTRA_TOKEN, TOKEN);
PendingIntent retryPendingIntent = PendingIntent
.getBroadcast(context, 0, retryIntent, 0);
AlarmManager am = (AlarmManager)
context.getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.ELAPSED_REALTIME,
SystemClock.elapsedRealtime() + nextAttempt,
retryPendingIntent);
// Next retry should wait longer.
if (backoffTimeMs < MAX_BACKOFF_MS) {
GCMRegistrar.setBackoff(context, backoffTimeMs * 2);
}
} else {
Log.d(TAG, "Not retrying failed operation");
}
} else {
// Unrecoverable error, notify app
onError(context, error);
}
}
SERVICE_NOT_AVAILABLE is one of the most frustrating problems with Google Cloud Messaging. It is an exception thrown by GoogleCloudMessaging.register(SENDER_ID), the function call that registers the device for push notifications and returns a registration ID.
SERVICE_NOT_AVAILABLE might mean that the user’s device can’t read the response to the registration request or a 500/503 error code was returned from the server. Developers have no way to fix this error because it is on Google’s end, so we can blindly suggest that the user should try again in a few hours.
SERVICE_NOT_AVAILABLE may occur on some devices even though the registration succeeded. This can be fixed by implementing a workaround broadcast receiver to catch the token when the call fails. I implemented this workaround and it may have fixed the problem for some users, but still I received many other SERVICE_NOT_AVAILABLE complaints.
SERVICE_NOT_AVAILABLE may occur because of an outdated or missing Google Play Services library on the device. In this case, the app could theoretically notify the user to update Google Play Services by opening the respective Google Play app listing. However, the app has no idea that this is why SERVICE_NOT_AVAILABLE was thrown, so it cannot blindly redirect the user to the Google Play Services app page on Google Play.
SERVICE_NOT_AVAILABLE may occur when the device’s clock is not synchronized with the network. Again, developers have no way of knowing that this is the exact problem, so we can blindly suggest to the user to check their system clock synchronization, hoping they are one of the very few whose clocks are not synchronized.
SERVICE_NOT_AVAILABLE may occur when a rooted user has deleted the Hangouts/GTalk app from their device (because they considered it bloatware). GCM is implemented and handled by Hangouts/GTalk, so it is not possible to use GCM without it.
SERVICE_NOT_AVAILABLE may occur if the user is running a device that does not have Google APIs installed (such as the Amazon Kindle). Nothing to do here, these users will never receive push notifications from your app.
Read more:
http://eladnava.com/google-cloud-messaging-extremely-unreliable/
These issues alone were enough to get me to start looking for GCM alternatives. I’d get a 1-star review on my app every day or two, with a comment containing the error message displayed when a SERVICE_NOT_AVAILABLE was thrown. There was nothing I could do to help these users, because the majority of them were receiving it for reasons out of their control.
An Alternative to Google Cloud Messaging
Pushy (https://pushy.me/) is a standalone push notification gateway, completely independent of GCM. It maintains its own background socket connection, just like GCM, to receive push notifications. The underlying protocol is MQTT, an extremely light-weight pub/sub protocol, utilizing very little network bandwidth and battery.
A huge advantage of Pushy is that the code for sending a push notification (from the server), and registering the device for push notifications, is actually interchangeable between GCM and Pushy. This makes it super easy to switch to Pushy after implementing GCM and having to ditch it for its instability.
(Full disclosure: I founded Pushy for my own projects and realized many apps would benefit from such a service)
Make sure that you changed the package name in the permissions part of your manifest :
<permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="YOUR_PACKAGE_NAME.permission.C2D_MESSAGE" />
I had a similar error due to an incorrect package name in that part.
For me - the device time wasn't correct. I changed the device settings to use "Automatic date & time", tried again and all good.
Cheers
I had the same problem but none of the above solutions solved the problem in my case. Fortunately I recently solved it and I want to explain how, hopping it will help others:
In my case, I was registering the push service in a custom application class (which is executed before any activity and I think is due to this that some things have not been initialized propertly). Changing it to the main activity solved the problem.
public class MyCustomApp extends Application {
#Override
public void onCreate() {
super.onCreate();
PushService.register(this); //BAD IDEA, don't register pushes in Application Class
}
}
I had a similar problem. Worked fine on a google nexus (Android 4.4.2) but not on a Samsung galaxy s3 (Android 4.1.2).
I was getting SERVICE_NOT_AVAILABLE on registration on the Samsung. It turned out the time on Samsung was off. It was not set to auto update with Network Time. Once I fixed that GCM worked like a charm. Thanks - Umesh
For me there was connection problem. Change internet connection solved my problem
For me, I had turned of "Background Data Access" for google services by checking "Restrict background data" in Data usage option on my Galaxy S4. As soon as I turned it on problem resolved on cellarer network. On Wifi it was working fine.
In my case, the solution was to add a new intent-filter action, REGISTRATION, to the manifest, per https://snowdog.co/blog/dealing-with-service_not_available-google-cloud-messaging/
<receiver
android:name=".RemoteNotificationReceiver"
android:permission="com.getset.getset.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.getset.getset.c2dm.intent.RECEIVE" />
<action android:name="com.getset.getset.c2dm.intent.REGISTRATION" />
<category android:name="com.getset.getset" />
</intent-filter>
</receiver>
I have to admit that I'm surprised that this works, given it's missing from the tutorial, but taking it out definitely turns a successful registration id into an exception.
Note: using Nexus 5 API 21 (Lollipop) emulator.
For me, the problem was the phone was not connected to the internet. I disconnect and connect to Wi-Fi, and tested connectivity with Browser and tested again. Worked like a charm :-)
I had turned of "Background Data Access" for google services. By unchecking "Restrict background data" in Data usage option It works for me !
For me goolge blocked my IP!! I had to reset my DSL conn to get a new IP from the pool and everything worked again, idk why they blocked me, maybe for trying many apps? Anyway is working now, i hope this help somebody else :)
For me,SERVICE_NOT_AVAILABLE problem was in my application project because of the receiver class.
So I solved after implementing the receiver like the following.
<receiver
android:name="receiver name"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE"/>
<action android:name="com.google.android.c2dm.intent.REGISTRATION"/>
<category android:name="your package"/>
</intent-filter>
</receiver>
I hope that will help you :-) .
I had a OnePlus2 which couldn’t receive pushes when on data. When I connected with logcat, I saw a lot of this error, but am unsure if it is related.
I gave up trying to find a setting which corresponded to it and just factory reset the device. OnePlus devices running OxygenOS sometimes get weird configuration errors when installing software updates and a factory reset followed by restore from Google Backup gets things working again faster than it would take to understand the underlying issue (and it might be that the user doesn’t even have the right access to fix the underlying issue).
In my case, this happened because my mobile phone does not have a SIM card inside it.
I guess that having the sim card sets the Automatic time on the device, which resolves this.
After a long struggle i managed to sort out this issue.
Make sure that Google Play Services app is up-to-date and that its background synchronization is not disabled on your phone.
Related
I'm trying to build an Android app in Android Studio to detect the precise call state of outgoing calls. I'm new to Java, and I'm going around in circles with a few problems.
The basic calls states are working fine for me per this youtube guide https://www.youtube.com/watch?v=rlzfcqDlovg. That tutorial uses "TelephonyManager.EXTRA_STATE" in its main class and the "android.intent.action.PHONE_STATE" receiver in the AndroidManifest. It successfully detects when an outgoing call is placed and ended, but NOT when it actually starts ringing/is answered/etc.
I'm trying to get the PreciseCallState of outgoing calls using a couple of StackOverFlow guides like this one How to Use PreciseCallState and other similar discussions, but I'm stuck with a few points:
The basic receiver in AndroidManifest worked fine listening to "android.intent.action.PHONE_STATE". But my precise receiver, listening to "android.intent.action.PRECISE_CALL_STATE" doesn't fire at all, when a call is placed, answered, ended etc.
Even if my receiver DID fire when the PRECISE_CALL_STATE changed, Android Studio doesn't recognize "TelephonyManager.EXTRA_FOREGROUND_CALL_STATE", and won't let me build the app when I try to use this line. I've tried using several "Hidden API bypass" scripts like this one https://github.com/LSPosed/AndroidHiddenApiBypass, but with no luck - I'm unsure how exactly to use this, as the instructions on these type of resources aren't clear to me. All I can figure out is to include their dependencies and "import" the package, not how to actually use it in my script.
Other points:
I know that Google introduced restrictopms on non-standard packages (including reflection) in API level 28 (refer https://developer.android.com/guide/app-compatibility/restrictions-non-sdk-interfaces, so I've tried using API/SDK versions 25 through 32, all with no luck. My current attempt is using SDK version 30.
I've installed my app as a system app using Magisk Systemizer, per other Stackoverflow suggestions for using PreciseCallState, but this didn't fix my issues.
The app doesn't ask for the "READ_PRECISE_PHONE_STATE" permission at all, either when it's installed as a system app or a regular app. I'm not sure if this is okay, but I imagine I'm missing something.
I'd appreciate any help on these 2 issues, I've been trying to research and figure this out for a solid week now!
My code:
AndroidManifest:
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
<application...
...
<receiver android:name=".CallReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<!-- (unused) <action android:name="android.intent.action.PHONE_STATE" />-->
<action android:name="android.intent.action.PRECISE_CALL_STATE" />
<!-- (unused) <action android:name="android.intent.action.NEW_OUTGOING_CALL" />-->
</intent-filter>
</receiver>
</application>
MainActivity:
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PRECISE_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.READ_PRECISE_PHONE_STATE},1);
}
CallReceiver:
public class CallReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String myString = "new PreciseCallState detected...";
Toast.makeText(context, myString, Toast.LENGTH_LONG).show();
//String myPreciseCallState = intent.getIntExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, -2);
//Toast.makeText(context, myString + myPreciseCallState, Toast.LENGTH_LONG).show();
// (unused) //String basicCallState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
}
}
I'm working on making an Android version of an iOS app I made earlier this year.
I have a Python Flask API that is supposed to send a push notification via Firebase Cloud Messaging to Android and iOS devices when a certain endpoint is called.
My iOS app is working perfectly, but on Android I don't receive any notifications (neither in foreground nor background).
In my Python code, I'm using a MulticastMessage:
push_notification = messaging.MulticastMessage(
device_tokens,
notification=messaging.Notification(title=title, body=message),
data=data,
apns=messaging.APNSConfig(
payload=messaging.APNSPayload(
messaging.Aps(sound="default")
)
),
android=messaging.AndroidConfig(
notification=messaging.AndroidNotification(
sound="default"
)
)
)
response = messaging.send_multicast(push_notification)
device_tokens is a list of the registration tokens of the devices I want to send the notification to. I verified that one of the tokens is, indeed, the token that my Android Client is using.
data is a dictionary of the following form:
{
"uid": "<user-uid-here>"
}
On the client side, I tried to follow the documentation pretty closely. I added my google-services.json file, added and applied the plugin in the Gradle files, and added the Firebase Messaging dependency. Then I created a Messaging Service and updated my app manifest:
MessagingService.java
public class MessagingService extends FirebaseMessagingService {
public MessagingService() {
super();
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.w("Debug", "RECEIVED MESSAGE");
}
}
AndroidManifest.xml
<!--Inside application tag-->
<service
android:name=".model.MessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="#mipmap/ic_launcher" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="#color/colorAccent" />
I should mention that at some point it was sort of working (sometimes I would get the notification, sometimes I wouldn't), but I can't remember exactly what I did that broke it (if I did do anything at all).
I've Googled in a lot of places, but nothing seems to be working.
Am I missing something? I'm pretty confident the problem is not with the server, since the iOS app is handling the notifications just fine.
NOTE: I want to be able to receive messages from both foreground and background state.
EDIT: I am running this on an emulator; perhaps that might be related to the problem? I remember sometimes before the device wouldn't get the notification for a long time...
I host widgets in my app and it seems, that if i start my app before booting of the device is completed, widgets cannot be created properly. Widgets then seem to be not loaded completely or not initialized/updated correctly. For instance: BatteryBotIndicator-Widget, which shows the battery status in percentage, shows a value of "XX" instead of some number like "70%". If i then restart my app and try to recreate the widget with:
AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
it gives me null for appWidgetInfo (i fetch appWidgetId from SQLite database). And widget cannot be recreated.
It is kind of difficult to debug the real cause in this situation to find out what is exactly causing this (Starting Debugger at the right time). I assume the AppWidgetManager is not ready yet or something.
What i can say for sure: If i wait until i receive the broadcast-event BOOT_COMPLETED all widgets are created properly.
So how can i pause the execution of onCreate until booting is completed?
I can think of putting the thread to sleep in a while loop until the BroadcastReceiver (BOOT_COMPLETED) is setting a bool-variable in application-data to true. But i dont want to wait for this event always at starting of my app, as you can imagine ;)
if i start my app before booting of the device is completed, widgets cannot be created properly.
please explain more what exactly do you mean when you say - "not properly" . this might be relevant to understand if you're widget really depends on something related to the boot.
I can think of putting the thread to sleep in a while loop until the BroadcastReceiver (BOOT_COMPLETED) is setting a bool-variable in application-data to true
very bad idea.. also from performances and design reasons
instead, why not simply register to boot complete broadcast from the manifest, and when you recevice it - simply send the relevant broadcast to update your widget? AppWidgetProvider is already extends BroadcastReceiver, so you can simply add it intent filter for boot complete broadcast.
this is how to add intent filter to boot complete:
<receiver android:name="MyWidgetProvider" >
<intent-filter >
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<meta-data
...
</receiver>
and this is how to react to it from the widget provider implementation:
#Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals("android.intent.action.BOOT_COMPLETED")){
doTheUpdateHereExactlyLikeHowYouUpdateItFromAnywhereElse();
} else {
super.onReceive(context,intent);
}
}
for more information - follow this tutorial :https://laaptu.wordpress.com/2013/08/12/android-update-app-widget-with-listview-after-phone-reboot/
I hope this is not to generic but I am developing an app for the Sony SmartWatch. When ever I make a mistake like allowing a null pointer exception. I can not get my app to restart. It's like it stays in the crashed state forever. To make the problem worse I also stop receiving messages via Logcat pertaining the app. When I uninstall and reinstall the app It's not listed in the SmartWatch app on the phone. Like it won't register. This is difficult to trouble shoot since I don't get any Log messages at this point. The only thing I can do is uninstall the app. Restart my phone. Then reinstall the app. At that point it's back to normal and I can start writing code again. So that brings me to my questions.
Is there a better way to re-register a control?
Will this happen to end users? If the app crashes will they need to uninstall, reboot and install to recover?
Some Detail (names have been changed to protect the inocent):
I have created a Broadcast Reciever and in my mainfest set it to listen for these broadcasts.
<receiver android:name=".MyExtensionReceiver" >
<intent-filter>
<!-- Receiver intents -->
<action android:name="com.sonyericsson.extras.liveware.aef.registration.EXTENSION_REGISTER_REQUEST" />
<action android:name="com.sonyericsson.extras.liveware.aef.registration.ACCESSORY_CONNECTION" />
<!-- Control intents -->
<action android:name="com.sonyericsson.extras.aef.control.START" />
<action android:name="com.sonyericsson.extras.aef.control.STOP" />
<action android:name="com.sonyericsson.extras.aef.control.PAUSE" />
<action android:name="com.sonyericsson.extras.aef.control.RESUME" />
<action android:name="com.sonyericsson.extras.aef.control.ERROR" />
<action android:name="com.sonyericsson.extras.aef.control.TOUCH_EVENT" />
<action android:name="com.sonyericsson.extras.aef.control.SWIPE_EVENT" />
</intent-filter>
Code for MyExtensionReceiver:
public class MyExtensionReceiver extends BroadcastReceiver {
public MyExtensionReceiver() {
super();
Log.d("mytag", "MyExtensionReceiver Loaded");
Dbg.setLogTag("mytag");
}
#Override
public void onReceive(Context context, Intent intent) {
Log.d("mytag", "onReceive: " + intent.getAction());
intent.setClass(context, MyExtensionReceiver.class);
context.startService(intent);
}
}
Even if my app is crashing I should still get a log message when onReceive is called. It's like the EXTENSION_REGISTER_REQUEST broadcast never gets sent. I just keep uninstalling rebooting and reinstalling over and over. Eventually the app gets found by the SmartConnect App.
It doesn't seem to have anything to do with the BroadcastReceiver. Without using one, I'm having the same annoying problem. I need to restart the phone in order to get things running normal again, as neither disabling/enabling the app helps a bit, nor killing the SmartWatch phone app (as I see no other way to restart it).
I would also appreciate some help from Sony on this matter.
Just came across this issue, giving some grey!! To work around this issue, just create a new intent using string and launch that with context.
Intent intent = new Intent("MY.PACKAGE.NAME.MyExtensionReceiver");
context.startService(intent);
I have been developing an app, and I need to close another app in my code. Does anyone know any api to call to close an app?
BTW: my app will be pre-installed.
thanks
Since Android 2.2 (i.e. going forward), you can only close the background processes of other apps, you are no longer able to close their main activities.
If your app is targeting Android <2.2, look atandroid.permission.RESTART_PACKAGE.
If you want it to work properly on 2.2 and above (which you should :-)), look at android.permission.KILL_BACKGROUND_PROCESSES, but again, this only closes background services and such and might "mess up" the other app rather than doing any good.
With the right permissions, you can then do the following:
private ActivityManager am = (ActivityManager) this.getSystemService(ACTIVITY_SERVICE);
am.restartPackage("com.jimmy.appToBeClosed");
Try This
ActivityManager am = (ActivityManager) getApplicationContext().getSystemService("activity");
Method forceStopPackage;
forceStopPackage =am.getClass().getDeclaredMethod("forceStopPackage",String.class);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(am, pkg);
In manifest file add this
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES"></uses-permission>
If both applications are yours, you can use AIDL for inter-process communication to send a message telling the other application to close. See http://developer.android.com/guide/developing/tools/aidl.html.
I have been able to close another app on Android 12 successfully. Here is how:
Basically, I am closing another app from a service although you should be able to do it from an app too.
My service is a privileged system app that gets installed in system/priv-app/ (It has LOCAL_PRIVILEGED_MODULE := true in its Android.mk)
I added <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" /> in AndroidManifest.xml
I added in privapp-permissions.xml
<privapp-permissions package="<my service package name>">
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
</privapp-permissions>
I called in my service this method with the package name of the application I want to close:
private void closePackageApp(String namePackage) {
ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
try {
Method forceStopPackage = activityManager.getClass().
getDeclaredMethod("forceStopPackage", String.class);
forceStopPackage.setAccessible(true);
forceStopPackage.invoke(activityManager, namePackage);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
}
I tested this and in the logs, I can see the app is being closed. However the app is not removed from the recent screen (logs suggested the app was disposed without first being removed with the input manager!).
However, I am sure the app was really being closed when it was in the background by comparing its lifecycle on opening again. Normally, it is onPause->onResume but now it is onPause->onCreate.
You don't ever really want to close another application, due to Android activity lifecycle.
There's no benefit, and always detriment to closing another app if it's not yours, and very little benefit to closing your own.
http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
If you know for certain that you'll never, ever need a root activity and its children (an "app"), you can stop it to free memory (it doesn't free that much), but if you do the user may restart it while it's still in cache, stopped, which can cause problems if the stopped state is restored. So this is a bad practice.