Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 092a6647 authored by Lyn Han's avatar Lyn Han Committed by Lyn
Browse files

Add FSI view binder and wm config

Bug: 243421660
Test: visual
Change-Id: I39ede9bc83ebd6710ff4441282dc2072165c7521
parent 3e92172c
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.systemui.shortcut.ShortcutKeyDispatcher
import com.android.systemui.statusbar.notification.fsi.FsiChromeRepo
import com.android.systemui.statusbar.notification.InstantAppNotifier
import com.android.systemui.statusbar.notification.fsi.FsiChromeViewModelFactory
import com.android.systemui.statusbar.notification.fsi.FsiChromeViewBinder
import com.android.systemui.statusbar.phone.KeyguardLiftController
import com.android.systemui.stylus.StylusUsiPowerStartable
import com.android.systemui.temporarydisplay.chipbar.ChipbarCoordinator
@@ -93,6 +94,12 @@ abstract class SystemUICoreStartableModule {
    @ClassKey(FsiChromeViewModelFactory::class)
    abstract fun bindFSIChromeWindowViewModel(sysui: FsiChromeViewModelFactory): CoreStartable

    /** Inject into FsiChromeWindowBinder.  */
    @Binds
    @IntoMap
    @ClassKey(FsiChromeViewBinder::class)
    abstract fun bindFsiChromeWindowBinder(sysui: FsiChromeViewBinder): CoreStartable

    /** Inject into GarbageMonitor.Service.  */
    @Binds
    @IntoMap
+99 −0
Original line number Diff line number Diff line
package com.android.systemui.statusbar.notification.fsi

import android.content.Context
import android.view.LayoutInflater
import android.view.WindowManager
import com.android.systemui.CoreStartable
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.notification.fsi.FsiDebug.Companion.log
import com.android.systemui.statusbar.phone.CentralSurfaces
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import java.util.concurrent.Executor
import javax.inject.Inject

@SysUISingleton
class FsiChromeViewBinder
@Inject
constructor(
    val context: Context,
    val windowManager: WindowManager,
    val viewModelFactory: FsiChromeViewModelFactory,
    val layoutInflater: LayoutInflater,
    val centralSurfaces: CentralSurfaces,
    @Main val mainExecutor: Executor,
    @Application val scope: CoroutineScope,
) : CoreStartable {

    companion object {
        private const val classTag = "FsiChromeViewBinder"
    }

    private val fsiChromeView =
        layoutInflater.inflate(R.layout.fsi_chrome_view, null /* root */, false /* attachToRoot */)
            as FsiChromeView

    var addedToWindowManager = false
    var cornerRadius: Int = context.resources.getDimensionPixelSize(
            R.dimen.notification_corner_radius)

    override fun start() {
        val methodTag = "start"
        log("$classTag $methodTag ")

        scope.launch {
            log("$classTag $methodTag launch ")
            viewModelFactory.viewModelFlow.collect { vm -> updateForViewModel(vm) }
        }
    }

    private fun updateForViewModel(vm: FsiChromeViewModel?) {
        val methodTag = "updateForViewModel"

        if (vm == null) {
            log("$classTag $methodTag viewModel is null, removing from window manager")

            if (addedToWindowManager) {
                windowManager.removeView(fsiChromeView)
                addedToWindowManager = false
            }
            return
        }

        bindViewModel(vm, windowManager)

        if (addedToWindowManager) {
            log("$classTag $methodTag already addedToWindowManager")
        } else {
            windowManager.addView(fsiChromeView, FsiTaskViewConfig.getWmLayoutParams("PackageName"))
            addedToWindowManager = true
        }
    }

    private fun bindViewModel(
        vm: FsiChromeViewModel,
        windowManager: WindowManager,
    ) {
        log("$classTag bindViewModel")

        fsiChromeView.appIconImageView.setImageDrawable(vm.appIcon)
        fsiChromeView.appNameTextView.text = vm.appName

        fsiChromeView.dismissButton.setOnClickListener { vm.onDismiss() }
        fsiChromeView.fullscreenButton.setOnClickListener { vm.onFullscreen() }

        vm.taskView.cornerRadius = cornerRadius.toFloat()
        vm.taskView.startActivity(
            vm.fsi,
            FsiTaskViewConfig.getFillInIntent(),
            FsiTaskViewConfig.getActivityOptions(context, windowManager),
            FsiTaskViewConfig.getLaunchBounds(windowManager)
        )

        log("$classTag bindViewModel started taskview activity")
        fsiChromeView.addView(vm.taskView)
    }
}
+75 −0
Original line number Diff line number Diff line
package com.android.systemui.statusbar.notification.fsi

import android.app.ActivityOptions
import android.content.Context
import android.content.Intent
import android.graphics.PixelFormat
import android.graphics.Rect
import android.os.Binder
import android.view.ViewGroup
import android.view.WindowManager

/**
 * Config for adding the FsiChromeView window to WindowManager and starting the FSI activity.
 */
class FsiTaskViewConfig {

    companion object {

        private const val classTag = "FsiTaskViewConfig"

        fun getWmLayoutParams(packageName: String): WindowManager.LayoutParams {
            val params: WindowManager.LayoutParams?
            params =
                WindowManager.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                    WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE or
                        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED or
                            WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER,
                    PixelFormat.TRANSLUCENT
                )
            params.setTrustedOverlay()
            params.fitInsetsTypes = 0
            params.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
            params.token = Binder()
            params.packageName = packageName
            params.layoutInDisplayCutoutMode =
                WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
            params.privateFlags =
                params.privateFlags or WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS
            return params
        }

        fun getFillInIntent(): Intent {
            val fillInIntent = Intent()
            fillInIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT)
            fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
            // FLAG_ACTIVITY_NEW_TASK is auto-applied because
            // we're starting the FSI activity from a non-Activity context
            return fillInIntent
        }

        fun getLaunchBounds(windowManager: WindowManager): Rect {
            // TODO(b/243421660) check this works for non-resizeable activity
            return Rect()
        }

        fun getActivityOptions(context: Context, windowManager: WindowManager): ActivityOptions {
            // Custom options so there is no activity transition animation
            val options =
                ActivityOptions.makeCustomAnimation(context, 0 /* enterResId */, 0 /* exitResId */)

            options.taskAlwaysOnTop = true

            options.pendingIntentLaunchFlags =
                Intent.FLAG_ACTIVITY_NEW_DOCUMENT or
                    Intent.FLAG_ACTIVITY_MULTIPLE_TASK or
                    Intent.FLAG_ACTIVITY_NEW_TASK

            options.launchBounds = getLaunchBounds(windowManager)
            return options
        }
    }
}