Stop app loading by itself after unlocking device? - android

I am currently creating an Android app that appears to re-open by itself after locking and unlocking the screen of the device.
I'm using a BroadcastReceiver to detect when the power button is pressed. When the power button is detected, an intent is created that should return the user to the login page in the app.
I believe that this is causing the problem but am unsure of how to fix it. I believe that when the user unlocks the device, the intent is followed through and therefore the user is presented with the login screen, regardless of what screen or app they were viewing prior to locking the device. Please note that this only happens if my app is still running in the background.
Below I have included my BroadcastReceiver code.
public class ScreenReceiver extends BroadcastReceiver {
public static boolean wasScreenOn = true;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
Intent n = new Intent(context, MainActivity.class);
context.startActivity(n);
wasScreenOn = false;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
wasScreenOn = true;
}
}
}
Hopefully somebody can help me with this.

Related

Prevent my android app starts automatically when the device/screen is sleeping/locked

The problem is that if my app is running and the device (screen) is locked, the app is restarted while the device is locked (I know because I can hear the sound of my app at startup).
[Edit]
This seems very complicated. I think it would be easier to turn off sounds in the app, but I do not know how to do this only when the device is asleep:
public void playSound(int id){
if(!DEVICE_IS_ASLEEP())
snds[id].play(soundID[id], 1, 1, 0, 0, 1);
}
you may registerReceiver using Context (probably inside Service)
//assuming user starting Service by press smth in app (or simple open it), so the screen will be on for sure
boolean screenOn=true;
//put this inside your onCreate
private void initBroadcasts(){
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(Intent.ACTION_USER_PRESENT);
//new feature from API 17 - screensaver (?)
if(android.os.Build.VERSION.SDK_INT>=17){
filter.addAction(Intent.ACTION_DREAMING_STARTED);
filter.addAction(Intent.ACTION_DREAMING_STOPPED);
}
screenOn = getScreenUnlocked();
this.registerReceiver(screenBroadcastReceiver, filter);
}
screenBroadcastReceiver is a BroadcastReceiver as below:
private BroadcastReceiver screenBroadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent myIntent) {
if(myIntent.getAction().equals(Intent.ACTION_SCREEN_ON))
screenOn=getScreenUnlocked();
else if(myIntent.getAction().equals(Intent.ACTION_SCREEN_OFF))
screenOn=false;
else if(myIntent.getAction().equals(Intent.ACTION_USER_PRESENT))
screenOn=true;
else if(android.os.Build.VERSION.SDK_INT>=17){
if(myIntent.getAction().equals(Intent.ACTION_DREAMING_STARTED))
screenOn=false;
else if(myIntent.getAction().equals(Intent.ACTION_DREAMING_STOPPED))
screenOn=getScreenUnlocked();
}
}
};
check if screen is unlocked:
private boolean getScreenUnlocked(){
KeyguardManager kgMgr =
(KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
return !kgMgr.inKeyguardRestrictedInputMode();
}
When configuration changes happens with app like screen lock, the activity is restarted. You will get so many answers on stackoverflow to avoid this problem like this; but according to Google Engineers, it is bad practice to retain the activity. You will get the proper answer about how to avoid this problem here

How to start new activity from lockscreen?

I am creating simple widget for contact management, which allows user to dial and send sms to desired contact.
It works fine as "normal widget", but when I add it as lockscreen widget on Android 4.2, sms app or dial app does not start.
Well in fact they star, but "behind" lockscreen, so user still must manually unlock screen to be able to dial/send sms.
I searched web for some solution, but nothing come in handy.
I' am aware of FLAG_DISABLE_KEYGUARD or FLAG_SHOW_WHEN_LOCKED, but since sms/dial apps are not "mine" so i dont know if they set up proper flag.
As a workaround i tried to create my activity which set those flag and then simply starts desired one (dial or sms), but this does not help.
There is a way to unlock screen, but this involves using KeyguardManager and KeyguardLock (which work fine), but in a result of using KeyguardLock.newKeyguardLock() I end up with phone not being able to turn lock automatically, surely because I do not release this lock (it causes lock to appear again, which is not what i want).
In fact, this widget should work simmilarly to default sms widget or mail widget on lock screen?
So, my question is, how to achieve that and start new activity from lockscreen?
Well, i found solution myself. it turned out i was close :)
To launch 3rd party app/activity, simplest solution is to create some kind of proxy activity, which will set proper flags on window and then launches desired activity and FINISHES.
sample code is shown below:
calling intent in widget (calling proxy):
#Override
public void onReceive(Context context, Intent intent) {
Utilities.printLog(TAG, "onReceive");
Utilities.printLog(TAG, "intent: " + intent);
if (intent.getAction().equals(ACTION)) {
final String number = intent.getStringExtra(EXTRAS);
Toast.makeText(context, "Selected number: " + number,
Toast.LENGTH_SHORT)
.show();
/** REMOVING KEYGUARD RECEIVER **/
// not really an option - lock is still holded by widget and screen
// cannot be locked again ;(
// KeyguardManager keyguardManager = (KeyguardManager) context
// .getSystemService(Context.KEYGUARD_SERVICE);
// KeyguardLock lock = keyguardManager
// .newKeyguardLock(Context.KEYGUARD_SERVICE);
// lock.disableKeyguard();
final Intent activity = new Intent(context, MainActivity.class);
activity.putExtras(intent.getExtras());
activity.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
activity.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
activity.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
context.startActivity(activity);
}
super.onReceive(context, intent);
}
in proxy activity just call:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().requestFeature(Window.FEATURE_NO_TITLE);
// getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
final Intent callingIntent = getIntent();
final String actionToLaunch = callingIntent.getStringExtra(ContactsStackWidgetProvider.ACTION);
final String number = callingIntent.getStringExtra(ContactsStackWidgetProvider.EXTRAS);
final Intent activity = new Intent();
if (actionToLaunch.equals(Intent.ACTION_DIAL)) {
activity.setAction(Intent.ACTION_DIAL);
activity.setData(Uri.parse("tel:"+number));
} else if (actionToLaunch.equals(Intent.ACTION_SENDTO)) {
activity.setAction(Intent.ACTION_SENDTO);
activity.setData(Uri.parse("sms:"+number));
} else {
throw new IllegalArgumentException("Unrecognized action: "
+ actionToLaunch);
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
startActivity(activity);
finish();//it is important to finish, but after a small delay
}
}, 50L);
}

