1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.fragments;
16 
17 import android.app.Fragment;
18 import android.content.res.Configuration;
19 import android.os.Handler;
20 import android.util.ArrayMap;
21 import android.util.Log;
22 import android.view.View;
23 
24 import com.android.systemui.Dumpable;
25 import com.android.systemui.dagger.SysUISingleton;
26 import com.android.systemui.dump.DumpManager;
27 import com.android.systemui.statusbar.policy.ConfigurationController;
28 
29 import java.io.PrintWriter;
30 
31 import javax.inject.Inject;
32 import javax.inject.Provider;
33 
34 /**
35  * Holds a map of root views to FragmentHostStates and generates them as needed.
36  * Also dispatches the configuration changes to all current FragmentHostStates.
37  */
38 @SysUISingleton
39 public class FragmentService implements Dumpable {
40 
41     private static final String TAG = "FragmentService";
42 
43     private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>();
44     /**
45      * A map with the means to create fragments via Dagger injection.
46      *
47      * key: the fragment class name.
48      * value: A {@link Provider} for the Fragment
49      */
50     private final ArrayMap<String, Provider<? extends Fragment>> mInjectionMap = new ArrayMap<>();
51     private final Handler mHandler = new Handler();
52     private final FragmentHostManager.Factory mFragmentHostManagerFactory;
53 
54     private ConfigurationController.ConfigurationListener mConfigurationListener =
55             new ConfigurationController.ConfigurationListener() {
56                 @Override
57                 public void onConfigChanged(Configuration newConfig) {
58                     for (FragmentHostState state : mHosts.values()) {
59                         state.sendConfigurationChange(newConfig);
60                     }
61                 }
62             };
63 
64     @Inject
FragmentService( FragmentHostManager.Factory fragmentHostManagerFactory, ConfigurationController configurationController, DumpManager dumpManager)65     public FragmentService(
66             FragmentHostManager.Factory fragmentHostManagerFactory,
67             ConfigurationController configurationController,
68             DumpManager dumpManager) {
69         mFragmentHostManagerFactory = fragmentHostManagerFactory;
70         configurationController.addCallback(mConfigurationListener);
71 
72         dumpManager.registerNormalDumpable(this);
73     }
74 
getInjectionMap()75     ArrayMap<String, Provider<? extends Fragment>> getInjectionMap() {
76         return mInjectionMap;
77     }
78 
79     /**
80      * Adds a new Dagger component object that provides method(s) to create fragments via injection.
81      */
addFragmentInstantiationProvider( Class<?> fragmentCls, Provider<? extends Fragment> provider)82     public void addFragmentInstantiationProvider(
83             Class<?> fragmentCls, Provider<? extends Fragment> provider) {
84         String fragmentName = fragmentCls.getName();
85         if (mInjectionMap.containsKey(fragmentName)) {
86             Log.w(TAG, "Fragment " + fragmentName + " is already provided by different"
87                     + " Dagger component; Not adding method");
88             return;
89         }
90         mInjectionMap.put(fragmentName, provider);
91     }
92 
getFragmentHostManager(View view)93     public FragmentHostManager getFragmentHostManager(View view) {
94         View root = view.getRootView();
95         FragmentHostState state = mHosts.get(root);
96         if (state == null) {
97             state = new FragmentHostState(root);
98             mHosts.put(root, state);
99         }
100         return state.getFragmentHostManager();
101     }
102 
removeAndDestroy(View view)103     public void removeAndDestroy(View view) {
104         final FragmentHostState state = mHosts.remove(view.getRootView());
105         if (state != null) {
106             state.mFragmentHostManager.destroy();
107         }
108     }
109 
destroyAll()110     public void destroyAll() {
111         for (FragmentHostState state : mHosts.values()) {
112             state.mFragmentHostManager.destroy();
113         }
114     }
115 
116     @Override
dump(PrintWriter pw, String[] args)117     public void dump(PrintWriter pw, String[] args) {
118         pw.println("Dumping fragments:");
119         for (FragmentHostState state : mHosts.values()) {
120             state.mFragmentHostManager.getFragmentManager().dump("  ", null, pw, args);
121         }
122     }
123 
124     private class FragmentHostState {
125         private final View mView;
126 
127         private FragmentHostManager mFragmentHostManager;
128 
FragmentHostState(View view)129         public FragmentHostState(View view) {
130             mView = view;
131             mFragmentHostManager = mFragmentHostManagerFactory.create(mView);
132         }
133 
sendConfigurationChange(Configuration newConfig)134         public void sendConfigurationChange(Configuration newConfig) {
135             mHandler.post(() -> handleSendConfigurationChange(newConfig));
136         }
137 
getFragmentHostManager()138         public FragmentHostManager getFragmentHostManager() {
139             return mFragmentHostManager;
140         }
141 
handleSendConfigurationChange(Configuration newConfig)142         private void handleSendConfigurationChange(Configuration newConfig) {
143             mFragmentHostManager.onConfigurationChanged(newConfig);
144         }
145     }
146 }
147