Android Wear: Listen to incoming notifications - service

Is it possible to listen for incoming notifications in an Wearable Android App? I have tried to implement a NotificationListenerService, but the service's onNotificationPosted() is never called:
public class MyListenerService extends NotificationListenerService {
#Override
public void onCreate() {
super.onCreate();
Log.d("NotificationListener", "This works....");
}
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
Log.i("NotificationListener", "... but this method won't be called.");
}
}

Try this:
adb shell settings put secure enabled_notification_listeners com.google.android.wearable.app/com.google.android.clockwork.stream.NotificationCollectorService:$YOUR_PACKAGE/$YOUR_PACKAGE.$YOUR_NOTIFICATION_LISTENER

It's not possible to use a NotificationListenerService in Android Wear as there is no screen for the user to allow this.
You have to do it in the device's app and to use the Wearable Data Layer API to perform the action on Wear's side.

Related

How to create a background service in .NET Maui

I'm new to mobile app development and am learning .NET Maui. The app I'm creating needs to listen for Accelerometer events, and send a notification to a web service if the events meet certain criteria. The bit I'm struggling with is how to have the app run in the background, i.e. with no UI visible, without going to sleep, as I'd want the user to close the UI completely. So I'm thinking the app needs to run as some kind of service, with the option to show a UI when needed - how can this be done?
i know it's beign a while but will post an answer for future users!
First we need to understand that background services depends on which platform we use.(thanks Jason) And i will focus on ANDROID, based on Xamarin Documentation (thanks Eli), adapted to Maui.
Since we are working with ANDROID, on MauiProgram we will add the following:
/// Add dependecy injection to main page
builder.Services.AddSingleton<MainPage>();
#if ANDROID
builder.Services.AddTransient<IServiceTest, DemoServices>();
#endif
And we create our Interface for DI which provides us the methods to start and stop the foreground service
public interface IServiceTest
{
void Start();
void Stop();
}
Then, before platform code we need to add Android Permissions on AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Android Main Activity
public class MainActivity : MauiAppCompatActivity
{
//set an activity on main application to get the reference on the service
public static MainActivity ActivityCurrent { get; set; }
public MainActivity()
{
ActivityCurrent = this;
}
}
And Finally we create our Android foreground service. Check Comments Below. Also on xamarin docs, they show the different properties for notification Builder.
[Service]
public class DemoServices : Service, IServiceTest //we implement our service (IServiceTest) and use Android Native Service Class
{
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
[return: GeneratedEnum]//we catch the actions intents to know the state of the foreground service
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (intent.Action == "START_SERVICE")
{
RegisterNotification();//Proceed to notify
}
else if (intent.Action == "STOP_SERVICE")
{
StopForeground(true);//Stop the service
StopSelfResult(startId);
}
return StartCommandResult.NotSticky;
}
//Start and Stop Intents, set the actions for the MainActivity to get the state of the foreground service
//Setting one action to start and one action to stop the foreground service
public void Start()
{
Intent startService = new Intent(MainActivity.ActivityCurrent, typeof(DemoServices));
startService.SetAction("START_SERVICE");
MainActivity.ActivityCurrent.StartService(startService);
}
public void Stop()
{
Intent stopIntent = new Intent(MainActivity.ActivityCurrent, this.Class);
stopIntent.SetAction("STOP_SERVICE");
MainActivity.ActivityCurrent.StartService(stopIntent);
}
private void RegisterNotification()
{
NotificationChannel channel = new NotificationChannel("ServiceChannel", "ServiceDemo", NotificationImportance.Max);
NotificationManager manager = (NotificationManager)MainActivity.ActivityCurrent.GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(channel);
Notification notification = new Notification.Builder(this, "ServiceChannel")
.SetContentTitle("Service Working")
.SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
.SetOngoing(true)
.Build();
StartForeground(100, notification);
}
}
Now we have our foreground Service working on Android, that show a notification ("Service Working"). Every time it starts. I make a show message foreground service to see it better while testing, in your case it suppose to close the app if that's what you want, but the functioning it's the same.
So having our background service working only left a way to call it so on our main page (as example) i will do the following:
MainPage.xaml
<VerticalStackLayout>
<Label
Text="Welcome to .NET Multi-platform App UI"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="start Services"
Clicked="OnServiceStartClicked"
HorizontalOptions="Center" />
<Button Text="Stop Service" Clicked="Button_Clicked"></Button>
</VerticalStackLayout>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
IServiceTest Services;
public MainPage(IServiceTest Services_)
{
InitializeComponent();
ToggleAccelerometer();
Services = Services_;
}
//method to start manually foreground service
private void OnServiceStartClicked(object sender, EventArgs e)
{
Services.Start();
}
//method to stop manually foreground service
private void Button_Clicked(object sender, EventArgs e)
{
Services.Stop();
}
//method to work with accelerometer
public void ToggleAccelerometer()
{
if (Accelerometer.Default.IsSupported)
{
if (!Accelerometer.Default.IsMonitoring)
{
Accelerometer.Default.ReadingChanged += Accelerometer_ReadingChanged;
Accelerometer.Default.Start(SensorSpeed.UI);
}
else
{
Accelerometer.Default.Stop();
Accelerometer.Default.ReadingChanged -= Accelerometer_ReadingChanged;
}
}
}
//on accelerometer property change we call our service and it would send a message
private void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEventArgs e)
{
Services.Start(); //this will never stop until we made some logic here
}
}
It's a long Answer and it would be great to have more official documentation about this! Hope it helps! If anyone can provide more info about IOS, Windows, MacCatalyst would be awesome!

