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.view.View; 22 23 import com.android.systemui.Dumpable; 24 import com.android.systemui.SystemUIRootComponent; 25 import com.android.systemui.qs.QSFragment; 26 import com.android.systemui.statusbar.phone.NavigationBarFragment; 27 import com.android.systemui.statusbar.policy.ConfigurationController; 28 29 import java.io.FileDescriptor; 30 import java.io.PrintWriter; 31 import java.lang.reflect.Method; 32 import java.lang.reflect.Modifier; 33 34 import javax.inject.Inject; 35 import javax.inject.Singleton; 36 37 import dagger.Subcomponent; 38 39 /** 40 * Holds a map of root views to FragmentHostStates and generates them as needed. 41 * Also dispatches the configuration changes to all current FragmentHostStates. 42 */ 43 @Singleton 44 public class FragmentService implements Dumpable { 45 46 private static final String TAG = "FragmentService"; 47 48 private final ArrayMap<View, FragmentHostState> mHosts = new ArrayMap<>(); 49 private final ArrayMap<String, Method> mInjectionMap = new ArrayMap<>(); 50 private final Handler mHandler = new Handler(); 51 private final FragmentCreator mFragmentCreator; 52 53 private ConfigurationController.ConfigurationListener mConfigurationListener = 54 new ConfigurationController.ConfigurationListener() { 55 @Override 56 public void onConfigChanged(Configuration newConfig) { 57 for (FragmentHostState state : mHosts.values()) { 58 state.sendConfigurationChange(newConfig); 59 } 60 } 61 }; 62 63 @Inject FragmentService(SystemUIRootComponent rootComponent, ConfigurationController configurationController)64 public FragmentService(SystemUIRootComponent rootComponent, 65 ConfigurationController configurationController) { 66 mFragmentCreator = rootComponent.createFragmentCreator(); 67 initInjectionMap(); 68 configurationController.addCallback(mConfigurationListener); 69 } 70 getInjectionMap()71 ArrayMap<String, Method> getInjectionMap() { 72 return mInjectionMap; 73 } 74 getFragmentCreator()75 FragmentCreator getFragmentCreator() { 76 return mFragmentCreator; 77 } 78 initInjectionMap()79 private void initInjectionMap() { 80 for (Method method : FragmentCreator.class.getDeclaredMethods()) { 81 if (Fragment.class.isAssignableFrom(method.getReturnType()) 82 && (method.getModifiers() & Modifier.PUBLIC) != 0) { 83 mInjectionMap.put(method.getReturnType().getName(), method); 84 } 85 } 86 } 87 getFragmentHostManager(View view)88 public FragmentHostManager getFragmentHostManager(View view) { 89 View root = view.getRootView(); 90 FragmentHostState state = mHosts.get(root); 91 if (state == null) { 92 state = new FragmentHostState(root); 93 mHosts.put(root, state); 94 } 95 return state.getFragmentHostManager(); 96 } 97 removeAndDestroy(View view)98 public void removeAndDestroy(View view) { 99 final FragmentHostState state = mHosts.remove(view.getRootView()); 100 if (state != null) { 101 state.mFragmentHostManager.destroy(); 102 } 103 } 104 destroyAll()105 public void destroyAll() { 106 for (FragmentHostState state : mHosts.values()) { 107 state.mFragmentHostManager.destroy(); 108 } 109 } 110 111 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)112 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 113 pw.println("Dumping fragments:"); 114 for (FragmentHostState state : mHosts.values()) { 115 state.mFragmentHostManager.getFragmentManager().dump(" ", fd, pw, args); 116 } 117 } 118 119 /** 120 * The subcomponent of dagger that holds all fragments that need injection. 121 */ 122 @Subcomponent 123 public interface FragmentCreator { 124 /** 125 * Inject a NavigationBarFragment. 126 */ createNavigationBarFragment()127 NavigationBarFragment createNavigationBarFragment(); 128 /** 129 * Inject a QSFragment. 130 */ createQSFragment()131 QSFragment createQSFragment(); 132 } 133 134 private class FragmentHostState { 135 private final View mView; 136 137 private FragmentHostManager mFragmentHostManager; 138 FragmentHostState(View view)139 public FragmentHostState(View view) { 140 mView = view; 141 mFragmentHostManager = new FragmentHostManager(FragmentService.this, mView); 142 } 143 sendConfigurationChange(Configuration newConfig)144 public void sendConfigurationChange(Configuration newConfig) { 145 mHandler.post(() -> handleSendConfigurationChange(newConfig)); 146 } 147 getFragmentHostManager()148 public FragmentHostManager getFragmentHostManager() { 149 return mFragmentHostManager; 150 } 151 handleSendConfigurationChange(Configuration newConfig)152 private void handleSendConfigurationChange(Configuration newConfig) { 153 mFragmentHostManager.onConfigurationChanged(newConfig); 154 } 155 } 156 } 157