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 17 package com.android.systemui; 18 19 import android.app.ActivityThread; 20 import android.content.Context; 21 import android.content.res.AssetManager; 22 import android.content.res.Resources; 23 import android.os.Handler; 24 import android.util.Log; 25 26 import com.android.internal.annotations.VisibleForTesting; 27 import com.android.systemui.dagger.DaggerGlobalRootComponent; 28 import com.android.systemui.dagger.GlobalRootComponent; 29 import com.android.systemui.dagger.SysUIComponent; 30 import com.android.systemui.dagger.WMComponent; 31 import com.android.systemui.navigationbar.gestural.BackGestureTfClassifierProvider; 32 import com.android.systemui.screenshot.ScreenshotNotificationSmartActionsProvider; 33 import com.android.wm.shell.transition.ShellTransitions; 34 35 import java.util.Optional; 36 import java.util.concurrent.ExecutionException; 37 import java.util.concurrent.Executor; 38 39 /** 40 * Class factory to provide customizable SystemUI components. 41 */ 42 public class SystemUIFactory { 43 private static final String TAG = "SystemUIFactory"; 44 45 static SystemUIFactory mFactory; 46 private GlobalRootComponent mRootComponent; 47 private WMComponent mWMComponent; 48 private SysUIComponent mSysUIComponent; 49 private boolean mInitializeComponents; 50 getInstance()51 public static <T extends SystemUIFactory> T getInstance() { 52 return (T) mFactory; 53 } 54 createFromConfig(Context context)55 public static void createFromConfig(Context context) { 56 createFromConfig(context, false); 57 } 58 59 @VisibleForTesting createFromConfig(Context context, boolean fromTest)60 public static void createFromConfig(Context context, boolean fromTest) { 61 if (mFactory != null) { 62 return; 63 } 64 65 final String clsName = context.getString(R.string.config_systemUIFactoryComponent); 66 if (clsName == null || clsName.length() == 0) { 67 throw new RuntimeException("No SystemUIFactory component configured"); 68 } 69 70 try { 71 Class<?> cls = null; 72 cls = context.getClassLoader().loadClass(clsName); 73 mFactory = (SystemUIFactory) cls.newInstance(); 74 mFactory.init(context, fromTest); 75 } catch (Throwable t) { 76 Log.w(TAG, "Error creating SystemUIFactory component: " + clsName, t); 77 throw new RuntimeException(t); 78 } 79 } 80 81 @VisibleForTesting cleanup()82 static void cleanup() { 83 mFactory = null; 84 } 85 SystemUIFactory()86 public SystemUIFactory() {} 87 88 @VisibleForTesting init(Context context, boolean fromTest)89 public void init(Context context, boolean fromTest) 90 throws ExecutionException, InterruptedException { 91 // Only initialize components for the main system ui process running as the primary user 92 mInitializeComponents = !fromTest 93 && android.os.Process.myUserHandle().isSystem() 94 && ActivityThread.currentProcessName().equals(ActivityThread.currentPackageName()); 95 mRootComponent = buildGlobalRootComponent(context); 96 // Stand up WMComponent 97 mWMComponent = mRootComponent.getWMComponentBuilder().build(); 98 if (mInitializeComponents) { 99 // Only initialize when not starting from tests since this currently initializes some 100 // components that shouldn't be run in the test environment 101 mWMComponent.init(); 102 } 103 104 // And finally, retrieve whatever SysUI needs from WMShell and build SysUI. 105 SysUIComponent.Builder builder = mRootComponent.getSysUIComponent(); 106 if (mInitializeComponents) { 107 // Only initialize when not starting from tests since this currently initializes some 108 // components that shouldn't be run in the test environment 109 builder = prepareSysUIComponentBuilder(builder, mWMComponent) 110 .setPip(mWMComponent.getPip()) 111 .setLegacySplitScreen(mWMComponent.getLegacySplitScreen()) 112 .setSplitScreen(mWMComponent.getSplitScreen()) 113 .setOneHanded(mWMComponent.getOneHanded()) 114 .setBubbles(mWMComponent.getBubbles()) 115 .setHideDisplayCutout(mWMComponent.getHideDisplayCutout()) 116 .setShellCommandHandler(mWMComponent.getShellCommandHandler()) 117 .setAppPairs(mWMComponent.getAppPairs()) 118 .setTaskViewFactory(mWMComponent.getTaskViewFactory()) 119 .setTransitions(mWMComponent.getTransitions()) 120 .setStartingSurface(mWMComponent.getStartingSurface()) 121 .setDisplayAreaHelper(mWMComponent.getDisplayAreaHelper()) 122 .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper()) 123 .setRecentTasks(mWMComponent.getRecentTasks()) 124 .setCompatUI(Optional.of(mWMComponent.getCompatUI())) 125 .setDragAndDrop(Optional.of(mWMComponent.getDragAndDrop())); 126 } else { 127 // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option 128 // is separating this logic into newly creating SystemUITestsFactory. 129 builder = prepareSysUIComponentBuilder(builder, mWMComponent) 130 .setPip(Optional.ofNullable(null)) 131 .setLegacySplitScreen(Optional.ofNullable(null)) 132 .setSplitScreen(Optional.ofNullable(null)) 133 .setOneHanded(Optional.ofNullable(null)) 134 .setBubbles(Optional.ofNullable(null)) 135 .setHideDisplayCutout(Optional.ofNullable(null)) 136 .setShellCommandHandler(Optional.ofNullable(null)) 137 .setAppPairs(Optional.ofNullable(null)) 138 .setTaskViewFactory(Optional.ofNullable(null)) 139 .setTransitions(new ShellTransitions() {}) 140 .setDisplayAreaHelper(Optional.ofNullable(null)) 141 .setStartingSurface(Optional.ofNullable(null)) 142 .setTaskSurfaceHelper(Optional.ofNullable(null)) 143 .setRecentTasks(Optional.ofNullable(null)) 144 .setCompatUI(Optional.ofNullable(null)) 145 .setDragAndDrop(Optional.ofNullable(null)); 146 } 147 mSysUIComponent = builder.build(); 148 if (mInitializeComponents) { 149 mSysUIComponent.init(); 150 } 151 152 // Every other part of our codebase currently relies on Dependency, so we 153 // really need to ensure the Dependency gets initialized early on. 154 Dependency dependency = mSysUIComponent.createDependency(); 155 dependency.start(); 156 } 157 158 /** 159 * Prepares the SysUIComponent builder before it is built. 160 * @param sysUIBuilder the builder provided by the root component's getSysUIComponent() method 161 * @param wm the built WMComponent from the root component's getWMComponent() method 162 */ prepareSysUIComponentBuilder( SysUIComponent.Builder sysUIBuilder, WMComponent wm)163 protected SysUIComponent.Builder prepareSysUIComponentBuilder( 164 SysUIComponent.Builder sysUIBuilder, WMComponent wm) { 165 return sysUIBuilder; 166 } 167 buildGlobalRootComponent(Context context)168 protected GlobalRootComponent buildGlobalRootComponent(Context context) { 169 return DaggerGlobalRootComponent.builder() 170 .context(context) 171 .build(); 172 } 173 shouldInitializeComponents()174 protected boolean shouldInitializeComponents() { 175 return mInitializeComponents; 176 } 177 getRootComponent()178 public GlobalRootComponent getRootComponent() { 179 return mRootComponent; 180 } 181 getWMComponent()182 public WMComponent getWMComponent() { 183 return mWMComponent; 184 } 185 getSysUIComponent()186 public SysUIComponent getSysUIComponent() { 187 return mSysUIComponent; 188 } 189 190 /** 191 * Returns the list of system UI components that should be started. 192 */ getSystemUIServiceComponents(Resources resources)193 public String[] getSystemUIServiceComponents(Resources resources) { 194 return resources.getStringArray(R.array.config_systemUIServiceComponents); 195 } 196 197 /** 198 * Returns the list of system UI components that should be started per user. 199 */ getSystemUIServiceComponentsPerUser(Resources resources)200 public String[] getSystemUIServiceComponentsPerUser(Resources resources) { 201 return resources.getStringArray(R.array.config_systemUIServiceComponentsPerUser); 202 } 203 204 /** 205 * Creates an instance of ScreenshotNotificationSmartActionsProvider. 206 * This method is overridden in vendor specific implementation of Sys UI. 207 */ 208 public ScreenshotNotificationSmartActionsProvider createScreenshotNotificationSmartActionsProvider( Context context, Executor executor, Handler uiHandler)209 createScreenshotNotificationSmartActionsProvider( 210 Context context, Executor executor, Handler uiHandler) { 211 return new ScreenshotNotificationSmartActionsProvider(); 212 } 213 214 /** 215 * Creates an instance of BackGestureTfClassifierProvider. 216 * This method is overridden in vendor specific implementation of Sys UI. 217 */ createBackGestureTfClassifierProvider( AssetManager am, String modelName)218 public BackGestureTfClassifierProvider createBackGestureTfClassifierProvider( 219 AssetManager am, String modelName) { 220 return new BackGestureTfClassifierProvider(); 221 } 222 } 223