I made an Android app that should play a sound when event is received, it works when app is in focus, but when the app is closed/collapsed sound doesnt play, only standard notification.
How to start a sound/music that is placed inside the app when app with the foreground service?
Main activity:
public class MainActivity extends AppCompatActivity {
private Intent alarmServiceIntent;
private ServiceConnection sConn;
private boolean bound;
private boolean alarm = false;
#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Init();
}
private void Init() {
alarmServiceIntent = new Intent(this, AlarmService.class);
sConn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder binder) {
bound = true;
}
public void onServiceDisconnected(ComponentName name) {
bound = false;
}
};
ContextCompat.startForegroundService(this, alarmServiceIntent);
}
private void playAlarm() {
bindService(alarmServiceIntent, sConn, BIND_AUTO_CREATE);
}
public void stopAlarm(View v) {
if (sConn != null ) {
unbindService(sConn);
}
if(alarmServiceIntent != null) {
stopService(alarmServiceIntent);
}
}
//here is the method to receive event and call playAlarm
}
Alarm service:
public class AlarmService extends Service{
private final String CHANNEL_ID = "ID";
private final String CHANNEL_NAME = "NAME";
private IBinder mBinder = new MyBinder();
private MediaPlayer player;
#Nullable
#Override
public IBinder onBind(Intent intent) {
play();
return mBinder;
}
#Override
public boolean onUnbind(Intent intent) {
onStop();
return super.onUnbind(intent);
}
#Override
public void onCreate() {
player = MediaPlayer.create(this,R.raw.alarm);
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
super.onCreate();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
pendingIntent = PendingIntent.getActivity
(this, 0, notificationIntent, PendingIntent.FLAG_MUTABLE);
}
else
{
pendingIntent = PendingIntent.getActivity
(this, 0, notificationIntent, PendingIntent.FLAG_ONE_SHOT);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("TITLE")
.setSmallIcon(R.mipmap.icon)
.setContentIntent(pendingIntent)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel( CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
mNotificationManager.createNotificationChannel(channel);
new NotificationCompat.Builder(this, CHANNEL_ID);
}
startForeground(619, notification);
return START_REDELIVER_INTENT;
}
public void play() {
if(player == null) {
player = MediaPlayer.create(this,R.raw.alarm);
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
}
Log.v("ALARM", "play: 12345");
player.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
);
player.setVolume(2,2);
AudioManager audioManager = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
// audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
player.setLooping(true);
player.start();
}
class MyBinder extends Binder {
AlarmService getService(){
return AlarmService.this;
}
}
}
You should override onDestroy method and call stop there.
#Override
public void onDestroy() {
player.stop();
}
Related
When the app is in the foreground can get calls well, but when is in the background and a call is active and the run app: it can not get that's call.
When the app is in the foreground, get call works well (get push-notification and connecting is being automatically, also you can push "Incoming Call" notification to connecting call).
I fixed it in swift but I cant fix it for android.
ios fixed with this funcs:
func applicationDidEnterBackground(_ application: UIApplication) {
if !isCallScreen {
UIApplication.shared.unregisterForRemoteNotifications()
}
}
func funBack() {
let state = UIApplication.shared.applicationState
if state == .background {
UIApplication.shared.unregisterForRemoteNotifications()
}
if isCallScreen {
isCallScreen = false
DispatchQueue.main.async {
self.window?.rootViewController?.navigationController?.popViewController(animated: true)
}
}
}
Messaging service
public class MessagingService extends FirebaseMessagingService {
private int notificationNumber = 1;
private LocalBroadcastManager broadcaster;
private int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
private DatabaseReference mDatabase;
private SinchClient sinchClient;
private SharedPref pref;
public static boolean firsttimeFun = true;
#Override
public void onCreate() {
broadcaster = LocalBroadcastManager.getInstance(this);
pref = new SharedPref(this);
}
#RequiresApi(api = Build.VERSION_CODES.N)
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
//
if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
NotificationResult result = sinchClient.relayRemotePushNotificationPayload(
remoteMessage.getData());
}
if (!AppLifecycleListener.isActivityVisible()) {
AppLifecycleListener.activityResumed();
}
// it's NOT Sinch message - process yourself
class FcmListenerService extends FirebaseMessagingService {
#Override
public void onMessageReceived(RemoteMessage remoteMessage){
Map data = remoteMessage.getData();
if (SinchHelpers.isSinchPushPayload(data)) {
new ServiceConnection() {
private Map payload;
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (sinchClient != null) {
NotificationResult result = sinchClient.relayRemotePushNotificationPayload(payload);
// handle result, e.g. show a notification or similar
}
}
#Override
public void onServiceDisconnected(ComponentName name) {}
public void relayMessageData(Map<String, String> data) {
payload = data;
getApplicationContext().bindService(new Intent(getApplicationContext(), CallActivity.class), this, BIND_AUTO_CREATE);
}
}.relayMessageData(data);
}
}
}
// String bundleString = remoteMessage.getNotification().getBody();
//
// String bundleString = remoteMessage.getData().get("message");
Map bundle = remoteMessage.getData();
String callId = bundle.get("callID").toString();
String groupname = bundle.get("group").toString();
try {
bundle.get("hangup").toString();
Intent intent = new Intent("MyData");
intent.putExtra("callID", callId);
broadcaster.sendBroadcast(intent);
return;
} catch (Exception e) {
e.printStackTrace();
}
//IF app is in background use return for ignore notifications
if (!AppLifecycleListener.isActivityVisible()) {
sendNotification(callId, groupname);
//return;
}
Log.i("MessageFrom", "From: " + callId);
if (firsttimeFun) {
firsttimeFun = false;
startActivity(new Intent(this, CallActivity.class).putExtra("callerId", callId).putExtra("name", groupname).putExtra("isOutGoing", false).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
if (AppLifecycleListener.isActivityVisible())
sendNotification(callId, groupname);
//return;
// sendNotification(bundle.get("message").toString());
}
#Override
public void onNewToken(String s) {
/* HashMap map=new HashMap();
map.put("fcmToken",s);
mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("Users").child(pref.getUserId()).updateChildren(map);*/
}
#RequiresApi(api = Build.VERSION_CODES.N)
private void sendNotification(String callId, String groupname) {
PendingIntent contentIntent;
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, CallActivity.class).putExtra("callerId", callId).putExtra("name", groupname).putExtra("isOutGoing", false), 0);
int notifyID = 1;
String CHANNEL_ID = "CallAppChanel";// The id of the channel.
CharSequence name = getString(R.string.channel_name);// The user-visible name of the channel.
int importance = NotificationManager.IMPORTANCE_HIGH;
NotificationChannel mChannel = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mChannel = new NotificationChannel(CHANNEL_ID, "Channel 1", importance);
}
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.icon)
.setContentTitle("Incoming Call")
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setContentIntent(contentIntent)
.setColor(getResources().getColor(R.color.purple))
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setChannelId(CHANNEL_ID)
.setPriority(importance)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.build();
int notificationId = new Random().nextInt(100) + 1;
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mNotificationManager.createNotificationChannel(mChannel);
mNotificationManager.notify(notificationId, notification);
} else {
mNotificationManager.notify(notificationId, notification);
}
}
}
AppLifecycleListener
public class AppLifecycleListener extends Application implements Application.ActivityLifecycleCallbacks, LifecycleObserver {
private Context context;
Activity activityRunning;
private static Application instance;
private static boolean activityVisible;
private boolean inForeground;
public void setContext(Context context) {
this.context = context;
}
public Context getContext() {
return this.context;
}
public static Context getContextApp() {
return instance.getApplicationContext();
}
#Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
MultiDex.install(this);
/*getVersionRequest(this);*/
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
activityRunning = activity;
}
#Override
public void onActivityStarted(#NonNull Activity activity) {
}
#Override
public void onActivityResumed(Activity activity) {
// Utility.logCatMsg("Activity Resume : " + activity.getLocalClassName());
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener((Activity) context, new OnSuccessListener<InstanceIdResult>() {
#Override
public void onSuccess(InstanceIdResult instanceIdResult) {
String newToken = instanceIdResult.getToken();
Log.e("newToken",newToken);
}
});
}
#Override
public void onActivityPaused(Activity activity) {
// Utility.logCatMsg("Activity Pause : " + activity.getLocalClassName());
}
#Override
public void onActivityStopped(Activity activity) {
// Utility.logCatMsg("Activity Stop : " + activity.getLocalClassName());
}
#Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
}
#Override
public void onActivityDestroyed(Activity activity) {
// Utility.logCatMsg("Activity Destroyed : " + activity.getLocalClassName());
}
public static boolean isActivityVisible() {
return activityVisible;
}
public static void activityResumed() {
activityVisible = true;
}
public static void activityPaused() {
activityVisible = false;
}
}
I try to app runs in background and service listens if screen on app launch on lock screen, we can do android 9 and 9- but we cant achieve android 9+, We use JobIntentService for android 9+ it runs sometimes how can we do that??
YourService.java extend JobIntentService
public class YourService extends JobIntentService {
public static final int JOB_ID = 1;
public static void enqueueWork(Context context, Intent work) {
enqueueWork(context, YourService.class, JOB_ID, work);
}
#Override
protected void onHandleWork(#NonNull Intent intent) {
Log.e("çalıştı","çalıştı job");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Haydi Kurtuluşa")
//.setContentText(input)
.setSmallIcon(R.drawable.more)
.setContentIntent(pendingIntent)
.setNumber(0)
.build();
Log.e("Myservice","myservice jobbbbb");
startForeground(1, notification);
}
}
MyReceiver.java
public class MyReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
//#RequiresApi(api = Build.VERSION_CODES.O)
#Override
public void onReceive(Context context, Intent intent) {
Log.e("ekran", "açıldı");
if(intent.getAction().equals("android.intent.action.SCREEN_ON") ){
wasScreenOn = true;
Log.e("evet screen on","evet screen on");
Intent i = new Intent(context, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent =
PendingIntent.getActivity(context, 0, i, 0);
try {
pendingIntent.send();
Log.e("pendingIntent","pendingIntent");
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
Log.e("printStackTrace","printStackTrace");
}
}
Intent startServiceIntent = new Intent(context, MyService.class);
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) {
context.startForegroundService(startServiceIntent);
Log.e("Myservice","myservice receicer en alt");
}
else {
context.startService(startServiceIntent);
Log.e("Myservice","myservice receicer en dahaaaa alt");
}
YourService.enqueueWork(context, new Intent());
}
}
MyService.java
public class MyService extends Service {
MainActivity mainActivity = new MainActivity();
MyReceiver myReceiver = new MyReceiver();
public MyService() {
}
#Override
public void onCreate() {
super.onCreate();
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId){
// do your jobs here
// startForeground();
//return super.onStartCommand(intent, flags, startId);
String input = intent.getStringExtra("inputExtra");
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Haydi Kurtuluşa")
//.setContentText(input)
.setSmallIcon(R.drawable.more)
.setContentIntent(pendingIntent)
.setNumber(0) // bildirim simgesinin 1 diye gösterilip gösterilmemesini sağlar
.build();
Log.e("Myservice","myservice onstartcommand");
startForeground(1, notification);
return START_NOT_STICKY;
}
#Override
public void onDestroy() {
Log.e("service destroy","service destroy");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = prefs.edit();
editor.putBoolean("ilkk", true);
editor.commit();
super.onDestroy();
}
}
This code is in MainActivity
final Window win= getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
// win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
setTurnScreenOn(true);
setShowWhenLocked(true);
}
// REVEIRVER
// bu dinliyor eğer ekran açılırsa tak MyReceiver classa gönderiyor.
IntentFilter screenStateFilter = new IntentFilter();
screenStateFilter.addAction(Intent.ACTION_SCREEN_ON);
screenStateFilter.addAction(Intent.ACTION_SCREEN_OFF);
myReceiver =new MyReceiver();
registerReceiver(myReceiver,screenStateFilter);
Log.e("geldi3","geldi3");
Log.e("burada ","geldi");
I've made an Android app that main feature is to play audio stream from my server. But for some reason music stops playing after about 20 minutes and the app is throwing ProtocolException (logs from app on Android Studio logcat image).
Android Studio logcat
This error is even more weird because it occurs only on some devices. Error occurs on multiple Xiaomi devices (all with Android 10) and Samsung Galaxy S9 (also with Android 10) but on Samsung Galaxy S10 (Android 10) and Huawai tablet that error doesn't occur and music is being played as long as user does not stop it.
This is my PlayerService class code that is responsible for running MediaPlayer as a service:
public class PlayerService extends Service {
private static final String CHANNEL_ID = "PlayerServiceChannel";
private static final int SERVICE_ID = 1;
private MediaPlayer player;
private Notification notification;
private JsonObjectHandler jsonObjectHandler;
private int streamIndex = 9999;
private Messenger messenger;
private PendingIntent pendingIntent;
private NotificationManager notificationManager;
private PendingIntent closeApp;
private WifiManager.WifiLock wifiLock;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
JSONObject jsonObject = new JSONObject(Objects.requireNonNull(intent.getStringExtra("JsonInfo")));
jsonObjectHandler = new JsonObjectHandler(jsonObject);
} catch (JSONException e) {
jsonObjectHandler = null;
}
return START_REDELIVER_INTENT;
}
#Override
public void onCreate() {
super.onCreate();
wifiLock = ((WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE))
.createWifiLock(WifiManager.WIFI_MODE_FULL_HIGH_PERF, "playerServiceWiFiLock");
HandlerThread thread = new HandlerThread("ServiceStartArgument", Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
Looper mServiceLooper = thread.getLooper();
ServiceHandler mServiceHandler = new ServiceHandler(mServiceLooper);
messenger = new Messenger(mServiceHandler);
PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
#Override
public void onCallStateChanged(int state, String incomingNumber) {
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
case TelephonyManager.CALL_STATE_OFFHOOK:
stopForeground(true);
stopSelf();
break;
case TelephonyManager.CALL_STATE_IDLE:
break;
}
super.onCallStateChanged(state, incomingNumber);
}
};
TelephonyManager mgr = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
if (mgr != null) {
mgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
}
createNotificationChannel();
Intent notificationIntent = new Intent(this, LoginActivity.class);
pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
stopSelf();
unregisterReceiver(this);
System.exit(0);
}
};
IntentFilter intentFilter = new IntentFilter("android.intent.CLOSE_APP");
registerReceiver(broadcastReceiver, intentFilter);
Intent intentClose = new Intent("android.intent.CLOSE_APP");
closeApp = PendingIntent.getBroadcast(this, 0, intentClose, 0);
updateNotification(streamIndex);
startForeground(SERVICE_ID, notification);
}
private NotificationCompat.Builder createNotification(int streamIndex) {
String defaultValue;
if (jsonObjectHandler == null || streamIndex == 9999) {
defaultValue = "";
} else {
defaultValue =
jsonObjectHandler.getPlaylistButtons().get(streamIndex).getButtonName();
}
return new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ikonastream48)
.setContentIntent(pendingIntent)
.setContentTitle(getString(R.string.app_name))
.setContentText(defaultValue)
.setDefaults(0)
.setSound(null)
.addAction(R.drawable.ic_close_black, getString(R.string.close), closeApp);
}
private void updateNotification(int streamIndex) {
notification = createNotification(streamIndex).build();
notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
assert notificationManager != null;
notificationManager.notify(SERVICE_ID, notification);
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID, "Example Service Channel", NotificationManager.IMPORTANCE_DEFAULT);
serviceChannel.setSound(null, null);
notificationManager = getSystemService(NotificationManager.class);
if (notificationManager != null) {
notificationManager.createNotificationChannel(serviceChannel);
}
}
}
private void stopServicePlayer() {
if (player != null) {
player.stop();
player.reset();
player.release();
player = null;
}
stopForeground(true);
}
#Override
public void onDestroy() {
super.onDestroy();
stopServicePlayer();
if (wifiLock.isHeld()) wifiLock.release();
}
private void sendMessageBroadcast(Intent intent) {
LocalBroadcastManager.getInstance(getApplicationContext()).sendBroadcast(intent);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
if (streamIndex != 9999) {
Intent intent1 = new Intent("streamIndex");
intent1.putExtra("INDEX", streamIndex);
sendMessageBroadcast(intent1);
}
return messenger.getBinder();
}
private final class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
if (msg.what == 0) {
player = new MediaPlayer();
player.setOnErrorListener((mp, what, extra) -> false);
player.setAudioAttributes(new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build());
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setWakeMode(getApplicationContext(), PowerManager.PARTIAL_WAKE_LOCK);
streamIndex = msg.arg1;
updateNotification(streamIndex);
try {
player.setOnPreparedListener(mediaPlayer -> {
mediaPlayer.start();
Intent intent = new Intent("streamIndex");
intent.putExtra("INDEX", streamIndex);
sendMessageBroadcast(intent);
});
player.setDataSource(jsonObjectHandler
.getPlaylistButtons()
.get(streamIndex)
.getButtonStreamAddress());
} catch (IOException e) {
e.printStackTrace();
}
player.prepareAsync();
if (!wifiLock.isHeld()) wifiLock.acquire();
} else if (msg.what == 1) {
Intent intent2 = new Intent("streamIndex");
intent2.putExtra("INDEX", streamIndex);
sendMessageBroadcast(intent2);
}
}
}
}
Thank you for all responses in advance!
P.S. The code was written few years ago (at the beginning of my programming journey), so I'm aware that it looks bad and need to be rewritten in better way.
Disable caches and retry :
Map<String, String> headers = new HashMap<>();
headers.put("Content-Type", "audio/mp3");
headers.put("Accept-Ranges", "bytes");
headers.put("Status", "206");
headers.put("Cache-control", "no-cache");
Uri uri = Uri.parse(yourContentUrl);
player.setDataSource(getApplicationContext(), uri, headers);
The problem was on the server side. When the stream was switched from CBR to the VBR in the Lame encoder, the problem stop occurring.
SO, I have a MainActivity that has a button which starts a service, MyService. I want the service to show the notification with a custom title,text,icon,etc. The service is a foreground service. not a bound service. everything works fine but the only thing is about my notification is keep showing "tap for more information" and clicking on it leads me to the settings page of my application. despite having the pendingIntent on my MainActivity.
What I want is to have a Notification with custom Title,Text,icon and an action to stop the service.
this is my MainActivity.java class
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.start_tracking).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startCommand();
}
});
}
void startCommand() {
startService(new Intent(this, MyService.class));
}
}
Myservice.java file
public class MyService extends Service {
boolean mServiceIsStarted = false;
void moveToStartedState() {
Intent myIntentbuilder = new IntentBuilder(this).setmCommandId(Command.START).build();
Log.d(TAG, "moveToStartedState: Running on Android O - startForegroundService(intent)");
ContextCompat.startForegroundService(this, myIntentbuilder);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "onStartCommand: ");
boolean containsCommand = IntentBuilder.containsCommand(intent);
routeIntentToCommand(intent);
return START_NOT_STICKY;
}
void routeIntentToCommand(Intent intent) {
if (intent != null) {
if (IntentBuilder.containsCommand(intent)) {
processCommand(IntentBuilder.getCommand(intent));
} else
commandStart();
}
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate: ");
}
void showNotification() {
Log.d(TAG, "showNotification: ");
HandleNotification.O.createNotification(this);
}
private void processCommand(int command) {
try {
switch (command) {
case Command.START:
commandStart();
break;
case Command.STOP:
commandStop();
break;
}
} catch (Exception e) {
e(TAG, "processCommand: exception", e);
}
}
void commandStop() {
stopSelf();
stopForeground(true);
}
void commandStart() {
if (!mServiceIsStarted) {
mServiceIsStarted = true;
moveToStartedState();
return;
}
//
HandleNotification.O.createNotification(this);
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
IntentBuilder.java class
#IntDef({Command.INVALID, Command.STOP, Command.START})
#Retention(RetentionPolicy.SOURCE)
#interface Command {
int INVALID = -1;
int STOP = 0;
int START = 1;
}
public class IntentBuilder {
private static final String KEY_MESSAGE = "msg";
private static final String KEY_COMMAND = "cmd";
private Context mContext;
private String mMessage;
private #Command
int mCommandId = Command.INVALID;
public static IntentBuilder getInstance(Context mContext) {
return new IntentBuilder(mContext);
}
public IntentBuilder(Context mContext) {
this.mContext = mContext;
}
public void setmContext(Context mContext) {
this.mContext = mContext;
}
public IntentBuilder setmMessage(String mMessage) {
this.mMessage = mMessage;
return this;
}
public IntentBuilder setmCommandId(int mCommandId) {
this.mCommandId = mCommandId;
return this;
}
private static final String TAG = "IntentBuilder";
public Intent build() {
Log.e(TAG, "build: context cannot be null" + mContext);
Intent intent = new Intent(mContext, MyService.class);
if (mMessage != null)
intent.putExtra(KEY_MESSAGE, mMessage);
if (mCommandId != Command.INVALID)
intent.putExtra(KEY_COMMAND, mCommandId);
return intent;
}
public static boolean containsCommand(Intent intent) {
return intent.getExtras() != null && intent.getExtras().containsKey(KEY_COMMAND);
}
public static boolean containsMessage(Intent intent) {
return intent.getExtras() != null && intent.getExtras().containsKey(KEY_MESSAGE);
}
public static #Command
int getCommand(Intent intent) {
final #Command int commandId = intent.getExtras().getInt(KEY_COMMAND);
return commandId;
}
public static String getMessage(Intent intent) {
return intent.getExtras().getString(KEY_MESSAGE);
}
}
HandleNotification.java file
public class HandleNotification {
public static class O {
public static int getRandomNumber() {
return new Random().nextInt(100000);
}
static PendingIntent getLaunchActivityPI(Service context) {
Intent intent = new Intent(context, MainActivity.class);
return PendingIntent.getActivity(context, getRandomNumber(), intent, 0);
}
static PendingIntent getStopServicePI(Service context) {
PendingIntent pendingIntent;
{
Intent intent = new IntentBuilder(context).setmCommandId(Command.STOP).build();
pendingIntent = PendingIntent.getService(context, getRandomNumber(), intent, 0);
}
return pendingIntent;
}
public static final Integer ONGOING_NOTIFICATION_ID = getRandomNumber();
public static final String CHANNEL_ID = String.valueOf(getRandomNumber());
private static final String TAG = "O";
public static void createNotification(Service context) {
Log.d(TAG, "createNotification: ");
String channelId = createChannel(context);
Notification notification = buildNotification(channelId, context);
context.startForeground(ONGOING_NOTIFICATION_ID, notification);
}
static Notification buildNotification(String channelId, Service context) {
PendingIntent piMainActivity = getLaunchActivityPI(context);
PendingIntent piStopService = getStopServicePI(context);
Icon poweroff = Icon.createWithResource(context, android.R.drawable.star_big_on);
Notification.Action stopAction = new Notification.Action
.Builder(poweroff, "STOP", piStopService).build();
return new Notification.Builder(context, channelId)
.addAction(stopAction)
.setContentTitle("Tracking...")
.setContentText("I'm tracking your location now... ")
.setContentIntent(piMainActivity)
.build();
}
#NonNull
private static String createChannel(Context service) {
NotificationManager notificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
CharSequence channelName = "Start Location Updates";
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel notificationChannel = new NotificationChannel(CHANNEL_ID, channelName, importance);
notificationManager.createNotificationChannel(notificationChannel);
return CHANNEL_ID;
}
}
}
Use NotificationCompat.Builder. You can follow how to create one here
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(textTitle)
.setContentText(textContent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
You can add your custom small or big icon, title, content, and other properties.
An example from a project that I did long ago
private void LockNotification() {
NotificationCompat.Builder builder = new
NotificationCompat.Builder(getApplicationContext());
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("key","launch_about");
PendingIntent pendingIntent =
PendingIntent.getActivity(getApplicationContext(), 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
// Set the title, text, and icon
builder.setContentTitle(getString(R.string.app_name))
.setContentText("App Lock Enabled")
.setSmallIcon(R.drawable.ic_applock)
.setContentIntent(pendingIntent)
.setOngoing(true);
// Get an instance of the Notification Manager
NotificationManager notifyManager = (NotificationManager)
getSystemService(Context.NOTIFICATION_SERVICE);
// Build the notification and post it
notifyManager.notify(0, builder.build());
}
So, im working on making daily notifications for my app. And it works somehow, but the problem is that everytime i start the app or restart, it starts a notification randomly. Its just really frustating.
I've been going trough the code many times, and i just cant see why its happens
So here is everything that have to do with notifications
MainActivity.java
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
public NavigationView navigationView;
private NotificationManagerCompat notificationManager;
SharedPreferences preferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Notifications
preferences = getSharedPreferences("shared preferences", Context.MODE_PRIVATE);
SetNotification();
}
public void SetNotification(){
if (GetNotificationsChecked()){
Intent notificationIntent =new Intent(this,Notification_Reciever.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,notificationIntent,PendingIntent.FLAG_ONE_SHOT);
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(preferences.getString("notificationsHour", "15"))) ;
calendar.set(Calendar.MINUTE, Integer.valueOf(preferences.getString("notificationsMinute", "00"))) ;
if (manager != null) {
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
}
public boolean GetNotificationsChecked(){
boolean i = preferences.getBoolean("notifications", true);
return i;
}
}
Notification_reciever.java
public class Notification_Reciever extends BroadcastReceiver {
private NotificationManagerCompat notificationManagerCompat;
#Override
public void onReceive(Context context, Intent intent) {
Intent activityIntent = new Intent(context, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(context,
0, activityIntent, 0);
notificationManagerCompat = NotificationManagerCompat.from(context);
Notification notification = new NotificationCompat.Builder(context,CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_face)
.setContentTitle("Your Daily Life Tip!")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_ALARM)
.setContentIntent(contentIntent)
.setStyle(new NotificationCompat.BigTextStyle()
.setSummaryText("Daily Notification"))
.setAutoCancel(true)
.setContentText(getlifetip(context))
.setColor(Color.parseColor("#EE3D33"))
.build();
notificationManagerCompat.notify(0, notification);
}
public String getlifetip(Context context){
//gets lifetip from jsonobject
}
MyService.java
public class MyService extends Service {
SharedPreferences preferences;
public MyService(){
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
SetNotification();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null){
SetNotification();
}else Toast.makeText(this, "Intent was null", Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent, flags,startId);
}
public void SetNotification(){
preferences = getSharedPreferences("shared preferences", Context.MODE_PRIVATE);
if (GetNotificationsChecked()){
Intent notificationIntent =new Intent(this,Notification_Reciever.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this,0,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
try{
manager.cancel(pendingIntent);
}catch (Exception ignored){}
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.HOUR_OF_DAY, Integer.valueOf(preferences.getString("notificationsHour", "15"))) ;
calendar.set(Calendar.MINUTE, Integer.valueOf(preferences.getString("notificationsMinute", "00"))) ;
if (manager != null) {
manager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(),AlarmManager.INTERVAL_DAY, pendingIntent);
}
}
}
public boolean GetNotificationsChecked(){
boolean i = preferences.getBoolean("notifications", true);
return i;
}
}
BootReciever.java
public class BootReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent i = new Intent(context,MyService.class);
context.startService(i);
}
}
App.java
public class App extends Application {
public static final String CHANNEL_1_ID = "dailylifetip";
#Override
public void onCreate() {
super.onCreate();
CreateNotificationChannel();
}
private void CreateNotificationChannel(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel1 = new NotificationChannel(
CHANNEL_1_ID,
"Daily Life Tips",
NotificationManager.IMPORTANCE_HIGH
);
channel1.setDescription("This is the daily life tips channel");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel1);
}
}
}
Manifest
<receiver android:name=".Notification_Reciever"/>
<service android:name=".MyService" android:enabled="true" android:exported="true"/>
The user selects the hour and minute of the day in an options menu, and is saved in preferences. And then should give an notification everyday on that time. And that works!. But everytime you open the app it randomly sends you a notifications, there is no errors.