I'm trying to create an alarm app which is supposed to ring after a given period of time.
It works when the screen is switched on; I open the app and the alarm goes off after 5 second. Which is exactly what I want.
Now, I want my app to function the same way when the screen is switched off. So, if I open my app and then close the screen, I want the app to switch on the screen after 5 seconds and then ring the alarm.
I tried SCREEN_BRIGHT_WAKE_LOCK (did put in the required permissions) but it did not work. The alarm rang for like half a second and then then switched off. The screen did not turn on at all. Also, SCREEN_BRIGHT_WAKE_LOCK has been deprecated and the documentation suggests using FLAG_KEEP_SCREEN_ON which is useful only if the screen is already switched on and we wan to keep it that way. Not turn it on from off state.
What will I have to do to solve the above problem? Use a service? Also, the screen is locked with number lock.
Here is my code which works only when the screen is switched on:
public class AlarmReceiverActivity extends Activity {
private MediaPlayer mMediaPlayer;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.activity_alarm_receiver);
Button stopAlarm = (Button) findViewById(R.id.stopAlarm);
stopAlarm.setOnTouchListener(new View.OnTouchListener() {
public boolean onTouch(View arg0, MotionEvent arg1) {
mMediaPlayer.stop();
mMediaPlayer.release();
finish();
return false;
}
});
playSound(this, getAlarmUri());
}
private void playSound(Context context, Uri alert) {
mMediaPlayer = new MediaPlayer();
try {
mMediaPlayer.setDataSource(context, alert);
final AudioManager audioManager = (AudioManager) context
.getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0) {
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
try {
mMediaPlayer.prepare();
mMediaPlayer.start();
} catch (IOException e) {
System.out.println("Oops");
}
}
} catch (IOException e1) {
System.out.println("OOPS");
}
}
//Get an alarm sound. Try for an alarm. If none set, try notification,
//Otherwise, ringtone.
private Uri getAlarmUri() {
Uri alert = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_ALARM);
if (alert == null) {
alert = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
if (alert == null) {
alert = RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
}
}
return alert;
}
}
I was dealing with this issue recently.
this is what worked for me:
public class YourActivity extends Activity {
...
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_view);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON |
WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
...
}
helpful links:
Android Activity Not Showing When Screen is Woken Up and Lock Screen Not Disabling
http://weimenglee.blogspot.co.il/2013/04/android-tip-waking-up-screen-and.html
Android Galaxy S4 -- Activity that is visible over lock screen
also do NOT use dialog theme for the activity!!!
Related
I am using onFocusChangeListener to track when the user has finished editing an edittext inside a fragment. In certain cases, based on the user input, this triggers a ringtone alarm to start playing. The ringtone alarm continues until another event triggers it to stop, such as another edit in the edittext field or if the fragment is exited, through onStop().
It seems that the onFocusChange listener gets called again AFTER onStop(), which is problematic because it can trigger the ringtone alarm again, and won't stop even if the application is closed.
in onCreateView, set listener:
mTextEdit = (EditText) rootView
.findViewById(R.id.userInput);
mTextEdit.setOnFocusChangeListener(this);
and
#Override
public void onStop() {
super.onStop();
// stop alarm from sounding if fragment is stopped.
stopAlarm();
}
#Override
public void onFocusChange(View view, boolean hasFocus) {
if (!hasFocus) { // Only do when exiting focus
if (view.getId()==R.id.userInput)
{ startAlarm(); // method to start ringtone alarm }
}
}
private void startAlarm() {
// stop existing ringtone
if (mAlarmManager != null) { stopAlarm(); }
// set and play new ring tone
try {
Log.d(TAG, "Ringtone: " + mAlarmURI.toString());
mAlarmManager = RingtoneManager.getRingtone(getActivity(), mAlarmURI);
mAlarmManager.play();
Log.d(TAG, "Alarm is playing");
} catch (Exception e) {
// failed to get/play ringtone
e.printStackTrace();
}
}
private void stopAlarm() {
if (mAlarmManager != null)
try {
mAlarmManager.stop();
} catch (Exception e) {
// failed to stop ringtone
e.printStackTrace();
Log.d(TAG, "Failed to stop ringtone.");
}
mAlarmManager = null;
}
Thanks to Rushi, I think I have my answer. It's not pretty. I need to stop the alarm in two places, onStop() and onDestroy() because the state cycle can be different for different events.
If the user navigates to a preference setting and back:
onPause()
onStop() - stop alarm here
onResume()
if the user navigates out of the fragment:
onPause()
onStop() - stop alarm here
onFocusChange() - alarm is retriggered
onDestroy() - stop alarm again
I am writing an app to show an activity over the lock screen when the phone is locked and screen off.
When the user leave the activity, the keyguard should be shown.
The common way to detect whether the phone is locked by by receiver and ACTION.SCREEN_OFF.
It works perfectly if the user press lock button the lock and screen off the phone.
However, after ICS, the phone may not be locked as soon as the phone is screen off.
So, how can I get the lock event or how can I get the value of Automatically lock as the picture below?
I know inKeyguardRestrictedInputMode() is a way to check if the phone is locked.
but it cannot report automatically when the phone is locked just like receiver.
The Screenshot from Setting in Android 4.1.2
you can get the timeout value by following code:
mResolver = this.getContentResolver();
long timeout = Settings.Secure.getInt(mResolver,
"lock_screen_lock_after_timeout",
0);
I solved by using thread to check if the device is locked.
The part of code in the service:
private BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
Log.d("Receiver", "Screen ON");
} else {
new Thread(new mRunnable()).start();
}
}
};
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case 1:
Intent i = new Intent();
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
i.setClass(getBaseContext(), activity.class);
startActivity(i);
break;
}
super.handleMessage(msg);
}
};
class mRunnable implements Runnable {
public void run() {
while (!Thread.currentThread().isInterrupted()) {
if (isLocked()) {
mHandler.sendEmptyMessage(1);
Thread.currentThread().interrupt();
}
else {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}
}
private boolean isLocked() {
mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);
return mKeyguardManager.inKeyguardRestrictedInputMode();
}
I listed it here for the others who are finding the answer. I just draft as a solution and I have not consider the performance of the code and program yet.
I making the application where an activity launch is scheduled by AlarmManager. I would like to appear even if the screen is turned off and device is locked.
To achive this a set the Window flags
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
And try to obtain lock for the screen
if(_lock == null)
{
PowerManager pm = (PowerManager)App.getAppContext()
.getSystemService(Context.POWER_SERVICE);
_lock = pm.newWakeLock(
PowerManager.FULL_WAKE_LOCK, "ScreenOn");
_lock.acquire();
}
The _lock is PowerManager.WakeLock which is released in onPause
protected void onPause()
{
if(_lock != null)
{
_lock.release();
}
}
This code is executed in onCreate and onRestart. Everything works OK if the activity is not launched yet.
But if it was launched earlier the screen is not turned off.
onRestart is called first
onResume is then called
onPause is called immediately
So the activity is not launched. My question is how to turn on the screen in such situation. (I am using API 15).
I came up with the solution. I created a new activity which will be trying to turn on the screen in the onCreate() and then wait until it is turned on. When the screen is ok it will launch the activity which should be displayed. To make the Android always create this activity
public class TurnOnScreen extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
if (pm.isScreenOn()) openActivity();
else {
registerReceiver(mScreenOnReceiver, new IntentFilter(
Intent.ACTION_SCREEN_ON));
reciever_registered = true;
turnScreenOn();
}
}
#Override
public void onDestroy() {
super.onDestroy();
if (reciever_registered) {
unregisterReceiver(mScreenOnReceiver);
reciever_registered = false;
}
}
private boolean reciever_registered = false;
private final BroadcastReceiver mScreenOnReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
openActivity();
}
};
private void openActivity() {
Intent intent = new Intent();
// ....
finish();
}
private void turnScreenOn() {
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
| WindowManager.LayoutParams.FLAG_ALLOW_LOCK_WHILE_SCREEN_ON);
}
}
I am still looking for explanations why the screen is not turned on in onRestart.
Have you heard of "The Lighted Green Room"? Check out the code below, it may be what you're looking for.
http://code.google.com/p/ch-bfh-fbi-mobicomp-2011/source/browse/ch_simplix_android_repetitive_service/src/com/androidbook/longrun/LightedGreenRoom.java?spec=svn38&r=37
Just use your code :
final Window win = getWindow();
win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
| WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
in onCreate() only and remove all those other Activity-Cycle methods if they are not doing anything else then this.
I don't think you need any more code to use to perform it.
In my application I disable the keyguard lock (i.e.Remove Lockscreen) using the code below and it works fine until I click on any notification in the notification bar. If I click on a notification the lock screen is automatically re-enabled. Any help is appreciated.
private void remove_lockscreen() {
final CheckBoxPreference lock = (CheckBoxPreference) findPreference("remove_lockscreen");
KeyguardManager km = (KeyguardManager)getSystemService(KEYGUARD_SERVICE);
KeyguardLock kl = km.newKeyguardLock("keyguard_lock");
if (lock.isChecked()) {
prefEdit("remove_lockscreen", 1);
Toast.makeText(getBaseContext(), "Lockscreen will not be shown", Toast.LENGTH_SHORT).show();
kl.disableKeyguard();
}
else if (!lock.isChecked()) {
prefEdit("remove_lockscreen", 0);
Toast.makeText(getBaseContext(), "Lockscreen will be shown", Toast.LENGTH_SHORT).show();
kl.reenableKeyguard();
android.os.Process.killProcess(android.os.Process.myPid());
}
}
I've noticed the same issue for some time. It only occurs on Honeycomb (Android 3.0) and up. After a great deal of experimentation and hair-pulling, I seem to have found a solution that works for me. It's not clear exactly what's going on or why, but here's what I've figured out.
It seems that on Android 3.0+, after the keyguard is disabled, when a notification is pressed, the old KeyguardLock expires, but thankfully the ACTION_USER_PRESENT Broadcast is fired at that point, so we have a chance to correct the issue.
One point that's not at all obvious from the documentation is that it seems to be necessary to reenable the old KeyguardLock before getting a new one and disabling it again. Another "gotcha" I discovered is that disabling through the new KeyguardLock immediately after reenabling through the old one produces only intermittent success. I resolved this by waiting 300ms before disabling.
Here's a slightly simplified version of my code; it should be easy to adapt to your app:
private KeyguardLock kl;
private KeyguardManager km;
private final Handler mHandler = new Handler();
private final Runnable runDisableKeyguard = new Runnable() {
public void run() {
kl = km.newKeyguardLock(getPackageName());
kl.disableKeyguard();
}
};
private void setEnablednessOfKeyguard(boolean enabled) {
if (enabled) {
if (kl != null) {
unregisterReceiver(mUserPresentReceiver);
mHandler.removeCallbacks(runDisableKeyguard);
kl.reenableKeyguard();
kl = null;
}
} else {
if (km.inKeyguardRestrictedInputMode()) {
registerReceiver(mUserPresentReceiver, userPresent);
} else {
if (kl != null)
kl.reenableKeyguard();
else
registerReceiver(mUserPresentReceiver, userPresent);
mHandler.postDelayed(runDisableKeyguard, 300);
}
}
}
private final BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())){
if (sp_store.getBoolean(KEY_DISABLE_LOCKING, false))
setEnablednessOfKeyguard(false);
}
}
};
I have a working alarm app, but wanted to add a feature where the user gets the choice between "Play alarm continuously till acknowledged" and "play alarm sound once".
I then looked at my alrm ringing code expecting to see some kind of "repeat" flag which I could optionally remove - but there was none. So how do I play the alarm sound just once?
My existing code looks like this:
private void playSound(Context context, Uri alert)
{
mMediaPlayer = new MediaPlayer();
try
{
mMediaPlayer.setDataSource(context, alert);
final AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
if (audioManager.getStreamVolume(AudioManager.STREAM_ALARM) != 0)
{
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_ALARM);
mMediaPlayer.prepare();
mMediaPlayer.start();
}
}
catch (IOException e)
{
// oops!
}
}
Actually in each alarm sound there is a FLAG named ANDROID_LOOP which force your sound to loop. Unfortunatly you can't change that flag even using MediaPlayer.setLooping(false).
But you still can manually stop your player after a certain time. For example getDuration will give you the length of your sound.
int duration = mMediaPlayer.getDuration();
Runnable stopSoundRunnable = new Runnable() {
#Override
public void run() {
mMediaPlayer.stop();
}
};
mSoundHanlder.postDelayed(stopSoundRunnable, duration);