Getting error Attempted to start a foreground service (xxx) with a broken notification (no icon: Notification(pri=0 contentView=null --- - android-service

I do not understand this error message in Android Studio. Looking at the source code this error is caused by the small icon being null. But I set the icon (both large and small) and the notification is present WITH my icon. I even used the Asset Studio to create this icon specifically for notifications.
There are a lot of other posts on this topic but they all seem related to those trying to HIDE the notification in some way. I want it so that my service is not killed by Android!
Here is the full error
Attempted to start a foreground service (ComponentInfo{com.lni.pchademophg/com.lni.pchademophg.BaseManager}) with a broken notification (no icon: Notification(pri=0 contentView=null vibrate=null sound=null defaults=0x0 flags=0x40 color=0x00000000 vis=PRIVATE secFlags=0x0 secPriority=0))
Why the error? ( I guess I shouldn't complain, everything works as I need it to work ... at least it appears so, but the error is unsettling and I would like to understand it.)
This error is occurring on a 6.0.1 device (have not tried a 10 yet)
Here is my code which is in the 'onsStartCommand()' method of the service:
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
createNotificationChannel();
Notification.Builder builder = new Notification.Builder(context, mChannel.getId())
.setContentTitle(getString(R.string.app_name))
.setSmallIcon(R.drawable.ic_stat_name)
.setContentText("Pcha Personal Health Gateway")
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_stat_name))
.setAutoCancel(true);
Notification notification = builder.build();
startForeground(NOTIFICATION_ID, notification);
}
else
{
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context, "BtleScanChannel");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N)
{
notificationBuilder.setPriority(NotificationManager.IMPORTANCE_LOW);
}
notificationBuilder.setContentTitle(getString(R.string.app_name))
.setContentTitle(getString(R.string.app_name))
.setContentText("Pcha Personal Health Gateway")
.setSmallIcon(R.drawable.ic_stat_name)
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(),
R.drawable.ic_stat_name));
startForeground(NOTIFICATION_ID, notificationBuilder.build());
}
return START_STICKY;
}
Any ideas? What are the consequences?

Related

Xamarin.Forms Communication Between Two Pages Within Same App on Different Devices

Technologies, frameworks and devices I'm using:
Framework: Xamarin.Forms
IDE: Visual Studio 2022
Physical Device (smartphone): Zebra TC26 (Android 10)
Physical Device (smartwatch): Samsung Galaxy Watch4 (Android 11)
Problem definition
Currently I have a test Xamarin.Forms project that consists of two different UIs (XAML files):
User Interface 1: HomePage.XAML - This screen should be displayed on the smartphone
User Interface 2: WatchScreen.XAML - This screen should be displayed on the smartwatch
With code below I make sure HomePage.XAML is deployed to a smartphone and watchscreen is deployed to a smartwatch:
Page homePage = new NavigationPage(new HomePage());
// BuildVersionCodes.R is a reference to Android version 11 (mostly now used by Wear OS 3.x)
if (Build.VERSION.SdkInt == BuildVersionCodes.R)
{
// SM-R870 is a reference to the Samsung Galaxy Watch4
// Note: This is needed to ensure the UI is specific to the UI of a smartwatch
if (Build.Model == "SM-R870")
{
Page watchScreen = new NavigationPage(new WatchScreen());
MainPage = watchScreen;
}
}
else
{
MainPage = homePage;
}
Now I want to make these pages on different devices communicate with each other. HomePage.xaml exists within the main Xamarin.Forms project as well as WatchScreen.xaml.
The way I want them to communicate with each other is by sending a message or something. A Xamarin.Forms project also comes with a native project. In this native Xamarin.Android project I try to retrieve inside the MainActivity.cs the button that exists within the main project by using (in WatchScreen.xaml this button exists and in WatchScreen.xaml.cs I have a method that gives this button back).
Method in WatchScreen.xaml.cs that gives button back:
public Button GetSendButtonFromWearableUI() => btnSendMessage;
In MainActivity.cs I get this method by using:
Button button = (App.Current.MainPage.Navigation.NavigationStack.LastOrDefault() as WatchScreen)
.GetSendButtonFromWearableUI();
Whenever I click on the button by doing this:
button.Clicked += delegate
{
SendData();
};
Some data should be sent from MainActivity.cs and catched by HomePage.xaml and displayed on it. I tried several approaches but I didn't succeed in achieving what needs to happen.. Therefore, I'm wondering if you guys could help me out with this and would be much appreciated.
In the meantime I've been investigating this issue and came up with a solution. Follow steps below to get the same result. To make this solution work I've combined the Wearable Data Layer API from Google and MessagingCenter from Microsoft.
Also the example below shows only the communication from the smartwatch to the smartphone. In order to reverse processes you can put the send button on the HomePage instead of the smartwatch screen and make sure to subscribe to the correct messages.
One last note: keep in mind that code used below from Google is deprecated but it still works...
References used to make this work:
Syncing Data Between Wearable and Handheld Devices Using Xamarin in Android
Installed dependencies on the Xamarin.Android project within Xamarin.Forms project:
Xamarin.Android.Support.v4
Xamarin.GooglePlayServices.Base
Xamarin.GooglePlayServices.Wearable
MessageKeys.cs
This class is used to declare message keys that are being used to send and receive messages between devices.
public class MessageKeys
{
public const string Smartwatch = "Smartwatch";
public const string Smartphone = "Smartphone";
}
Xamarin.Forms (Base project) - App.xaml.cs
In the App.xaml.cs, as pointed out earlier, I'm making sure the wearable UI displays WatchScreen.xaml and any other devices display regular Android UI -> HomePage.xaml.
Xamarin.Forms (Base project) - WatchScreen.xaml.cs
Send message from Wearable device to Android smartphone.
private void btnSendMessage_Clicked(object sender, EventArgs e)
{
MessagingCenter.Send(Xamarin.Forms.Application.Current, MessageKeys.Smartwatch);
}
Xamarin.Forms (Base project) - HomePage.xaml.cs
public HomePage()
{
InitializeComponent();
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, MessageKeys.Smartphone, (sender) =>
{
DisplayAlert("Message", "Wearable message received!", "OK");
});
}
Xamarin.Forms (Native Android Project) - MainActivity.cs
Within MainActivity.cs I implement the following interfaces:
public class MainActivity : WearableActivity, DataClient.IOnDataChangedListener,
GoogleApiClient.IConnectionCallbacks, GoogleApiClient.IOnConnectionFailedListener
Variables:
private GoogleApiClient client;
const string syncPath = "/[project name]/[subdirectory for watch]";
Internal class 'MessageReceiver' for receiving broadcast messages:
[BroadcastReceiver]
public class MessageReciever : BroadcastReceiver
{
MainActivity main;
public MessageReciever() { }
public MessageReciever(MainActivity owner) { this.main = owner; }
public override void OnReceive(Context context, Intent intent)
{
main.ProcessMessage(intent);
}
}
Registering receiver (to receive through Wearable Data Layer API), creating Google Client and Subscribing to smartwatch message (to retrieve message through MessagingCenter)
protected override void OnCreate(Bundle bundle)
{
IntentFilter filter = new IntentFilter(Intent.ActionSend);
MessageReciever receiver = new MessageReciever(this);
LocalBroadcastManager.GetInstance(this).RegisterReceiver(receiver, filter);
client = new GoogleApiClient.Builder(this, this, this)
.AddApi(WearableClass.Api)
.Build();
MessagingCenter.Subscribe<Xamarin.Forms.Application>(Xamarin.Forms.Application.Current, MessageKeys.Smartwatch, (sender) =>
{
SendData();
});
}
ProcessMessage method: sends received message from wearable to smartphone
public void ProcessMessage(Intent intent)
{
// For now I'm not sending the payload...
string message = intent.GetStringExtra("WearMessage");
MessagingCenter.Send(Xamarin.Forms.Application.Current, MessageKeys.Smartphone);
}
SendData(), OnStart(), OnStop(), OnDataChanged (didn't do anything with this part, because this is to receive messages outside the project and I don't need it for now), OnConnected(), OnConnectionSuspended(), OnConnectionFailed():
See the reference to see what code has been used, since code is exactly the same... P.S.: one thing for SendData has been changed. If you want to keep sending data, remove 'client.Disconenct()' from finally after the try and catch block.
Xamarin.Forms (Native Android Project) - WearableService inherits from WearableListenerService:
WearableService is a new class and created within the native project. Also for this part see the reference, because it's the exact same code being used within my project.
To get an overall overview of what's happening, I've visualized this in the diagram below: (example shows how communication works from smartwatch to smartphone)
If you want to communicate from smartphone to smartwatch, you could do something like this:
That's it guys. Now you will receive messages within the same application using the Wearable Data Layer API and MessagingCenter. Instead of having separate projects, we just use separate UIs to make this happen...

Android Vitals “Bad Behaviour” Flags

