1 /*
2  * Copyright 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.core.features
18 
19 import com.android.photopicker.core.configuration.PhotopickerConfiguration
20 import com.android.photopicker.core.events.Event
21 import com.android.photopicker.core.events.RegisteredEventClass
22 
23 /**
24  * The base feature interface, that exposes hooks from the [FeatureManager] that is available to all
25  * features. It's unlikely that features will want to implement this directly, but rather implement
26  * a different interface, such as [PhotopickerUiFeature] which inherits from the base interface.
27  */
28 interface PhotopickerFeature {
29 
30     /**
31      * Features must claim a [FeatureToken]. This is used to identify calls the feature makes such
32      * as dispatching events (to ensure the feature has registered for these events). This must be
33      * unique for any given runtime configuration of enabled features. Multiple features may claim
34      * the same token, but they can never be enabled in the same configuration, or an
35      * [IllegalStateException] will be thrown during initialization.
36      */
37     val token: String
38 
39     /**
40      * Establishes the contract of Events that this feature requires from outside dependencies. Any
41      * [Event] that is listened to inside any codepath this feature encapsulates should be
42      * registered in this set.
43      *
44      * In the event the feature has indicated it should be enabled (in its Registration check) and
45      * it's set of consumed events is not fulfilled by the global events produced this will cause a
46      * RuntimeException if [PhotopickerConfiguration.isDeviceDebuggable] is true.
47      *
48      * For non debuggable devices, the error is not thrown to avoid crashes if possible, but this
49      * should be considered a state which should be avoided at all costs.
50      */
51     val eventsConsumed: Set<RegisteredEventClass>
52 
53     /**
54      * Establishes the contract of Events that this Feature produces.
55      *
56      * Any [Event] that is dispatched inside any codepath this feature encapsulates should be
57      * registered in the returned set.
58      *
59      * The events produced here is used to compute the list of globally produced events to check if
60      * all required events in a runtime configuration are produceable. Note: This does not mean that
61      * events WILL be produced, as that may be user-interaction dependant, but this helps to catch
62      * implicit or undeclared dependencies between features that rely on the Event bus.
63      *
64      * If an event is dispatched in a feature which is not present in its eventsProduced registry,
65      * this will trigger a RuntimeException when [PhotopickerConfiguration.isDeviceDebuggable] is
66      * true, and a warning will be logged otherwise.
67      */
68     val eventsProduced: Set<RegisteredEventClass>
69 
70     /**
71      * Notification hook that the [FeatureManager] is about to emit a new configuration, and
72      * reinitialize the active Feature set.
73      *
74      * It is highly likely that shortly after this call completes the current instance of this class
75      * will be de-referenced and (potentially) be re-created if the Registration check still
76      * indicates it should be enabled with the new configuration.
77      *
78      * The UI tree will be re-composed shortly after, and persistent state should be saved in
79      * associated view models to avoid state loss.
80      */
onConfigurationChangednull81     fun onConfigurationChanged(config: PhotopickerConfiguration) {}
82 }
83