KeyguardBottomAreaView: cleanup.

1. Removes the feature flag
2. Removes dead code

Fix: 241137298
Test: Manually verified that the home controls button shows up in the
lock-screen, animates properly, and responds to clicks properly. The
device can be unlocked and re-loced.

Change-Id: I7a76bdf84ede1c67e5901487d5572a9c1704fc68
Merged-In: I7a76bdf84ede1c67e5901487d5572a9c1704fc68
This commit is contained in:
Alejandro Nijamkin
2022-09-06 13:47:59 -07:00
committed by Ale Nijamkin
parent d2a99344b0
commit 2470dfa8f0
8 changed files with 130 additions and 831 deletions

View File

@@ -83,48 +83,6 @@
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:visibility="gone" />
<ImageView
android:id="@+id/wallet_button"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
android:layout_gravity="bottom|end"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/ic_wallet_lockscreen"
android:background="@drawable/keyguard_bottom_affordance_bg"
android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:contentDescription="@string/accessibility_wallet_button"
android:visibility="gone" />
<ImageView
android:id="@+id/qr_code_scanner_button"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
android:layout_gravity="bottom|end"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/ic_qr_code_scanner"
android:background="@drawable/keyguard_bottom_affordance_bg"
android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:contentDescription="@string/accessibility_qr_code_scanner_button"
android:visibility="gone" />
<ImageView
android:id="@+id/controls_button"
android:layout_height="@dimen/keyguard_affordance_fixed_height"
android:layout_width="@dimen/keyguard_affordance_fixed_width"
android:layout_gravity="bottom|start"
android:scaleType="center"
android:tint="?android:attr/textColorPrimary"
android:src="@drawable/controls_icon"
android:background="@drawable/keyguard_bottom_affordance_bg"
android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
android:contentDescription="@string/quick_controls_title"
android:visibility="gone" />
<FrameLayout
android:id="@+id/overlay_container"
android:layout_width="match_parent"

View File

