1 /* 2 * Copyright (C) 2023 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.systemui.qs.tiles.impl.custom.data.repository 18 19 import android.content.ComponentName 20 import android.content.pm.PackageInfo 21 import android.content.pm.PackageManager 22 import android.content.pm.ServiceInfo 23 import android.os.Bundle 24 import android.os.UserHandle 25 import com.android.systemui.qs.external.PackageManagerAdapter 26 import com.android.systemui.util.mockito.any 27 import com.android.systemui.util.mockito.eq 28 import com.android.systemui.util.mockito.mock 29 import com.android.systemui.util.mockito.whenever 30 import org.hamcrest.BaseMatcher 31 import org.hamcrest.Description 32 import org.mockito.ArgumentMatchers.anyInt 33 import org.mockito.hamcrest.MockitoHamcrest.intThat 34 35 /** 36 * Facade for [PackageManagerAdapter] to provide a fake-like behaviour. You can create this class 37 * and then get [packageManagerAdapter] to use in your test code. 38 * 39 * This allows to mock [PackageManagerAdapter] to provide a custom behaviour for 40 * [CustomTileRepository.isTileActive], [CustomTileRepository.isTileToggleable], 41 * [com.android.systemui.qs.external.TileServiceManager.isToggleableTile] or 42 * [com.android.systemui.qs.external.TileServiceManager.isActiveTile] when the real objects are 43 * used. 44 * 45 * The user this is set up must be a real user (`user >= 0`) or [UserHandle.USER_ALL]. 46 */ 47 class FakePackageManagerAdapterFacade( 48 val componentName: ComponentName, <lambda>null49 val packageManagerAdapter: PackageManagerAdapter = mock {}, 50 user: Int = UserHandle.USER_ALL, 51 ) { 52 53 private var isToggleable: Boolean = false 54 private var isActive: Boolean = false 55 56 init { 57 if (user == UserHandle.USER_ALL) { 58 setForAllUsers() 59 } else if (user >= 0) { 60 setExclusiveForUser(user) 61 } else { 62 throw IllegalArgumentException("User must be a real user or UserHandle.USER_ALL") 63 } 64 } 65 createServiceInfonull66 private fun createServiceInfo(): ServiceInfo { 67 return ServiceInfo().apply { 68 metaData = 69 Bundle().apply { 70 putBoolean( 71 android.service.quicksettings.TileService.META_DATA_TOGGLEABLE_TILE, 72 isToggleable 73 ) 74 putBoolean( 75 android.service.quicksettings.TileService.META_DATA_ACTIVE_TILE, 76 isActive 77 ) 78 } 79 } 80 } 81 setIsActivenull82 fun setIsActive(isActive: Boolean) { 83 this.isActive = isActive 84 } 85 setIsToggleablenull86 fun setIsToggleable(isToggleable: Boolean) { 87 this.isToggleable = isToggleable 88 } 89 setExclusiveForUsernull90 fun setExclusiveForUser(newUser: Int) { 91 check(newUser >= 0) 92 val notEqualMatcher = NotEqualMatcher(newUser) 93 if (newUser == 0) { 94 whenever(packageManagerAdapter.getServiceInfo(eq(componentName), any())).thenAnswer { 95 createServiceInfo() 96 } 97 } 98 whenever( 99 packageManagerAdapter.getPackageInfoAsUser( 100 eq(componentName.packageName), 101 anyInt(), 102 eq(newUser) 103 ) 104 ) 105 .thenAnswer { PackageInfo().apply { packageName = componentName.packageName } } 106 whenever( 107 packageManagerAdapter.getPackageInfoAsUser( 108 eq(componentName.packageName), 109 anyInt(), 110 intThat(notEqualMatcher), 111 ) 112 ) 113 .thenThrow(PackageManager.NameNotFoundException()) 114 115 whenever( 116 packageManagerAdapter.getServiceInfo( 117 eq(componentName), 118 anyInt(), 119 intThat(notEqualMatcher) 120 ) 121 ) 122 .thenAnswer { null } 123 whenever(packageManagerAdapter.getServiceInfo(eq(componentName), anyInt(), eq(newUser))) 124 .thenAnswer { createServiceInfo() } 125 } 126 setForAllUsersnull127 fun setForAllUsers() { 128 whenever(packageManagerAdapter.getServiceInfo(eq(componentName), any())).thenAnswer { 129 createServiceInfo() 130 } 131 whenever( 132 packageManagerAdapter.getPackageInfoAsUser( 133 eq(componentName.packageName), 134 anyInt(), 135 anyInt() 136 ) 137 ) 138 .thenAnswer { PackageInfo().apply { packageName = componentName.packageName } } 139 whenever(packageManagerAdapter.getServiceInfo(eq(componentName), anyInt(), anyInt())) 140 .thenAnswer { createServiceInfo() } 141 } 142 } 143 144 private class NotEqualMatcher(private val notEqualValue: Int) : BaseMatcher<Int>() { describeTonull145 override fun describeTo(description: Description?) { 146 description?.appendText("!= $notEqualValue") 147 } 148 matchesnull149 override fun matches(item: Any?): Boolean { 150 return (item as? Int)?.equals(notEqualValue)?.not() ?: true 151 } 152 } 153