1 /* <lambda>null2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.app.viewcapture 18 19 import android.content.Intent 20 import android.media.permission.SafeCloseable 21 import android.testing.AndroidTestingRunner 22 import android.view.Choreographer 23 import android.view.View 24 import android.widget.LinearLayout 25 import android.widget.TextView 26 import androidx.test.ext.junit.rules.ActivityScenarioRule 27 import androidx.test.filters.SmallTest 28 import androidx.test.platform.app.InstrumentationRegistry 29 import com.android.app.viewcapture.TestActivity.Companion.TEXT_VIEW_COUNT 30 import com.android.app.viewcapture.data.ExportedData 31 import junit.framework.Assert.assertEquals 32 import org.junit.Rule 33 import org.junit.Test 34 import org.junit.runner.RunWith 35 36 @SmallTest 37 @RunWith(AndroidTestingRunner::class) 38 class ViewCaptureTest { 39 40 private val memorySize = 100 41 private val initPoolSize = 15 42 private val viewCapture by lazy { 43 object : 44 ViewCapture(memorySize, initPoolSize, Choreographer.getInstance(), MAIN_EXECUTOR) {} 45 } 46 47 private val activityIntent = 48 Intent(InstrumentationRegistry.getInstrumentation().context, TestActivity::class.java) 49 50 @get:Rule val activityScenarioRule = ActivityScenarioRule<TestActivity>(activityIntent) 51 52 @Test 53 fun testViewCaptureDumpsOneFrameAfterInvalidate() { 54 activityScenarioRule.scenario.onActivity { activity -> 55 Choreographer.getInstance().postFrameCallback { 56 val closeable = startViewCaptureAndInvalidateNTimes(1, activity) 57 val rootView = activity.findViewById<View>(android.R.id.content) 58 val exportedData = viewCapture.getDumpTask(rootView).get().get() 59 60 assertEquals(1, exportedData.frameDataList.size) 61 verifyTestActivityViewHierarchy(exportedData) 62 closeable.close() 63 } 64 } 65 } 66 67 @Test 68 fun testViewCaptureDumpsCorrectlyAfterRecyclingStarted() { 69 activityScenarioRule.scenario.onActivity { activity -> 70 Choreographer.getInstance().postFrameCallback { 71 val closeable = startViewCaptureAndInvalidateNTimes(memorySize + 5, activity) 72 val rootView = activity.findViewById<View>(android.R.id.content) 73 val exportedData = viewCapture.getDumpTask(rootView).get().get() 74 75 // since ViewCapture MEMORY_SIZE is [viewCaptureMemorySize], only 76 // [viewCaptureMemorySize] frames are exported, although the view is invalidated 77 // [viewCaptureMemorySize + 5] times 78 assertEquals(memorySize, exportedData.frameDataList.size) 79 verifyTestActivityViewHierarchy(exportedData) 80 closeable.close() 81 } 82 } 83 } 84 85 private fun startViewCaptureAndInvalidateNTimes(n: Int, activity: TestActivity): SafeCloseable { 86 val rootView: View = activity.findViewById(android.R.id.content) 87 val closeable: SafeCloseable = viewCapture.startCapture(rootView, "rootViewId") 88 dispatchOnDraw(rootView, times = n) 89 return closeable 90 } 91 92 private fun dispatchOnDraw(view: View, times: Int) { 93 if (times > 0) { 94 view.viewTreeObserver.dispatchOnDraw() 95 dispatchOnDraw(view, times - 1) 96 } 97 } 98 99 private fun verifyTestActivityViewHierarchy(exportedData: ExportedData) { 100 for (frame in exportedData.frameDataList) { 101 val testActivityRoot = 102 frame.node // FrameLayout (android.R.id.content) 103 .childrenList 104 .first() // LinearLayout (set by setContentView()) 105 assertEquals(TEXT_VIEW_COUNT, testActivityRoot.childrenList.size) 106 assertEquals( 107 LinearLayout::class.qualifiedName, 108 exportedData.getClassname(testActivityRoot.classnameIndex) 109 ) 110 assertEquals( 111 TextView::class.qualifiedName, 112 exportedData.getClassname(testActivityRoot.childrenList.first().classnameIndex) 113 ) 114 } 115 } 116 } 117