@@ -50,12 +50,10 @@ constructor(
viewsIdToTranslate =
setOf(
ViewIdToTranslate(R.id.keyguard_status_area, LEFT, filterNever),
ViewIdToTranslate(R.id.controls_button, LEFT, filterNever),
ViewIdToTranslate(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
ViewIdToTranslate(
R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever),
ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
progressProvider = unfoldProgressProvider)

View File

@@ -88,13 +88,6 @@ public class Flags {
public static final ResourceBooleanFlag FACE_SCANNING_ANIM =
new ResourceBooleanFlag(205, R.bool.config_enableFaceScanningAnimation);
/**
* Whether the KeyguardBottomArea(View|Controller) should use the modern architecture or the old
* one.
*/
public static final ReleasedFlag MODERN_BOTTOM_AREA = new ReleasedFlag(206, true);
public static final UnreleasedFlag LOCKSCREEN_CUSTOM_CLOCKS = new UnreleasedFlag(207);
/**

View File

@@ -116,7 +116,6 @@ import com.android.systemui.biometrics.AuthController;
import com.android.systemui.camera.CameraGestureHelper;
import com.android.systemui.classifier.Classifier;
import com.android.systemui.classifier.FalsingCollector;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.qualifiers.DisplayId;
import com.android.systemui.dagger.qualifiers.Main;
@@ -139,7 +138,6 @@ import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
import com.android.systemui.plugins.qs.QS;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
import com.android.systemui.screenrecord.RecordingController;
import com.android.systemui.shade.transition.ShadeTransitionController;
import com.android.systemui.shared.system.QuickStepContract;
@@ -216,7 +214,6 @@ import com.android.systemui.util.LargeScreenUtils;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.Utils;
import com.android.systemui.util.time.SystemClock;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import com.android.wm.shell.animation.FlingAnimationUtils;
import java.io.PrintWriter;
@@ -324,9 +321,6 @@ public final class NotificationPanelViewController extends PanelViewController {
private final FragmentService mFragmentService;
private final ScrimController mScrimController;
private final PrivacyDotViewController mPrivacyDotViewController;
private final QuickAccessWalletController mQuickAccessWalletController;
private final QRCodeScannerController mQRCodeScannerController;
private final ControlsComponent mControlsComponent;
private final NotificationRemoteInputManager mRemoteInputManager;
private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -695,8 +689,8 @@ public final class NotificationPanelViewController extends PanelViewController {
};
private final CameraGestureHelper mCameraGestureHelper;
private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@@ -745,8 +739,6 @@ public final class NotificationPanelViewController extends PanelViewController {
NavigationModeController navigationModeController,
FragmentService fragmentService,
ContentResolver contentResolver,
QuickAccessWalletController quickAccessWalletController,
QRCodeScannerController qrCodeScannerController,
RecordingController recordingController,
LargeScreenShadeHeaderController largeScreenShadeHeaderController,
ScreenOffAnimationController screenOffAnimationController,
@@ -754,7 +746,6 @@ public final class NotificationPanelViewController extends PanelViewController {
PanelExpansionStateManager panelExpansionStateManager,
NotificationRemoteInputManager remoteInputManager,
Optional<SysUIUnfoldComponent> unfoldComponent,
ControlsComponent controlsComponent,
InteractionJankMonitor interactionJankMonitor,
QsFrameTranslateController qsFrameTranslateController,
SysUiState sysUiState,
@@ -767,8 +758,8 @@ public final class NotificationPanelViewController extends PanelViewController {
ShadeTransitionController shadeTransitionController,
SystemClock systemClock,
CameraGestureHelper cameraGestureHelper,
Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) {
super(view,
falsingManager,
dozeLog,
@@ -790,9 +781,6 @@ public final class NotificationPanelViewController extends PanelViewController {
mVibratorHelper = vibratorHelper;
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
mQuickAccessWalletController = quickAccessWalletController;
mQRCodeScannerController = qrCodeScannerController;
mControlsComponent = controlsComponent;
mMetricsLogger = metricsLogger;
mConfigurationController = configurationController;
mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
@@ -896,7 +884,7 @@ public final class NotificationPanelViewController extends PanelViewController {
mQsFrameTranslateController = qsFrameTranslateController;
updateUserSwitcherFlags();
mKeyguardBottomAreaViewModelProvider = keyguardBottomAreaViewModelProvider;
mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
onFinishInflate();
keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -950,7 +938,7 @@ public final class NotificationPanelViewController extends PanelViewController {
}
});
mCameraGestureHelper = cameraGestureHelper;
mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
}
@VisibleForTesting
@@ -1275,17 +1263,7 @@ public final class NotificationPanelViewController extends PanelViewController {
}
private void initBottomArea() {
if (mFeatureFlags.isEnabled(Flags.MODERN_BOTTOM_AREA)) {
mKeyguardBottomArea.init(mKeyguardBottomAreaViewModelProvider.get(), mFalsingManager);
} else {
// TODO(b/235403546): remove this method call when the new implementation is complete
// and these are not needed.
mKeyguardBottomArea.init(
mFalsingManager,
mQuickAccessWalletController,
mControlsComponent,
mQRCodeScannerController);
}
mKeyguardBottomArea.init(mKeyguardBottomAreaViewModel, mFalsingManager);
}
@VisibleForTesting
@@ -1402,7 +1380,6 @@ public final class NotificationPanelViewController extends PanelViewController {
}
mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
mStackScrollerMeasuringPass++;
requestScrollerTopPaddingUpdate(animate);
@@ -1452,7 +1429,7 @@ public final class NotificationPanelViewController extends PanelViewController {
mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
mKeyguardStatusViewController.isClockTopAligned());
mClockPositionAlgorithm.run(mClockPositionResult);
mKeyguardBottomAreaInteractorProvider.get().setClockPosition(
mKeyguardBottomAreaInteractor.setClockPosition(
mClockPositionResult.clockX, mClockPositionResult.clockY);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
@@ -3295,8 +3272,7 @@ public final class NotificationPanelViewController extends PanelViewController {
getExpandedFraction());
float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
alpha *= mBottomAreaShadeAlpha;
mKeyguardBottomArea.setComponentAlphas(alpha);
mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
mKeyguardBottomAreaInteractor.setAlpha(alpha);
mLockIconViewController.setAlpha(alpha);
}
@@ -3495,8 +3471,7 @@ public final class NotificationPanelViewController extends PanelViewController {
}
private void updateDozingVisibilities(boolean animate) {
mKeyguardBottomArea.setDozing(mDozing, animate);
mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
if (!mDozing && animate) {
mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
}
@@ -3797,8 +3772,7 @@ public final class NotificationPanelViewController extends PanelViewController {
mView.setDozing(dozing);
mDozing = dozing;
mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
mKeyguardBottomArea.setDozing(mDozing, animate);
mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
mKeyguardStatusBarViewController.setDozing(mDozing);
if (dozing) {
@@ -3847,7 +3821,6 @@ public final class NotificationPanelViewController extends PanelViewController {
public void dozeTimeTick() {
mLockIconViewController.dozeTimeTick();
mKeyguardBottomArea.dozeTimeTick();
mKeyguardStatusViewController.dozeTimeTick();
if (mInterpolatedDarkAmount > 0) {
positionClockAndNotifications();
@@ -4670,7 +4643,6 @@ public final class NotificationPanelViewController extends PanelViewController {
public void onDozeAmountChanged(float linearAmount, float amount) {
mInterpolatedDarkAmount = amount;
mLinearDarkAmount = linearAmount;
mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
positionClockAndNotifications();
}
}

View File

@@ -1,682 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
import android.app.ActivityTaskManager;
import android.app.admin.DevicePolicyManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.os.UserHandle;
import android.service.quickaccesswallet.GetWalletCardsError;
import android.service.quickaccesswallet.GetWalletCardsResponse;
import android.service.quickaccesswallet.QuickAccessWalletClient;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.WindowInsets;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.controls.dagger.ControlsComponent;
import com.android.systemui.controls.management.ControlsListingController;
import com.android.systemui.controls.ui.ControlsActivity;
import com.android.systemui.controls.ui.ControlsUiController;
import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder;
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
import com.android.systemui.plugins.ActivityStarter;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.wallet.controller.QuickAccessWalletController;
import java.util.ArrayList;
import java.util.List;
/**
* Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
* text.
*/
public class KeyguardBottomAreaView extends FrameLayout {
private static final String TAG = "CentralSurfaces/KeyguardBottomAreaView";
private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
private ImageView mWalletButton;
private ImageView mQRCodeScannerButton;
private ImageView mControlsButton;
private boolean mHasCard = false;
private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
private QuickAccessWalletController mQuickAccessWalletController;
private QRCodeScannerController mQRCodeScannerController;
private ControlsComponent mControlsComponent;
private boolean mControlServicesAvailable = false;
@Nullable private View mAmbientIndicationArea;
private ViewGroup mIndicationArea;
private TextView mIndicationText;
private TextView mIndicationTextBottom;
private ViewGroup mOverlayContainer;
private ActivityStarter mActivityStarter;
private KeyguardStateController mKeyguardStateController;
private FalsingManager mFalsingManager;
private boolean mDozing;
private int mIndicationBottomMargin;
private int mIndicationPadding;
private float mDarkAmount;
private int mBurnInXOffset;
private int mBurnInYOffset;
private final ControlsListingController.ControlsListingCallback mListingCallback =
serviceInfos -> post(() -> {
boolean available = !serviceInfos.isEmpty();
if (available != mControlServicesAvailable) {
mControlServicesAvailable = available;
updateControlsVisibility();
updateAffordanceColors();
}
});
private final KeyguardStateController.Callback mKeyguardStateCallback =
new KeyguardStateController.Callback() {
@Override
public void onKeyguardShowingChanged() {
if (mKeyguardStateController.isShowing()) {
if (mQuickAccessWalletController != null) {
mQuickAccessWalletController.queryWalletCards(mCardRetriever);
}
}
}
};
@Nullable private KeyguardBottomAreaViewBinder.Binding mBinding;
private boolean mUsesBinder;
public KeyguardBottomAreaView(Context context) {
this(context, null);
}
public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
/**
* Initializes the view.
*/
public void init(
final KeyguardBottomAreaViewModel viewModel,
final FalsingManager falsingManager) {
Log.i(TAG, System.identityHashCode(this) + " initialized with a binder");
mUsesBinder = true;
mBinding = KeyguardBottomAreaViewBinder.bind(this, viewModel, falsingManager);
}
/**
* Initializes the {@link KeyguardBottomAreaView} with the given dependencies
*
* @deprecated Use
* {@link #init(KeyguardBottomAreaViewModel, FalsingManager)} instead
*/
@Deprecated
public void init(
FalsingManager falsingManager,
QuickAccessWalletController controller,
ControlsComponent controlsComponent,
QRCodeScannerController qrCodeScannerController) {
if (mUsesBinder) {
return;
}
Log.i(TAG, "initialized without a binder");
mFalsingManager = falsingManager;
mQuickAccessWalletController = controller;
mQuickAccessWalletController.setupWalletChangeObservers(
mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
mQuickAccessWalletController.updateWalletPreference();
mQuickAccessWalletController.queryWalletCards(mCardRetriever);
updateWalletVisibility();
mControlsComponent = controlsComponent;
mControlsComponent.getControlsListingController().ifPresent(
c -> c.addCallback(mListingCallback));
mQRCodeScannerController = qrCodeScannerController;
mQRCodeScannerController.registerQRCodeScannerChangeObservers(
QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
updateQRCodeButtonVisibility();
updateAffordanceColors();
}
/**
* Initializes this instance of {@link KeyguardBottomAreaView} based on the given instance of
* another {@link KeyguardBottomAreaView}
*/
public void initFrom(KeyguardBottomAreaView oldBottomArea) {
if (mUsesBinder) {
return;
}
// if it exists, continue to use the original ambient indication container
// instead of the newly inflated one
if (mAmbientIndicationArea != null) {
// remove old ambient indication from its parent
View originalAmbientIndicationView =
oldBottomArea.findViewById(R.id.ambient_indication_container);
((ViewGroup) originalAmbientIndicationView.getParent())
.removeView(originalAmbientIndicationView);
// remove current ambient indication from its parent (discard)
ViewGroup ambientIndicationParent = (ViewGroup) mAmbientIndicationArea.getParent();
int ambientIndicationIndex =
ambientIndicationParent.indexOfChild(mAmbientIndicationArea);
ambientIndicationParent.removeView(mAmbientIndicationArea);
// add the old ambient indication to this view
ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex);
mAmbientIndicationArea = originalAmbientIndicationView;
// update burn-in offsets
dozeTimeTick();
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (mUsesBinder) {
return;
}
mOverlayContainer = findViewById(R.id.overlay_container);
mWalletButton = findViewById(R.id.wallet_button);
mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button);
mControlsButton = findViewById(R.id.controls_button);
mIndicationArea = findViewById(R.id.keyguard_indication_area);
mAmbientIndicationArea = findViewById(R.id.ambient_indication_container);
mIndicationText = findViewById(R.id.keyguard_indication_text);
mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
mIndicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
mBurnInYOffset = getResources().getDimensionPixelSize(
R.dimen.default_burn_in_prevention_offset);
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
mKeyguardStateController.addCallback(mKeyguardStateCallback);
setClipChildren(false);
setClipToPadding(false);
mActivityStarter = Dependency.get(ActivityStarter.class);
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
updateWalletVisibility();
updateQRCodeButtonVisibility();
updateControlsVisibility();
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
if (mUsesBinder) {
return;
}
final IntentFilter filter = new IntentFilter();
filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
mKeyguardStateController.addCallback(mKeyguardStateCallback);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mUsesBinder) {
return;
}
mKeyguardStateController.removeCallback(mKeyguardStateCallback);
if (mQuickAccessWalletController != null) {
mQuickAccessWalletController.unregisterWalletChangeObservers(
WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
}
if (mQRCodeScannerController != null) {
mQRCodeScannerController.unregisterQRCodeScannerChangeObservers(
QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
}
if (mControlsComponent != null) {
mControlsComponent.getControlsListingController().ifPresent(
c -> c.removeCallback(mListingCallback));
}
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mUsesBinder) {
if (mBinding != null) {
mBinding.onConfigurationChanged();
}
return;
}
mIndicationBottomMargin = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_margin_bottom);
mBurnInYOffset = getResources().getDimensionPixelSize(
R.dimen.default_burn_in_prevention_offset);
MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
if (mlp.bottomMargin != mIndicationBottomMargin) {
mlp.bottomMargin = mIndicationBottomMargin;
mIndicationArea.setLayoutParams(mlp);
}
// Respect font size setting.
mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(
com.android.internal.R.dimen.text_size_small_material));
ViewGroup.LayoutParams lp = mWalletButton.getLayoutParams();
lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
mWalletButton.setLayoutParams(lp);
lp = mQRCodeScannerButton.getLayoutParams();
lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
mQRCodeScannerButton.setLayoutParams(lp);
lp = mControlsButton.getLayoutParams();
lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
mControlsButton.setLayoutParams(lp);
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
updateWalletVisibility();
updateQRCodeButtonVisibility();
updateAffordanceColors();
}
private void updateWalletVisibility() {
if (mUsesBinder) {
return;
}
if (mDozing
|| mQuickAccessWalletController == null
|| !mQuickAccessWalletController.isWalletEnabled()
|| !mHasCard) {
mWalletButton.setVisibility(GONE);
if (mControlsButton.getVisibility() == GONE) {
mIndicationArea.setPadding(0, 0, 0, 0);
}
} else {
mWalletButton.setVisibility(VISIBLE);
mWalletButton.setOnClickListener(this::onWalletClick);
mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
}
}
private void updateControlsVisibility() {
if (mUsesBinder) {
return;
}
if (mControlsComponent == null) return;
mControlsButton.setImageResource(mControlsComponent.getTileImageId());
mControlsButton.setContentDescription(getContext()
.getString(mControlsComponent.getTileTitleId()));
updateAffordanceColors();
boolean hasFavorites = mControlsComponent.getControlsController()
.map(c -> c.getFavorites().size() > 0)
.orElse(false);
if (mDozing
|| !hasFavorites
|| !mControlServicesAvailable
|| mControlsComponent.getVisibility() != AVAILABLE) {
mControlsButton.setVisibility(GONE);
if (mWalletButton.getVisibility() == GONE) {
mIndicationArea.setPadding(0, 0, 0, 0);
}
} else {
mControlsButton.setVisibility(VISIBLE);
mControlsButton.setOnClickListener(this::onControlsClick);
mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
}
}
public void setDarkAmount(float darkAmount) {
if (mUsesBinder) {
return;
}
if (darkAmount == mDarkAmount) {
return;
}
mDarkAmount = darkAmount;
dozeTimeTick();
}
/**
* Returns a list of animators to use to animate the indication areas.
*/
public List<ViewPropertyAnimator> getIndicationAreaAnimators() {
if (mUsesBinder) {
return checkNotNull(mBinding).getIndicationAreaAnimators();
}
List<ViewPropertyAnimator> animators =
new ArrayList<>(mAmbientIndicationArea != null ? 2 : 1);
animators.add(mIndicationArea.animate());
if (mAmbientIndicationArea != null) {
animators.add(mAmbientIndicationArea.animate());
}
return animators;
}
@Override
public boolean hasOverlappingRendering() {
return false;
}
private void startFinishDozeAnimation() {
long delay = 0;
if (mWalletButton.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mWalletButton, delay);
}
if (mQRCodeScannerButton.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mQRCodeScannerButton, delay);
}
if (mControlsButton.getVisibility() == View.VISIBLE) {
startFinishDozeAnimationElement(mControlsButton, delay);
}
}
private void startFinishDozeAnimationElement(View element, long delay) {
element.setAlpha(0f);
element.setTranslationY(element.getHeight() / 2);
element.animate()
.alpha(1f)
.translationY(0f)
.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
.setStartDelay(delay)
.setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
}
public void setDozing(boolean dozing, boolean animate) {
if (mUsesBinder) {
return;
}
mDozing = dozing;
updateWalletVisibility();
updateControlsVisibility();
updateQRCodeButtonVisibility();
if (dozing) {
mOverlayContainer.setVisibility(INVISIBLE);
} else {
mOverlayContainer.setVisibility(VISIBLE);
if (animate) {
startFinishDozeAnimation();
}
}
}
public void dozeTimeTick() {
if (mUsesBinder) {
return;
}
int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
- mBurnInYOffset;
mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
if (mAmbientIndicationArea != null) {
mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
}
}
public void setAntiBurnInOffsetX(int burnInXOffset) {
if (mUsesBinder) {
return;
}
if (mBurnInXOffset == burnInXOffset) {
return;
}
mBurnInXOffset = burnInXOffset;
mIndicationArea.setTranslationX(burnInXOffset);
if (mAmbientIndicationArea != null) {
mAmbientIndicationArea.setTranslationX(burnInXOffset);
}
}
/**
* Sets the alpha of various sub-components, for example the indication areas and bottom quick
* action buttons. Does not set the alpha of the lock icon.
*/
public void setComponentAlphas(float alpha) {
if (mUsesBinder) {
return;
}
setImportantForAccessibility(
alpha == 0f
? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
if (mAmbientIndicationArea != null) {
mAmbientIndicationArea.setAlpha(alpha);
}
mIndicationArea.setAlpha(alpha);
mWalletButton.setAlpha(alpha);
mQRCodeScannerButton.setAlpha(alpha);
mControlsButton.setAlpha(alpha);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int bottom = insets.getDisplayCutout() != null
? insets.getDisplayCutout().getSafeInsetBottom() : 0;
if (isPaddingRelative()) {
setPaddingRelative(getPaddingStart(), getPaddingTop(), getPaddingEnd(), bottom);
} else {
setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottom);
}
return insets;
}
private void updateQRCodeButtonVisibility() {
if (mUsesBinder) {
return;
}
if (mQuickAccessWalletController != null
&& mQuickAccessWalletController.isWalletEnabled()) {
// Don't enable if quick access wallet is enabled
return;
}
if (mQRCodeScannerController != null
&& mQRCodeScannerController.isEnabledForLockScreenButton()) {
mQRCodeScannerButton.setVisibility(VISIBLE);
mQRCodeScannerButton.setOnClickListener(this::onQRCodeScannerClicked);
mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
} else {
mQRCodeScannerButton.setVisibility(GONE);
if (mControlsButton.getVisibility() == GONE) {
mIndicationArea.setPadding(0, 0, 0, 0);
}
}
}
private void onQRCodeScannerClicked(View view) {
if (mUsesBinder) {
return;
}
Intent intent = mQRCodeScannerController.getIntent();
if (intent != null) {
try {
ActivityTaskManager.getService().startActivityAsUser(
null, getContext().getBasePackageName(),
getContext().getAttributionTag(), intent,
intent.resolveTypeIfNeeded(getContext().getContentResolver()),
null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
UserHandle.CURRENT.getIdentifier());
} catch (RemoteException e) {
// This is unexpected. Nonetheless, just log the error and prevent the UI from
// crashing
Log.e(TAG, "Unexpected intent: " + intent
+ " when the QR code scanner button was clicked");
}
}
}
private void updateAffordanceColors() {
if (mUsesBinder) {
return;
}
int iconColor = Utils.getColorAttrDefaultColor(
mContext,
com.android.internal.R.attr.textColorPrimary);
mWalletButton.getDrawable().setTint(iconColor);
mControlsButton.getDrawable().setTint(iconColor);
mQRCodeScannerButton.getDrawable().setTint(iconColor);
ColorStateList bgColor = Utils.getColorAttr(
mContext,
com.android.internal.R.attr.colorSurface);
mWalletButton.setBackgroundTintList(bgColor);
mControlsButton.setBackgroundTintList(bgColor);
mQRCodeScannerButton.setBackgroundTintList(bgColor);
}
private void onWalletClick(View v) {
if (mUsesBinder) {
return;
}
// More coming here; need to inform the user about how to proceed
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
}
ActivityLaunchAnimator.Controller animationController = createLaunchAnimationController(v);
mQuickAccessWalletController.startQuickAccessUiIntent(
mActivityStarter, animationController, mHasCard);
}
protected ActivityLaunchAnimator.Controller createLaunchAnimationController(View view) {
return ActivityLaunchAnimator.Controller.fromView(view, null);
}
private void onControlsClick(View v) {
if (mUsesBinder) {
return;
}
if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
return;
}
Intent intent = new Intent(mContext, ControlsActivity.class)
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
.putExtra(ControlsUiController.EXTRA_ANIMATE, true);
ActivityLaunchAnimator.Controller controller =
v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */)
: null;
if (mControlsComponent.getVisibility() == AVAILABLE) {
mActivityStarter.startActivity(intent, true /* dismissShade */, controller,
true /* showOverLockscreenWhenLocked */);
} else {
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller);
}
}
private class WalletCardRetriever implements
QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
@Override
public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
mHasCard = !response.getWalletCards().isEmpty();
Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
if (tileIcon != null) {
mWalletButton.setImageDrawable(tileIcon);
}
post(() -> {
updateWalletVisibility();
updateAffordanceColors();
});
}
@Override
public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
mHasCard = false;
post(() -> {
updateWalletVisibility();
updateAffordanceColors();
});
}
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.statusbar.phone
import android.content.Context
import android.content.res.Configuration
import android.util.AttributeSet
import android.view.View
import android.view.ViewGroup
import android.view.ViewPropertyAnimator
import android.view.WindowInsets
import android.widget.FrameLayout
import com.android.systemui.R
import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
import com.android.systemui.plugins.FalsingManager
/**
* Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
* elements. A secondary concern is the interaction of the quick affordance elements with the
* indication area between them, though the indication area is primarily controlled elsewhere.
*/
class KeyguardBottomAreaView
@JvmOverloads
constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
defStyleRes: Int = 0,
) :
FrameLayout(
context,
attrs,
defStyleAttr,
defStyleRes,
) {
private var ambientIndicationArea: View? = null
private lateinit var binding: KeyguardBottomAreaViewBinder.Binding
/** Initializes the view. */
fun init(
viewModel: KeyguardBottomAreaViewModel,
falsingManager: FalsingManager,
) {
binding = bind(this, viewModel, falsingManager)
}
/**
* Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
* [KeyguardBottomAreaView]
*/
fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
// if it exists, continue to use the original ambient indication container
// instead of the newly inflated one
ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
// remove old ambient indication from its parent
val originalAmbientIndicationView =
oldBottomArea.findViewById<View>(R.id.ambient_indication_container)
(originalAmbientIndicationView.parent as ViewGroup).removeView(
originalAmbientIndicationView
)
// remove current ambient indication from its parent (discard)
val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
val ambientIndicationIndex =
ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
// add the old ambient indication to this view
ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
ambientIndicationArea = originalAmbientIndicationView
}
}
override fun onFinishInflate() {
super.onFinishInflate()
ambientIndicationArea = findViewById(R.id.ambient_indication_container)
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
binding.onConfigurationChanged()
}
/** Returns a list of animators to use to animate the indication areas. */
val indicationAreaAnimators: List<ViewPropertyAnimator>
get() = binding.getIndicationAreaAnimators()
override fun hasOverlappingRendering(): Boolean {
return false
}
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
val bottom = insets.displayCutout?.safeInsetBottom ?: 0
if (isPaddingRelative) {
setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
} else {
setPadding(paddingLeft, paddingTop, paddingRight, bottom)
}
return insets
}
}

