1 /* 2 * Copyright (C) 2020 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.keyguard; 18 19 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; 20 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; 21 22 import static com.android.keyguard.KeyguardClockSwitch.LARGE; 23 import static com.android.keyguard.KeyguardClockSwitch.SMALL; 24 import static com.android.systemui.Flags.smartspaceRelocateToBottom; 25 import static com.android.systemui.flags.Flags.LOCKSCREEN_WALLPAPER_DREAM_ENABLED; 26 import static com.android.systemui.util.kotlin.JavaAdapterKt.collectFlow; 27 28 import android.annotation.Nullable; 29 import android.database.ContentObserver; 30 import android.os.UserHandle; 31 import android.provider.Settings; 32 import android.text.TextUtils; 33 import android.view.View; 34 import android.view.ViewGroup; 35 import android.widget.FrameLayout; 36 import android.widget.LinearLayout; 37 38 import androidx.annotation.NonNull; 39 import androidx.annotation.VisibleForTesting; 40 41 import com.android.systemui.Dumpable; 42 import com.android.systemui.dagger.qualifiers.Background; 43 import com.android.systemui.dagger.qualifiers.Main; 44 import com.android.systemui.dump.DumpManager; 45 import com.android.systemui.flags.FeatureFlagsClassic; 46 import com.android.systemui.keyguard.KeyguardUnlockAnimationController; 47 import com.android.systemui.keyguard.MigrateClocksToBlueprint; 48 import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor; 49 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; 50 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager; 51 import com.android.systemui.log.LogBuffer; 52 import com.android.systemui.log.core.LogLevel; 53 import com.android.systemui.log.dagger.KeyguardClockLog; 54 import com.android.systemui.plugins.clocks.ClockController; 55 import com.android.systemui.plugins.statusbar.StatusBarStateController; 56 import com.android.systemui.res.R; 57 import com.android.systemui.shared.clocks.ClockRegistry; 58 import com.android.systemui.shared.regionsampling.RegionSampler; 59 import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController; 60 import com.android.systemui.statusbar.notification.AnimatableProperty; 61 import com.android.systemui.statusbar.notification.PropertyAnimator; 62 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerAlwaysOnDisplayViewBinder; 63 import com.android.systemui.statusbar.notification.shared.NotificationIconContainerRefactor; 64 import com.android.systemui.statusbar.notification.stack.AnimationProperties; 65 import com.android.systemui.statusbar.phone.NotificationIconAreaController; 66 import com.android.systemui.statusbar.phone.NotificationIconContainer; 67 import com.android.systemui.util.ViewController; 68 import com.android.systemui.util.concurrency.DelayableExecutor; 69 import com.android.systemui.util.settings.SecureSettings; 70 71 import kotlinx.coroutines.DisposableHandle; 72 73 import java.io.PrintWriter; 74 import java.util.Locale; 75 import java.util.concurrent.Executor; 76 import java.util.function.Consumer; 77 78 import javax.inject.Inject; 79 80 /** 81 * Injectable controller for {@link KeyguardClockSwitch}. 82 */ 83 public class KeyguardClockSwitchController extends ViewController<KeyguardClockSwitch> 84 implements Dumpable { 85 private static final String TAG = "KeyguardClockSwitchController"; 86 87 private final StatusBarStateController mStatusBarStateController; 88 private final ClockRegistry mClockRegistry; 89 private final KeyguardSliceViewController mKeyguardSliceViewController; 90 private final NotificationIconAreaController mNotificationIconAreaController; 91 private final LockscreenSmartspaceController mSmartspaceController; 92 private final SecureSettings mSecureSettings; 93 private final DumpManager mDumpManager; 94 private final ClockEventController mClockEventController; 95 private final LogBuffer mLogBuffer; 96 private final NotificationIconContainerAlwaysOnDisplayViewBinder mNicViewBinder; 97 private FrameLayout mSmallClockFrame; // top aligned clock 98 private FrameLayout mLargeClockFrame; // centered clock 99 100 @KeyguardClockSwitch.ClockSize 101 private int mCurrentClockSize = SMALL; 102 103 private int mKeyguardSmallClockTopMargin = 0; 104 private int mKeyguardLargeClockTopMargin = 0; 105 private int mKeyguardDateWeatherViewInvisibility = View.INVISIBLE; 106 private final ClockRegistry.ClockChangeListener mClockChangedListener; 107 108 private ViewGroup mStatusArea; 109 110 // If the SMARTSPACE flag is set, keyguard_slice_view is replaced by the following views. 111 private ViewGroup mDateWeatherView; 112 private View mWeatherView; 113 private View mSmartspaceView; 114 115 private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController; 116 private final InWindowLauncherUnlockAnimationManager mInWindowLauncherUnlockAnimationManager; 117 118 private boolean mShownOnSecondaryDisplay = false; 119 private boolean mOnlyClock = false; 120 private boolean mIsActiveDreamLockscreenHosted = false; 121 private final FeatureFlagsClassic mFeatureFlags; 122 private KeyguardInteractor mKeyguardInteractor; 123 private KeyguardClockInteractor mKeyguardClockInteractor; 124 private final DelayableExecutor mUiExecutor; 125 private final Executor mBgExecutor; 126 private boolean mCanShowDoubleLineClock = true; 127 private DisposableHandle mAodIconsBindHandle; 128 @Nullable private NotificationIconContainer mAodIconContainer; 129 130 @VisibleForTesting 131 final Consumer<Boolean> mIsActiveDreamLockscreenHostedCallback = 132 (Boolean isLockscreenHosted) -> { 133 if (mIsActiveDreamLockscreenHosted == isLockscreenHosted) { 134 return; 135 } 136 mIsActiveDreamLockscreenHosted = isLockscreenHosted; 137 updateKeyguardStatusAreaVisibility(); 138 }; 139 private final ContentObserver mDoubleLineClockObserver = new ContentObserver(null) { 140 @Override 141 public void onChange(boolean change) { 142 updateDoubleLineClock(); 143 } 144 }; 145 private final ContentObserver mShowWeatherObserver = new ContentObserver(null) { 146 @Override 147 public void onChange(boolean change) { 148 setWeatherVisibility(); 149 } 150 }; 151 152 private final KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener 153 mKeyguardUnlockAnimationListener = 154 new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() { 155 @Override 156 public void onUnlockAnimationFinished() { 157 // For performance reasons, reset this once the unlock animation ends. 158 setClipChildrenForUnlock(true); 159 } 160 }; 161 162 @Inject KeyguardClockSwitchController( KeyguardClockSwitch keyguardClockSwitch, StatusBarStateController statusBarStateController, ClockRegistry clockRegistry, KeyguardSliceViewController keyguardSliceViewController, NotificationIconAreaController notificationIconAreaController, LockscreenSmartspaceController smartspaceController, NotificationIconContainerAlwaysOnDisplayViewBinder nicViewBinder, KeyguardUnlockAnimationController keyguardUnlockAnimationController, SecureSettings secureSettings, @Main DelayableExecutor uiExecutor, @Background Executor bgExecutor, DumpManager dumpManager, ClockEventController clockEventController, @KeyguardClockLog LogBuffer logBuffer, KeyguardInteractor keyguardInteractor, KeyguardClockInteractor keyguardClockInteractor, FeatureFlagsClassic featureFlags, InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager)163 public KeyguardClockSwitchController( 164 KeyguardClockSwitch keyguardClockSwitch, 165 StatusBarStateController statusBarStateController, 166 ClockRegistry clockRegistry, 167 KeyguardSliceViewController keyguardSliceViewController, 168 NotificationIconAreaController notificationIconAreaController, 169 LockscreenSmartspaceController smartspaceController, 170 NotificationIconContainerAlwaysOnDisplayViewBinder nicViewBinder, 171 KeyguardUnlockAnimationController keyguardUnlockAnimationController, 172 SecureSettings secureSettings, 173 @Main DelayableExecutor uiExecutor, 174 @Background Executor bgExecutor, 175 DumpManager dumpManager, 176 ClockEventController clockEventController, 177 @KeyguardClockLog LogBuffer logBuffer, 178 KeyguardInteractor keyguardInteractor, 179 KeyguardClockInteractor keyguardClockInteractor, 180 FeatureFlagsClassic featureFlags, 181 InWindowLauncherUnlockAnimationManager inWindowLauncherUnlockAnimationManager) { 182 super(keyguardClockSwitch); 183 mStatusBarStateController = statusBarStateController; 184 mClockRegistry = clockRegistry; 185 mKeyguardSliceViewController = keyguardSliceViewController; 186 mNotificationIconAreaController = notificationIconAreaController; 187 mSmartspaceController = smartspaceController; 188 mNicViewBinder = nicViewBinder; 189 mSecureSettings = secureSettings; 190 mUiExecutor = uiExecutor; 191 mBgExecutor = bgExecutor; 192 mKeyguardUnlockAnimationController = keyguardUnlockAnimationController; 193 mDumpManager = dumpManager; 194 mClockEventController = clockEventController; 195 mLogBuffer = logBuffer; 196 mView.setLogBuffer(mLogBuffer); 197 mFeatureFlags = featureFlags; 198 mKeyguardInteractor = keyguardInteractor; 199 mKeyguardClockInteractor = keyguardClockInteractor; 200 mInWindowLauncherUnlockAnimationManager = inWindowLauncherUnlockAnimationManager; 201 202 mClockChangedListener = new ClockRegistry.ClockChangeListener() { 203 @Override 204 public void onCurrentClockChanged() { 205 if (!MigrateClocksToBlueprint.isEnabled()) { 206 setClock(mClockRegistry.createCurrentClock()); 207 } 208 } 209 @Override 210 public void onAvailableClocksChanged() { } 211 }; 212 } 213 214 /** 215 * When set, limits the information shown in an external display. 216 */ setShownOnSecondaryDisplay(boolean shownOnSecondaryDisplay)217 public void setShownOnSecondaryDisplay(boolean shownOnSecondaryDisplay) { 218 mShownOnSecondaryDisplay = shownOnSecondaryDisplay; 219 } 220 221 /** 222 * Mostly used for alternate displays, limit the information shown 223 * 224 * @deprecated use {@link KeyguardClockSwitchController#setShownOnSecondaryDisplay} 225 */ 226 @Deprecated setOnlyClock(boolean onlyClock)227 public void setOnlyClock(boolean onlyClock) { 228 mOnlyClock = onlyClock; 229 } 230 231 /** 232 * Used for status view to pass the screen offset from parent view 233 */ setLockscreenClockY(int clockY)234 public void setLockscreenClockY(int clockY) { 235 if (mView.screenOffsetYPadding != clockY) { 236 mView.screenOffsetYPadding = clockY; 237 mView.post(() -> mView.updateClockTargetRegions()); 238 } 239 } 240 241 /** 242 * Attach the controller to the view it relates to. 243 */ 244 @Override onInit()245 protected void onInit() { 246 mKeyguardSliceViewController.init(); 247 248 if (!MigrateClocksToBlueprint.isEnabled()) { 249 mSmallClockFrame = mView.findViewById(R.id.lockscreen_clock_view); 250 mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large); 251 } 252 253 if (!mOnlyClock) { 254 mDumpManager.unregisterDumpable(getClass().getSimpleName()); // unregister previous 255 mDumpManager.registerDumpable(getClass().getSimpleName(), this); 256 } 257 258 if (mFeatureFlags.isEnabled(LOCKSCREEN_WALLPAPER_DREAM_ENABLED)) { 259 mStatusArea = mView.findViewById(R.id.keyguard_status_area); 260 collectFlow(mStatusArea, mKeyguardInteractor.isActiveDreamLockscreenHosted(), 261 mIsActiveDreamLockscreenHostedCallback); 262 } 263 } 264 getView()265 public KeyguardClockSwitch getView() { 266 return mView; 267 } 268 hideSliceViewAndNotificationIconContainer()269 private void hideSliceViewAndNotificationIconContainer() { 270 View ksv = mView.findViewById(R.id.keyguard_slice_view); 271 ksv.setVisibility(View.GONE); 272 273 View nic = mView.findViewById( 274 R.id.left_aligned_notification_icon_container); 275 if (nic != null) { 276 nic.setVisibility(View.GONE); 277 } 278 } 279 280 @Override onViewAttached()281 protected void onViewAttached() { 282 mClockRegistry.registerClockChangeListener(mClockChangedListener); 283 setClock(mClockRegistry.createCurrentClock()); 284 if (!MigrateClocksToBlueprint.isEnabled()) { 285 mClockEventController.registerListeners(mView); 286 } 287 mKeyguardSmallClockTopMargin = 288 mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin); 289 mKeyguardLargeClockTopMargin = 290 mView.getResources().getDimensionPixelSize( 291 com.android.systemui.customization.R.dimen.keyguard_large_clock_top_margin); 292 mKeyguardDateWeatherViewInvisibility = 293 mView.getResources().getInteger(R.integer.keyguard_date_weather_view_invisibility); 294 295 if (mShownOnSecondaryDisplay) { 296 mView.setLargeClockOnSecondaryDisplay(true); 297 mClockEventController.setLargeClockOnSecondaryDisplay(true); 298 displayClock(LARGE, /* animate= */ false); 299 hideSliceViewAndNotificationIconContainer(); 300 return; 301 } 302 303 if (mOnlyClock) { 304 hideSliceViewAndNotificationIconContainer(); 305 return; 306 } 307 updateAodIcons(); 308 mStatusArea = mView.findViewById(R.id.keyguard_status_area); 309 310 mBgExecutor.execute(() -> { 311 mSecureSettings.registerContentObserverForUserSync( 312 Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, 313 false, /* notifyForDescendants */ 314 mDoubleLineClockObserver, 315 UserHandle.USER_ALL 316 ); 317 318 mSecureSettings.registerContentObserverForUserSync( 319 Settings.Secure.LOCK_SCREEN_WEATHER_ENABLED, 320 false, /* notifyForDescendants */ 321 mShowWeatherObserver, 322 UserHandle.USER_ALL 323 ); 324 }); 325 326 updateDoubleLineClock(); 327 328 mKeyguardUnlockAnimationController.addKeyguardUnlockAnimationListener( 329 mKeyguardUnlockAnimationListener); 330 331 if (mSmartspaceController.isEnabled()) { 332 View ksv = mView.findViewById(R.id.keyguard_slice_view); 333 int viewIndex = mStatusArea.indexOfChild(ksv); 334 ksv.setVisibility(View.GONE); 335 336 removeViewsFromStatusArea(); 337 addSmartspaceView(); 338 // TODO(b/261757708): add content observer for the Settings toggle and add/remove 339 // weather according to the Settings. 340 if (mSmartspaceController.isDateWeatherDecoupled()) { 341 addDateWeatherView(); 342 } 343 } 344 if (!MigrateClocksToBlueprint.isEnabled()) { 345 setDateWeatherVisibility(); 346 setWeatherVisibility(); 347 } 348 349 } 350 getNotificationIconAreaHeight()351 int getNotificationIconAreaHeight() { 352 if (MigrateClocksToBlueprint.isEnabled()) { 353 return 0; 354 } else if (NotificationIconContainerRefactor.isEnabled()) { 355 return mAodIconContainer != null ? mAodIconContainer.getHeight() : 0; 356 } else { 357 return mNotificationIconAreaController.getHeight(); 358 } 359 } 360 361 @Nullable getAodNotifIconContainer()362 View getAodNotifIconContainer() { 363 return mAodIconContainer; 364 } 365 366 @Override onViewDetached()367 protected void onViewDetached() { 368 mClockRegistry.unregisterClockChangeListener(mClockChangedListener); 369 if (!MigrateClocksToBlueprint.isEnabled()) { 370 mClockEventController.unregisterListeners(); 371 } 372 setClock(null); 373 374 mBgExecutor.execute(() -> { 375 mSecureSettings.unregisterContentObserverSync(mDoubleLineClockObserver); 376 mSecureSettings.unregisterContentObserverSync(mShowWeatherObserver); 377 }); 378 379 mKeyguardUnlockAnimationController.removeKeyguardUnlockAnimationListener( 380 mKeyguardUnlockAnimationListener); 381 } 382 onLocaleListChanged()383 void onLocaleListChanged() { 384 if (mSmartspaceController.isEnabled()) { 385 removeViewsFromStatusArea(); 386 addSmartspaceView(); 387 if (mSmartspaceController.isDateWeatherDecoupled()) { 388 mDateWeatherView.removeView(mWeatherView); 389 addDateWeatherView(); 390 setDateWeatherVisibility(); 391 setWeatherVisibility(); 392 } 393 } 394 } 395 addDateWeatherView()396 private void addDateWeatherView() { 397 if (MigrateClocksToBlueprint.isEnabled()) { 398 return; 399 } 400 mDateWeatherView = (ViewGroup) mSmartspaceController.buildAndConnectDateView(mView); 401 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 402 MATCH_PARENT, WRAP_CONTENT); 403 mStatusArea.addView(mDateWeatherView, 0, lp); 404 int startPadding = getContext().getResources().getDimensionPixelSize( 405 R.dimen.below_clock_padding_start); 406 int endPadding = getContext().getResources().getDimensionPixelSize( 407 R.dimen.below_clock_padding_end); 408 mDateWeatherView.setPaddingRelative(startPadding, 0, endPadding, 0); 409 addWeatherView(); 410 } 411 addWeatherView()412 private void addWeatherView() { 413 if (MigrateClocksToBlueprint.isEnabled()) { 414 return; 415 } 416 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 417 WRAP_CONTENT, WRAP_CONTENT); 418 mWeatherView = mSmartspaceController.buildAndConnectWeatherView(mView); 419 // Place weather right after the date, before the extras 420 final int index = mDateWeatherView.getChildCount() == 0 ? 0 : 1; 421 mDateWeatherView.addView(mWeatherView, index, lp); 422 mWeatherView.setPaddingRelative(0, 0, 4, 0); 423 } 424 addSmartspaceView()425 private void addSmartspaceView() { 426 if (MigrateClocksToBlueprint.isEnabled()) { 427 return; 428 } 429 430 if (smartspaceRelocateToBottom()) { 431 return; 432 } 433 434 mSmartspaceView = mSmartspaceController.buildAndConnectView(mView); 435 LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams( 436 MATCH_PARENT, WRAP_CONTENT); 437 mStatusArea.addView(mSmartspaceView, 0, lp); 438 int startPadding = getContext().getResources().getDimensionPixelSize( 439 R.dimen.below_clock_padding_start); 440 int endPadding = getContext().getResources().getDimensionPixelSize( 441 R.dimen.below_clock_padding_end); 442 mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0); 443 444 mKeyguardUnlockAnimationController.setLockscreenSmartspace(mSmartspaceView); 445 mInWindowLauncherUnlockAnimationManager.setLockscreenSmartspace(mSmartspaceView); 446 447 mView.setSmartspace(mSmartspaceView); 448 } 449 450 /** 451 * Apply dp changes on configuration change 452 */ onConfigChanged()453 public void onConfigChanged() { 454 mView.onConfigChanged(); 455 mKeyguardSmallClockTopMargin = 456 mView.getResources().getDimensionPixelSize(R.dimen.keyguard_clock_top_margin); 457 mKeyguardLargeClockTopMargin = 458 mView.getResources().getDimensionPixelSize( 459 com.android.systemui.customization.R.dimen.keyguard_large_clock_top_margin); 460 mKeyguardDateWeatherViewInvisibility = 461 mView.getResources().getInteger(R.integer.keyguard_date_weather_view_invisibility); 462 mView.updateClockTargetRegions(); 463 setDateWeatherVisibility(); 464 } 465 466 /** 467 * Enable or disable split shade center specific positioning 468 */ setSplitShadeCentered(boolean splitShadeCentered)469 public void setSplitShadeCentered(boolean splitShadeCentered) { 470 mView.setSplitShadeCentered(splitShadeCentered); 471 } 472 473 /** 474 * Set if the split shade is enabled 475 */ setSplitShadeEnabled(boolean splitShadeEnabled)476 public void setSplitShadeEnabled(boolean splitShadeEnabled) { 477 mSmartspaceController.setSplitShadeEnabled(splitShadeEnabled); 478 } 479 480 /** 481 * Set which clock should be displayed on the keyguard. The other one will be automatically 482 * hidden. 483 */ displayClock(@eyguardClockSwitch.ClockSize int clockSize, boolean animate)484 public void displayClock(@KeyguardClockSwitch.ClockSize int clockSize, boolean animate) { 485 if (!mCanShowDoubleLineClock && clockSize == KeyguardClockSwitch.LARGE) { 486 return; 487 } 488 489 mCurrentClockSize = clockSize; 490 setDateWeatherVisibility(); 491 492 ClockController clock = getClock(); 493 boolean appeared = mView.switchToClock(clockSize, animate); 494 if (clock != null && animate && appeared && clockSize == LARGE) { 495 mUiExecutor.executeDelayed(() -> clock.getLargeClock().getAnimations().enter(), 496 KeyguardClockSwitch.CLOCK_IN_START_DELAY_MILLIS); 497 } 498 } 499 500 /** 501 * Animates the clock view between folded and unfolded states 502 */ animateFoldToAod(float foldFraction)503 public void animateFoldToAod(float foldFraction) { 504 ClockController clock = getClock(); 505 if (clock != null) { 506 clock.getSmallClock().getAnimations().fold(foldFraction); 507 clock.getLargeClock().getAnimations().fold(foldFraction); 508 } 509 } 510 511 /** 512 * Refresh clock. Called in response to TIME_TICK broadcasts. 513 */ refresh()514 void refresh() { 515 mLogBuffer.log(TAG, LogLevel.INFO, "refresh"); 516 if (mSmartspaceController != null) { 517 mSmartspaceController.requestSmartspaceUpdate(); 518 } 519 ClockController clock = getClock(); 520 if (clock != null) { 521 clock.getSmallClock().getEvents().onTimeTick(); 522 clock.getLargeClock().getEvents().onTimeTick(); 523 } 524 } 525 526 /** 527 * Update position of the view, with optional animation. Move the slice view and the clock 528 * slightly towards the center in order to prevent burn-in. Y positioning occurs at the 529 * view parent level. The large clock view will scale instead of using x position offsets, to 530 * keep the clock centered. 531 */ updatePosition(int x, float scale, AnimationProperties props, boolean animate)532 void updatePosition(int x, float scale, AnimationProperties props, boolean animate) { 533 x = getCurrentLayoutDirection() == View.LAYOUT_DIRECTION_RTL ? -x : x; 534 if (!MigrateClocksToBlueprint.isEnabled()) { 535 PropertyAnimator.setProperty(mSmallClockFrame, AnimatableProperty.TRANSLATION_X, 536 x, props, animate); 537 PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_X, 538 scale, props, animate); 539 PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y, 540 scale, props, animate); 541 542 } 543 544 if (mStatusArea != null) { 545 PropertyAnimator.setProperty(mStatusArea, KeyguardStatusAreaView.TRANSLATE_X_AOD, 546 x, props, animate); 547 } 548 } 549 550 /** 551 * Get y-bottom position of the currently visible clock on the keyguard. 552 * We can't directly getBottom() because clock changes positions in AOD for burn-in 553 */ getClockBottom(int statusBarHeaderHeight)554 int getClockBottom(int statusBarHeaderHeight) { 555 ClockController clock = getClock(); 556 if (clock == null) { 557 return 0; 558 } 559 560 if (MigrateClocksToBlueprint.isEnabled()) { 561 return 0; 562 } 563 564 if (mLargeClockFrame.getVisibility() == View.VISIBLE) { 565 // This gets the expected clock bottom if mLargeClockFrame had a top margin, but it's 566 // top margin only contributed to height and didn't move the top of the view (as this 567 // was the computation previously). As we no longer have a margin, we add this back 568 // into the computation manually. 569 int frameHeight = mLargeClockFrame.getHeight(); 570 int clockHeight = clock.getLargeClock().getView().getHeight(); 571 return frameHeight / 2 + clockHeight / 2 + mKeyguardLargeClockTopMargin / -2; 572 } else { 573 int clockHeight = clock.getSmallClock().getView().getHeight(); 574 return clockHeight + statusBarHeaderHeight + mKeyguardSmallClockTopMargin; 575 } 576 } 577 578 /** 579 * Get the height of the currently visible clock on the keyguard. 580 */ getClockHeight()581 int getClockHeight() { 582 ClockController clock = getClock(); 583 if (clock == null) { 584 return 0; 585 } 586 587 if (mLargeClockFrame.getVisibility() == View.VISIBLE) { 588 return clock.getLargeClock().getView().getHeight(); 589 } else { 590 return clock.getSmallClock().getView().getHeight(); 591 } 592 } 593 isClockTopAligned()594 boolean isClockTopAligned() { 595 if (MigrateClocksToBlueprint.isEnabled()) { 596 return mKeyguardClockInteractor.getClockSize().getValue().getLegacyValue() == LARGE; 597 } 598 return mLargeClockFrame.getVisibility() != View.VISIBLE; 599 } 600 updateAodIcons()601 private void updateAodIcons() { 602 if (!MigrateClocksToBlueprint.isEnabled()) { 603 NotificationIconContainer nic = (NotificationIconContainer) 604 mView.findViewById( 605 com.android.systemui.res.R.id.left_aligned_notification_icon_container); 606 if (NotificationIconContainerRefactor.isEnabled()) { 607 if (mAodIconsBindHandle != null) { 608 mAodIconsBindHandle.dispose(); 609 } 610 if (nic != null) { 611 mAodIconsBindHandle = mNicViewBinder.bindWhileAttached(nic); 612 mAodIconContainer = nic; 613 } 614 } else { 615 mNotificationIconAreaController.setupAodIcons(nic); 616 mAodIconContainer = nic; 617 } 618 } 619 } 620 setClock(ClockController clock)621 private void setClock(ClockController clock) { 622 if (MigrateClocksToBlueprint.isEnabled()) { 623 return; 624 } 625 if (clock != null && mLogBuffer != null) { 626 mLogBuffer.log(TAG, LogLevel.INFO, "New Clock"); 627 } 628 629 mClockEventController.setClock(clock); 630 mView.setClock(clock, mStatusBarStateController.getState()); 631 setDateWeatherVisibility(); 632 } 633 634 @Nullable getClock()635 public ClockController getClock() { 636 if (MigrateClocksToBlueprint.isEnabled()) { 637 return mKeyguardClockInteractor.getCurrentClock().getValue(); 638 } else { 639 return mClockEventController.getClock(); 640 } 641 } 642 getCurrentLayoutDirection()643 private int getCurrentLayoutDirection() { 644 return TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()); 645 } 646 updateDoubleLineClock()647 private void updateDoubleLineClock() { 648 if (MigrateClocksToBlueprint.isEnabled()) { 649 return; 650 } 651 mCanShowDoubleLineClock = mSecureSettings.getIntForUser( 652 Settings.Secure.LOCKSCREEN_USE_DOUBLE_LINE_CLOCK, mView.getResources() 653 .getInteger(com.android.internal.R.integer.config_doublelineClockDefault), 654 UserHandle.USER_CURRENT) != 0; 655 656 if (!mCanShowDoubleLineClock) { 657 mUiExecutor.execute(() -> displayClock(KeyguardClockSwitch.SMALL, 658 /* animate */ true)); 659 } 660 } 661 setDateWeatherVisibility()662 private void setDateWeatherVisibility() { 663 if (mDateWeatherView != null) { 664 mUiExecutor.execute(() -> { 665 mDateWeatherView.setVisibility(clockHasCustomWeatherDataDisplay() 666 ? mKeyguardDateWeatherViewInvisibility 667 : View.VISIBLE); 668 }); 669 } 670 } 671 setWeatherVisibility()672 private void setWeatherVisibility() { 673 if (mWeatherView != null) { 674 mUiExecutor.execute(() -> { 675 mWeatherView.setVisibility( 676 mSmartspaceController.isWeatherEnabled() ? View.VISIBLE : View.GONE); 677 }); 678 } 679 } 680 updateKeyguardStatusAreaVisibility()681 private void updateKeyguardStatusAreaVisibility() { 682 if (mStatusArea != null) { 683 mUiExecutor.execute(() -> { 684 mStatusArea.setVisibility( 685 mIsActiveDreamLockscreenHosted ? View.INVISIBLE : View.VISIBLE); 686 }); 687 } 688 } 689 690 /** 691 * Sets the clipChildren property on relevant views, to allow the smartspace to draw out of 692 * bounds during the unlock transition. 693 */ setClipChildrenForUnlock(boolean clip)694 private void setClipChildrenForUnlock(boolean clip) { 695 if (mStatusArea != null) { 696 mStatusArea.setClipChildren(clip); 697 } 698 } 699 700 @Override dump(@onNull PrintWriter pw, @NonNull String[] args)701 public void dump(@NonNull PrintWriter pw, @NonNull String[] args) { 702 pw.println("currentClockSizeLarge: " + (mCurrentClockSize == LARGE)); 703 pw.println("mCanShowDoubleLineClock: " + mCanShowDoubleLineClock); 704 mView.dump(pw, args); 705 mClockRegistry.dump(pw, args); 706 ClockController clock = getClock(); 707 if (clock != null) { 708 clock.dump(pw); 709 } 710 final RegionSampler smallRegionSampler = mClockEventController.getSmallRegionSampler(); 711 if (smallRegionSampler != null) { 712 smallRegionSampler.dump(pw); 713 } 714 final RegionSampler largeRegionSampler = mClockEventController.getLargeRegionSampler(); 715 if (largeRegionSampler != null) { 716 largeRegionSampler.dump(pw); 717 } 718 } 719 720 /** Returns true if the clock handles the display of weather information */ clockHasCustomWeatherDataDisplay()721 private boolean clockHasCustomWeatherDataDisplay() { 722 ClockController clock = getClock(); 723 if (clock == null) { 724 return false; 725 } 726 727 return ((mCurrentClockSize == LARGE) ? clock.getLargeClock() : clock.getSmallClock()) 728 .getConfig().getHasCustomWeatherDataDisplay(); 729 } 730 removeViewsFromStatusArea()731 private void removeViewsFromStatusArea() { 732 for (int i = mStatusArea.getChildCount() - 1; i >= 0; i--) { 733 final View childView = mStatusArea.getChildAt(i); 734 if (childView.getTag(R.id.tag_smartspace_view) != null) { 735 mStatusArea.removeViewAt(i); 736 } 737 } 738 } 739 } 740