简体   繁体   中英

How to disable home button in Android like lock screen apps do?

I know this question is asked many times but I found that none of the solution is working. I tried the code given below...

   protected void onPause() {
   super.onPause();
    Intent intent = new Intent(this,LockActivity.class);
    intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    }

What it does is that it bring the current activity again to front when android home screen is launched but it takes almost 3-4 seconds to bring activity againt to front when home screen is launched.

I have used some lock screen apps which don't even start the home screen when home button is clicked. I want to achieve something like that.

I have also used onUserLeavesHint method, onKeyDown method and onKeyDispatch method but none of them worked for me.

And please don't answer or comment like it is not possible to disable home button in Android. For such answers or comments I would suggest you to go through some Lock Screen apps on PlayStore. Also I found a working app on github along source code. It was working on my phone and the app used disableKeyguard but when I do the same in my app it doesn't work (disableKeyguard is deprecated but I use @supress warnings("deprecation")).

source - https://github.com/shaobin0604/Android-HomeKey-Locker

//Copy this class
public class HomeKeyLocker {
    private OverlayDialog mOverlayDialog;
    public void lock(Activity activity) {
        if (mOverlayDialog == null) {
            mOverlayDialog = new OverlayDialog(activity);
            mOverlayDialog.show();
        }
    }
    public void unlock() {
        if (mOverlayDialog != null) {
            mOverlayDialog.dismiss();
            mOverlayDialog = null;
        }
    }
    private static class OverlayDialog extends AlertDialog {

        public OverlayDialog(Activity activity) {
            super(activity, R.style.OverlayDialog);
            WindowManager.LayoutParams params = getWindow().getAttributes();
            params.type =  WindowManager.LayoutParams.TYPE_SYSTEM_ERROR;
            params.dimAmount = 0.0F; // transparent
            params.width = 0;
            params.height = 0;
            params.gravity = Gravity.BOTTOM;
            getWindow().setAttributes(params);
            getWindow().setFlags( WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED |  WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, 0xffffff);
            setOwnerActivity(activity);
            setCancelable(false);
        }

        public final boolean dispatchTouchEvent(MotionEvent motionevent) {
            return true;
        }

        protected final void onCreate(Bundle bundle) {
            super.onCreate(bundle);
            FrameLayout framelayout = new FrameLayout(getContext());
            framelayout.setBackgroundColor(0);
            setContentView(framelayout);
        }
    }
}

//Paste this in your activity
mHomeKeyLocker = new HomeKeyLocker();
mHomeKeyLocker.lock(this);

The sure way of providing a flawless, non-root lockscreen functionality is by combining your "locker" app idea with a launcher app.

A simple change in the manifest will allow your app to register as a homescreen/launcher, which will give your .apk full control of the home button:

<application
    android:launchMode="singleTask"
    android:clearTaskOnLaunch="true"
    android:stateNotNeeded="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="ch.arnab.simplelauncher.HomeScreen"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:excludeFromRecents="true"
        android:screenOrientation="nosensor">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <!-- These 2 intent-filters identify a launcher: -->
            <category android:name="android.intent.category.HOME" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity>
</application>

Pulled from this tutorial

You will then have two activities, one for your home-screen, one for your lock screen.

You'll have to detect when the screen is turned off/turned on , to show your lock screen activity:

public class MainActivity extends Activity {

    //Create a receiver for screen-on/screen-off
    BroadcastReceiver mybroadcast = new BroadcastReceiver() {   
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                //Show lock-screen
            }
            else if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                //Also show lock-screen, to remove flicker/delay when screen on?
            }

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

        registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
        registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));
    }
}

Pulled from this answer

FYI: since your "lock screen" will still be considered part of your launcher at this point, apps will be able to launch on top of your lock-screen, which is bad if: the user has access to the notification drawer to click on messages/Tweets etc , but can also be good for: being able to answer incoming calls without unlocking the phone.

Either way, your lock screen activity should override onPause , check whether the user is "authenticated", if he is not, assume that the user opened something and should go back to the lock screen:

@Override
public void onPause() {
    super.onPause();
    if(password!=storedPassword) {
      //Lockscreen activity shouldn't ever be escaped without the right password!
      //Return to launcher without root!
      Intent homeIntent = new Intent(Intent.ACTION_MAIN);
      homeIntent.addCategory(Intent.CATEGORY_HOME);
      homeIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
      startActivity(homeIntent);
    }
}