Google Play recently released the “Android Vitals” feature in the Google Play Console whereby they present analytic information about the released app.
The Android Vitals tab contains analytic information like crashes, ANR, multi-crashes, Slow Rendering, Frozen Frames, etc. They also show “bad behaviour” metrics whereby they compare the analytics of your app with benchmarks. If your app gets flagged with bad beahviours flags, then supposedly it can impact your rankings/downloads etc.
Is anyone else experiencing bad behaviour flags in their app on google play?
Has anyone else seen a dramatic decrease in organic traffic since the Android Vitals tab was introduced?
Does anyone have any advice on how to best solve these “bad behaviour” flags considering our Apps are developed with AS
Thanks in advance
bad behav image
installs
java.lang.NullPointerException:
at com.mydemoapp.player.activity.Dashboard$37.subscribeActual (Dashboard.java:2033)
at io.reactivex.Observable.subscribe (Observable.java:10179)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$1.run (ObservableSubscribeOn.java:39)
at io.reactivex.Scheduler$1.run (Scheduler.java:134)
at io.reactivex.internal.schedulers.ScheduledRunnable.run (ScheduledRunnable.java:59)
at io.reactivex.internal.schedulers.ScheduledRunnable.call (ScheduledRunnable.java:51)
at java.util.concurrent.FutureTask.run (FutureTask.java:237)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run (ScheduledThreadPoolExecutor.java:272)
at java.util.concurrent.ThreadPoolExecutor.runWorker (ThreadPoolExecutor.java:1133)
at java.util.concurrent.ThreadPoolExecutor$Worker.run (ThreadPoolExecutor.java:607)
at java.lang.Thread.run (Thread.java:761)
--
private Observable<ArrayList<HashMap<String, String>>> provideSongListOberservable() {
return new Observable<ArrayList<HashMap<String, String>>>() {
#Override
protected void subscribeActual(Observer<? super ArrayList<HashMap<String, String>>> observer) {
File home = new File(MEDIA_PATH);
String[] values = getResources().getStringArray(R.array.array_songs);
ArrayList<HashMap<String, String>> songsList = new ArrayList<>();
if (home.listFiles(new FileExtensionFilter()).length > 0) {
for (File file : home.listFiles(new FileExtensionFilter())) {
try {
HashMap<String, String> song = new HashMap<>();
song.put(KEY_SONG_TITLE,
values[Integer.parseInt(file.getName().split("_")[1].substring(0,
(file.getName().split("_")[1].length() - 4))) - 1]);
song.put(KEY_SONG_PATH, file.getPath());
// Adding each song to SongList
songsList.add(song);
} catch (Exception e) {
e.printStackTrace();
}
}
}
observer.onNext(songsList);
}
};
}
An "App crashing" bad behavior means your app is crashing a lot.
Google Play has publicly said (eg this talk) that it will use bad behavior as a signal when deciding which how to order apps in search results, and choose which apps to promote.
In order to fix this - get your development team to make crash fixing a priority, not just adding new features. Use the crash reports in the Play console to find out the bugs in your app, and fix them.

Open Android activity automatically on receiving notification

I have to launch the app on receiving notification. The following piece of code works fine when the app is killed and notification is received (i.e the code inside if condition). But when the app is running in foreground or background, multiple instances of the activity gets created(i.e snippet in else condition). It's not the MainActivity that has to be launched on receiving the notification, instead it's some other activity containing the broadcast Receiver.
I have added the following lines in the onMessage of GCMintentService class.
if (currentPackage.equalsIgnoreCase(context.getPackageName()
.toString())) {
broadcastMessage(context, message);
} else {
Intent mIntent = new Intent(context, MainActivity.class);
mIntent.setAction(Intent.ACTION_MAIN);
mIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mIntent);
}
In the activity, under onReceive method of BroadcastReceiver, i am starting the activity again.
private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
startActivity(getIntent().setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
}
};
I also had this requirement in one of my application. We can achieve it if we call
Intent mIntent = new Intent(context, MainActivity.class);
mIntent.setAction(Intent.ACTION_MAIN);
mIntent.addCategory(Intent.CATEGORY_LAUNCHER);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mIntent);
broadcastMessage(context, message);
In the main activity use the following in the broadcast receiver that would receive the broadcasted message above.
WakeLock wakeLock = null;
KeyguardManager kgMgr = (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
boolean locked = kgMgr.inKeyguardRestrictedInputMode();
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
if (!pm.isScreenOn()) {
wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP, "MyWakeLock");
wakeLock.acquire();
}
if (locked) {
Window mWindow = getWindow();
mWindow.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
}
Personally I feel that this is not the best of the answers and also best of the ideas to open the app directly when received a notification as there will be many functions like onCreate onResume, will be triggered automatically, spoil the users work if they are in a really important work by opening another app directly, also we need to put a lot of flags or use any other method to manage the flow of the application, when user open the app, app comes from background, app opened due notification and all such cases. Avoid it as it spoils the whole user experience.

Message Dialog not displaying on Windows 8 tablet - Caliburn.Micro/C#

