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

Commit 8a8fe9ce authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 12849324 from 00099f54 to 25Q2-release

Change-Id: Ib502a6977c70f15601fd2f0d7751ce294ffe2a0d
parents bd22a6a2 00099f54
Loading
Loading
Loading
Loading
+0 −45
Original line number Diff line number Diff line
@@ -22,7 +22,6 @@ import android.os.Bundle
import androidx.annotation.AnyThread
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.fragment.app.Fragment

/**
 * Interface provides preference metadata (title, summary, icon, etc.).
@@ -170,47 +169,3 @@ interface PreferenceMetadata {
/** Metadata of preference category. */
@AnyThread
open class PreferenceCategory(override val key: String, override val title: Int) : PreferenceGroup

/** Metadata of preference screen. */
@AnyThread
interface PreferenceScreenMetadata : PreferenceMetadata {

    /**
     * The screen title resource, which precedes [getScreenTitle] if provided.
     *
     * By default, screen title is same with [title].
     */
    val screenTitle: Int
        get() = title

    /** Returns dynamic screen title, use [screenTitle] whenever possible. */
    fun getScreenTitle(context: Context): CharSequence? = null

    /** Returns the fragment class to show the preference screen. */
    fun fragmentClass(): Class<out Fragment>?

    /**
     * Indicates if [getPreferenceHierarchy] returns a complete hierarchy of the preference screen.
     *
     * If `true`, the result of [getPreferenceHierarchy] will be used to inflate preference screen.
     * Otherwise, it is an intermediate state called hybrid mode, preference hierarchy is
     * represented by other ways (e.g. XML resource) and [PreferenceMetadata]s in
     * [getPreferenceHierarchy] will only be used to bind UI widgets.
     */
    fun hasCompleteHierarchy(): Boolean = true

    /**
     * Returns the hierarchy of preference screen.
     *
     * The implementation MUST include all preferences into the hierarchy regardless of the runtime
     * conditions. DO NOT check any condition (except compile time flag) before adding a preference.
     */
    fun getPreferenceHierarchy(context: Context): PreferenceHierarchy

    /**
     * Returns the [Intent] to show current preference screen.
     *
     * @param metadata the preference to locate when show the screen
     */
    fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?): Intent? = null
}
+66 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.settingslib.metadata

import android.content.Context
import android.content.Intent
import androidx.annotation.AnyThread
import androidx.fragment.app.Fragment

/** Metadata of preference screen. */
@AnyThread
interface PreferenceScreenMetadata : PreferenceMetadata {

    /**
     * The screen title resource, which precedes [getScreenTitle] if provided.
     *
     * By default, screen title is same with [title].
     */
    val screenTitle: Int
        get() = title

    /** Returns dynamic screen title, use [screenTitle] whenever possible. */
    fun getScreenTitle(context: Context): CharSequence? = null

    /** Returns the fragment class to show the preference screen. */
    fun fragmentClass(): Class<out Fragment>?

    /**
     * Indicates if [getPreferenceHierarchy] returns a complete hierarchy of the preference screen.
     *
     * If `true`, the result of [getPreferenceHierarchy] will be used to inflate preference screen.
     * Otherwise, it is an intermediate state called hybrid mode, preference hierarchy is
     * represented by other ways (e.g. XML resource) and [PreferenceMetadata]s in
     * [getPreferenceHierarchy] will only be used to bind UI widgets.
     */
    fun hasCompleteHierarchy(): Boolean = true

    /**
     * Returns the hierarchy of preference screen.
     *
     * The implementation MUST include all preferences into the hierarchy regardless of the runtime
     * conditions. DO NOT check any condition (except compile time flag) before adding a preference.
     */
    fun getPreferenceHierarchy(context: Context): PreferenceHierarchy

    /**
     * Returns the [Intent] to show current preference screen.
     *
     * @param metadata the preference to locate when show the screen
     */
    fun getLaunchIntent(context: Context, metadata: PreferenceMetadata?): Intent? = null
}
+5 −4
Original line number Diff line number Diff line
@@ -21,9 +21,8 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner
import com.android.settingslib.spa.framework.util.collectLatestWithLifecycle
import com.android.settingslib.spaprivileged.framework.common.broadcastReceiverAsUserFlow

