1 /* 2 * Copyright 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.compose.animation.scene 18 19 import androidx.annotation.VisibleForTesting 20 import androidx.compose.runtime.Stable 21 22 /** 23 * A base class to create unique keys, associated to an [identity] that is used to check the 24 * equality of two key instances. 25 */ 26 @Stable 27 sealed class Key(val debugName: String, val identity: Any) { equalsnull28 override fun equals(other: Any?): Boolean { 29 if (this === other) return true 30 if (this.javaClass != other?.javaClass) return false 31 return identity == (other as? Key)?.identity 32 } 33 hashCodenull34 override fun hashCode(): Int { 35 return identity.hashCode() 36 } 37 toStringnull38 override fun toString(): String { 39 return "Key(debugName=$debugName)" 40 } 41 } 42 43 /** Key for a scene. */ 44 class SceneKey( 45 debugName: String, 46 identity: Any = Object(), 47 ) : Key(debugName, identity) { 48 @VisibleForTesting 49 // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can 50 // access internal members. 51 val testTag: String = "scene:$debugName" 52 53 /** The unique [ElementKey] identifying this scene's root element. */ 54 val rootElementKey = ElementKey(debugName, identity) 55 toStringnull56 override fun toString(): String { 57 return "SceneKey(debugName=$debugName)" 58 } 59 } 60 61 /** Key for an element. */ 62 class ElementKey( 63 debugName: String, 64 identity: Any = Object(), 65 66 /** 67 * The [ElementScenePicker] to use when deciding in which scene we should draw shared Elements 68 * or compose MovableElements. 69 */ 70 val scenePicker: ElementScenePicker = DefaultElementScenePicker, 71 ) : Key(debugName, identity), ElementMatcher { 72 @VisibleForTesting 73 // TODO(b/240432457): Make internal once PlatformComposeSceneTransitionLayoutTestsUtils can 74 // access internal members. 75 val testTag: String = "element:$debugName" 76 matchesnull77 override fun matches(key: ElementKey, scene: SceneKey): Boolean { 78 return key == this 79 } 80 toStringnull81 override fun toString(): String { 82 return "ElementKey(debugName=$debugName)" 83 } 84 85 companion object { 86 /** Matches any element whose [key identity][ElementKey.identity] matches [predicate]. */ withIdentitynull87 fun withIdentity(predicate: (Any) -> Boolean): ElementMatcher { 88 return object : ElementMatcher { 89 override fun matches(key: ElementKey, scene: SceneKey): Boolean { 90 return predicate(key.identity) 91 } 92 } 93 } 94 } 95 } 96 97 /** Key for a shared value of an element. */ 98 class ValueKey(debugName: String, identity: Any = Object()) : Key(debugName, identity) { toStringnull99 override fun toString(): String { 100 return "ValueKey(debugName=$debugName)" 101 } 102 } 103 104 /** 105 * Key for a transition. This can be used to specify which transition spec should be used when 106 * starting the transition between two scenes. 107 */ 108 class TransitionKey(debugName: String, identity: Any = Object()) : Key(debugName, identity) { toStringnull109 override fun toString(): String { 110 return "TransitionKey(debugName=$debugName)" 111 } 112 } 113