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