Search code examples
javaandroidflutterkotlinandroid-rom

shutting down android functionality like qs tiles, volume panel and navigation's


I am working on an well-being app that shuts your phone up for a given period of time (eg. 30min, 1hr, 1.5hr)

In this state user can only see a screen with remaining time on it and cannot

  • Access QS tiles
  • Access Volume panel
  • Navigate out of the Activity

something similar to Oneplus Zen mode

things i have thought of for doing this

  • Killing the SystemUI process.(by doing so the QS and volume panel would be dealt with most probably, maybe need root for that tho? also SystemUI automatically restarts itself, quite stubborn)

  • Making app a launcher Dynamically?(technically you can't navigate out of a launcher and on reboot you come back to it)

how can I get around accomplishing this? any ideas?


Solution

  • Making application the default launcher of the phone is more practical solution to what you're trying to achieve. I've done this previously in a Flutter application which was going to be installed on kiosk devices to get orders from customers and it worked perfectly. It's a bit tricky to make it work and there's lots of things to do. Here is a list of things I did back then:

    1. Use FLAG_SHOW_WHEN_LOCKED flag to the window to bypass the lock screen.

    2. Inside of onResume add FLAG_FULLSCREEN flags to hide the status bar.

    3. Make your MainActivity launcher by adding LAUNCHER category to in AndroidManifest.xml. Also you can add other attributes I used (Search for them if you don't know what are they supposed to do).

      <activity
          android:name=".MainActivity"
          android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
          android:excludeFromRecents="true"
          android:hardwareAccelerated="true"
          android:launchMode="singleInstance"
          android:showOnLockScreen="true"
          android:showWhenLocked="true"
          android:theme="@style/LaunchTheme"
          android:turnScreenOn="true"
          android:windowSoftInputMode="adjustResize">
          <intent-filter>
              <action android:name="android.intent.action.MAIN" />
      
              <category android:name="android.intent.category.LAUNCHER" />
              <category android:name="android.intent.category.HOME" />
              <category android:name="android.intent.category.DEFAULT" />
          </intent-filter>
      </activity>
      
    4. Listen for window focus changes in your MainActivity and bring your application to front if it lost the focus.

      private fun moveToFront() {
        val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)
        sendBroadcast(closeDialog)
        (activity.applicationContext.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager)
                .moveTaskToFront(activity.taskId, ActivityManager.MOVE_TASK_WITH_HOME)
        window.setFlags(
              WindowManager.LayoutParams.FLAG_FULLSCREEN,
              WindowManager.LayoutParams.FLAG_FULLSCREEN);
      }
      
      override fun onWindowFocusChanged(hasFocus: Boolean) {
        super.onWindowFocusChanged(hasFocus)
        if (!hasFocus) {
          moveToFront()
        }
      }
      
    5. I was also checking if my application is the default launcher.

      private fun isAppDefault(): Boolean {
        val intent = Intent(Intent.ACTION_MAIN)
        intent.addCategory(Intent.CATEGORY_HOME)
        val res: ResolveInfo = packageManager.resolveActivity(intent, 0)
        return res.activityInfo != null && (packageName
              == res.activityInfo.packageName)
      }
      
    6. And you're gonna need to communicate between Flutter and the platform using MethodChannel to enable and disable force mode and get the state of the application.