Screen on/off validate from android shell

I'm stuck at some validation for screen off and on test. I am using input keyevent 26 to put screen off and the same to wakeup. How to validate this test whether it was passed or failed. Is there any file where android write the state of the screen? any other way from dumpsys power? Can any one please suggest the way to check the state.
Thanks in advance.
You could write a simple app that has a broadcast receiver for the SCREEN ON and SCREEN OFF events, and log the events to the LogCat, and easily see it via adb logcat.
Here is some sample code for that. Make sure your app has been run at least once on the device, or it will not be registered for receiving the broadcast.
public class MyReceiver extends BroadcastReceiver {
private boolean SCREEN_ON = false;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
SCREEN_ON = true;
Log.d(C.TAG, "Screen on");
}
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
SCREEN_ON = false;
Log.d(C.TAG, "Screen off");
}
}
}

Problems with android lock in custom lock screen app

I built a custom lock screen app that uses a broadcast receiver and service to listen for when the user turns on or off the screen and from there launch my activity. The activity is supposed to completely replace the lock screen. In order to do this my app is supposed to disable the android stock lock so that my app can function as the new lock screen.
Instead what happens is once the application is first installed the the service first started the application appears to be working. and when the user first turns off the screen of their phone when they turn it back on they are presented with my app running on top and is able to unlock their phone with my app. But then once inside the android OS if the user presses the home button the next time they turn off the screen and turn it back on instead of being brought back to my application they are brought to the stock unlock screen with my application open underneath it, when it should be on top.
Here is my code:
My Service:
public class MyService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
super.onCreate();
Log.d("MyService","Service STARTED");
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
final BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
}
}
My broadcast receiver:
public class ScreenReceiver extends BroadcastReceiver {
public static ArrayList<String> runningApplications = new ArrayList<String>();
private Context ctext;
public static boolean screenIsLocked;
public static KeyguardManager keyguardManager;
public static KeyguardLock lock;
#Override
public void onReceive(final Context context, final Intent intent) {
ctext = context;
keyguardManager = (KeyguardManager)ctext.getSystemService(Activity.KEYGUARD_SERVICE);
lock = keyguardManager.newKeyguardLock(Context.KEYGUARD_SERVICE);
lock.disableKeyguard();
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenIsLocked = true;
Log.d("ScreenReceiver", "False");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenIsLocked = false;
Log.d("ScreenReceiver", "True");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
}
}
My activity that is started is basically empty with just one unlock button that calls finish(); when pressed.
The behavior of keyguard-related logic can vary from device to device. That's because lockscreens are often custom-made by device manufacturers (i.e. not stock), some of them respect the keyguard logic you use, some don't.
Also, afaik the newer way to control keyguard is to use window flags:
// inside activity
getWindow().addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD
| WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
This will not solve the problem though, devices still have their say about this.
E.g. from my experience, Galaxy Nexus will show your activity's window above keyguard but will not dismiss it (you'd think Google-branded device should respect the flag, eh), so if you hit the back button in your activity - you'll get standard lockscreen --- while HTC One X seems to handle the dismiss part properly: your activity window will cause standard lockscreen to get dismissed as expected.
I found no way to force all devices to behave properly. Android API is not meant to enable you to create custom lock screens (at least not currently). Take a look at the ones in the store - they all have the exact same problem of not being stable enough.
As Dianne Hackborn says in this Google Groups answer, anything you can do in this regard is a hack so expect it to break from time to time.
I tried to compile your code and got the same error you were talking about. I tried to modify it to make it to work and finally got the problem!!!
public class ScreenReceiver extends BroadcastReceiver {
public static ArrayList<String> runningApplications = new ArrayList<String>();
private Context ctext;
public static boolean screenIsLocked;
public static KeyguardManager keyguardManager;
public static KeyguardLock lock;
#Override
public void onReceive(final Context context, final Intent intent) {
ctext = context;
keyguardManager = (KeyguardManager)ctext.getSystemService(Activity.KEYGUARD_SERVICE);
lock = keyguardManager.newKeyguardLock(Context.KEYGUARD_SERVICE);
lock.disableKeyguard();
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
screenIsLocked = true;
Log.d("ScreenReceiver", "False");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
screenIsLocked = false;
Log.d("ScreenReceiver", "True");
Intent intenti = new Intent();
intenti.setClass(context, starterActivity.class);
intenti.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intenti.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intenti);
}
}
With this change to the broadcast receiver class I was able to overcome the problem
Try it and tell me if there is any problem.
EDIT:I think the problem might lie in the finish() method....Android dumps apps when it requires memory...I think finish() might be helping android in trashing the app(and this might be the reason why your problem occurs randomly)

