简体   繁体   中英

Start activity when user turns screen off?

I have an app whose security I would like to improve. When the user unlocks the device I would like the app to return to the login screen so that an intruder cannot use the app just by unlocking the device and having the app resume its original state.

I'm using a BroadcastReceiver to detect when power button is pressed but this currently results the login screen being loaded regardless of whether the user was using the app just before they pressed the power button.

Below I have included my BroadcastReceiver code, perhaps somebody could shed some light on this issue if possible?

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;
        }
    }
}

When a user clicks on the home button , onPause() and onStop() gets called. When they click on the back button (to exit the app), onPause(), onStop(), and finally onDestory() gets called. Finally, when they press the power button , onPause() and onStop() gets called.

They all have onPause() being called first. Override onPause() and go back to the main activity using intent. You can also clear the stack of activities so they can't hit the back button to go back into one.

MainActivity

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button goPrivate = (Button) findViewById(R.id.goPrivate);

        goPrivate.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this, Private.class));
            }
        });
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.vzw.www.myapplication.MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MAIN"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="GO TO PRIVATE"
        android:id="@+id/goPrivate"/>

</RelativeLayout>

Create a new activity. I named mine Private.java

Private.java

public class Private extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_private);
    }

    @Override
    protected void onPause() {
        super.onPause();
        startActivity(new Intent(Private.this, MainActivity.class));
    }
}

activity_private.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.vzw.www.myapplication.Private"
    android:layout_gravity="center">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="PRIVATE!"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true" />

</RelativeLayout>

Just create a blank project in Android Studio and try this. It works! :)

What happens if we click into ANOTHER activity and go deep into the app?

Create a boolean inside of Private class.

boolean goSuperClicked = false;

Updated private class is below:

public class Private extends AppCompatActivity {

    Button goSuper;
    boolean goSuperClicked = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_private);

        goSuper = (Button) findViewById(R.id.goSuper);

        goSuper.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                goSuperClicked = true;
                startActivity(new Intent(Private.this, SuperPrivate.class));
            }
        });
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d("onPause()", "onPause called");
        if (!goSuperClicked) {
            startActivity(new Intent(Private.this, MainActivity.class));
        }

    }
}

I don't think this is actually what you want. If they have a lock screen, they had to enter a password on it. You can be fairly sure its the right person. If you want this kind of behavior, you want to timeout the session due to inactivity instead.

Either way, the solution is the same. In onResume, you should check to see if they timed out/went to the lock screen. If so, launch the login screen as a new task (that will prevent the back button from taking you back to this screen) and finish() the current activity. Pass the login screen some info so it can recreate the current activity. When the user is verified, check for that info and create the proper activity from it. If the info doesn't exist, launch your standard homescreen.

The easiest way to pass it enough info to create the new Activity is to pass it a Bundle with the activity name or url, and the results of calling onSaveInstanceState.

Some suggestions:

1) Set up a broadcast receiver that detects a screen on/off intent.

Intent.ACTION_SCREEN_OFF and ACTION_SCREEN_ON

2) Implement broadcast receiver that starts Activity when it matches Screen off.

3) Detect Screen off and on via PowerManager

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
boolean isScreenOn = pm.isScreenOn();

4) Since screen off happens on onStop() callbacks, therefore, you have to put above code inside onStop() callbacks of your Activity lifecycle. Something like below.

PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
    boolean isScreenOn = pm.isScreenOff();
if(isScreenOn) {
 sendBroadcast(<your_screenOff_intent);
}

This is the way, but because of the security lock (to open your device), I think, it can't be implemented.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM