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

Unverified Commit f00e19e5 authored by Michael Bestas's avatar Michael Bestas
Browse files

Merge tag 'android-16.0.0_r3' into staging/lineage-23.0_merge-android-16.0.0_r3

Android 16.0.0 Release 3 (BP3A.250905.014)

# -----BEGIN PGP SIGNATURE-----
#
# iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaRO/HAAKCRDorT+BmrEO
# eABDAKCHX+ImmcK/w6jIx9GF/GDnbwVOUwCfV2iPX011ceTRMei5GzE0nKu+Vns=
# =Wooh
# -----END PGP SIGNATURE-----
# gpg: Signature made Wed Nov 12 00:56:28 2025 EET
# gpg:                using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78
# gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [ultimate]

# By Mike Schneider (36) and others
# Via Android (Google) Code Review (82) and others
* tag 'android-16.0.0_r3': (117 commits)
  Remove the hairline drawn on the OverlayShade background
  Using an efficient circular buffer as a logging structure.
  Convert BitmapInfo to Kotlin to help with customization
  viewcapture tracing: fix formatting
  Add AOD support in TorusLib
  Converting FastBitmapDrawable to kotlin
  Add BUGFIX flag smartspace_weather_use_monochrome_font_icons.
  Move custom Launcher theme flag to shared SysUI package (3/3)
  Add helper method to get drawable info about the badge. This is to be able to map the data to the widget picker's data types.
  Disable surface effects when a theme controller doesn't support adaptive themed icons
  Fix possibile deadlock with registering listeners for sys decor.
  We might have delta zero when we change segment
  MM tests should fail if they produce unexpected wtf logs
  Move coroutine tracing feature to sysprop
  Fix semantics missing on segment non-`CanBeLastSegment` segments
  Add utility to print debug version of a motion spec
  MM Remove unused libraries in mechanics-compose lib
  Reland cache snow flakes and reduce snow layers It can save ~30% GPU power
  Null check bitmapInfo in fastBitmapDrawable
  Revert "Cache snow flakes and reduce snow layers"
  ...

Change-Id: I5911d55ae7213360da91cf649d0746178601383f
parents 6aa57611 f63b90cc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -11,5 +11,7 @@ checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPL

ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES}

alint_hook =  ${REPO_ROOT}/vendor/google/tools/alint

[Tool Paths]
ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh
+31 −10
Original line number Diff line number Diff line
@@ -137,13 +137,6 @@ flag {
    bug: "391401141"
}

flag {
    name: "enable_lpp_squeeze_effect"
    namespace: "systemui"
    description: "Enables squeeze effect on power button long press launching Gemini"
    bug: "396099245"
}

