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

Commit c309da55 authored by Tianfan Zhang's avatar Tianfan Zhang Committed by Android (Google) Code Review
Browse files

Merge "Create UnderlayRepository and UnderlayInteractor to trigger...

Merge "Create UnderlayRepository and UnderlayInteractor to trigger UnderlayView creation/destruction logic. The broadcast should be a temporary solution and may be migrated to Binder very soon." into main
parents 7df8a23d b708b398
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.underlay

import com.android.systemui.CoreStartable
import com.android.systemui.underlay.ui.startable.UnderlayCoreStartable
import dagger.Binds
import dagger.Module
import dagger.multibindings.ClassKey
+48 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.systemui.underlay

import android.graphics.PixelFormat
import android.view.Gravity
import android.view.WindowManager.LayoutParams

object UnderlayUtils {
    fun getUnderlayLayoutParams(
        width: Int,
        height: Int,
        readyToShowUnderlay: Boolean,
    ): LayoutParams {
        val touchFlag =
            if (readyToShowUnderlay) {
                LayoutParams.FLAG_NOT_TOUCH_MODAL
            } else {
                LayoutParams.FLAG_NOT_TOUCHABLE
            }
        return LayoutParams(
                width,
                height,
                LayoutParams.TYPE_STATUS_BAR_ADDITIONAL,
                LayoutParams.FLAG_NOT_FOCUSABLE or touchFlag,
                PixelFormat.TRANSLUCENT,
            )
            .apply {
                alpha = if (readyToShowUnderlay) 1f else 0f
                gravity = Gravity.BOTTOM or Gravity.START
                fitInsetsTypes = 0
                isFitInsetsIgnoringVisibility = false
            }
    }
}
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.underlay.data.repository

import android.content.IntentFilter
import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Background
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn

@SysUISingleton
class UnderlayRepository
@Inject
constructor(
    @Background private val backgroundScope: CoroutineScope,
    broadcastDispatcher: BroadcastDispatcher,
) {
    val isUnderlayAttached: StateFlow<Boolean> =
        broadcastDispatcher
            .broadcastFlow(
                filter =
                    IntentFilter().apply {
                        addAction(ACTION_CREATE_UNDERLAY)
                        addAction(ACTION_DESTROY_UNDERLAY)
                    }
            ) { intent, _ ->
                intent.action == ACTION_CREATE_UNDERLAY
            }
            .stateIn(
                scope = backgroundScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = false,
            )

    private companion object {
        const val ACTION_CREATE_UNDERLAY = "com.systemui.underlay.action.CREATE_UNDERLAY"
        const val ACTION_DESTROY_UNDERLAY = "com.systemui.underlay.action.DESTROY_UNDERLAY"
    }
}
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 * Copyright 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
@@ -14,32 +14,12 @@
 * limitations under the License.
 */

package com.android.systemui.underlay
package com.android.systemui.underlay.domain.interactor

import android.util.Log
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.underlay.shared.flag.UnderlayFlag
import com.android.systemui.underlay.data.repository.UnderlayRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow

/**
 * Core startable for the underlay.
 *
 * This is responsible for starting the underlay and its dependencies.
 */
@SysUISingleton
class UnderlayCoreStartable @Inject constructor() : CoreStartable {

    override fun start() {
        if (!UnderlayFlag.isEnabled) {
            Log.d(TAG, "Underlay flag is disabled, not starting.")
            return
        }

        Log.d(TAG, "start!")
    }

    private companion object {
        const val TAG = "UnderlayCoreStartable"
    }
class UnderlayInteractor @Inject constructor(repository: UnderlayRepository) {
    val isUnderlayAttached: StateFlow<Boolean> = repository.isUnderlayAttached
}
+87 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.underlay.ui.startable

import android.util.Log
import android.view.WindowManager
import com.android.systemui.CoreStartable
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.underlay.UnderlayUtils
import com.android.systemui.underlay.domain.interactor.UnderlayInteractor
import com.android.systemui.underlay.shared.flag.UnderlayFlag
import com.android.systemui.underlay.ui.view.UnderlayWindowRootView
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

/**
 * Core startable for the underlay.
 *
 * This is responsible for starting the underlay and its dependencies.
 */
@SysUISingleton
class UnderlayCoreStartable
@Inject
constructor(
    private val windowManager: WindowManager,
    private val underlayInteractor: UnderlayInteractor,
    private val underlayWindowRootView: UnderlayWindowRootView,
    @Application private val mainScope: CoroutineScope,
) : CoreStartable {

    override fun start() {
        if (!UnderlayFlag.isEnabled) {
            Log.d(TAG, "Underlay flag is disabled, not starting.")
            return
        }

        Log.d(TAG, "start!")
        mainScope.launch {
            underlayInteractor.isUnderlayAttached.collect { isUnderlayAttached ->
                if (isUnderlayAttached) {
                    createUnderlayView()
                } else {
                    destroyUnderlayView()
                }
            }
        }
    }

    private fun createUnderlayView() {
        if (!underlayWindowRootView.isAttachedToWindow) {
            windowManager.addView(
                underlayWindowRootView,
                UnderlayUtils.getUnderlayLayoutParams(
                    width = WindowManager.LayoutParams.MATCH_PARENT,
                    height = WindowManager.LayoutParams.WRAP_CONTENT,
                    readyToShowUnderlay = false,
                ),
            )
        }
    }

    private fun destroyUnderlayView() {
        if (underlayWindowRootView.isAttachedToWindow) {
            windowManager.removeView(underlayWindowRootView)
        }
    }

    private companion object {
        const val TAG = "UnderlayCoreStartable"
    }
}
Loading