-1

I am trying to make a view in Android which cannot be closed. I mean that all UI system buttons (Home, back, status bar, etc.) are disabled. Destination way to close app or to open not blocked view is NFC card.

I have been trying to do this for last week and i have no more idea. Maybe someone of you will know how to do that. Thanks for any help.

I am able to hide navigation and status bar, but if I swipe from edge of the screen then it appears again.

Most of working things I have found on the developer.android.com and in (GitHub repo).

But still I am able to close app.

Playground code: https://github.com/BoguskiAdam/AndroidNoUiButtons

_________________________

EDIT:

I have seen few applications like that. I want to make it to be something like in the 'kiosk' mode. User shouldn't be allowed to minimalize application. He may only use it but he can't go to the first view. Only I can open first view using NFC card. NFC is configured to open first view (which is not available for user) which contains configuration etc and allows me to close app.

_________________________

Manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.adam.nohome">

    <uses-permission android:name="android.permission.REORDER_TASKS"/>

    <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            tools:ignore="GoogleAppIndexingWarning">
        <activity
                android:name=".MainActivity"
                android:configChanges="orientation|keyboardHidden|screenSize"
                android:label="Test label"
                android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity
                android:name=".NoUiActivity"
                android:configChanges="orientation|keyboardHidden|screenSize"
                android:label="Test tittle"
                android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <category android:name="android.intent.category.LAUNCHER" />
                <category android:name="android.intent.category.HOME" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>

</manifest>

View XML:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#000"
        tools:context=".NoUiActivity">
</android.support.constraint.ConstraintLayout>

View code:

package com.example.adam.nohome

import android.app.ActivityManager
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.PersistableBundle
import android.util.Log
import android.view.*

class NoUiActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        supportActionBar?.setDisplayHomeAsUpEnabled(false)

        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_no_ui)

        hideUi()
    }

    override fun onPause() {
        val activityManager = applicationContext
            .getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

        activityManager.moveTaskToFront(taskId, 0)
        super.onPause()
    }

    private fun hideUi() {
        window.statusBarColor = Color.TRANSPARENT

        setGestureDetector()
        hideSystemUI()
        setUiListener()
    }

    private fun setGestureDetector() {
        val contentView = window.decorView
        contentView.isClickable = true
        val clickDetector = GestureDetector(this,
            object : GestureDetector.SimpleOnGestureListener() {
                override fun onSingleTapUp(e: MotionEvent): Boolean {
                    hideSystemUI()
                    return true
                }
            }
        )
        contentView.setOnTouchListener { _, motionEvent -> clickDetector.onTouchEvent(motionEvent) }
    }

        private fun hideSystemUI() {
        window.decorView.systemUiVisibility = (
                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        or View.SYSTEM_UI_FLAG_FULLSCREEN
                        //or View.SYSTEM_UI_FLAG_LOW_PROFILE
                        or View.SYSTEM_UI_FLAG_IMMERSIVE
                )
    }


//    private fun hideSystemUI() {
//        window.decorView.systemUiVisibility = (
//                View.SYSTEM_UI_FLAG_LAYOUT_STABLE
//                        or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
//                        or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
//                        or View.SYSTEM_UI_FLAG_IMMERSIVE
//                )
//    }

    private fun setUiListener() {
        window.decorView.setOnSystemUiVisibilityChangeListener { flags ->
            run {
                supportActionBar?.hide()
                hideSystemUI()
            }
        }
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        //handle the click on the back arrow click

        val result = when (item.itemId) {
            android.R.id.home -> {
                onBackPressed()
                true
            }

            else -> super.onOptionsItemSelected(item)
        }
        return result
    }


    override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        hideSystemUI()
    }

    // It recognize here only 'Back' button
    override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
        if (keyCode == KeyEvent.KEYCODE_BACK || keyCode == KeyEvent.KEYCODE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
            return true;
        }
        return super.onKeyDown(keyCode, event)
    }
}

First view that opens view that cannot be closed:

First view

Second view that shouldn't allow to easily go close app:

Second view

Second view after swipe from edge of the screen:

Second view after swipe

SOLVED: Used Spinned screen / kiosk / Cosu mode. I had additional problem with allowing NFC but found workaround. How can I send a string through NFC while Screen-Pinning?

Acha47
  • 7
  • 3
  • 3
    the user always has to be able to close your app whenever he wants. If your app can't be closed, then it is a malware app (virus). That's why there is no way (and should be no way) to do what you want. – Vladyslav Matviienko Nov 23 '18 at 08:51
  • 2
    I don't know how to solve your problem. But I think users should have the right to exit or close the application whenever they want. – Hello World Nov 23 '18 at 08:55

1 Answers1

0

You might want to take a look at

https://developer.android.com/work/cosu

This allows you to lock a single application to the screen, and hide the Home and Recents buttons to prevent users from escaping the app.

Beware that this is only possible if you own the device, you can NOT do this with the phone from your target audience.

These type of things are mainly used used for a single purpose, such as digital signage, ticket printing, point of sale, or inventory management.

Bastien verschaete
  • 445
  • 1
  • 3
  • 10