How do I pass an Activity via MethodChannel in Flutter?

I'm making a Flutter app that needs to call a third party library (jar file provided).
The Java documentation for the third-party API object is created by calling something
public class MainActivity extends Activity {
private ThirdPartyAPI mAPI;
private ThirdPartyAPICallbacks mCallbacks = new ThirdPartyAPICallbacks(){
#Override
public void Connected() {
}
};
protected void onCreate(Bundle savedInstanceState) {
mAPI = new ThirdPartyAPI(this, mCallbacks); // how do we do the equivalent in Flutter?
}
}
How do I do this in Flutter?
I tried MethodChannel, but I don't know what to pass as the Activity instance to the ThirdPartyAPI constructor.
MethodChannel doesn't and will never allow to send something like an Activity.
The only types allowed are the following from the official DOCS:
If you really need to send something to Flutter, you'd need to create a method on Flutter which will call Java/Kotlin side, then get anything important you need from that 3rd party API/Library/Etc and send that info back to Flutter using a MethodChannel.
You don't transfer to Activity across the method channel. It only ever exists at the Java end. Instead it gets 'attached' to the Java end of the channel.
When creating a plugin (this is probably preferred as you can re-use it in different projects), make sure the plugin class also implements ActivityAware. Create stub implementation for the four methods required, in particular onAttachedToActivity.
For example:
public class ThirdPartyApiPlugin implements FlutterPlugin, ActivityAware {
#Override
public void onAttachedToActivity(ActivityPluginBinding binding) {
Activity activity = binding.getActivity();
mAPI = new ThirdPartyAPI(activity, mCallbacks);
}
If not using a plugin, modify the MainActivity class as described here.
public class MainActivity extends FlutterActivity {
private static final String CHANNEL = "someChannelName";
#Override
public void configureFlutterEngine(#NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
mAPI = new ThirdPartyAPI(this, mCallbacks);
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL)
.setMethodCallHandler(
(call, result) -> {
// Note: this method is invoked on the main thread.
// TODO
}
);
}
}

Android 8.1 REALLY Persistent Foreground Service Notification

