[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
This commit is contained in:
Matt Pietal
2021-07-23 14:47:37 -04:00
parent f192f0803a
commit 9172eef0cd
7 changed files with 153 additions and 18 deletions

View File

@@ -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"

View File

@@ -906,8 +906,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>

View File

@@ -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>

View File

@@ -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<ControlsServiceInfo> 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();
}
}
}

View File

@@ -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) {

View File

@@ -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);