For better user experience, you should give your user the option to allow a few apps to bypass the lockscreen (such as Spotify), you can include that in the if statement above (ex. if(password!=storedPassword||isForegroundAppSpotify) ).

As far as loading apps on your homescreen, you can refer to tutorials on Google for creating your own launcher activity.

Combining launcher+lock-screen is the easiest way to avoid root access. You may find it easier to use root, but you'll limit your customer base.

Hope this helps!

You can use the shaobin0604 library to do this. It will disable the Back button too. You activity will look like this:


public class MainActivity extends Activity {

HomeKeyLocker homeKeyLocker;

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

    homeKeyLocker = new HomeKeyLocker();
    homeKeyLocker.lock(this);
}

}

I have done a lot of research to design a lock screen and finally found a solution. Android disabled the feature to override System bars except the back button. But there is a little work around to make this work:

Understand and implement screen pinning patiently and you will be successful.

You can create an app to control what all applications you want to implement screen pinning in or you can implement screen pinning directly in the same application you want to pin.

I'm going to show you the later implementation in this article:

1. Firstly your app should be the device owner.

You can do it in several ways and the easiest is to execute the command:

adb shell dpm set-device-owner [yourPackageName]/.[MyDeviceAdminReceiver]

Create a receiver(MyDeviceAdminReceiver) that extends DeviceAdminReceiver. You needn't have any code in here. For more info on Device owner implementation refer this link
http://florent-dupont.blogspot.com/2015/02/10-things-to-know-about-device-owner.html

Register the receiver in the AndroidManifest.xml file this way :

<receiver
       android:name=".MyDeviceAdminReceiver"
       android:label="@string/app_name"
       android:permission="android.permission.BIND_DEVICE_ADMIN">
     <meta-data
       android:name="android.app.device_admin"
       android:resource="@xml/device_admin" />

       <intent-filter>
         <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
       </intent-filter>
  </receiver>

2. Your onCreate method should look like this:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_lock_screen);

    ComponentName deviceAdmin = new ComponentName(this, MyDeviceAdminReceiver.class);
    DevicePolicyManager mDpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);


    if (mDpm.isDeviceOwnerApp(getPackageName())) {
        mDpm.setLockTaskPackages(deviceAdmin, new String[]{getPackageName()});
    }

    if (mDpm.isLockTaskPermitted(this.getPackageName()))
        startLockTask();

3.To unpin the screen and make Navigation Bar functional :

Call the function stopLockTask() at a place in your code where you want to unpin. For example in my application, as soon as I verify that the user has typed the correct passcode, I call this function:

 if (userInput.length() == 4) {

                    if (userInput.equals(passcode)) {
                        userInput = "";
                        etxtPasscodeDisplay.setText("");
                        stopLockTask(); // this is what you need
                        unlockHomeButton(); // A method to show home screen when 
                         passcode is correct
                        finishAffinity(); //kill other activities
                    }

Extra Info which usually is required for lockscreens:

1. If your app is the first thing that comes up after boot :

You need a service(StartAtBootService) and a receiver (BootCompletedReceiver) for this.

2. If you want your app to show up after screen lock and unlock (the power button is pressed to lock and unlock):

Create AEScreenOnOffService that extends service and AEScreenOnOffReceiver that extends BroadcastReceiver to launch your activity when the screen is on.

For a detailed info on everything I mentioned here, refer http://www.sureshjoshi.com/mobile/android-kiosk-mode-without-root/
This is an excellent write up which helped me a lot. Special thanks to the author.

I need at least 10 reputation to post more than two links. As I'm new to stackoverflow I don't have enough reputation so I'm sorry for not being able to share all the links I referred. Will surely update the post once I get access.

Simple answer to your question is you cannot do that.

The solution that you have mention was suggested by me about four years ago [Link] .

onUserLeavesHint, onKeyDown and onKeyDispatch will never "disable" hardware keys.

If you really want to "handle" the Home button you will have to make your application as home screen. See this and this .

If you really want to disable your hardware key without making a home screen application, you should root your device and the delete the corresponding device file from the kernel module. (Try at your own risk!)

What you could do is override the home key function like this:

@Override public boolean onKeyDown(int keyCode, KeyEvent event)
{
    if(keyCode == KeyEvent.KEYCODE_HOME)
    {
        //The Code Want to Perform.
    }
});

Then you should be able to prevent the user to go back to home screen using this button. Hope that works for you.

EDIT: The problem with overriding the home button is it is considered as a security hole by Google, so each time someone finds a way to override it Google patches this "hole".

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