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.Transitions; 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 .setTaskSurfaceHelper(mWMComponent.getTaskSurfaceHelper()); 122 } else { 123 // TODO: Call on prepareSysUIComponentBuilder but not with real components. Other option 124 // is separating this logic into newly creating SystemUITestsFactory. 125 builder = prepareSysUIComponentBuilder(builder, mWMComponent) 126 .setPip(Optional.ofNullable(null)) 127 .setLegacySplitScreen(Optional.ofNullable(null)) 128 .setSplitScreen(Optional.ofNullable(null)) 129 .setOneHanded(Optional.ofNullable(null)) 130 .setBubbles(Optional.ofNullable(null)) 131 .setHideDisplayCutout(Optional.ofNullable(null)) 132 .setShellCommandHandler(Optional.ofNullable(null)) 133 .setAppPairs(Optional.ofNullable(null)) 134 .setTaskViewFactory(Optional.ofNullable(null)) 135 .setTransitions(Transitions.createEmptyForTesting()) 136 .setStartingSurface(Optional.ofNullable(null)) 137 .setTaskSurfaceHelper(Optional.ofNullable(null)); 138 } 139 mSysUIComponent = builder.build(); 140 if (mInitializeComponents) { 141 mSysUIComponent.init(); 142 } 143 144 // Every other part of our codebase currently relies on Dependency, so we 145 // really need to ensure the Dependency gets initialized early on. 146 Dependency dependency = mSysUIComponent.createDependency(); 147 dependency.start(); 148 } 149 150 /** 151 * Prepares the SysUIComponent builder before it is built. 152 * @param sysUIBuilder the builder provided by the root component's getSysUIComponent() method 153 * @param wm the built WMComponent from the root component's getWMComponent() method 154 */ prepareSysUIComponentBuilder( SysUIComponent.Builder sysUIBuilder, WMComponent wm)155 protected SysUIComponent.Builder prepareSysUIComponentBuilder( 156 SysUIComponent.Builder sysUIBuilder, WMComponent wm) { 157 return sysUIBuilder; 158 } 159 buildGlobalRootComponent(Context context)160 protected GlobalRootComponent buildGlobalRootComponent(Context context) { 161 return DaggerGlobalRootComponent.builder() 162 .context(context) 163 .build(); 164 } 165 shouldInitializeComponents()166 protected boolean shouldInitializeComponents() { 167 return mInitializeComponents; 168 } 169 getRootComponent()170 public GlobalRootComponent getRootComponent() { 171 return mRootComponent; 172 } 173 getWMComponent()174 public WMComponent getWMComponent() { 175 return mWMComponent; 176 } 177 getSysUIComponent()178 public SysUIComponent getSysUIComponent() { 179 return mSysUIComponent; 180 } 181 182 /** 183 * Returns the list of system UI components that should be started. 184 */ getSystemUIServiceComponents(Resources resources)185 public String[] getSystemUIServiceComponents(Resources resources) { 186 return resources.getStringArray(R.array.config_systemUIServiceComponents); 187 } 188 189 /** 190 * Returns the list of system UI components that should be started per user. 191 */ getSystemUIServiceComponentsPerUser(Resources resources)192 public String[] getSystemUIServiceComponentsPerUser(Resources resources) { 193 return resources.getStringArray(R.array.config_systemUIServiceComponentsPerUser); 194 } 195 196 /** 197 * Creates an instance of ScreenshotNotificationSmartActionsProvider. 198 * This method is overridden in vendor specific implementation of Sys UI. 199 */ 200 public ScreenshotNotificationSmartActionsProvider createScreenshotNotificationSmartActionsProvider( Context context, Executor executor, Handler uiHandler)201 createScreenshotNotificationSmartActionsProvider( 202 Context context, Executor executor, Handler uiHandler) { 203 return new ScreenshotNotificationSmartActionsProvider(); 204 } 205 206 /** 207 * Creates an instance of BackGestureTfClassifierProvider. 208 * This method is overridden in vendor specific implementation of Sys UI. 209 */ createBackGestureTfClassifierProvider( AssetManager am, String modelName)210 public BackGestureTfClassifierProvider createBackGestureTfClassifierProvider( 211 AssetManager am, String modelName) { 212 return new BackGestureTfClassifierProvider(); 213 } 214 } 215