diff --git a/packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml b/packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml similarity index 100% rename from packages/SystemUI/res/drawable/wallet_lockscreen_bg.xml rename to packages/SystemUI/res/drawable/keyguard_bottom_affordance_bg.xml diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml index 9ce83a789f59d..3a4985f35c35b 100644 --- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml +++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml @@ -82,18 +82,32 @@ + + 48dp 48dp - 48dp - 48dp + 48dp + 48dp 32dp 32dp diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 70ed81788e58d..51eabf60385ec 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -764,6 +764,8 @@ @android:color/black @null @android:color/black + + @drawable/ic_blank @*android:color/primary_text_material_dark @@ -898,5 +900,7 @@ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index 91d503bac4fe6..0a4e59c0391e6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK; import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; +import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE; import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON; import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK; @@ -40,6 +41,7 @@ import android.content.ServiceConnection; import android.content.pm.ActivityInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.graphics.drawable.Drawable; import android.os.AsyncTask; @@ -81,6 +83,11 @@ import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.assist.AssistManager; import com.android.systemui.camera.CameraIntents; +import com.android.systemui.controls.ControlsServiceInfo; +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.plugins.ActivityStarter; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.plugins.IntentButtonProvider; @@ -98,6 +105,8 @@ import com.android.systemui.tuner.TunerService; import com.android.systemui.wallet.controller.QuickAccessWalletController; import com.android.systemui.wallet.ui.WalletActivity; +import java.util.List; + /** * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status * text. @@ -133,9 +142,12 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private KeyguardAffordanceView mLeftAffordanceView; private ImageView mWalletButton; + private ImageView mControlsButton; private boolean mHasCard = false; private WalletCardRetriever mCardRetriever = new WalletCardRetriever(); private QuickAccessWalletController mQuickAccessWalletController; + private ControlsComponent mControlsComponent; + private boolean mControlServicesAvailable = false; private ViewGroup mIndicationArea; private TextView mIndicationText; @@ -188,6 +200,19 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL private ActivityIntentHelper mActivityIntentHelper; private KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private ControlsListingController.ControlsListingCallback mListingCallback = + new ControlsListingController.ControlsListingCallback() { + public void onServicesUpdated(List serviceInfos) { + boolean available = !serviceInfos.isEmpty(); + + if (available != mControlServicesAvailable) { + mControlServicesAvailable = available; + updateControlsVisibility(); + updateAffordanceColors(); + } + } + }; + public KeyguardBottomAreaView(Context context) { this(context, null); } @@ -253,6 +278,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mRightAffordanceView = findViewById(R.id.camera_button); mLeftAffordanceView = findViewById(R.id.left_button); mWalletButton = findViewById(R.id.wallet_button); + mControlsButton = findViewById(R.id.controls_button); mIndicationArea = findViewById(R.id.keyguard_indication_area); mIndicationText = findViewById(R.id.keyguard_indication_text); mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom); @@ -276,6 +302,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mIndicationPadding = getResources().getDimensionPixelSize( R.dimen.keyguard_indication_area_padding); updateWalletVisibility(); + updateControlsVisibility(); } /** @@ -328,6 +355,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mQuickAccessWalletController.unregisterWalletChangeObservers( WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE); } + + if (mControlsComponent != null) { + mControlsComponent.getControlsListingController().ifPresent( + c -> c.removeCallback(mListingCallback)); + } } private void initAccessibility() { @@ -369,13 +401,20 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateLeftAffordanceIcon(); lp = mWalletButton.getLayoutParams(); - lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width); - lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_wallet_width); + lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width); + lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height); mWalletButton.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(); + updateAffordanceColors(); } private void updateRightAffordanceIcon() { @@ -454,22 +493,38 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL || !mQuickAccessWalletController.isWalletEnabled() || !mHasCard) { mWalletButton.setVisibility(GONE); - mIndicationArea.setPadding(0, 0, 0, 0); - } else { - Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon(); - if (tileIcon != null) { - mWalletButton.setImageDrawable(tileIcon); + + if (mControlsButton.getVisibility() == GONE) { + mIndicationArea.setPadding(0, 0, 0, 0); } - mWalletButton.getDrawable().setTint( - Utils.getColorAttr( - mContext, - com.android.internal.R.attr.textColorPrimary).getDefaultColor()); + } else { mWalletButton.setVisibility(VISIBLE); mWalletButton.setOnClickListener(this::onWalletClick); mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0); } } + private void updateControlsVisibility() { + if (mControlsComponent == null) return; + + 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 boolean isLeftVoiceAssist() { return mLeftIsVoiceAssist; } @@ -751,6 +806,9 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL if (mWalletButton.getVisibility() == View.VISIBLE) { startFinishDozeAnimationElement(mWalletButton, delay); } + if (mControlsButton.getVisibility() == View.VISIBLE) { + startFinishDozeAnimationElement(mControlsButton, delay); + } if (mLeftAffordanceView.getVisibility() == View.VISIBLE) { startFinishDozeAnimationElement(mLeftAffordanceView, delay); delay += DOZE_ANIMATION_STAGGER_DELAY; @@ -824,6 +882,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL updateCameraVisibility(); updateLeftAffordanceIcon(); updateWalletVisibility(); + updateControlsVisibility(); if (dozing) { mOverlayContainer.setVisibility(INVISIBLE); @@ -857,6 +916,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mRightAffordanceView.setAlpha(alpha); mIndicationArea.setAlpha(alpha); mWalletButton.setAlpha(alpha); + mControlsButton.setAlpha(alpha); } private class DefaultLeftButton implements IntentButton { @@ -950,6 +1010,32 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL mQuickAccessWalletController.queryWalletCards(mCardRetriever); updateWalletVisibility(); + updateAffordanceColors(); + } + + private void updateAffordanceColors() { + int iconColor = Utils.getColorAttrDefaultColor( + mContext, + com.android.internal.R.attr.textColorPrimary); + mWalletButton.getDrawable().setTint(iconColor); + mControlsButton.getDrawable().setTint(iconColor); + + ColorStateList bgColor = Utils.getColorAttr( + mContext, + com.android.internal.R.attr.colorSurface); + mWalletButton.setBackgroundTintList(bgColor); + mControlsButton.setBackgroundTintList(bgColor); + } + + /** + * Initialize controls via the ControlsComponent + */ + public void initControls(ControlsComponent controlsComponent) { + mControlsComponent = controlsComponent; + mControlsComponent.getControlsListingController().ifPresent( + c -> c.addCallback(mListingCallback)); + + updateAffordanceColors(); } private void onWalletClick(View v) { @@ -974,19 +1060,41 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL } } + private void onControlsClick(View v) { + 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); + + if (mControlsComponent.getVisibility() == AVAILABLE) { + mContext.startActivity(intent); + } else { + mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */); + } + } + 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); + } updateWalletVisibility(); + updateAffordanceColors(); } @Override public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) { mHasCard = false; updateWalletVisibility(); + updateAffordanceColors(); } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 7958301370f5f..11e6b7d920f8a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -97,6 +97,7 @@ import com.android.systemui.animation.Interpolators; import com.android.systemui.biometrics.AuthController; import com.android.systemui.classifier.Classifier; import com.android.systemui.classifier.FalsingCollector; +import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.doze.DozeLog; @@ -321,6 +322,7 @@ public class NotificationPanelViewController extends PanelViewController { private final ScrimController mScrimController; private final PrivacyDotViewController mPrivacyDotViewController; private final QuickAccessWalletController mQuickAccessWalletController; + private final ControlsComponent mControlsComponent; private final NotificationRemoteInputManager mRemoteInputManager; // Maximum # notifications to show on Keyguard; extras will be collapsed in an overflow card. @@ -717,7 +719,8 @@ public class NotificationPanelViewController extends PanelViewController { @Main Executor uiExecutor, SecureSettings secureSettings, UnlockedScreenOffAnimationController unlockedScreenOffAnimationController, - NotificationRemoteInputManager remoteInputManager) { + NotificationRemoteInputManager remoteInputManager, + ControlsComponent controlsComponent) { super(view, falsingManager, dozeLog, keyguardStateController, (SysuiStatusBarStateController) statusBarStateController, vibratorHelper, statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(), @@ -727,6 +730,7 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardMediaController = keyguardMediaController; mPrivacyDotViewController = privacyDotViewController; mQuickAccessWalletController = quickAccessWalletController; + mControlsComponent = controlsComponent; mMetricsLogger = metricsLogger; mActivityManager = activityManager; mConfigurationController = configurationController; @@ -1177,6 +1181,7 @@ public class NotificationPanelViewController extends PanelViewController { mKeyguardBottomArea.setUserSetupComplete(mUserSetupComplete); mKeyguardBottomArea.setFalsingManager(mFalsingManager); mKeyguardBottomArea.initWallet(mQuickAccessWalletController); + mKeyguardBottomArea.initControls(mControlsComponent); } private void updateMaxDisplayedNotifications(boolean recompute) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java index f8fc22495d8dc..76fc4d44b96b5 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java @@ -85,6 +85,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.biometrics.AuthController; import com.android.systemui.classifier.FalsingCollectorFake; import com.android.systemui.classifier.FalsingManagerFake; +import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.doze.DozeLog; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.fragments.FragmentService; @@ -298,6 +299,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { private RemoteInputController mRemoteInputController; @Mock private RecordingController mRecordingController; + @Mock + private ControlsComponent mControlsComponent; private SysuiStatusBarStateController mStatusBarStateController; private NotificationPanelViewController mNotificationPanelViewController; @@ -440,7 +443,8 @@ public class NotificationPanelViewTest extends SysuiTestCase { new FakeExecutor(new FakeSystemClock()), mSecureSettings, mUnlockedScreenOffAnimationController, - mNotificationRemoteInputManager); + mNotificationRemoteInputManager, + mControlsComponent); mNotificationPanelViewController.initDependencies( mStatusBar, mNotificationShelfController);