1 /*
2  * Copyright (C) 2016 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 package com.android.documentsui;
17 
18 import static java.lang.annotation.ElementType.FIELD;
19 import static java.lang.annotation.RetentionPolicy.SOURCE;
20 
21 import android.view.MenuItem;
22 
23 import androidx.annotation.Nullable;
24 import androidx.annotation.VisibleForTesting;
25 import androidx.recyclerview.selection.SelectionTracker;
26 import androidx.recyclerview.widget.RecyclerView;
27 
28 import com.android.documentsui.MenuManager.SelectionDetails;
29 import com.android.documentsui.base.DebugHelper;
30 import com.android.documentsui.base.EventHandler;
31 import com.android.documentsui.base.Features;
32 import com.android.documentsui.base.Lookup;
33 import com.android.documentsui.base.RootInfo;
34 import com.android.documentsui.dirlist.AppsRowManager;
35 import com.android.documentsui.picker.PickResult;
36 import com.android.documentsui.queries.SearchViewManager;
37 import com.android.documentsui.ui.DialogController;
38 import com.android.documentsui.ui.MessageBuilder;
39 
40 import java.lang.annotation.Retention;
41 import java.lang.annotation.Target;
42 import java.util.Collection;
43 import java.util.function.Consumer;
44 
45 /**
46  * Provides access to runtime dependencies.
47  */
48 public class Injector<T extends ActionHandler> {
49 
50     public final Features features;
51     public final ActivityConfig config;
52     public final MessageBuilder messages;
53     public final Lookup<String, String> fileTypeLookup;
54     public final Consumer<Collection<RootInfo>> shortcutsUpdater;
55 
56     public MenuManager menuManager;
57     public DialogController dialogs;
58     public SearchViewManager searchManager;
59     public AppsRowManager appsRowManager;
60 
61     public PickResult pickResult;
62 
63     public final DebugHelper debugHelper;
64 
65     @ContentScoped
66     public ActionModeController actionModeController;
67 
68     @ContentScoped
69     public ProfileTabsController profileTabsController;
70 
71     @ContentScoped
72     public T actions;
73 
74     @ContentScoped
75     public FocusManager focusManager;
76 
77     @ContentScoped
78     public DocsSelectionHelper selectionMgr;
79 
80     private final Model mModel;
81 
82     // must be initialized before calling super.onCreate because prefs
83     // are used in State initialization.
Injector( Features features, ActivityConfig config, MessageBuilder messages, DialogController dialogs, Lookup<String, String> fileTypeLookup, Consumer<Collection<RootInfo>> shortcutsUpdater)84     public Injector(
85             Features features,
86             ActivityConfig config,
87             MessageBuilder messages,
88             DialogController dialogs,
89             Lookup<String, String> fileTypeLookup,
90             Consumer<Collection<RootInfo>> shortcutsUpdater) {
91         this(features, config, messages, dialogs, fileTypeLookup,
92                 shortcutsUpdater, new Model(features));
93     }
94 
95     @VisibleForTesting
Injector( Features features, ActivityConfig config, MessageBuilder messages, DialogController dialogs, Lookup<String, String> fileTypeLookup, Consumer<Collection<RootInfo>> shortcutsUpdater, Model model)96     public Injector(
97             Features features,
98             ActivityConfig config,
99             MessageBuilder messages,
100             DialogController dialogs,
101             Lookup<String, String> fileTypeLookup,
102             Consumer<Collection<RootInfo>> shortcutsUpdater,
103             Model model) {
104 
105         this.features = features;
106         this.config = config;
107         this.messages = messages;
108         this.dialogs = dialogs;
109         this.fileTypeLookup = fileTypeLookup;
110         this.shortcutsUpdater = shortcutsUpdater;
111         this.mModel = model;
112         this.debugHelper = new DebugHelper(this);
113     }
114 
getModel()115     public Model getModel() {
116         return mModel;
117     }
118 
getFocusManager(RecyclerView view, Model model)119     public FocusManager getFocusManager(RecyclerView view, Model model) {
120         assert (focusManager != null);
121         return focusManager.reset(view, model);
122     }
123 
updateSharedSelectionTracker(SelectionTracker<String> selectionTracker)124     public void updateSharedSelectionTracker(SelectionTracker<String> selectionTracker) {
125         selectionMgr.reset(selectionTracker);
126     }
127 
getActionModeController( SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker)128     public final ActionModeController getActionModeController(
129             SelectionDetails selectionDetails, EventHandler<MenuItem> menuItemClicker) {
130         return actionModeController.reset(selectionDetails, menuItemClicker);
131     }
132 
133     /**
134      * Obtains action handler and resets it if necessary.
135      *
136      * @param contentLock the lock held by
137      *            {@link com.android.documentsui.selection.BandSelectionHelper} and
138      *            {@link com.android.documentsui.selection.GestureSelectionHelper} to prevent
139      *            loader from updating result during band/gesture selection. May be {@code null} if
140      *            called from {@link com.android.documentsui.sidebar.RootsFragment}.
141      * @return the action handler
142      */
getActionHandler(@ullable ContentLock contentLock)143     public T getActionHandler(@Nullable ContentLock contentLock) {
144 
145         // provide our friend, RootsFragment, early access to this special feature!
146         if (contentLock == null) {
147             return actions;
148         }
149 
150         return actions.reset(contentLock);
151     }
152 
153     /**
154      * Decorates a field that that is injected.
155      */
156     @Retention(SOURCE)
157     @Target(FIELD)
158     public @interface Injected {
159 
160     }
161 
162     /**
163      * Decorates a field that holds an object that must be reset in the current content scope
164      * (i.e. DirectoryFragment). Fields decorated with this must have an associated
165      * accessor on Injector that, when call, reset the object for the calling context.
166      */
167     @Retention(SOURCE)
168     @Target(FIELD)
169     public @interface ContentScoped {
170 
171     }
172 }
173