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 androidx.window.area
18 
19 import android.os.Binder
20 import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_PRESENT_ON_AREA
21 import androidx.window.area.WindowAreaCapability.Operation.Companion.OPERATION_TRANSFER_ACTIVITY_TO_AREA
22 import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_ACTIVE
23 import androidx.window.area.WindowAreaCapability.Status.Companion.WINDOW_AREA_STATUS_UNSUPPORTED
24 import androidx.window.core.ExperimentalWindowApi
25 import androidx.window.core.ExtensionsUtil
26 import androidx.window.extensions.area.WindowAreaComponent
27 import androidx.window.layout.WindowMetrics
28 
29 /**
30  * The current state of a window area. The [WindowAreaInfo] can represent a part of or an entire
31  * display in the system. These values can be used to modify the UI to show/hide controls and
32  * determine when features can be enabled.
33  */
34 @ExperimentalWindowApi
35 class WindowAreaInfo
36 internal constructor(
37 
38     /**
39      * The [WindowMetrics] that represent the size of the area. Used to determine if the behavior
40      * desired fits the size of the window area available.
41      */
42     var metrics: WindowMetrics,
43 
44     /** The [Type] of this window area */
45     val type: Type,
46 
47     /** [Binder] token to identify the specific WindowArea */
48     val token: Binder,
49     private val windowAreaComponent: WindowAreaComponent
50 ) {
51 
52     internal val capabilityMap = HashMap<WindowAreaCapability.Operation, WindowAreaCapability>()
53 
54     /**
55      * Returns the [WindowAreaCapability] corresponding to the [operation] provided. If this
56      * [WindowAreaCapability] does not exist for this [WindowAreaInfo], a [WindowAreaCapability]
57      * with a [WINDOW_AREA_STATUS_UNSUPPORTED] value is returned.
58      */
getCapabilitynull59     fun getCapability(operation: WindowAreaCapability.Operation): WindowAreaCapability {
60         return capabilityMap[operation]
61             ?: WindowAreaCapability(operation, WINDOW_AREA_STATUS_UNSUPPORTED)
62     }
63 
64     /**
65      * Returns the current active [WindowAreaSession] is one is currently active for the provided
66      * [operation]
67      *
68      * @throws IllegalStateException if there is no active session for the provided [operation]
69      */
getActiveSessionnull70     fun getActiveSession(operation: WindowAreaCapability.Operation): WindowAreaSession? {
71         if (getCapability(operation).status != WINDOW_AREA_STATUS_ACTIVE) {
72             throw IllegalStateException("No session is currently active")
73         }
74 
75         if (type == Type.TYPE_REAR_FACING) {
76             // TODO(b/273807246) We should cache instead of always creating a new session
77             return createRearFacingSession(operation)
78         }
79         return null
80     }
81 
createRearFacingSessionnull82     private fun createRearFacingSession(
83         operation: WindowAreaCapability.Operation
84     ): WindowAreaSession {
85         return when (operation) {
86             OPERATION_TRANSFER_ACTIVITY_TO_AREA -> RearDisplaySessionImpl(windowAreaComponent)
87             OPERATION_PRESENT_ON_AREA ->
88                 RearDisplayPresentationSessionPresenterImpl(
89                     windowAreaComponent,
90                     windowAreaComponent.rearDisplayPresentation!!,
91                     ExtensionsUtil.safeVendorApiLevel
92                 )
93             else -> {
94                 throw IllegalArgumentException("Invalid operation provided")
95             }
96         }
97     }
98 
99     /** Represents a type of [WindowAreaInfo] */
100     @ExperimentalWindowApi
101     class Type private constructor(private val description: String) {
toStringnull102         override fun toString(): String {
103             return description
104         }
105 
106         companion object {
107             /**
108              * Type of window area that is facing the same direction as the rear camera(s) on the
109              * device.
110              */
111             @JvmField val TYPE_REAR_FACING = Type("REAR FACING")
112         }
113     }
114 
equalsnull115     override fun equals(other: Any?): Boolean {
116         return other is WindowAreaInfo &&
117             metrics == other.metrics &&
118             type == other.type &&
119             capabilityMap.entries == other.capabilityMap.entries
120     }
121 
hashCodenull122     override fun hashCode(): Int {
123         var result = metrics.hashCode()
124         result = 31 * result + type.hashCode()
125         result = 31 * result + capabilityMap.entries.hashCode()
126         return result
127     }
128 
toStringnull129     override fun toString(): String {
130         return "WindowAreaInfo{ Metrics: $metrics, type: $type, " +
131             "Capabilities: ${capabilityMap.entries} }"
132     }
133 }
134