• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.statusbar.phone;
18 
19 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_NAVIGATION_BARS;
20 import static android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS;
21 
22 import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_LIGHTS_OUT_TRANSPARENT;
23 import static com.android.systemui.shared.statusbar.phone.BarTransitions.MODE_TRANSPARENT;
24 
25 import android.content.Context;
26 import android.graphics.Rect;
27 import android.util.Log;
28 import android.view.Display;
29 import android.view.InsetsFlags;
30 import android.view.ViewDebug;
31 import android.view.WindowInsetsController.Appearance;
32 
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 
36 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
37 import com.android.internal.view.AppearanceRegion;
38 import com.android.systemui.dagger.qualifiers.Application;
39 import com.android.systemui.dagger.qualifiers.Main;
40 import com.android.systemui.dump.DumpManager;
41 import com.android.systemui.navigationbar.NavigationModeController;
42 import com.android.systemui.plugins.DarkIconDispatcher;
43 import com.android.systemui.statusbar.data.model.StatusBarAppearance;
44 import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore;
45 import com.android.systemui.statusbar.data.repository.StatusBarModePerDisplayRepository;
46 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore;
47 import com.android.systemui.statusbar.layout.BoundsPair;
48 import com.android.systemui.statusbar.policy.BatteryController;
49 import com.android.systemui.util.Compile;
50 import com.android.systemui.util.kotlin.JavaAdapterKt;
51 
52 import dagger.assisted.Assisted;
53 import dagger.assisted.AssistedFactory;
54 import dagger.assisted.AssistedInject;
55 
56 import kotlin.coroutines.CoroutineContext;
57 
58 import kotlinx.coroutines.CoroutineScope;
59 
60 import java.io.PrintWriter;
61 import java.util.ArrayList;
62 
63 import javax.inject.Inject;
64 
65 /**
66  * Controls how light status bar flag applies to the icons.
67  */
68 public class LightBarControllerImpl implements
69         BatteryController.BatteryStateChangeCallback, LightBarController {
70 
71     private static final String TAG = "LightBarController";
72     private static final boolean DEBUG_NAVBAR = Compile.IS_DEBUG;
73     private static final boolean DEBUG_LOGS = Compile.IS_DEBUG && Log.isLoggable(TAG, Log.DEBUG);
74 
75     private static final float NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD = 0.1f;
76 
77     private final int mDisplayId;
78     private final CoroutineScope mCoroutineScope;
79     private final SysuiDarkIconDispatcher mStatusBarIconController;
80     private final BatteryController mBatteryController;
81     private final NavigationModeController mNavModeController;
82     private final DumpManager mDumpManager;
83     private final StatusBarModePerDisplayRepository mStatusBarModeRepository;
84     private final CoroutineContext mMainContext;
85     private final BiometricUnlockController mBiometricUnlockController;
86 
87     private LightBarTransitionsController mNavigationBarController;
88     private @Appearance int mAppearance;
89     private AppearanceRegion[] mAppearanceRegions = new AppearanceRegion[0];
90     private int mStatusBarMode;
91     private BoundsPair mStatusBarBounds = new BoundsPair(new Rect(), new Rect());
92     private int mNavigationBarMode;
93     private int mNavigationMode;
94 
95     /**
96      * Whether the navigation bar should be light factoring in already how much alpha the scrim has.
97      * "Light" refers to the background color of the navigation bar, so when this is true,
98      * it's referring to a state where the navigation bar icons are tinted dark.
99      */
100     private boolean mNavigationLight;
101 
102     /**
103      * Whether the flags indicate that a light navigation bar is requested.
104      * "Light" refers to the background color of the navigation bar, so when this is true,
105      * it's referring to a state where the navigation bar icons would be tinted dark.
106      * This doesn't factor in the scrim alpha yet.
107      */
108     private boolean mHasLightNavigationBar;
109 
110     /**
111      * {@code true} if {@link #mHasLightNavigationBar} should be ignored and forcefully make
112      * {@link #mNavigationLight} {@code false}.
113      */
114     private boolean mForceDarkForScrim;
115     /**
116      * {@code true} if {@link #mHasLightNavigationBar} should be ignored and forcefully make
117      * {@link #mNavigationLight} {@code true}.
118      */
119     private boolean mForceLightForScrim;
120 
121     private boolean mQsCustomizing;
122     private boolean mQsExpanded;
123     private boolean mBouncerVisible;
124     private boolean mGlobalActionsVisible;
125 
126     private boolean mDirectReplying;
127     private boolean mNavbarColorManagedByIme;
128 
129     private boolean mIsCustomizingForBackNav;
130 
131     private String mLastSetScrimStateLog;
132     private String mLastNavigationBarAppearanceChangedLog;
133     private StringBuilder mLogStringBuilder = null;
134 
135     private final String mDumpableName;
136 
137     private final NavigationModeController.ModeChangedListener mNavigationModeListener =
138             (mode) -> mNavigationMode = mode;
139 
140     @AssistedInject
LightBarControllerImpl( @ssisted int displayId, @Assisted CoroutineScope coroutineScope, @Assisted DarkIconDispatcher darkIconDispatcher, BatteryController batteryController, NavigationModeController navModeController, @Assisted StatusBarModePerDisplayRepository statusBarModeRepository, DumpManager dumpManager, @Main CoroutineContext mainContext, BiometricUnlockController biometricUnlockController)141     public LightBarControllerImpl(
142             @Assisted int displayId,
143             @Assisted CoroutineScope coroutineScope,
144             @Assisted DarkIconDispatcher darkIconDispatcher,
145             BatteryController batteryController,
146             NavigationModeController navModeController,
147             @Assisted StatusBarModePerDisplayRepository statusBarModeRepository,
148             DumpManager dumpManager,
149             @Main CoroutineContext mainContext,
150             BiometricUnlockController biometricUnlockController) {
151         mDisplayId = displayId;
152         mCoroutineScope = coroutineScope;
153         mStatusBarIconController = (SysuiDarkIconDispatcher) darkIconDispatcher;
154         mBatteryController = batteryController;
155         mNavModeController = navModeController;
156         mDumpManager = dumpManager;
157         mStatusBarModeRepository = statusBarModeRepository;
158         mMainContext = mainContext;
159         mBiometricUnlockController = biometricUnlockController;
160         String dumpableNameSuffix =
161                 displayId == Display.DEFAULT_DISPLAY ? "" : String.valueOf(displayId);
162         mDumpableName = getClass().getSimpleName() + dumpableNameSuffix;
163     }
164 
165     @Override
start()166     public void start() {
167         if (mDisplayId == Display.DEFAULT_DISPLAY) {
168             // Can only register on default display, because NavigationBar creates its own instance
169             // as well as PerDisplayStore.
170             // TODO: b/380394368 - make sure there is only one instance per display.
171             mDumpManager.registerCriticalDumpable(mDumpableName, this);
172         }
173         mBatteryController.addCallback(this);
174         mNavigationMode = mNavModeController.addListener(mNavigationModeListener);
175         JavaAdapterKt.collectFlow(
176                 mCoroutineScope,
177                 mMainContext,
178                 mStatusBarModeRepository.getStatusBarAppearance(),
179                 this::onStatusBarAppearanceChanged);
180     }
181 
182     @Override
stop()183     public void stop() {
184         mDumpManager.unregisterDumpable(mDumpableName);
185         mBatteryController.removeCallback(this);
186         mNavModeController.removeListener(mNavigationModeListener);
187     }
188 
189     @Override
setNavigationBar(LightBarTransitionsController navigationBar)190     public void setNavigationBar(LightBarTransitionsController navigationBar) {
191         mNavigationBarController = navigationBar;
192         updateNavigation();
193     }
194 
onStatusBarAppearanceChanged(@ullable StatusBarAppearance params)195     private void onStatusBarAppearanceChanged(@Nullable StatusBarAppearance params) {
196         if (params == null) {
197             return;
198         }
199         int newStatusBarMode = params.getMode().toTransitionModeInt();
200         boolean sbModeChanged = mStatusBarMode != newStatusBarMode;
201         mStatusBarMode = newStatusBarMode;
202 
203         boolean sbBoundsChanged = !mStatusBarBounds.equals(params.getBounds());
204         mStatusBarBounds = params.getBounds();
205 
206         onStatusBarAppearanceChanged(
207                 params.getAppearanceRegions().toArray(new AppearanceRegion[0]),
208                 sbModeChanged,
209                 sbBoundsChanged,
210                 params.getNavbarColorManagedByIme());
211     }
212 
onStatusBarAppearanceChanged( AppearanceRegion[] appearanceRegions, boolean sbModeChanged, boolean sbBoundsChanged, boolean navbarColorManagedByIme)213     private void onStatusBarAppearanceChanged(
214             AppearanceRegion[] appearanceRegions,
215             boolean sbModeChanged,
216             boolean sbBoundsChanged,
217             boolean navbarColorManagedByIme) {
218         final int numStacks = appearanceRegions.length;
219         boolean stackAppearancesChanged = mAppearanceRegions.length != numStacks;
220         for (int i = 0; i < numStacks && !stackAppearancesChanged; i++) {
221             stackAppearancesChanged |= !appearanceRegions[i].equals(mAppearanceRegions[i]);
222         }
223 
224         if (stackAppearancesChanged
225                 || sbModeChanged
226                 // Be sure to re-draw when the status bar bounds have changed because the status bar
227                 // icons may have moved to be part of a different appearance region. See b/301605450
228                 || sbBoundsChanged
229                 || mIsCustomizingForBackNav) {
230             mAppearanceRegions = appearanceRegions;
231             updateStatus(mAppearanceRegions);
232             mIsCustomizingForBackNav = false;
233         }
234         mNavbarColorManagedByIme = navbarColorManagedByIme;
235     }
236 
237     @Override
onNavigationBarAppearanceChanged(@ppearance int appearance, boolean nbModeChanged, int navigationBarMode, boolean navbarColorManagedByIme)238     public void onNavigationBarAppearanceChanged(@Appearance int appearance, boolean nbModeChanged,
239             int navigationBarMode, boolean navbarColorManagedByIme) {
240         int diff = appearance ^ mAppearance;
241         if ((diff & APPEARANCE_LIGHT_NAVIGATION_BARS) != 0 || nbModeChanged) {
242             final boolean last = mNavigationLight;
243             mHasLightNavigationBar = isLight(appearance, navigationBarMode,
244                     APPEARANCE_LIGHT_NAVIGATION_BARS);
245             final boolean ignoreScrimForce = mDirectReplying && mNavbarColorManagedByIme;
246             final boolean darkForScrim = mForceDarkForScrim && !ignoreScrimForce;
247             final boolean lightForScrim = mForceLightForScrim && !ignoreScrimForce;
248             final boolean darkForQs = (mQsCustomizing || mQsExpanded) && !mBouncerVisible;
249             final boolean darkForTop = darkForQs || mGlobalActionsVisible;
250             mNavigationLight =
251                     ((mHasLightNavigationBar && !darkForScrim) || lightForScrim) && !darkForTop;
252             if (DEBUG_NAVBAR) {
253                 mLastNavigationBarAppearanceChangedLog = getLogStringBuilder()
254                         .append("onNavigationBarAppearanceChanged()")
255                         .append(" appearance=").append(appearance)
256                         .append(" nbModeChanged=").append(nbModeChanged)
257                         .append(" navigationBarMode=").append(navigationBarMode)
258                         .append(" navbarColorManagedByIme=").append(navbarColorManagedByIme)
259                         .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
260                         .append(" ignoreScrimForce=").append(ignoreScrimForce)
261                         .append(" darkForScrim=").append(darkForScrim)
262                         .append(" lightForScrim=").append(lightForScrim)
263                         .append(" darkForQs=").append(darkForQs)
264                         .append(" darkForTop=").append(darkForTop)
265                         .append(" mNavigationLight=").append(mNavigationLight)
266                         .append(" last=").append(last)
267                         .append(" timestamp=").append(System.currentTimeMillis())
268                         .toString();
269                 if (DEBUG_LOGS) Log.d(TAG, mLastNavigationBarAppearanceChangedLog);
270             }
271             if (mNavigationLight != last) {
272                 updateNavigation();
273             }
274         }
275         mAppearance = appearance;
276         mNavigationBarMode = navigationBarMode;
277         mNavbarColorManagedByIme = navbarColorManagedByIme;
278     }
279 
280     @Override
onNavigationBarModeChanged(int newBarMode)281     public void onNavigationBarModeChanged(int newBarMode) {
282         mHasLightNavigationBar = isLight(mAppearance, newBarMode, APPEARANCE_LIGHT_NAVIGATION_BARS);
283     }
284 
reevaluate()285     private void reevaluate() {
286         onStatusBarAppearanceChanged(
287                 mAppearanceRegions,
288                 /* sbModeChanged= */ true,
289                 /* sbBoundsChanged= */ true,
290                 mNavbarColorManagedByIme);
291         onNavigationBarAppearanceChanged(mAppearance, true /* nbModeChanged */,
292                 mNavigationBarMode, mNavbarColorManagedByIme);
293     }
294 
295     @Override
setQsCustomizing(boolean customizing)296     public void setQsCustomizing(boolean customizing) {
297         if (mQsCustomizing == customizing) return;
298         mQsCustomizing = customizing;
299         reevaluate();
300     }
301 
302     @Override
setQsExpanded(boolean expanded)303     public void setQsExpanded(boolean expanded) {
304         if (mQsExpanded == expanded) return;
305         mQsExpanded = expanded;
306         reevaluate();
307     }
308 
309     @Override
setGlobalActionsVisible(boolean visible)310     public void setGlobalActionsVisible(boolean visible) {
311         if (mGlobalActionsVisible == visible) return;
312         mGlobalActionsVisible = visible;
313         reevaluate();
314     }
315 
316     @Override
customizeStatusBarAppearance(AppearanceRegion appearance)317     public void customizeStatusBarAppearance(AppearanceRegion appearance) {
318         if (appearance != null) {
319             final ArrayList<AppearanceRegion> appearancesList = new ArrayList<>();
320             appearancesList.add(appearance);
321             for (int i = 0; i < mAppearanceRegions.length; i++) {
322                 final AppearanceRegion ar = mAppearanceRegions[i];
323                 if (appearance.getBounds().contains(ar.getBounds())) {
324                     continue;
325                 }
326                 appearancesList.add(ar);
327             }
328 
329             final AppearanceRegion[] newAppearances = new AppearanceRegion[appearancesList.size()];
330             updateStatus(appearancesList.toArray(newAppearances));
331             mIsCustomizingForBackNav = true;
332         } else {
333             mIsCustomizingForBackNav = false;
334             updateStatus(mAppearanceRegions);
335         }
336     }
337 
338     @Override
setDirectReplying(boolean directReplying)339     public void setDirectReplying(boolean directReplying) {
340         if (mDirectReplying == directReplying) return;
341         mDirectReplying = directReplying;
342         reevaluate();
343     }
344 
345     @Override
setScrimState(ScrimState scrimState, float scrimBehindAlpha, GradientColors scrimInFrontColor)346     public void setScrimState(ScrimState scrimState, float scrimBehindAlpha,
347             GradientColors scrimInFrontColor) {
348         boolean bouncerVisibleLast = mBouncerVisible;
349         boolean forceDarkForScrimLast = mForceDarkForScrim;
350         boolean forceLightForScrimLast = mForceLightForScrim;
351         mBouncerVisible =
352                 scrimState == ScrimState.BOUNCER || scrimState == ScrimState.BOUNCER_SCRIMMED;
353         final boolean forceForScrim = mBouncerVisible
354                 || scrimBehindAlpha >= NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
355         final boolean scrimColorIsLight = scrimInFrontColor.supportsDarkText();
356 
357         mForceDarkForScrim = forceForScrim && !scrimColorIsLight;
358         mForceLightForScrim = forceForScrim && scrimColorIsLight;
359         if (mBouncerVisible != bouncerVisibleLast) {
360             reevaluate();
361         } else if (mHasLightNavigationBar) {
362             if (mForceDarkForScrim != forceDarkForScrimLast) reevaluate();
363         } else {
364             if (mForceLightForScrim != forceLightForScrimLast) reevaluate();
365         }
366         if (DEBUG_NAVBAR) {
367             mLastSetScrimStateLog = getLogStringBuilder()
368                     .append("setScrimState()")
369                     .append(" scrimState=").append(scrimState)
370                     .append(" scrimBehindAlpha=").append(scrimBehindAlpha)
371                     .append(" scrimInFrontColor=").append(scrimInFrontColor)
372                     .append(" forceForScrim=").append(forceForScrim)
373                     .append(" scrimColorIsLight=").append(scrimColorIsLight)
374                     .append(" mHasLightNavigationBar=").append(mHasLightNavigationBar)
375                     .append(" mBouncerVisible=").append(mBouncerVisible)
376                     .append(" mForceDarkForScrim=").append(mForceDarkForScrim)
377                     .append(" mForceLightForScrim=").append(mForceLightForScrim)
378                     .append(" timestamp=").append(System.currentTimeMillis())
379                     .toString();
380             if (DEBUG_LOGS) Log.d(TAG, mLastSetScrimStateLog);
381         }
382     }
383 
384     @NonNull
getLogStringBuilder()385     private StringBuilder getLogStringBuilder() {
386         if (mLogStringBuilder == null) {
387             mLogStringBuilder = new StringBuilder();
388         }
389         mLogStringBuilder.setLength(0);
390         return mLogStringBuilder;
391     }
392 
isLight(int appearance, int barMode, int flag)393     private static boolean isLight(int appearance, int barMode, int flag) {
394         final boolean isTransparentBar = (barMode == MODE_TRANSPARENT
395                 || barMode == MODE_LIGHTS_OUT_TRANSPARENT);
396         final boolean light = (appearance & flag) != 0;
397         return isTransparentBar && light;
398     }
399 
animateChange()400     private boolean animateChange() {
401         int unlockMode = mBiometricUnlockController.getMode();
402         return unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING
403                 && unlockMode != BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
404     }
405 
updateStatus(AppearanceRegion[] appearanceRegions)406     private void updateStatus(AppearanceRegion[] appearanceRegions) {
407         final int numStacks = appearanceRegions.length;
408         final ArrayList<Rect> lightBarBounds = new ArrayList<>();
409 
410         for (int i = 0; i < numStacks; i++) {
411             final AppearanceRegion ar = appearanceRegions[i];
412             if (isLight(ar.getAppearance(), mStatusBarMode, APPEARANCE_LIGHT_STATUS_BARS)) {
413                 lightBarBounds.add(ar.getBounds());
414             }
415         }
416 
417         if (lightBarBounds.isEmpty()) {
418             // If no one is light, all icons become white.
419             mStatusBarIconController
420                     .getTransitionsController()
421                     .setIconsDark(false, animateChange());
422         } else if (lightBarBounds.size() == numStacks) {
423             // If all stacks are light, all icons get dark.
424             mStatusBarIconController.setIconsDarkArea(null);
425             mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
426         } else {
427             // Not the same for every stack, magic!
428             mStatusBarIconController.setIconsDarkArea(lightBarBounds);
429             mStatusBarIconController.getTransitionsController().setIconsDark(true, animateChange());
430         }
431     }
432 
updateNavigation()433     private void updateNavigation() {
434         if (mNavigationBarController != null
435                 && mNavigationBarController.supportsIconTintForNavMode(mNavigationMode)) {
436             mNavigationBarController.setIconsDark(mNavigationLight, animateChange());
437         }
438     }
439 
440     @Override
onPowerSaveChanged(boolean isPowerSave)441     public void onPowerSaveChanged(boolean isPowerSave) {
442         reevaluate();
443     }
444 
445     @Override
dump(PrintWriter pw, String[] args)446     public void dump(PrintWriter pw, String[] args) {
447         pw.println("LightBarController: ");
448         pw.print(" mAppearance="); pw.println(ViewDebug.flagsToString(
449                 InsetsFlags.class, "appearance", mAppearance));
450         final int numStacks = mAppearanceRegions.length;
451         for (int i = 0; i < numStacks; i++) {
452             final boolean isLight = isLight(mAppearanceRegions[i].getAppearance(), mStatusBarMode,
453                     APPEARANCE_LIGHT_STATUS_BARS);
454             pw.print(" stack #"); pw.print(i); pw.print(": ");
455             pw.print(mAppearanceRegions[i].toString()); pw.print(" isLight="); pw.println(isLight);
456         }
457 
458         pw.print(" mNavigationLight="); pw.println(mNavigationLight);
459         pw.print(" mHasLightNavigationBar="); pw.println(mHasLightNavigationBar);
460         pw.println();
461         pw.print(" mStatusBarMode="); pw.print(mStatusBarMode);
462         pw.print(" mNavigationBarMode="); pw.println(mNavigationBarMode);
463         pw.println();
464         pw.print(" mForceDarkForScrim="); pw.println(mForceDarkForScrim);
465         pw.print(" mForceLightForScrim="); pw.println(mForceLightForScrim);
466         pw.println();
467         pw.print(" mQsCustomizing="); pw.println(mQsCustomizing);
468         pw.print(" mQsExpanded="); pw.println(mQsExpanded);
469         pw.print(" mBouncerVisible="); pw.println(mBouncerVisible);
470         pw.print(" mGlobalActionsVisible="); pw.println(mGlobalActionsVisible);
471         pw.print(" mDirectReplying="); pw.println(mDirectReplying);
472         pw.print(" mNavbarColorManagedByIme="); pw.println(mNavbarColorManagedByIme);
473         pw.println();
474         pw.println(" Recent Calculation Logs:");
475         pw.print("   "); pw.println(mLastSetScrimStateLog);
476         pw.print("   "); pw.println(mLastNavigationBarAppearanceChangedLog);
477 
478         pw.println();
479 
480         LightBarTransitionsController transitionsController =
481                 mStatusBarIconController.getTransitionsController();
482         if (transitionsController != null) {
483             pw.println(" StatusBarTransitionsController:");
484             transitionsController.dump(pw, args);
485             pw.println();
486         }
487 
488         if (mNavigationBarController != null) {
489             pw.println(" NavigationBarTransitionsController:");
490             mNavigationBarController.dump(pw, args);
491             pw.println();
492         }
493     }
494 
495     /** Injectable factory for creating a {@link LightBarControllerImpl}. */
496     @AssistedFactory
497     @FunctionalInterface
498     public interface Factory {
499 
500         /** Creates a {@link LightBarControllerImpl}. */
create( int displayId, @NonNull CoroutineScope coroutineScope, @NonNull DarkIconDispatcher darkIconDispatcher, @NonNull StatusBarModePerDisplayRepository statusBarModePerDisplayRepository)501         LightBarControllerImpl create(
502                 int displayId,
503                 @NonNull CoroutineScope coroutineScope,
504                 @NonNull DarkIconDispatcher darkIconDispatcher,
505                 @NonNull StatusBarModePerDisplayRepository statusBarModePerDisplayRepository);
506     }
507 
508     public static class LegacyFactory implements LightBarController.Factory {
509 
510         private final Factory mFactory;
511         private final CoroutineScope mApplicationScope;
512         private final DarkIconDispatcherStore mDarkIconDispatcherStore;
513         private final StatusBarModeRepositoryStore mStatusBarModeRepositoryStore;
514 
515         @Inject
LegacyFactory( LightBarControllerImpl.Factory factory, @Application CoroutineScope applicationScope, DarkIconDispatcherStore darkIconDispatcherStore, StatusBarModeRepositoryStore statusBarModeRepositoryStore)516         public LegacyFactory(
517                 LightBarControllerImpl.Factory factory,
518                 @Application CoroutineScope applicationScope,
519                 DarkIconDispatcherStore darkIconDispatcherStore,
520                 StatusBarModeRepositoryStore statusBarModeRepositoryStore) {
521             mFactory = factory;
522             mApplicationScope = applicationScope;
523             mDarkIconDispatcherStore = darkIconDispatcherStore;
524             mStatusBarModeRepositoryStore = statusBarModeRepositoryStore;
525         }
526 
527         @NonNull
528         @Override
create(@onNull Context context)529         public LightBarController create(@NonNull Context context) {
530             // TODO: b/380394368 - Make sure correct per display instances are used.
531             LightBarControllerImpl lightBarController = mFactory.create(
532                     context.getDisplayId(),
533                     mApplicationScope,
534                     mDarkIconDispatcherStore.getDefaultDisplay(),
535                     mStatusBarModeRepositoryStore.getDefaultDisplay()
536             );
537             // Calling start() manually to keep the legacy behavior. Before, LightBarControllerImpl
538             // was doing work in the constructor, which moved to start().
539             lightBarController.start();
540             return lightBarController;
541         }
542     }
543 }
544