[DO NOT MERGE] Controls Lockscreen affordance
Place a button on the lockscreen similar to the wallet
affordance. Only enable the button if:
1. User has enabled the setting
2. Device control services are enabled
3. The user has favorited at least 1 control
Fixes: 194435266
Test: manual
Change-Id: Idc755656e2d3b7df77bf95d06f076b63349ece9a
(cherry picked from commit 9172eef0cd7130404fdc265087210729d076439b)
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 9ce83a7..3a4985f 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -82,18 +82,32 @@
<ImageView
android:id="@+id/wallet_button"
- android:layout_height="@dimen/keyguard_affordance_wallet_height"
- android:layout_width="@dimen/keyguard_affordance_wallet_width"
+ 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/wallet_lockscreen_bg"
+ 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/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/ic_device_light"
+ 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"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 06e4483..7ee6a9b 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -916,8 +916,8 @@
<dimen name="keyguard_affordance_height">48dp</dimen>
<dimen name="keyguard_affordance_width">48dp</dimen>
- <dimen name="keyguard_affordance_wallet_height">48dp</dimen>
- <dimen name="keyguard_affordance_wallet_width">48dp</dimen>
+ <dimen name="keyguard_affordance_fixed_height">48dp</dimen>
+ <dimen name="keyguard_affordance_fixed_width">48dp</dimen>
<dimen name="keyguard_affordance_horizontal_offset">32dp</dimen>
<dimen name="keyguard_affordance_vertical_offset">32dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 70ed817..51eabf6 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -764,6 +764,8 @@
<item name="android:windowBackground">@android:color/black</item>
<item name="android:windowAnimationStyle">@null</item>
<item name="android:statusBarColor">@android:color/black</item>
+ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
<item name="wallpaperTextColor">@*android:color/primary_text_material_dark</item>
</style>
@@ -898,5 +900,7 @@
<style name="Wallet.Theme" parent="@android:style/Theme.DeviceDefault">
<item name="android:colorBackground">@android:color/system_neutral1_900</item>
<item name="android:itemBackground">@android:color/system_neutral1_800</item>
+ <!-- Setting a placeholder will avoid using the SystemUI icon on the splash screen. -->
+ <item name="android:windowSplashScreenAnimatedIcon">@drawable/ic_blank</item>
</style>
</resources>
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 91d503b..0a4e59c 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 @@
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.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.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.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 @@
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 @@
private ActivityIntentHelper mActivityIntentHelper;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private ControlsListingController.ControlsListingCallback mListingCallback =
+ new ControlsListingController.ControlsListingCallback() {
+ public void onServicesUpdated(List<ControlsServiceInfo> serviceInfos) {
+ boolean available = !serviceInfos.isEmpty();
+
+ if (available != mControlServicesAvailable) {
+ mControlServicesAvailable = available;
+ updateControlsVisibility();
+ updateAffordanceColors();
+ }
+ }
+ };
+
public KeyguardBottomAreaView(Context context) {
this(context, null);
}
@@ -253,6 +278,7 @@
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 @@
mIndicationPadding = getResources().getDimensionPixelSize(
R.dimen.keyguard_indication_area_padding);
updateWalletVisibility();
+ updateControlsVisibility();
}
/**
@@ -328,6 +355,11 @@
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 @@
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 @@
|| !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 @@
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 @@
updateCameraVisibility();
updateLeftAffordanceIcon();
updateWalletVisibility();
+ updateControlsVisibility();
if (dozing) {
mOverlayContainer.setVisibility(INVISIBLE);
@@ -857,6 +916,7 @@
mRightAffordanceView.setAlpha(alpha);
mIndicationArea.setAlpha(alpha);
mWalletButton.setAlpha(alpha);
+ mControlsButton.setAlpha(alpha);
}
private class DefaultLeftButton implements IntentButton {
@@ -950,6 +1010,32 @@
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 @@
}
}
+ 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 8afdb87..e4d283e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -104,6 +104,7 @@
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;
@@ -326,6 +327,7 @@
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.
@@ -730,7 +732,8 @@
SecureSettings secureSettings,
SplitShadeHeaderController splitShadeHeaderController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- NotificationRemoteInputManager remoteInputManager) {
+ NotificationRemoteInputManager remoteInputManager,
+ ControlsComponent controlsComponent) {
super(view, falsingManager, dozeLog, keyguardStateController,
(SysuiStatusBarStateController) statusBarStateController, vibratorHelper,
statusBarKeyguardViewManager, latencyTracker, flingAnimationUtilsBuilder.get(),
@@ -740,6 +743,7 @@
mKeyguardMediaController = keyguardMediaController;
mPrivacyDotViewController = privacyDotViewController;
mQuickAccessWalletController = quickAccessWalletController;
+ mControlsComponent = controlsComponent;
mMetricsLogger = metricsLogger;
mActivityManager = activityManager;
mConfigurationController = configurationController;
@@ -1188,6 +1192,7 @@
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 d2f87ec..cbaca3a 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
@@ -88,6 +88,7 @@
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;
@@ -297,6 +298,8 @@
private NotificationRemoteInputManager mNotificationRemoteInputManager;
@Mock
private RecordingController mRecordingController;
+ @Mock
+ private ControlsComponent mControlsComponent;
private SysuiStatusBarStateController mStatusBarStateController;
private NotificationPanelViewController mNotificationPanelViewController;
@@ -440,7 +443,8 @@
mSecureSettings,
mSplitShadeHeaderController,
mUnlockedScreenOffAnimationController,
- mNotificationRemoteInputManager);
+ mNotificationRemoteInputManager,
+ mControlsComponent);
mNotificationPanelViewController.initDependencies(
mStatusBar,
mNotificationShelfController);