/**
@@ -35,6 +34,8 @@ fun DisposableBroadcastReceiverAsUser(
    userHandle: UserHandle,
    onReceive: (Intent) -> Unit,
) {
    LocalContext.current.broadcastReceiverAsUserFlow(intentFilter, userHandle)
        .collectLatestWithLifecycle(LocalLifecycleOwner.current, action = onReceive)
    val context = LocalContext.current
    LaunchedEffect(Unit) {
        context.broadcastReceiverAsUserFlow(intentFilter, userHandle).collect(onReceive)
    }
}
+46 −26
Original line number Diff line number Diff line
@@ -22,10 +22,11 @@ import android.content.Intent
import android.content.IntentFilter
import android.os.UserHandle
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.lifecycle.testing.TestLifecycleOwner
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
@@ -38,12 +39,12 @@ import org.mockito.kotlin.mock

@RunWith(AndroidJUnit4::class)
class DisposableBroadcastReceiverAsUserTest {
    @get:Rule
    val composeTestRule = createComposeRule()
    @get:Rule val composeTestRule = createComposeRule()

    private var registeredBroadcastReceiver: BroadcastReceiver? = null

    private val context = mock<Context> {
    private val context =
        mock<Context> {
            on {
                registerReceiverAsUser(
                    any(),
@@ -53,19 +54,24 @@ class DisposableBroadcastReceiverAsUserTest {
                    isNull(),
                    eq(Context.RECEIVER_NOT_EXPORTED),
                )
        } doAnswer {
            } doAnswer
                {
                    registeredBroadcastReceiver = it.arguments[0] as BroadcastReceiver
                    null
                }

            on { unregisterReceiver(any()) } doAnswer
                {
                    if (registeredBroadcastReceiver === it.arguments[0]) {
                        registeredBroadcastReceiver = null
                    }
                }
        }

    @Test
    fun broadcastReceiver_registered() {
        composeTestRule.setContent {
            CompositionLocalProvider(
                LocalContext provides context,
                LocalLifecycleOwner provides TestLifecycleOwner(),
            ) {
            CompositionLocalProvider(LocalContext provides context) {
                DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {}
            }
        }
@@ -77,10 +83,7 @@ class DisposableBroadcastReceiverAsUserTest {
    fun broadcastReceiver_isCalledOnReceive() {
        var onReceiveIsCalled = false
        composeTestRule.setContent {
            CompositionLocalProvider(
                LocalContext provides context,
                LocalLifecycleOwner provides TestLifecycleOwner(),
            ) {
            CompositionLocalProvider(LocalContext provides context) {
                DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {
                    onReceiveIsCalled = true
                }
@@ -92,6 +95,23 @@ class DisposableBroadcastReceiverAsUserTest {
        composeTestRule.waitUntil { onReceiveIsCalled }
    }

    @Test
    fun broadcastReceiver_unregistered() {
        var isBroadcastReceiverRegistered by mutableStateOf(true)
        composeTestRule.setContent {
            if (isBroadcastReceiverRegistered) {
                CompositionLocalProvider(LocalContext provides context) {
                    DisposableBroadcastReceiverAsUser(INTENT_FILTER, USER_HANDLE) {}
                }
            }
        }
        composeTestRule.waitUntil { registeredBroadcastReceiver != null }

        isBroadcastReceiverRegistered = false

        composeTestRule.waitUntil { registeredBroadcastReceiver == null }
    }

    private companion object {
        val USER_HANDLE: UserHandle = UserHandle.of(0)

+2 −2
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull
import com.android.settingslib.spa.testutils.toListWithTimeout
import com.android.settingslib.spaprivileged.framework.common.asUser
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.async
import kotlinx.coroutines.delay
@@ -35,6 +34,7 @@ import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever

@RunWith(AndroidJUnit4::class)
class PermissionsChangedFlowTest {
@@ -49,7 +49,7 @@ class PermissionsChangedFlowTest {
    }

    private val context: Context = spy(ApplicationProvider.getApplicationContext()) {
        on { asUser(APP.userHandle) } doReturn mock
        doReturn(mock).whenever(mock).createContextAsUser(APP.userHandle, 0)
        on { packageManager } doReturn mockPackageManager
    }

Loading