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

Commit 12edf2b0 authored by Mark Renouf's avatar Mark Renouf Committed by Automerger Merge Worker
Browse files

Merge "Fix swapped int params in DisplayContentInfo ctor" into tm-qpr-dev am: 3c5854a4

parents 5cd5175f 3c5854a4
Loading
Loading
Loading
Loading
+4 −2
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.screenshot
package com.android.systemui.screenshot


import android.graphics.Insets
import android.graphics.Insets
import android.util.Log
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import android.view.WindowManager.TAKE_SCREENSHOT_PROVIDED_IMAGE
import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
import com.android.internal.util.ScreenshotHelper.HardwareBitmapBundler
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
import com.android.internal.util.ScreenshotHelper.ScreenshotRequest
@@ -61,8 +62,9 @@ class RequestProcessor @Inject constructor(
        ) {
        ) {


            val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
            val info = policy.findPrimaryContent(policy.getDefaultDisplayId())
            Log.d(TAG, "findPrimaryContent: $info")


            result = if (policy.isManagedProfile(info.userId)) {
            result = if (policy.isManagedProfile(info.user.identifier)) {
                val image = capture.captureTask(info.taskId)
                val image = capture.captureTask(info.taskId)
                    ?: error("Task snapshot returned a null Bitmap!")
                    ?: error("Task snapshot returned a null Bitmap!")


@@ -70,7 +72,7 @@ class RequestProcessor @Inject constructor(
                ScreenshotRequest(
                ScreenshotRequest(
                    TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source,
                    TAKE_SCREENSHOT_PROVIDED_IMAGE, request.source,
                    HardwareBitmapBundler.hardwareBitmapToBundle(image),
                    HardwareBitmapBundler.hardwareBitmapToBundle(image),
                    info.bounds, Insets.NONE, info.taskId, info.userId, info.component
                    info.bounds, Insets.NONE, info.taskId, info.user.identifier, info.component
                )
                )
            } else {
            } else {
                // Create a new request of the same type which includes the top component
                // Create a new request of the same type which includes the top component
+2 −1
Original line number Original line Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.systemui.screenshot
import android.annotation.UserIdInt
import android.annotation.UserIdInt
import android.content.ComponentName
import android.content.ComponentName
import android.graphics.Rect
import android.graphics.Rect
import android.os.UserHandle
import android.view.Display
import android.view.Display


/**
/**
@@ -42,7 +43,7 @@ interface ScreenshotPolicy {
    data class DisplayContentInfo(
    data class DisplayContentInfo(
        val component: ComponentName,
        val component: ComponentName,
        val bounds: Rect,
        val bounds: Rect,
        @UserIdInt val userId: Int,
        val user: UserHandle,
        val taskId: Int,
        val taskId: Int,
    )
    )


+66 −58
Original line number Original line Diff line number Diff line
@@ -29,9 +29,11 @@ import android.content.Intent
import android.graphics.Rect
import android.graphics.Rect
import android.os.Process
import android.os.Process
import android.os.RemoteException
import android.os.RemoteException
import android.os.UserHandle
import android.os.UserManager
import android.os.UserManager
import android.util.Log
import android.util.Log
import android.view.Display.DEFAULT_DISPLAY
import android.view.Display.DEFAULT_DISPLAY
import com.android.internal.annotations.VisibleForTesting
import com.android.internal.infra.ServiceConnector
import com.android.internal.infra.ServiceConnector
import com.android.systemui.SystemUIService
import com.android.systemui.SystemUIService
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
@@ -45,21 +47,13 @@ import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
import kotlinx.coroutines.withContext


@SysUISingleton
@SysUISingleton
internal class ScreenshotPolicyImpl @Inject constructor(
internal open class ScreenshotPolicyImpl @Inject constructor(
    context: Context,
    context: Context,
    private val userMgr: UserManager,
    private val userMgr: UserManager,
    private val atmService: IActivityTaskManager,
    private val atmService: IActivityTaskManager,
    @Background val bgDispatcher: CoroutineDispatcher,
    @Background val bgDispatcher: CoroutineDispatcher,
) : ScreenshotPolicy {
) : ScreenshotPolicy {


    private val systemUiContent =
        DisplayContentInfo(
            ComponentName(context, SystemUIService::class.java),
            Rect(),
            ActivityTaskManager.INVALID_TASK_ID,
            Process.myUserHandle().identifier,
        )

    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
    private val proxyConnector: ServiceConnector<IScreenshotProxy> =
        ServiceConnector.Impl(
        ServiceConnector.Impl(
            context,
            context,
@@ -78,6 +72,9 @@ internal class ScreenshotPolicyImpl @Inject constructor(
    }
    }


    private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
    private fun nonPipVisibleTask(info: RootTaskInfo): Boolean {
        if (DEBUG) {
            debugLogRootTaskInfo(info)
        }
        return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
        return info.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED &&
            info.isVisible &&
            info.isVisible &&
            info.isRunning &&
            info.isRunning &&
@@ -99,27 +96,14 @@ internal class ScreenshotPolicyImpl @Inject constructor(
        }
        }


        val taskInfoList = getAllRootTaskInfosOnDisplay(displayId)
        val taskInfoList = getAllRootTaskInfosOnDisplay(displayId)
        if (DEBUG) {
            debugLogRootTaskInfos(taskInfoList)
        }


        // If no visible task is located, then report SystemUI as the foreground content
        // If no visible task is located, then report SystemUI as the foreground content
        val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent
        val target = taskInfoList.firstOrNull(::nonPipVisibleTask) ?: return systemUiContent

        return target.toDisplayContentInfo()
        val topActivity: ComponentName = target.topActivity ?: error("should not be null")
        val topChildTask = target.childTaskIds.size - 1
        val childTaskId = target.childTaskIds[topChildTask]
        val childTaskUserId = target.childTaskUserIds[topChildTask]
        val childTaskBounds = target.childTaskBounds[topChildTask]

        return DisplayContentInfo(topActivity, childTaskBounds, childTaskId, childTaskUserId)
    }
    }


    private fun debugLogRootTaskInfos(taskInfoList: List<RootTaskInfo>) {
    private fun debugLogRootTaskInfo(info: RootTaskInfo) {
        for (info in taskInfoList) {
        Log.d(TAG, "RootTaskInfo={" +
            Log.d(
                TAG,
                "[root task info] " +
                "taskId=${info.taskId} " +
                "taskId=${info.taskId} " +
                "parentTaskId=${info.parentTaskId} " +
                "parentTaskId=${info.parentTaskId} " +
                "position=${info.position} " +
                "position=${info.position} " +
@@ -137,7 +121,8 @@ internal class ScreenshotPolicyImpl @Inject constructor(
                "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
                "childTaskIds=${Arrays.toString(info.childTaskIds)} " +
                "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
                "childUserIds=${Arrays.toString(info.childTaskUserIds)} " +
                "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
                "childTaskBounds=${Arrays.toString(info.childTaskBounds)} " +
                    "childTaskNames=${Arrays.toString(info.childTaskNames)}"
                "childTaskNames=${Arrays.toString(info.childTaskNames)}" +
                "}"
        )
        )


        for (j in 0 until info.childTaskIds.size) {
        for (j in 0 until info.childTaskIds.size) {
@@ -148,9 +133,9 @@ internal class ScreenshotPolicyImpl @Inject constructor(
            Log.d(TAG, "        ***  childTaskNames[$j]: ${info.childTaskNames[j]}")
            Log.d(TAG, "        ***  childTaskNames[$j]: ${info.childTaskNames[j]}")
        }
        }
    }
    }
    }


    private suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
    @VisibleForTesting
    open suspend fun getAllRootTaskInfosOnDisplay(displayId: Int): List<RootTaskInfo> =
        withContext(bgDispatcher) {
        withContext(bgDispatcher) {
            try {
            try {
                atmService.getAllRootTaskInfosOnDisplay(displayId)
                atmService.getAllRootTaskInfosOnDisplay(displayId)
@@ -160,7 +145,8 @@ internal class ScreenshotPolicyImpl @Inject constructor(
            }
            }
        }
        }


    private suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
    @VisibleForTesting
    open suspend fun isNotificationShadeExpanded(): Boolean = suspendCoroutine { k ->
        proxyConnector
        proxyConnector
            .postForResult { it.isNotificationShadeExpanded }
            .postForResult { it.isNotificationShadeExpanded }
            .whenComplete { expanded, error ->
            .whenComplete { expanded, error ->
@@ -171,8 +157,30 @@ internal class ScreenshotPolicyImpl @Inject constructor(
            }
            }
    }
    }


    companion object {
    @VisibleForTesting
        const val TAG: String = "ScreenshotPolicyImpl"
    internal val systemUiContent =
        const val DEBUG: Boolean = false
        DisplayContentInfo(
            ComponentName(context, SystemUIService::class.java),
            Rect(),
            Process.myUserHandle(),
            ActivityTaskManager.INVALID_TASK_ID
        )
}
}

private const val TAG: String = "ScreenshotPolicyImpl"
private const val DEBUG: Boolean = false

@VisibleForTesting
internal fun RootTaskInfo.toDisplayContentInfo(): DisplayContentInfo {
    val topActivity: ComponentName = topActivity ?: error("should not be null")
    val topChildTask = childTaskIds.size - 1
    val childTaskId = childTaskIds[topChildTask]
    val childTaskUserId = childTaskUserIds[topChildTask]
    val childTaskBounds = childTaskBounds[topChildTask]

    return DisplayContentInfo(
        topActivity,
        childTaskBounds,
        UserHandle.of(childTaskUserId),
        childTaskId)
}
}
+5 −4
Original line number Original line Diff line number Diff line
@@ -23,6 +23,7 @@ import android.graphics.Insets
import android.graphics.Rect
import android.graphics.Rect
import android.hardware.HardwareBuffer
import android.hardware.HardwareBuffer
import android.os.Bundle
import android.os.Bundle
import android.os.UserHandle
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_KEY_CHORD
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
import android.view.WindowManager.ScreenshotSource.SCREENSHOT_OTHER
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
import android.view.WindowManager.TAKE_SCREENSHOT_FULLSCREEN
@@ -97,7 +98,7 @@ class RequestProcessorTest {
        policy.setManagedProfile(USER_ID, false)
        policy.setManagedProfile(USER_ID, false)
        policy.setDisplayContentInfo(
        policy.setDisplayContentInfo(
            policy.getDefaultDisplayId(),
            policy.getDefaultDisplayId(),
            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))


        val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
        val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
        val processor = RequestProcessor(imageCapture, policy, flags, scope)
        val processor = RequestProcessor(imageCapture, policy, flags, scope)
@@ -120,7 +121,7 @@ class RequestProcessorTest {
        // Indicate that the primary content belongs to a manged profile
        // Indicate that the primary content belongs to a manged profile
        policy.setManagedProfile(USER_ID, true)
        policy.setManagedProfile(USER_ID, true)
        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))


        val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
        val request = ScreenshotRequest(TAKE_SCREENSHOT_FULLSCREEN, SCREENSHOT_KEY_CHORD)
        val processor = RequestProcessor(imageCapture, policy, flags, scope)
        val processor = RequestProcessor(imageCapture, policy, flags, scope)
@@ -160,7 +161,7 @@ class RequestProcessorTest {


        policy.setManagedProfile(USER_ID, false)
        policy.setManagedProfile(USER_ID, false)
        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))


        val processedRequest = processor.process(request)
        val processedRequest = processor.process(request)


@@ -183,7 +184,7 @@ class RequestProcessorTest {
        // Indicate that the primary content belongs to a manged profile
        // Indicate that the primary content belongs to a manged profile
        policy.setManagedProfile(USER_ID, true)
        policy.setManagedProfile(USER_ID, true)
        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
        policy.setDisplayContentInfo(policy.getDefaultDisplayId(),
            DisplayContentInfo(component, bounds, USER_ID, TASK_ID))
            DisplayContentInfo(component, bounds, UserHandle.of(USER_ID), TASK_ID))


        val processedRequest = processor.process(request)
        val processedRequest = processor.process(request)


+227 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2022 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.screenshot

import android.app.ActivityTaskManager.RootTaskInfo
import android.app.IActivityTaskManager
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
import android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.app.WindowConfiguration.WINDOWING_MODE_PINNED
import android.content.ComponentName
import android.content.Context
import android.graphics.Rect
import android.os.UserHandle
import android.os.UserManager
import android.testing.AndroidTestingRunner
import com.android.systemui.SysuiTestCase
import com.android.systemui.screenshot.ScreenshotPolicy.DisplayContentInfo
import com.android.systemui.util.mockito.mock
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import org.junit.Test
import org.junit.runner.RunWith

// The following values are chosen to be distinct from commonly seen real values
private const val DISPLAY_ID = 100
private const val PRIMARY_USER = 2000
private const val MANAGED_PROFILE_USER = 3000

@RunWith(AndroidTestingRunner::class)
class ScreenshotPolicyImplTest : SysuiTestCase() {

    @Test
    fun testToDisplayContentInfo() {
        assertThat(fullScreenWorkProfileTask.toDisplayContentInfo())
            .isEqualTo(
                DisplayContentInfo(
                    ComponentName(
                        "com.google.android.apps.nbu.files",
                        "com.google.android.apps.nbu.files.home.HomeActivity"
                    ),
                    Rect(0, 0, 1080, 2400),
                    UserHandle.of(MANAGED_PROFILE_USER),
                    65))
    }

    @Test
    fun findPrimaryContent_ignoresPipTask() = runBlocking {
        val policy = fakeTasksPolicyImpl(
            mContext,
            shadeExpanded = false,
            tasks = listOf(
                    pipTask,
                    fullScreenWorkProfileTask,
                    launcherTask,
                    emptyTask)
        )

        val info = policy.findPrimaryContent(DISPLAY_ID)
        assertThat(info).isEqualTo(fullScreenWorkProfileTask.toDisplayContentInfo())
    }

    @Test
    fun findPrimaryContent_shadeExpanded_ignoresTopTask() = runBlocking {
        val policy = fakeTasksPolicyImpl(
            mContext,
            shadeExpanded = true,
            tasks = listOf(
                fullScreenWorkProfileTask,
                launcherTask,
                emptyTask)
        )

        val info = policy.findPrimaryContent(DISPLAY_ID)
        assertThat(info).isEqualTo(policy.systemUiContent)
    }

    @Test
    fun findPrimaryContent_emptyTaskList() = runBlocking {
        val policy = fakeTasksPolicyImpl(
            mContext,
            shadeExpanded = false,
            tasks = listOf()
        )

        val info = policy.findPrimaryContent(DISPLAY_ID)
        assertThat(info).isEqualTo(policy.systemUiContent)
    }

    @Test
    fun findPrimaryContent_workProfileNotOnTop() = runBlocking {
        val policy = fakeTasksPolicyImpl(
            mContext,
            shadeExpanded = false,
            tasks = listOf(
                launcherTask,
                fullScreenWorkProfileTask,
                emptyTask)
        )

        val info = policy.findPrimaryContent(DISPLAY_ID)
        assertThat(info).isEqualTo(launcherTask.toDisplayContentInfo())
    }

    private fun fakeTasksPolicyImpl(
        context: Context,
        shadeExpanded: Boolean,
        tasks: List<RootTaskInfo>
    ): ScreenshotPolicyImpl {
        val userManager = mock<UserManager>()
        val atmService = mock<IActivityTaskManager>()
        val dispatcher = Dispatchers.Unconfined

        return object : ScreenshotPolicyImpl(context, userManager, atmService, dispatcher) {
            override suspend fun isManagedProfile(userId: Int) = (userId == MANAGED_PROFILE_USER)
            override suspend fun getAllRootTaskInfosOnDisplay(displayId: Int) = tasks
            override suspend fun isNotificationShadeExpanded() = shadeExpanded
        }
    }

    private val pipTask = RootTaskInfo().apply {
        configuration.windowConfiguration.apply {
            windowingMode = WINDOWING_MODE_PINNED
            bounds = Rect(628, 1885, 1038, 2295)
            activityType = ACTIVITY_TYPE_STANDARD
        }
        displayId = DISPLAY_ID
        userId = PRIMARY_USER
        taskId = 66
        visible = true
        isVisible = true
        isRunning = true
        numActivities = 1
        topActivity = ComponentName(
            "com.google.android.youtube",
            "com.google.android.apps.youtube.app.watchwhile.WatchWhileActivity"
        )
        childTaskIds = intArrayOf(66)
        childTaskNames = arrayOf("com.google.android.youtube/" +
                "com.google.android.youtube.app.honeycomb.Shell\$HomeActivity")
        childTaskUserIds = intArrayOf(0)
        childTaskBounds = arrayOf(Rect(628, 1885, 1038, 2295))
    }

    private val fullScreenWorkProfileTask = RootTaskInfo().apply {
        configuration.windowConfiguration.apply {
            windowingMode = WINDOWING_MODE_FULLSCREEN
            bounds = Rect(0, 0, 1080, 2400)
            activityType = ACTIVITY_TYPE_STANDARD
        }
        displayId = DISPLAY_ID
        userId = MANAGED_PROFILE_USER
        taskId = 65
        visible = true
        isVisible = true
        isRunning = true
        numActivities = 1
        topActivity = ComponentName(
            "com.google.android.apps.nbu.files",
            "com.google.android.apps.nbu.files.home.HomeActivity"
        )
        childTaskIds = intArrayOf(65)
        childTaskNames = arrayOf("com.google.android.apps.nbu.files/" +
                "com.google.android.apps.nbu.files.home.HomeActivity")
        childTaskUserIds = intArrayOf(MANAGED_PROFILE_USER)
        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400))
    }

    private val launcherTask = RootTaskInfo().apply {
        configuration.windowConfiguration.apply {
            windowingMode = WINDOWING_MODE_FULLSCREEN
            bounds = Rect(0, 0, 1080, 2400)
            activityType = ACTIVITY_TYPE_HOME
        }
        displayId = DISPLAY_ID
        taskId = 1
        userId = PRIMARY_USER
        visible = true
        isVisible = true
        isRunning = true
        numActivities = 1
        topActivity = ComponentName(
            "com.google.android.apps.nexuslauncher",
            "com.google.android.apps.nexuslauncher.NexusLauncherActivity",
        )
        childTaskIds = intArrayOf(1)
        childTaskNames = arrayOf("com.google.android.apps.nexuslauncher/" +
                "com.google.android.apps.nexuslauncher.NexusLauncherActivity")
        childTaskUserIds = intArrayOf(0)
        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400))
    }

    private val emptyTask = RootTaskInfo().apply {
        configuration.windowConfiguration.apply {
            windowingMode = WINDOWING_MODE_FULLSCREEN
            bounds = Rect(0, 0, 1080, 2400)
            activityType = ACTIVITY_TYPE_UNDEFINED
        }
        displayId = DISPLAY_ID
        taskId = 2
        userId = PRIMARY_USER
        visible = false
        isVisible = false
        isRunning = false
        numActivities = 0
        childTaskIds = intArrayOf(3, 4)
        childTaskNames = arrayOf("", "")
        childTaskUserIds = intArrayOf(0, 0)
        childTaskBounds = arrayOf(Rect(0, 0, 1080, 2400), Rect(0, 2400, 1080, 4800))
    }
}