View File

@@ -547,8 +547,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mNavigationModeController,
mFragmentService,
mContentResolver,
mQuickAccessWalletController,
mQrCodeScannerController,
mRecordingController,
mLargeScreenShadeHeaderController,
mScreenOffAnimationController,
@@ -556,7 +554,6 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mPanelExpansionStateManager,
mNotificationRemoteInputManager,
mSysUIUnfoldComponent,
mControlsComponent,
mInteractionJankMonitor,
mQsFrameTranslateController,
mSysUiState,
@@ -569,8 +566,8 @@ public class NotificationPanelViewControllerTest extends SysuiTestCase {
mShadeTransitionController,
mSystemClock,
mock(CameraGestureHelper.class),
() -> mKeyguardBottomAreaViewModel,
() -> mKeyguardBottomAreaInteractor);
mKeyguardBottomAreaViewModel,
mKeyguardBottomAreaInteractor);
mNotificationPanelViewController.initDependencies(
mCentralSurfaces,
() -> {},

View File

@@ -1,54 +0,0 @@
package com.android.systemui.statusbar.phone
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper
import android.view.LayoutInflater
import androidx.test.filters.SmallTest
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.assist.AssistManager
import com.android.systemui.plugins.ActivityStarter
import com.android.systemui.statusbar.policy.AccessibilityController
import com.android.systemui.statusbar.policy.FlashlightController
import com.android.systemui.statusbar.policy.KeyguardStateController
import com.android.systemui.tuner.TunerService
import java.util.concurrent.Executor
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@SmallTest
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class KeyguardBottomAreaTest : SysuiTestCase() {
@Mock
private lateinit var mCentralSurfaces: CentralSurfaces
private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
@Before
fun setup() {
MockitoAnnotations.initMocks(this)
// Mocked dependencies
mDependency.injectMockDependency(AccessibilityController::class.java)
mDependency.injectMockDependency(ActivityStarter::class.java)
mDependency.injectMockDependency(AssistManager::class.java)
mDependency.injectTestDependency(Executor::class.java, Executor { it.run() })
mDependency.injectMockDependency(FlashlightController::class.java)
mDependency.injectMockDependency(KeyguardStateController::class.java)
mDependency.injectMockDependency(TunerService::class.java)
mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
}
@Test
fun initFrom_doesntCrash() {
val other = LayoutInflater.from(mContext).inflate(R.layout.keyguard_bottom_area,
null, false) as KeyguardBottomAreaView
other.initFrom(mKeyguardBottomArea)
}
}