flag {
  name: "cursor_hot_corner"
  namespace: "systemui"
@@ -158,6 +151,16 @@ flag {
    bug: "389741821"
}

flag {
    name: "smartspace_weather_use_monochrome_font_icons"
    namespace: "systemui"
    description: "Update Smartspace to use monochrome font icons for weather"
    bug: "389957594"
    metadata {
         purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "smartspace_ui_update_resources"
    namespace: "systemui"
@@ -167,11 +170,29 @@ flag {
}

flag {
    name: "smartspace_remoteviews_intent_handler"
    name: "enable_lpp_assist_invocation_effect"
    namespace: "systemui"
    description: "Enables Smartspace RemoteViews intent handling on lockscreen"
    bug: "399416038"
    description: "Enables invocation effect on power button long press for launching assistant"
    bug: "396099245"
    metadata {
         purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "enable_lpp_assist_invocation_haptic_effect"
    namespace: "systemui"
    description: "Enables haptics for the invocation effect on power button long press for launching assistant"
    bug: "412325043"
    metadata {
         purpose: PURPOSE_BUGFIX
    }
}

flag {
  name: "extendible_theme_manager"
  namespace: "launcher"
  description: "Enables custom theme manager in Launcher and Customization Picker"
  bug: "381897614"
}
+17 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package com.android.app.displaylib

import android.hardware.display.DisplayManager
import android.os.Handler
import android.view.IWindowManager
import dagger.Binds
import dagger.BindsInstance
import dagger.Component
@@ -40,6 +41,7 @@ interface DisplayLibComponent {
    interface Factory {
        fun create(
            @BindsInstance displayManager: DisplayManager,
            @BindsInstance windowManager: IWindowManager,
            @BindsInstance bgHandler: Handler,
            @BindsInstance bgApplicationScope: CoroutineScope,
            @BindsInstance backgroundCoroutineDispatcher: CoroutineDispatcher,
@@ -47,11 +49,18 @@ interface DisplayLibComponent {
    }

    val displayRepository: DisplayRepository
    val displaysWithDecorationsRepository: DisplaysWithDecorationsRepository
    val displaysWithDecorationsRepositoryCompat: DisplaysWithDecorationsRepositoryCompat
}

@Module
interface DisplayLibModule {
    @Binds fun bindDisplayManagerImpl(impl: DisplayRepositoryImpl): DisplayRepository

    @Binds
    fun bindDisplaysWithDecorationsRepositoryImpl(
        impl: DisplaysWithDecorationsRepositoryImpl
    ): DisplaysWithDecorationsRepository
}

/**
@@ -63,10 +72,17 @@ interface DisplayLibModule {
 */
fun createDisplayLibComponent(
    displayManager: DisplayManager,
    windowManager: IWindowManager,
    bgHandler: Handler,
    bgApplicationScope: CoroutineScope,
    backgroundCoroutineDispatcher: CoroutineDispatcher,
): DisplayLibComponent {
    return DaggerDisplayLibComponent.factory()
        .create(displayManager, bgHandler, bgApplicationScope, backgroundCoroutineDispatcher)
        .create(
            displayManager,
            windowManager,
            bgHandler,
            bgApplicationScope,
            backgroundCoroutineDispatcher,
        )
}
+40 −3
Original line number Diff line number Diff line
@@ -86,11 +86,28 @@ interface DisplayRepository {
    /**
     * Given a display ID int, return the corresponding Display object, or null if none exist.
     *
     * This method is guaranteed to not result in any binder call.
     * This method will not result in a binder call in most cases. The only exception is if there is
     * an existing binder call ongoing to get the [Display] instance already. In that case, this
     * will wait for the end of the binder call.
     */
    fun getDisplay(displayId: Int): Display? =
    fun getDisplay(displayId: Int): Display?

    /**
     * As [getDisplay], but it's always guaranteed to not block on any binder call.
     *
     * This might return null if the display id was not mapped to a [Display] object yet.
     */
    fun getCachedDisplay(displayId: Int): Display? =
        displays.value.firstOrNull { it.displayId == displayId }

    /**
     * Returns whether the given displayId is in the set of enabled displays.
     *
     * This is guaranteed to not cause a binder call. Use this instead of [getDisplay] (see its docs
     * for why)
     */
    fun containsDisplay(displayId: Int): Boolean = displayIds.value.contains(displayId)

    /** Represents a connected display that has not been enabled yet. */
    interface PendingDisplay {
        /** Id of the pending display. */
@@ -375,6 +392,24 @@ constructor(
            .map { defaultDisplay.state == Display.STATE_OFF }
            .distinctUntilChanged()

    override fun getDisplay(displayId: Int): Display? {
        val cachedDisplay = getCachedDisplay(displayId)
        if (cachedDisplay != null) return cachedDisplay
        // cachedDisplay could be null for 2 reasons:
        // 1. the displayId is being mapped to a display in the background, but the binder call is
        // not done
        // 2. the display is not there
        // In case of option one, let's get it synchronously from display manager to make sure for
        // this to be consistent.
        return if (displayIds.value.contains(displayId)) {
            traceSection("$TAG#getDisplayFallbackToDisplayManager") {
                getDisplayFromDisplayManager(displayId)
            }
        } else {
            null
        }
    }

    private fun <T> Flow<T>.debugLog(flowName: String): Flow<T> {
        return if (DEBUG) {
            traceEach(flowName, logcat = true, traceEmissionCount = true)
@@ -454,8 +489,10 @@ private sealed interface DisplayEvent {
 * upstream Flow.
 *
 * Useful for code that needs to compare the current value to the previous value.
 *
 * Note this has been taken from com.android.systemui.util.kotlin. It was copied to keep deps of
 * displaylib minimal (and avoid creating a new shared lib for it).
 */
// TODO b/401305290 - This should be moved to a shared lib, as it's also used by SystemUI.
fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> = flow {
    val noVal = Any()
    var previousValue: Any? = noVal
+119 −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.app.displaylib

import android.content.res.Configuration
import android.graphics.Rect
import android.view.IDisplayWindowListener
import android.view.IWindowManager
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.scan
import kotlinx.coroutines.flow.stateIn

/** Provides the displays with decorations. */
interface DisplaysWithDecorationsRepository {
    /** A [StateFlow] that maintains a set of display IDs that should have system decorations. */
    val displayIdsWithSystemDecorations: StateFlow<Set<Int>>
}

@Singleton
class DisplaysWithDecorationsRepositoryImpl
@Inject
constructor(
    private val windowManager: IWindowManager,
    bgApplicationScope: CoroutineScope,
    displayRepository: DisplayRepository,
) : DisplaysWithDecorationsRepository {

    private val decorationEvents: Flow<Event> = callbackFlow {
        val callback =
            object : IDisplayWindowListener.Stub() {
                override fun onDisplayAddSystemDecorations(displayId: Int) {
                    trySend(Event.Add(displayId))
                }

                override fun onDisplayRemoveSystemDecorations(displayId: Int) {
                    trySend(Event.Remove(displayId))
                }

                override fun onDesktopModeEligibleChanged(displayId: Int) {}

                override fun onDisplayAdded(p0: Int) {}

                override fun onDisplayConfigurationChanged(p0: Int, p1: Configuration?) {}

                override fun onDisplayRemoved(p0: Int) {}

                override fun onFixedRotationStarted(p0: Int, p1: Int) {}

                override fun onFixedRotationFinished(p0: Int) {}

                override fun onKeepClearAreasChanged(
                    p0: Int,
                    p1: MutableList<Rect>?,
                    p2: MutableList<Rect>?,
                ) {}
            }
        windowManager.registerDisplayWindowListener(callback)
        awaitClose { windowManager.unregisterDisplayWindowListener(callback) }
    }

    private val initialDisplayIdsWithDecorations: Set<Int> =
        displayRepository.displayIds.value
            .filter { windowManager.shouldShowSystemDecors(it) }
            .toSet()

    /**
     * A [StateFlow] that maintains a set of display IDs that should have system decorations.
     *
     * Updates to the set are triggered by:
     * - Removing displays via [displayRemovalEvent] emissions.
     *
     * The set is initialized with displays that qualify for system decorations based on
     * [WindowManager.shouldShowSystemDecors].
     */
    override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> =
        merge(decorationEvents, displayRepository.displayRemovalEvent.map { Event.Remove(it) })
            .scan(initialDisplayIdsWithDecorations) { displayIds: Set<Int>, event: Event ->
                when (event) {
                    is Event.Add -> displayIds + event.displayId
                    is Event.Remove -> displayIds - event.displayId
                }
            }
            .distinctUntilChanged()
            .stateIn(
                scope = bgApplicationScope,
                started = SharingStarted.WhileSubscribed(),
                initialValue = initialDisplayIdsWithDecorations,
            )

    private sealed class Event(val displayId: Int) {
        class Add(displayId: Int) : Event(displayId)

        class Remove(displayId: Int) : Event(displayId)
    }
}
Loading