1 /* <lambda>null2 * Copyright (C) 2024 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.photopicker.data 18 19 import android.content.ContentResolver 20 import android.content.UriMatcher 21 import android.database.ContentObserver 22 import android.net.Uri 23 24 /** 25 * Test implementation of Notification Service. It registers the observers in memory. Test writers 26 * can use [dispatchChangeToObservers] method to notify the registered content observers. 27 */ 28 class TestNotificationServiceImpl : NotificationService { 29 companion object { 30 private const val MATCH = 0 31 } 32 33 private val registeredObservers: MutableMap<Uri, UriObservers> = mutableMapOf() 34 35 override fun registerContentObserverCallback( 36 contentResolver: ContentResolver, 37 uri: Uri, 38 notifyDescendants: Boolean, 39 observer: ContentObserver 40 ) { 41 val uriObservers: UriObservers = registeredObservers[uri] ?: UriObservers() 42 uriObservers.add(observer, notifyDescendants) 43 registeredObservers.put(uri, uriObservers) 44 } 45 46 override fun unregisterContentObserverCallback( 47 contentResolver: ContentResolver, 48 observer: ContentObserver 49 ) { 50 registeredObservers.values.forEach { 51 it.remove(observer) 52 } 53 } 54 55 /** 56 * This method can be used to simulate notifying [ContentObserver]-s registered against a 57 * given Uri. 58 */ 59 fun dispatchChangeToObservers(uri: Uri) { 60 val uriBuilder = Uri.parse("content://" + uri.authority).buildUpon() 61 uri.pathSegments.forEach { 62 uriBuilder.appendPath(it) 63 val newUri = uriBuilder.build() 64 val allowExactMatch = newUri.equals(uri) 65 registeredObservers[newUri] 66 ?.getMatchedObservers(newUri, allowExactMatch) 67 ?.forEach { contentObserver: ContentObserver -> 68 contentObserver.dispatchChange( 69 /* selfChange */ true, 70 uri, 71 /* flags */ 0 72 ) 73 } 74 } 75 } 76 77 /** 78 * Represents the Content Observers registered against a Uri. A registered content observer can 79 * choose to be notified for descendant Uris. 80 */ 81 class UriObservers { 82 private val exactMatchObservers: MutableList<ContentObserver> = mutableListOf() 83 private val descendantMatchObservers: MutableList<ContentObserver> = mutableListOf() 84 85 fun add(observer: ContentObserver, notifyDescendants: Boolean) { 86 if (notifyDescendants) { 87 descendantMatchObservers.add(observer) 88 } else { 89 exactMatchObservers.add(observer) 90 } 91 } 92 93 fun remove(observer: ContentObserver): Boolean { 94 return exactMatchObservers.remove(observer) || 95 descendantMatchObservers.remove(observer) 96 } 97 98 fun getMatchedObservers(uri: Uri, allowExactMatch: Boolean): 99 Set<ContentObserver> { 100 val uriMatcher = UriMatcher(UriMatcher.NO_MATCH) 101 uriMatcher.addURI(uri.authority, uri.path, MATCH) 102 103 val observers: MutableSet<ContentObserver> = mutableSetOf() 104 if (uriMatcher.match(uri) == MATCH) { 105 if (allowExactMatch) { 106 observers.addAll(exactMatchObservers) 107 observers.addAll(descendantMatchObservers) 108 } else { 109 observers.addAll(descendantMatchObservers) 110 } 111 } 112 return observers 113 } 114 } 115 }