I'm updating my Android app to work with 8.1 from 7. It's not mass-market it's the main alerting app for managed devices - so it NEEDS to stay on.
I have a "persistent" notification for my Foreground service, BUT now in 8+ there's a slider to mute my app notifications.
I can see that android system notifications and other apps remove this slider and display message:
"Notifications from this app can't be turned off".
How do I replicate this pattern?
I've read through notification, service, and channel documentation.
I'm already creating a channel with IMPORTANCE_DEFAULT, using setOngoing(true), and calling startForeground() on the service with the persistent notification:
Here's my Service create and start and channel creation to give you the gist:
public static final String CHANNEL_ID = "ForegroundWebsocketNotificationsServiceChannel";
public static final String CHANNEL_NAME = "WCMobility Notifications";
public static final String CHANNEL_DESCRIPTION = "Required notification and update alerts for WCMobility";
#Override
public void onCreate() {
super.onCreate();
noteMgr = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
createNotificationChannel(CHANNEL_ID);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getAction();
notificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID);
notificationBuilder.setContentTitle("Service Started");
notificationBuilder.setContentText("Not connected, not receiving messages! ");
int notificationIconID = getIconResId(ICON_FILENAME);
notificationBuilder.setSmallIcon(notificationIconID);
notificationBuilder.setOngoing(true);
notificationIntent = new Intent(this, MainActivity.class);
try{ notificationIntent.putExtras(intent.getExtras());
}catch (Exception e){}
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(pendingIntent);
Notification notification = notificationBuilder.build();
startForeground(NOTIFICATION_ID, notification);
return START_NOT_STICKY;
}
private void createNotificationChannel(String channelId) {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(channelId, CHANNEL_NAME, importance);
channel.setDescription(CHANNEL_DESCRIPTION);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
noteMgr.createNotificationChannel(channel);
}
}
We learned that you can't fully block the user from turning off notifications, at least not on consumer devices. Our clients use MDMs and Managed Devices where they restrict access to settings pages etc for end users, plus since the app is primary app used on the phone, user base is not inclined to disable it. This has worked out for us. I did have to add a line to my ForegroundService class code to make the notification dismissable when there was no active session:
stopForeground(false);
stopSelf();
and make it persistant again when session resumed.
startForeground(notificationHelper.NOTIFICATION_ID, notification);
This has worked out for us so far.

Automatically open UWP app that launches on startup

I am working on a UWP app generated by Unity. Following the documentation on StartUpTasks here I have set the app to launch at startup, however when it does it launches minimized in the taskbar. I need the app to be open when it launches, but do not know what to call and where to make this happen.
This is the code generated by Unity:
namespace UnityToUWPApp
{
class App : IFrameworkView, IFrameworkViewSource
{
private WinRTBridge.WinRTBridge m_Bridge;
private AppCallbacks m_AppCallbacks;
public App()
{
SetupOrientation();
m_AppCallbacks = new AppCallbacks();
}
public virtual void Initialize(CoreApplicationView applicationView)
{
applicationView.Activated += ApplicationView_Activated;
CoreApplication.Suspending += CoreApplication_Suspending;
// Setup scripting bridge
m_Bridge = new WinRTBridge.WinRTBridge();
m_AppCallbacks.SetBridge(m_Bridge);
m_AppCallbacks.SetCoreApplicationViewEvents(applicationView);
}
private void CoreApplication_Suspending(object sender, SuspendingEventArgs e)
{
}
private void ApplicationView_Activated(CoreApplicationView sender, IActivatedEventArgs args)
{
CoreWindow.GetForCurrentThread().Activate();
}
public void SetWindow(CoreWindow coreWindow)
{
m_AppCallbacks.SetCoreWindowEvents(coreWindow);
m_AppCallbacks.InitializeD3DWindow();
}
public void Load(string entryPoint)
{
}
public void Run()
{
m_AppCallbacks.Run();
}
public void Uninitialize()
{
}
[MTAThread]
static void Main(string[] args)
{
var app = new App();
CoreApplication.Run(app);
}
public IFrameworkView CreateView()
{
return this;
}
private void SetupOrientation()
{
Unity.UnityGenerated.SetupDisplay();
}
}
}
How can I ensure that when the app starts it is open and active?
UWP apps that are set as Startup task get launched as minimized/suspended by design. This is to ensure a good user experience for Store app by default and avoid having a ton of apps launch into the user's face on boot.
Classic Win32 apps as well as desktop bridge apps can continue to start in the foreground for backwards compat/consistency reasons.
To accomplish your goal, you can include a simple launcher Win32 exe in your package and set that as startup task. Then when it starts you just launch the UWP from there into the foreground. Note that doing this will require you to declare the "runFullTrust" capability, which will require an additional onboard review for the Microsoft Store.
To declare the Win32 exe as startup task, follow the "desktop bridge" section from this doc topic:
https://learn.microsoft.com/en-us/uwp/api/Windows.ApplicationModel.StartupTask

toast when phone is plugged for charging using BroadCast Receiver but not working

I had done an simple app which display some text when the phone is plugged for charging. But its not working on my HTC One X. The below is the code, can any one help?
public class ChargingBroadcastReceiverActivity extends BroadcastReceiver {
#Override
public void onReceive(Context c, Intent i) {
String POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
if (i.getAction().equals(POWER_CONNECTED))
{
Toast.makeText(c, "Thanks For the Power", Toast.LENGTH_LONG).show();
}
}
}
did you set the required uses-permission in android manifest?
and try to use yorclassname.this for the context!