Device administrator disabling

Device administration app can not be uninstalled if it is not
disabled. User can disable "Device Administrators" from the settings.
When company gives android devices to its employees, company wants to
have a control over devices, their statuses and policies, but user can
easily get rid of that control. Does anybody know how it is possible
to prevent user from disabling Device Administrators?
Thanks.
There's no way to prevent the user from disabling Device Administrators, at least using the published APIs. The best you can do is disallow programs from running if certain policies aren't in place.
Some manufacturers (e.g., Samsung) have extended the base APIs to allow additional capabilities, but these are not part of the standard Android platform.
In DeviceAdminReceiver.java you could do something like this onDisableRequested:
public CharSequence onDisableRequested(Context context, Intent intent) {
SharedPreferences settings = context.getSharedPreferences(MainActivity.class.getName(), 0);
String DEVICE_ADMIN_CAN_DEACTIVATE = settings.getString("DEVICE_ADMIN_CAN_DEACTIVATE", null);
if(DEVICE_ADMIN_CAN_DEACTIVATE.equals("ON")){
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startMain);
return "OOPS!";
}else{
String msg_char_onDisable = context.getResources().getString(R.string.msg_char_onDisable);
return msg_char_onDisable;
}
}
There is a workaround to prevent disabling the device administrator.
When the user initiates deactivation and we recieve ACTION_DEVICE_ADMIN_DISABLE_REQUESTED callback, we re-launch the settings activity intent.
A message is allowed by the OS to be displayed asking for confirmation from the user. According to Android OS rules, for about 5 seconds, no app is allowed to launch on top of this confirmation dialog. So basically the settings activity we tried to open will only launch after 5 seconds.
To pass these 5 seconds without allowing the user to confirm deactivation, the phone is locked by the device administrator repeatedly in a background thread. After 5 seconds when the user unlocks the device, 'Settings' activity will have been restarted.
The following code for Device Admin Broadcast Receiver Class illustrates the above method.
DevAdminReceiver.java
public class DevAdminReceiver extends DeviceAdminReceiver {
DevicePolicyManager dpm;
long current_time;
Timer myThread;
#Override
public void onEnabled(#NonNull Context context, #NonNull Intent intent) {
super.onEnabled(context, intent);
Log.d("Root", "Device Owner Enabled");
}
#Nullable
#Override
public CharSequence onDisableRequested(#NonNull Context context, #NonNull Intent intent) {
Log.d("Device Admin","Disable Requested");
Intent startMain = new Intent(android.provider.Settings.ACTION_SETTINGS);
startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startMain);
dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
myThread = new Timer();
current_time = System.currentTimeMillis();
myThread.schedule(lock_task,0,1000);
return "Warning";
}
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ACTION_DEVICE_ADMIN_DISABLE_REQUESTED.equals(action)) {
CharSequence res = onDisableRequested(context, intent);
if (res != null) {
dpm.lockNow();
Bundle extras = getResultExtras(true);
extras.putCharSequence(EXTRA_DISABLE_WARNING, res);
}
}else if (ACTION_DEVICE_ADMIN_DISABLED.equals(action)) {
Log.d("Device Admin","Disabled");
}
}
// Repeatedly lock the phone every second for 5 seconds
TimerTask lock_task = new TimerTask() {
#Override
public void run() {
long diff = System.currentTimeMillis() - current_time;
if (diff<5000) {
Log.d("Timer","1 second");
dpm.lockNow();
}
else{
myThread.cancel();
}
}
};
}
Ensure force lock policy is set for the device admin in the resource file.
This is a purely a workaround and not an intended solution from the side of the developers. Apps which abuse Device Admin permissions are mostly taken down from the Google Play Store when exposed.
Complete sample code having the required Manifest declarations and resource xml file is present in the following repo
https://github.com/abinpaul1/Android-Snippets/tree/master/PermanentDeviceAdministrator

Categories

Resources