I tried making an app that sends a custom notification to android wear, that part worked but then I wanted to implement a service so that the app will send the notification every minute. But I am missing something,can you guys help me please? Thanks a lot! The error points to "this", I am new to android programming, I really don't know how to solve this.
public class MainActivity extends Activity {
public class notifService extends Service {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
public IBinder onBind(Intent arg0) {
return null;
}
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
final Intent intent1 = new Intent(this, notifService.class);
scheduler.scheduleWithFixedDelay(new Runnable() {
#Override
public void run() {
setContentView(R.layout.activity_main);
//Create PendingIntent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
//Create Notification Action
NotificationCompat.Action action = new NotificationCompat.Action.Builder(
R.mipmap.app_icon, getString(R.string.wearTitle), pendingIntent).build();
//Create Notification
Notification notification = new NotificationCompat.Builder(this)
.setContentText(getString(R.string.content))
.setContentTitle(getString(R.string.title))
.setSmallIcon((R.mipmap.app_icon))
.extend(new NotificationCompat.WearableExtender().addAction(action))
.build();
//Create Notification Manager
NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(this);
notificationManagerCompat.notify(001, notification);
}
}, 60, 60, TimeUnit.SECONDS);
Related
I have an app that schedules a bunch of notifications (user has to answer questionnaires) locally using AlarmManager. The notification should show at certain points in the future.
I schedule the notifications like this:
private void scheduleNotification(Notification notification, int delay, int scheduleId, int notificationId) {
Intent notificationIntent = new Intent(context, NotificationPublisher.class);
notificationIntent.putExtra(NotificationPublisher.NOTIFICATION_ID, notificationId);
notificationIntent.putExtra(NotificationPublisher.INTENT, notification);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, scheduleId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.SECOND, delay);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
The intent is received by a BroadcastReceiver that calls notify on the notification attached to the intent.
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification-id";
public static String INTENT = "notification";
#Override
public void onReceive(Context context, Intent intent) {
if (intent.hasExtra(INTENT)) {
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Notification notification = intent.getParcelableExtra(INTENT);
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
}
}
}
This works fine so far. The problem that I'm facing is that I only want to show the notification if the app is currently not open/shown. If it's open I want to show an AlertDialog instead.
I know that it might be a better idea to put only the plain content of the notification into the intent and only build it when it should be displayed and I want to refactor that later on.
My main problem is, how do I determine in the onReceive of my broadcast receiver if the app is currently showing to decide if a notification or an alert should be displayed?
Or is there an entirely different approach that might work better (for example using WorkManager)?
I think you can handle it on your BroadcastReceiver
public void onReceive(Context context, Intent intent) {
if (isForeground(context))
// AlertDialog
else
// Notification
}
public boolean isForeground(Context mContext) {
ActivityManager activityManager = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
List<ActivityManager.AppTask> tasks = activityManager.getAppTasks();
if (!tasks.isEmpty()) {
ComponentName topActivity = tasks.get(0).getTaskInfo().topActivity;
return topActivity.getPackageName().equals(mContext.getPackageName());
}
return true;
}
I am trying to create an app that will open another app at a specified time. To do this, I used an AlarmManager that starts a service. It works just fine if my app is open when the alarm is triggered. I get a notification that the service started, and the other app opens. However, if my app is in the background (after pressing the home button), and the alarm triggers, I get a notification that the service started, but the other app does not launch. What am I doing wrong? I am testing this on a Pixel 3 emulator running API level 29 (Android 10/Q).
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final int REQUEST_CODE=101;
public static int aHour;
public static int aMinute;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void setAlarm() {
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent intent = new Intent(this, amReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.set(Calendar.HOUR_OF_DAY, aHour);
calendar.set(Calendar.MINUTE, aMinute);
am.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), pendingIntent);
}
//Some code that sets aHour and aMinute
//Some code that triggers setAlarm()
}
amReciever.java
public class amReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context, launcherService.class);
ContextCompat.startForegroundService(getApplicationContext(), i);
}
}
launcherService.java
public class launcherService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText("App is launching.")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
Intent launcher = getApplicationContext().getPackageManager().getLaunchIntentForPackage("com.example.app");
if (launcher != null) {
startActivity(launcher);
}
return START_NOT_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
"Foreground Service Channel",
NotificationManager.IMPORTANCE_DEFAULT
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
}
AndroidManifest.xml
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<service android:name=".launcherService"
android:enabled="true"
android:exported="true" />
As of Android 10 (API level 29), you cannot start activities from the background anymore.
There are a number of exceptions to this rule that may or may not apply to your given scenario.
If none of the exceptions apply, you might want to consider displaying a high-priority notification, possibly with a full-screen Intent.
How to show Foreground Service activity by clicking Notification? When I use my code, it starts new activity, but I need the activity, where service is working. Here is my code (Android Oreo):
public class APSService : Service
{
public static bool isRunning = false;
public override void OnCreate()
{
base.OnCreate();
}
public override void OnDestroy()
{
isRunning = false;
base.OnDestroy();
}
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
isRunning = true;
byte[] input = intent.GetByteArrayExtra("inputExtra");
Intent notificationIntent = new Intent(this, Java.Lang.Class.FromType((typeof(MainActivity))));
PendingIntent pendingIntent = PendingIntent.GetActivity(this,
0, notificationIntent, 0);
var builder = new NotificationCompat.Builder(this, MainActivity.CHANNEL_ID)
.SetContentTitle("APS Service")
.SetSmallIcon(Resource.Drawable.notifypump)
.SetContentText("Start program...")
.SetContentIntent(pendingIntent);
Notification notification = builder.Build();
StartForeground(1, notification);
//do heavy work on background thread
return StartCommandResult.NotSticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
}
And in MainActivity in OnCreate:
protected override void OnCreate(Bundle savedInstanceState)
{
if (!APSService.isRunning)
{
createNotificationChannel();
startService();
}
else
{
NotificationChannel serviceChannel = new NotificationChannel
(
CHANNEL_ID,
"APS service Channel",
NotificationImportance.Default
);
notificationManager = (NotificationManager)GetSystemService(Java.Lang.Class.FromType((typeof(NotificationManager))));
notificationManager.CreateNotificationChannel(serviceChannel);
UpdateNotification("Loading...");
APSService.isRunning = true;
}
}
I hope you would help for solving this problem. Thanks a lot.
I write a demo about it, here is a GIF.
You can achieve the festure like following code.
[Service]
class MyForegroundService : Service
{
public const int SERVICE_RUNNING_NOTIFICATION_ID = 10000;
[return: GeneratedEnum]
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
CreateNotificationChannel();
string messageBody = "service starting";
// / Create an Intent for the activity you want to start
Intent resultIntent = new Intent(this,typeof(Activity1));
// Create the TaskStackBuilder and add the intent, which inflates the back stack
TaskStackBuilder stackBuilder = TaskStackBuilder.Create(this);
stackBuilder.AddNextIntentWithParentStack(resultIntent);
// Get the PendingIntent containing the entire back stack
PendingIntent resultPendingIntent = stackBuilder.GetPendingIntent(0, PendingIntentFlags.UpdateCurrent);
var notification = new Notification.Builder(this, "10111")
.SetContentIntent(resultPendingIntent)
.SetContentTitle("Foreground")
.SetContentText(messageBody)
.SetSmallIcon(Resource.Drawable.main)
.SetOngoing(true)
.Build();
StartForeground(SERVICE_RUNNING_NOTIFICATION_ID, notification);
//do you work
return StartCommandResult.Sticky;
}
public override IBinder OnBind(Intent intent)
{
return null;
}
void CreateNotificationChannel()
{
if (Build.VERSION.SdkInt < BuildVersionCodes.O)
{
// Notification channels are new in API 26 (and not a part of the
// support library). There is no need to create a notification
// channel on older versions of Android.
return;
}
var channelName = Resources.GetString(Resource.String.channel_name);
var channelDescription = GetString(Resource.String.channel_description);
var channel = new NotificationChannel("10111", channelName, NotificationImportance.Default)
{
Description = channelDescription
};
var notificationManager = (NotificationManager)GetSystemService(NotificationService);
notificationManager.CreateNotificationChannel(channel);
}
}
Here is my demo.
https://github.com/851265601/ForegroundServiceDemo
It's not clear to me what Activity you want to open
How to show Foreground Service activity
A Foreground service runs independently from your app
You are launching the MainActivity here:
Intent notificationIntent = new Intent(this,Java.Lang.Class.FromType((typeof(MainActivity))));
can you clarify what do want to do here?
ps: I know it's not an answer, can't comment yet
I am trying to send a http request to my server in the background after I closed the app. But the thread is always being killed. I already tried Workmanager, AlarmManager and BackgroundService. I have been searching in the internet for solutions for the last weeks and I couldn't find any solutions working in newer API's and without a ForegroundService which has to display a notification while running.
Starting AlarmManager:
//NotificationAlarm is the class implementing BroadcastReceiver
Intent intent = new Intent(context, NotificationAlarm.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, ALARM_ID, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setInexactRepeating(AlarmManager.RTC, System.currentTimeMillis(), 10000, pendingIntent);
Until about Android 6 the AlarmManager works to me. However in latest versions it keeps getting closed.
I used the following tutorial as template for BackgroundServices but it still did not work: https://medium.com/#raziaranisandhu/create-services-never-stop-in-android-b5dcfc5fb4b2
I'm Looking forward to an answer.
Did you ever tried ForegroundService?...
you can create class extended as service btw, just add the intent filter on the manifest.
Example from friend's class.
public class ForegroundService extends Service {
public static final String CHANNEL_ID = "ForegroundServiceChannel";
#Override
public void onCreate() {
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String input = intent.getStringExtra("inputExtra");
createNotificationChannel();
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Foreground Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
//do heavy work on a background thread
//stopSelf();
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
And start it as
startForegroundService(context,ForegroundService.class);
There is a lot of options
(Foreground service will start a notification until its dead)
I am running a foreground service via broadcast receiver on boot completed.
It starts the services as desired and take only a a fraction of the device memory use and when I launch the app it increased the device memory usage as it should but when I close the app it still takes too much of memory even though the app has been closed and only the foreground service is running. What I want is really that it should use the same amount of memory after app has been closed as of it was using before the app was opened.
So, I did some digging through Android Profiler and what I found is that when foreground service starts after the boot it only opens Application.class, BroadcastReceiver.class, Service.class and few other background classes. And as I open the app it opens all the above classes and other activities . But when I close the app it still uses the device memory for graphic supports. I don't know how to stop that memory usage after the app has been closed.
Here are some screenshots of my Android Profiler
Before Launching the App through Foreground Notification Memory used 65MB
remember the foreground notification was started from the broadcast receiver after boot complete.
After Launching the app from Notifications Memory used 146 MB
While surfing through activities Memory used 165 MB
After app has been closed Memory used 140 MB
Now I want to know how to achieve the task of using the previous amount of memory use that was 65MB?
Here are my BroadcastReceiver and Service.class code.
Broadcast Receiver
public class BootCompletedIntentListener extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if("android.intent.action.BOOT_COMPLETED".equals(intent.getAction())){
Intent serviceIntent = new Intent(context,ClipMonitorService.class);
ContextCompat.startForegroundService(context,serviceIntent);
}
}
}
Service
public class ClipMonitorService extends Service {
private static final String TAG = "ClipboardManager";
private ExecutorService mThreadPool = Executors.newSingleThreadExecutor();
private ClipboardManager mClipboardManager;
private PrefManager prefManager;
#Override
public void onCreate() {
super.onCreate();
prefManager = new PrefManager(this);
}
#Override
public void onDestroy() {
super.onDestroy();
if (mClipboardManager != null) {
mClipboardManager.removePrimaryClipChangedListener(
mOnPrimaryClipChangedListener);
}
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Intent settingIntent = new Intent(this, SettingActivity.class);
PendingIntent pendingSettIntent = PendingIntent.getActivity(this, 0, settingIntent, 0);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.custom_notification_layout);
remoteViews.setOnClickPendingIntent(R.id.btn_action, pendingSettIntent);
remoteViews.setTextViewText(R.id.notif_subtitle, "1 Clips copied Today");
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContent(remoteViews)
.setVisibility(Notification.VISIBILITY_SECRET)
.setPriority(NotificationCompat.PRIORITY_MIN)
.setContentIntent(pendingIntent)
.setColor(getResources().getColor(R.color.colorPrimary))
.setShowWhen(false)
.build();
startForeground(1, notification);
mClipboardManager =
(ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
mClipboardManager.addPrimaryClipChangedListener(
mOnPrimaryClipChangedListener);
return START_STICKY;
}
private ClipboardManager.OnPrimaryClipChangedListener mOnPrimaryClipChangedListener =
new ClipboardManager.OnPrimaryClipChangedListener() {
#Override
public void onPrimaryClipChanged() {
Log.d(TAG, "onPrimaryClipChangeds");
try {
String textToPaste = mClipboardManager.getPrimaryClip().getItemAt(0).getText().toString();
if (textToPaste.length() > 200) {
if (prefManager.isClipNotifOns()) {
mThreadPool.execute(new MakeNotifRunnable(
textToPaste));
}
}
} catch (Exception ignored) {
}
}
};
private class MakeNotifRunnable implements Runnable {
private final CharSequence mTextToWrite;
public MakeNotifRunnable(CharSequence text) {
mTextToWrite = text;
}
#Override
public void run() {
Intent notifIntent = new Intent(getApplicationContext(), PostNewsActivity.class);
notifIntent.putExtra("post", mTextToWrite);
NotificationManager notificationManager = (NotificationManager) getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
int notificationId = 2;
String channelId = "channel1";
String channelName = "Clipboard Monitor Notification";
int importance = 0;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
importance = NotificationManager.IMPORTANCE_DEFAULT;
}
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
NotificationChannel mChannel = new NotificationChannel(
channelId, channelName, importance);
notificationManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(), channelId)
.setSmallIcon(R.mipmap.ic_launcher_round)
.setContentTitle("Verify copied content")
.setContentText(mTextToWrite)
.setAutoCancel(true)
.setOnlyAlertOnce(true);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext());
stackBuilder.addNextIntent(notifIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
notificationManager.notify(notificationId, mBuilder.build());
}
}
}
Help me to reduce memory usage
I'll be thankful for your answer.
P.S: As I am new to android development I may have uploaded too much information with jargons .Pardon me for that.