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