Has anyone heard of any issues with MessageDialog's not displaying on Windows 8 tablets? Or more specifically Samsung 700t? It uses a regular intel process and not ARM. I built the app on a laptop and the messagedialog shows when debugging from the laptop, shows on the tablet simulator but doesn't show on the actual tablet.
I'm using the Caliburn.Micro IResult interface to display the messagedialog in the view.
Heres snippits of code that I'm using:
public IEnumerable<IResult> NavExecute(String method)
{
Windows.UI.ViewManagement.ApplicationView.TryUnsnap();
var conn = NetworkInformation.GetInternetConnectionProfile();
if (conn.GetNetworkConnectivityLevel() != NetworkConnectivityLevel.InternetAccess)
{
yield return new MessageDialogResult("Internet Connection Not Detected", "Connection Error");
netOn = false;
}
}
the above is in my view model base class, and heres the implementation of the IResult class itself:
public class MessageDialogResult : ResultBase
{
private readonly string _content;
private readonly string _title;
public MessageDialogResult(string content, string title)
{
_content = content;
_title = title;
}
public async override void Execute(ActionExecutionContext context)
{
var dialog = new MessageDialog(_content, _title);
await dialog.ShowAsync();
OnCompleted();
}
}
I doub't it's an issue with the code since I'm debugging in x86 mode on both devices (before anyone asks why I'm not debugging for all devices it's because I'm using SQLite which requires a seperate package for each arhitecture.)
I'm not sure if theres a setting somewhere in Windows 8 that disables in app popups, but I couldn't find one.
Any ideas?
Are you handling the callback of Coroutine.Execute?
The callback on Execute might be calling back with an exception thrown by the coroutine - this would silently fail if you weren't explicitly looking for it in the callback
Coroutine.Execute(YourEnumerator(), new ActionExecutionContext { Blah }, (o, e) => {
if(e.Error != null) // Something went wrong
});
Maybe the async await is throwing or something like that (can't think why!)
Edit:
Ah additionally stuff in your enumerator could also throw:
Windows.UI.ViewManagement.ApplicationView.TryUnsnap();
var conn = NetworkInformation.GetInternetConnectionProfile();
Either one could throw making the outer enumerator swallow an exception if not handled in the callback - or could be a nullref on conn?
The reason why GetInternetConnectionProfile() was returning a null ref was due to the fact that when on a laptop, if you disconnect from a wireless connection the laptop's internet connection profile defaults to ethernet, whereas the tablet (at least the Samsung 700T) doesn't have an ethernet port so it's connection profile doesn't exist if a wireless connection isn't established.
Thanks to Charleh for pointing me in the right direction.

Detect screen on/off from iOS service

I am developing a network monitor app that runs in background as a service. Is it possible to get a notification/call when the screen is turned on or off?
It exists in Android by using the following code:
private void registerScreenOnOffReceiver()
{
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(screenOnOffReceiver, filter);
}
screenOnOffReceiver is then called when screen is turned on/off. Is there a similar solution for iOS?
Edit:
The best I've found so far is UIApplicationProtectedDataWillBecomeUnavailable ( Detect if iPhone screen is on/off ) but it require the user to enable Data Protection (password protection) on the device.
You can use Darwin notifications, to listen for the events. I'm not 100% sure, but it looks to me, from running on a jailbroken iOS 5.0.1 iPhone 4, that one of these events might be what you need:
com.apple.iokit.hid.displayStatus
com.apple.springboard.hasBlankedScreen
com.apple.springboard.lockstate
Update: also, the following notification is posted when the phone locks (but not when it unlocks):
com.apple.springboard.lockcomplete
To use this, register for the event like this (this registers for just one event, but if that doesn't work for you, try the others):
CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), //center
NULL, // observer
displayStatusChanged, // callback
CFSTR("com.apple.iokit.hid.displayStatus"), // event name
NULL, // object
CFNotificationSuspensionBehaviorDeliverImmediately);
where displayStatusChanged is your event callback:
static void displayStatusChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
NSLog(#"event received!");
// you might try inspecting the `userInfo` dictionary, to see
// if it contains any useful info
if (userInfo != nil) {
CFShow(userInfo);
}
}
If you really want this code to run in the background as a service, and you're jailbroken, I would recommend looking into iOS Launch Daemons. As opposed to an app that you simply let run in the background, a launch daemon can start automatically after a reboot, and you don't have to worry about iOS rules for apps running tasks in the background.
Let us know how this works!
Using the lower-level notify API you can query the lockstate when a notification is received:
#import <notify.h>
int notify_token;
notify_register_dispatch("com.apple.springboard.lockstate", &notify_token, dispatch_get_main_queue(), ^(int token) {
uint64_t state = UINT64_MAX;
notify_get_state(token, &state);
NSLog(#"com.apple.springboard.lockstate = %llu", state);
});
Of course your app will have to start a UIBackgroundTask in order to get the notifications, which limits the usefulness of this technique due to the limited runtime allowed by iOS.
While iPhone screen is locked appdelegate method
"- (void)applicationWillResignActive:(UIApplication *)application"
will be called you can check that. Hope it may help you.