Hey there I am using below code to turn the device into silence mode.
public static void setDeviceOnSilent(Context context) {
AudioManager audioManager = (AudioManager) context.getSystemService(AUDIO_SERVICE);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}
The above code work well in all device except Gionee A1. Please suggest what is the problem i already given the NotificationAccessPolicyEnabled Permission. below is the code.
public static boolean isNotificationAccessPolicyEnabled(Context context) {
NotificationManager notificationManager;
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& !notificationManager.isNotificationPolicyAccessGranted()) {
Intent intent = new Intent(
android.provider.Settings
.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
context.startActivity(intent);
return false;
}
return true;
}
The code looks pretty much alright. Check the manifest for the necessary permissions.
Related
Prerequisites:
As a part of the requirement for my application, I need to make sure that the application won't be closed (killed) by the Android system while in background. For this purpose I implemented Foreground service, even though I don't do any actual process in background, just maintaining the state of the application. Everything works just fine, except one thing which is not fully clear to me how to fix.
The issue:
Sometimes (only once, for now), I receive this exception:
android.app.RemoteServiceException: Context.startForegroundService() did not then call Service.startForeground():
This exception is thrown when I'm trying to stop the foreground service while it wasn't actually started.
So, my question is - is there is a way to stop foreground service properly, making sure that it is not running before actually stopping it?
What I found at the moment is that I can have static instance for my service and compare to null before stopping service, or get the list of all services currently running. But all these look like some "hack" workarounds.
Here some code:
MyForegroundService:
public class ForegroundService extends Service {
public static final int NOTIFICATION_ID = 1;
public static final String CHANNEL_ID = "SessionForegroundServiceChannel";
public static final String ACTION_FOREGROUND_START = "ACTION_FOREGROUND_START";
public static final String ACTION_FOREGROUND_STOP = "ACTION_FOREGROUND_STOP";
public static void startForegroundService(Context context) {
Intent intent = new Intent(context, ForegroundService.class);
intent.setAction(ForegroundService.ACTION_FOREGROUND_START);
ContextCompat.startForegroundService(context, intent);
}
public static void stopForegroundService(Context context) {
Intent intent = new Intent(context, ForegroundService.class);
intent.setAction(ForegroundService.ACTION_FOREGROUND_STOP);
ContextCompat.startForegroundService(context, intent);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (ACTION_FOREGROUND_START.equals(intent.getAction())) {
createNotificationChannel();
Intent stopForegroundIntent = new Intent(this, ForegroundServiceBroadcastReceiver.class);
PendingIntent pendingLogoutIntent = PendingIntent.getBroadcast(this,
0, stopForegroundIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? null
: getString(R.string.app_short_name))
.setContentText(getString(R.string.foreground_description))
.setColor(getResources().getColor(R.color.color))
.setSmallIcon(R.drawable.ic_notification)
.addAction(R.drawable.ic_logout, getString(R.string.logout), pendingLogoutIntent)
.build();
startForeground(NOTIFICATION_ID, notification);
} else if (ACTION_FOREGROUND_STOP.equals(intent.getAction())) {
stopForeground(true);
stopSelf();
}
return START_STICKY;
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel serviceChannel = new NotificationChannel(
CHANNEL_ID,
getString(R.string.app_name),
NotificationManager.IMPORTANCE_LOW
);
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(serviceChannel);
}
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
<service
android:name=".ui.ForegroundService"
android:exported="false"
android:stopWithTask="true"/>
I also have BroadcastReceiver and EventBus to listen to some events and stop foreground depending on those events.
Can you please help me, guys?
Let me add more details to what #Pawel commented:
You get this exception if you don't call Service.startForeground within 3 seconds of calling Context.startForegroundService that's all there's to it.
Here is how the complete solution will look like:
When it comes to the case when you need to stop a foreground service you need to do the following (pseudo code):
if (action == START_FOREGROUND) {
...
startForeground(NOTIFICATION_ID, notification);
} else if (action == STOP_FOREGROUND) {
startForeground(NOTIFICATION_ID, closeNotification); //in case it wasn't started before
stopForeground(true);
stopSelf();
}
Even though it is not obvious, and any documentation don't directly say that when you need to stop foreground you need to start foreground before stopping it (if it wasn't started).
Thanks #Pawel for the hint.
so I made an app a couple months back that helped me improve my sleep. I have sleeping issues and, it sounds odd, but I use the app to vibrate my phone when I go to bed to give myself something to focus on to go to sleep, it is currently a vital aspect of my sleep routine.
However, I updated my phone to Android 10 yesterday and it completely broke the app. Before, the app would vibrate when I click the start button and continue to vibrate even after I lock the phone by using a background service, broadcast receiver, and wake lock. Now though, the app stops vibrating after I lock the phone and nothing in the console gives any reason as to why it is doing this.
If anyone could give advice on what I could change in the code or something, it would be much appreciated as I'm completely lost as to what to do and I have to get this to work somehow.
Here is the code:
Function in MainActivity that handles the beginning of the service Vibrate:
// Event for when the VIBRATE button is pressed
public void beginVibration(View view) {
// Given either of the bars are not 0
if (durationBar.getProgress() != 0 || delayBar.getProgress() != 0) {
// Get the values for each bar and set them accordingly in the vibration value array
long[] pattern = {0, durationBar.getProgress(), delayBar.getProgress()};
// Setup the ServiceConnection to monitor the Vibrate service
c = new ServiceConnection() {
#Override
public void onServiceConnected(ComponentName name, IBinder service) {
m_service = ((Vibrate.MyBinder)service).getService();
}
#Override
public void onServiceDisconnected(ComponentName name) {
m_service = null;
}
};
// Bind the service to the connection
bindService(i, c, BIND_AUTO_CREATE);
// Insert the pattern into the intent itself
i.putExtra("pattern", pattern);
// Start the vibrate service
this.startService(i);
}
}
Vibrate Service class:
public class Vibrate extends Service {
// Vibration object
private Vibrator v;
/*
THESE THREE ARE FOR PREVENTING THE VIBRATION FROM STOPPING AFTER THE PHONE IS PUT TO SLEEP
*/
// Wake Lock object
private PowerManager.WakeLock wl;
// Manager for the notifications
private NotificationManagerCompat m_notificationManager;
// BroadcastReceiver object
public BroadcastReceiver re;
public AudioAttributes audioAttributes;
// Not gonna lie, Idk what this does just know it is part of the binding process within MainActivity
public class MyBinder extends Binder {
public Vibrate getService() {
return Vibrate.this;
}
}
#Override
public void onCreate() {
super.onCreate();
// Acquire the Wake Lock
PowerManager pw = (PowerManager) getSystemService(POWER_SERVICE);
wl = pw.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "WL:");
wl.acquire();
// Get the vibration service
v = (Vibrator) getSystemService(VIBRATOR_SERVICE);
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
}
#Override
public int onStartCommand(Intent i, int flags, int startId) {
// Ensure that an intent with a long array has been passed
if (i != null && i.getExtras() != null) {
// Get the array
final long[] pattern = i.getExtras().getLongArray("pattern");
// Begin the vibration
v.vibrate(pattern, 0);
// Intialize the BroadcastReceiver and set it to trigger when the screen is turned off,
// thus triggering the vibrations
re = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Log.i("VIZZY: ", "VIBRATION STARTED");
v.vibrate(pattern, 0, audioAttributes);
Log.i("VIZZY: ", "VIBRATION BEGUn");
}
}
};
// Add a listener for when the screen turns off and register the receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
}
return Service.START_STICKY;
}
#Override
public void onDestroy() {
// If the phone was put to sleep, cancel the notification keeping the vibration going
if (m_notificationManager != null) {
m_notificationManager.cancel(001);
}
// Release the Wake Lock, unregister the BroadcastReceiver, and stop the vibrations
wl.release();
unregisterReceiver(re);
v.cancel();
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void addNotification() {
// create the notification
Notification.Builder m_notificationBuilder = new Notification.Builder(this)
.setContentTitle("VIZZY")
.setContentText("VIBRATING")
.setSmallIcon(R.mipmap.ic_launcher);
// create the pending intent and add to the notification
Intent intent = new Intent(this, Vibrate.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
m_notificationBuilder.setContentIntent(pendingIntent);
m_notificationManager = NotificationManagerCompat.from(this);
// send the notification
m_notificationManager.notify(001, m_notificationBuilder.build());
}
}
Thank you for anyone's help in advance.
I faced the same issue. And I found out that starting from target 29 vibration will work in background only with the proper audio attributes passed to the method:
public void vibrate(VibrationEffect vibe, AudioAttributes attributes);
You can try to use it in that way:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
vibrator.vibrate(VibrationEffect.createWaveform(pattern, 0),
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build());
} else {
vibrator.vibrate(pattern, 0);
}
It might not care about these instructions:
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
So it probably should be something alike:
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.Q){
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
registerReceiver(re, filter);
} else {
/* whatever it takes to make it work >= API level 29 */
}
Intent.ACTION_SCREEN_ON and Intent.ACTION_SCREEN_OFF generally require the app to be running. But the Android 10 behavior changes do not mention something alike that, therefore it is difficult to tell. Also receiving broadcasts does not tell anything about a recent change.
I use android 10 [android Q, galaxy 10],
I use android studio 3.3,
using AVD, and made a api 29 [android 10] virtual phone.
at the virtual machine,
I execute my app , after that, I launch other app like calendar, calculator.
so my app activity get into background mode.
when I receive a message at BroadcastReceiver.
I call startActivity.
here, code -->
public class myReceiver extends BroadcastReceiver {}
public void onReceive(Context context, Intent intent)
{
Intent intentRun = new Intent(context, LoginSuccess.class);
intentRun.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intentRun);
}
but LoginSuccess activity do not shows up.
[when my app is in background mode]
using same code, LoginSuccess activity show up very well
when my app is in foreground mode.
call stack capture image
above image shows call stack
right before I call startActivity in broadcast receiver.
I have read guide line for android 10 background activity issue.
[developer.android.com/~~ some location]
at the guide line,
I came to know that
if the activity exists in call stack, it can be started
even in background mode.
above code,
it try to start activity that exists in recent call stack.
why startActivity call fail in background mode ?
[maybe not fail , but anyway not activated into foreground]
With Android Q, it is impossible to start an activity from the background automatically if your app does not include those exceptions listed in the link below.
https://developer.android.com/guide/components/activities/background-starts
Possible Solutions:
1- You can choose just show a service notification, and start pending intent with a click
2- You can use full-screen intents to show your intent immediately as shown in the other answer and suggested by Google.
For full-screen intent solution, as described in the official document
The system UI may choose to display a heads-up notification, instead
of launching this intent, while the user is using the device.
3- To start the activity automatically in the background, The most possible solution in my view is adding "SYSTEM_ALERT_WINDOW" to the manifest file. And ask for user permission once when the app opened the first time. (The user can give this permission manually - (Settings-Apps-Your App-Advanced- Draw over other apps))
Example code to request permission :
In Manifest:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Somewhere in app:
public static int ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE= 2323;
//if the user already granted the permission or the API is below Android 10 no need to ask for permission
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
!Settings.canDrawOverlays(getContext()))
{RequestPermission()}
private void RequestPermission() {
// Check if Android M or higher
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// Show alert dialog to the user saying a separate permission is needed
// Launch the settings activity if the user prefers
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
Uri.parse("package:" + getActivity().getPackageName()));
startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ACTION_MANAGE_OVERLAY_PERMISSION_REQUEST_CODE) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(getContext())) {
PermissionDenied();
}
else
{
// Permission Granted-System will work
}
}
}
}
I'm open activity using the below logic. as google, blog says if you want to open activity in background service for use notification on android 10 or higher.
In Manifest:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
Example:
private void startActivity() {
Uri sound = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.siren);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
AudioAttributes attributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
String CHANNEL_ID = BuildConfig.APPLICATION_ID.concat("_notification_id");
String CHANNEL_NAME = BuildConfig.APPLICATION_ID.concat("_notification_name");
assert notificationManager != null;
NotificationChannel mChannel = notificationManager.getNotificationChannel(CHANNEL_ID);
if (mChannel == null) {
mChannel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_HIGH);
mChannel.setSound(sound, attributes);
notificationManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID);
builder.setSmallIcon(R.drawable.logo)
.setContentTitle(getString(R.string.app_name))
.setContentText(getString(R.string.login))
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(openScreen(Constants.NOTIFICATION_ID), true)
.setAutoCancel(true)
.setOngoing(true);
Notification notification = builder.build();
notificationManager.notify(Constants.NOTIFICATION_ID, notification);
} else {
startActivity(new Intent(BackgroundService.this, LoginActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
}
private PendingIntent openScreen(int notificationId) {
Intent fullScreenIntent = new Intent(this, LoginActivity.class);
fullScreenIntent.putExtra(Constants.NOTIFICATION_IDS, notificationId);
return PendingIntent.getActivity(this, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}
If you have root permissions you can simply use the am command for this in the shell:
public static final void switchAcitivty (final Context context) throws IOException {
final Runtime runtime = Runtime.getRuntime();
final String intentCommand = "su -c am start -n yourpackage/.MainActivity -a android.intent.action.VIEW";
Log.i("TAG", intentCommand);
runtime.exec(intentCommand);
}
It gets blocked without root permission (silently, which is annoying).
Very strange but launching activity from foreground service worked in release build. Was not working in debug build (when debugging via Android Studio).
i am testing my application and noticed that it is getting killed by the OS (ONLY ON OREO DEVICES) on certain devices (ON Samsung S8 there is no problem at all but on Huawei Y7 Prime the application is restarting when i open it again after having the screen off for more than 20 minutes..noting that in case i open the application directly after without waiting few minutes, then the application will open normally)
i also performed some logging to identify when and why the activity is getting destroyed but with no luck since there are no logs being written in this situation. also, i added the following code on the main activity which worked for the short time (pressing on the app icon first restarted the app on some devices but was fixed using the below code in onCreate function of the Main Activity)
if (!isTaskRoot()) {
final Intent intent = getIntent();
final String intentAction = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && intentAction != null && intentAction.equals(Intent.ACTION_MAIN)) {
isTaskRootEntered = true;
finish();
}
}
am i missing something? please any help regarding how to fix this case would be appreciated.
IMPORTANT NOTE: i have a foreground service that is kept on which retreives the user's location and saves it in a database. this service has a sticky notification and its working well until left for more than 20 minutes (AGAIN ONLY ON SOME DEVICES LIKE HUAWEI)
i am starting the foreground service the following way:
GVGPSServiceIntent = new Intent(context, GTMStarterService.class);
if(Build.VERSION.SDK_INT >= 26){
context.startForegroundService(GVGPSServiceIntent);
}
else context.startService(GVGPSServiceIntent);
the service looks like this
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
return START_STICKY;
}
#Override
public void onCreate() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Notification notification = updateNotificationContent();
startForeground("SendingPrcs".hashCode(), notification);
}
}
#Override
public void onDestroy() {
super.onDestroy();
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.cancel("SendingPrcs".hashCode());
}
}
When I open my second activity, I would like it to turn on Do Not Disturb mode on my android device. However, I want Do Not Disturb to only turn on through the second page (either by opening it or through a button created on the second page). The only code I found on stack overflow was in my Android Manifest File
<uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
I'm not sure where to go from here, any help is appreciated.
Use that method:
private void setRingerMode(Context context, int mode) {
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Check for DND permissions for API 24+
if (android.os.Build.VERSION.SDK_INT < 24 || (android.os.Build.VERSION.SDK_INT >= 24 && !nm.isNotificationPolicyAccessGranted())) {
AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
audioManager.setRingerMode(mode);
}
}
Where mode parameter can be AudioManager.RINGER_MODE_SILENT or
AudioManager.RINGER_MODE_NORMAL