Merge "Add quick access wallet tile." into sc-dev
This commit is contained in:
11
packages/SystemUI/res/drawable/ic_qs_wallet.xml
Normal file
11
packages/SystemUI/res/drawable/ic_qs_wallet.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,4L4,4c-1.11,0 -1.99,0.89 -1.99,2L2,18c0,1.11 0.89,2 2,2h16c1.11,0 2,
|
||||
-0.89 2,-2L22,6c0,-1.11 -0.89,-2 -2,-2zM20,18L4,18v-6h16v6zM20,8L4,8L4,6h16v2z"/>
|
||||
</vector>
|
||||
@@ -107,7 +107,7 @@
|
||||
|
||||
<!-- Tiles native to System UI. Order should match "quick_settings_tiles_default" -->
|
||||
<string name="quick_settings_tiles_stock" translatable="false">
|
||||
wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls,alarm
|
||||
wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,dark,work,cast,night,screenrecord,reverse,reduce_brightness,cameratoggle,mictoggle,controls,alarm,wallet
|
||||
</string>
|
||||
|
||||
<!-- The tiles to display in QuickSettings -->
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
<!-- People Tile flag -->
|
||||
<bool name="flag_conversations">false</bool>
|
||||
|
||||
<bool name="flag_wallet">false</bool>
|
||||
|
||||
<!-- The new animations to/from lockscreen and AOD! -->
|
||||
<bool name="flag_lockscreen_animations">false</bool>
|
||||
|
||||
|
||||
@@ -1621,6 +1621,12 @@
|
||||
<!-- Name of the alarm status bar icon. -->
|
||||
<string name="status_bar_alarm">Alarm</string>
|
||||
|
||||
<!-- Wallet strings -->
|
||||
<!-- Wallet empty state, title [CHAR LIMIT=32] -->
|
||||
<string name="wallet_title">Wallet</string>
|
||||
<!-- Secondary label of the quick access wallet tile. [CHAR LIMIT=32] -->
|
||||
<string name="wallet_secondary_label">Ready</string>
|
||||
|
||||
<!-- Name of the work status bar icon. -->
|
||||
<string name="status_bar_work">Work profile</string>
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.UserHandle;
|
||||
import android.service.quickaccesswallet.QuickAccessWalletClient;
|
||||
import android.view.Choreographer;
|
||||
import android.view.IWindowManager;
|
||||
import android.view.LayoutInflater;
|
||||
@@ -360,4 +361,11 @@ public class DependencyProvider {
|
||||
public ModeSwitchesController providesModeSwitchesController(Context context) {
|
||||
return new ModeSwitchesController(context);
|
||||
}
|
||||
|
||||
/** */
|
||||
@Provides
|
||||
@SysUISingleton
|
||||
public QuickAccessWalletClient provideQuickAccessWalletClient(Context context) {
|
||||
return QuickAccessWalletClient.create(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.android.systemui.qs.tiles.LocationTile;
|
||||
import com.android.systemui.qs.tiles.MicrophoneToggleTile;
|
||||
import com.android.systemui.qs.tiles.NfcTile;
|
||||
import com.android.systemui.qs.tiles.NightDisplayTile;
|
||||
import com.android.systemui.qs.tiles.QuickAccessWalletTile;
|
||||
import com.android.systemui.qs.tiles.ReduceBrightColorsTile;
|
||||
import com.android.systemui.qs.tiles.RotationLockTile;
|
||||
import com.android.systemui.qs.tiles.ScreenRecordTile;
|
||||
@@ -93,6 +94,7 @@ public class QSFactoryImpl implements QSFactory {
|
||||
private final Provider<MicrophoneToggleTile> mMicrophoneToggleTileProvider;
|
||||
private final Provider<DeviceControlsTile> mDeviceControlsTileProvider;
|
||||
private final Provider<AlarmTile> mAlarmTileProvider;
|
||||
private final Provider<QuickAccessWalletTile> mQuickAccessWalletTileProvider;
|
||||
|
||||
private final Lazy<QSHost> mQsHostLazy;
|
||||
private final Provider<CustomTile.Builder> mCustomTileBuilderProvider;
|
||||
@@ -129,7 +131,8 @@ public class QSFactoryImpl implements QSFactory {
|
||||
Provider<CameraToggleTile> cameraToggleTileProvider,
|
||||
Provider<MicrophoneToggleTile> microphoneToggleTileProvider,
|
||||
Provider<DeviceControlsTile> deviceControlsTileProvider,
|
||||
Provider<AlarmTile> alarmTileProvider) {
|
||||
Provider<AlarmTile> alarmTileProvider,
|
||||
Provider<QuickAccessWalletTile> quickAccessWalletTileProvider) {
|
||||
mQsHostLazy = qsHostLazy;
|
||||
mCustomTileBuilderProvider = customTileBuilderProvider;
|
||||
|
||||
@@ -161,6 +164,7 @@ public class QSFactoryImpl implements QSFactory {
|
||||
mMicrophoneToggleTileProvider = microphoneToggleTileProvider;
|
||||
mDeviceControlsTileProvider = deviceControlsTileProvider;
|
||||
mAlarmTileProvider = alarmTileProvider;
|
||||
mQuickAccessWalletTileProvider = quickAccessWalletTileProvider;
|
||||
}
|
||||
|
||||
public QSTile createTile(String tileSpec) {
|
||||
@@ -224,6 +228,8 @@ public class QSFactoryImpl implements QSFactory {
|
||||
return mDeviceControlsTileProvider.get();
|
||||
case "alarm":
|
||||
return mAlarmTileProvider.get();
|
||||
case "wallet":
|
||||
return mQuickAccessWalletTileProvider.get();
|
||||
}
|
||||
|
||||
// Custom tiles
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.qs.tiles;
|
||||
|
||||
import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.service.quickaccesswallet.QuickAccessWalletClient;
|
||||
import android.service.quicksettings.Tile;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.dagger.qualifiers.Background;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.FalsingManager;
|
||||
import com.android.systemui.plugins.qs.QSTile;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.qs.QSHost;
|
||||
import com.android.systemui.qs.logging.QSLogger;
|
||||
import com.android.systemui.qs.tileimpl.QSTileImpl;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Quick settings tile: Quick access wallet **/
|
||||
public class QuickAccessWalletTile extends QSTileImpl<QSTile.State> {
|
||||
|
||||
private static final String FEATURE_CHROME_OS = "org.chromium.arc";
|
||||
private final CharSequence mLabel = mContext.getString(R.string.wallet_title);
|
||||
// TODO(b/180959290): Re-create the QAW Client when the default NFC payment app changes.
|
||||
private final QuickAccessWalletClient mQuickAccessWalletClient;
|
||||
private final KeyguardStateController mKeyguardStateController;
|
||||
private final PackageManager mPackageManager;
|
||||
private final SecureSettings mSecureSettings;
|
||||
private final FeatureFlags mFeatureFlags;
|
||||
|
||||
@Inject
|
||||
public QuickAccessWalletTile(
|
||||
QSHost host,
|
||||
@Background Looper backgroundLooper,
|
||||
@Main Handler mainHandler,
|
||||
FalsingManager falsingManager,
|
||||
MetricsLogger metricsLogger,
|
||||
StatusBarStateController statusBarStateController,
|
||||
ActivityStarter activityStarter,
|
||||
QSLogger qsLogger,
|
||||
QuickAccessWalletClient quickAccessWalletClient,
|
||||
KeyguardStateController keyguardStateController,
|
||||
PackageManager packageManager,
|
||||
SecureSettings secureSettings,
|
||||
FeatureFlags featureFlags) {
|
||||
super(host, backgroundLooper, mainHandler, falsingManager, metricsLogger,
|
||||
statusBarStateController, activityStarter, qsLogger);
|
||||
mQuickAccessWalletClient = quickAccessWalletClient;
|
||||
mKeyguardStateController = keyguardStateController;
|
||||
mPackageManager = packageManager;
|
||||
mSecureSettings = secureSettings;
|
||||
mFeatureFlags = featureFlags;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public State newTileState() {
|
||||
State state = new State();
|
||||
state.handlesLongClick = false;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleClick() {
|
||||
mActivityStarter.postStartActivityDismissingKeyguard(
|
||||
mQuickAccessWalletClient.createWalletIntent(), /* delay= */ 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleUpdateState(State state, Object arg) {
|
||||
CharSequence qawLabel = mQuickAccessWalletClient.getServiceLabel();
|
||||
state.label = qawLabel == null ? mLabel : qawLabel;
|
||||
state.contentDescription = state.label;
|
||||
state.icon = ResourceIcon.get(R.drawable.ic_qs_wallet);
|
||||
boolean isDeviceLocked = !mKeyguardStateController.isUnlocked();
|
||||
if (mQuickAccessWalletClient.isWalletFeatureAvailable()) {
|
||||
state.state = isDeviceLocked ? Tile.STATE_INACTIVE : Tile.STATE_ACTIVE;
|
||||
state.secondaryLabel = isDeviceLocked
|
||||
? null
|
||||
: mContext.getString(R.string.wallet_secondary_label);
|
||||
state.stateDescription = state.secondaryLabel;
|
||||
} else {
|
||||
state.state = Tile.STATE_UNAVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMetricsCategory() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAvailable() {
|
||||
return mFeatureFlags.isQuickAccessWalletEnabled()
|
||||
&& mPackageManager.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)
|
||||
&& !mPackageManager.hasSystemFeature(FEATURE_CHROME_OS)
|
||||
&& mSecureSettings.getString(NFC_PAYMENT_DEFAULT_COMPONENT) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getLongClickIntent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTileLabel() {
|
||||
CharSequence qawLabel = mQuickAccessWalletClient.getServiceLabel();
|
||||
return qawLabel == null ? mLabel : qawLabel;
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,10 @@ public class FeatureFlags {
|
||||
return mFlagReader.isEnabled(R.bool.flag_monet);
|
||||
}
|
||||
|
||||
public boolean isQuickAccessWalletEnabled() {
|
||||
return mFlagReader.isEnabled(R.bool.flag_wallet);
|
||||
}
|
||||
|
||||
public boolean isNavigationBarOverlayEnabled() {
|
||||
return mFlagReader.isEnabled(R.bool.flag_navigation_bar_overlay);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* Copyright (C) 2021 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.qs.tiles;
|
||||
|
||||
import static android.content.pm.PackageManager.FEATURE_NFC_HOST_CARD_EMULATION;
|
||||
import static android.provider.Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT;
|
||||
|
||||
import static junit.framework.TestCase.assertEquals;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNull;
|
||||
import static junit.framework.TestCase.assertTrue;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Handler;
|
||||
import android.service.quickaccesswallet.QuickAccessWalletClient;
|
||||
import android.service.quicksettings.Tile;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.testing.TestableLooper;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.UiEventLogger;
|
||||
import com.android.internal.logging.testing.UiEventLoggerFake;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SysuiTestCase;
|
||||
import com.android.systemui.classifier.FalsingManagerFake;
|
||||
import com.android.systemui.plugins.ActivityStarter;
|
||||
import com.android.systemui.plugins.qs.QSTile;
|
||||
import com.android.systemui.plugins.statusbar.StatusBarStateController;
|
||||
import com.android.systemui.qs.QSTileHost;
|
||||
import com.android.systemui.qs.logging.QSLogger;
|
||||
import com.android.systemui.qs.tileimpl.QSTileImpl;
|
||||
import com.android.systemui.statusbar.FeatureFlags;
|
||||
import com.android.systemui.statusbar.policy.KeyguardStateController;
|
||||
import com.android.systemui.util.settings.SecureSettings;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
|
||||
@RunWith(AndroidTestingRunner.class)
|
||||
@TestableLooper.RunWithLooper(setAsMainLooper = true)
|
||||
@SmallTest
|
||||
public class QuickAccessWalletTileTest extends SysuiTestCase {
|
||||
|
||||
@Mock
|
||||
private QSTileHost mHost;
|
||||
@Mock
|
||||
private MetricsLogger mMetricsLogger;
|
||||
@Mock
|
||||
private StatusBarStateController mStatusBarStateController;
|
||||
@Mock
|
||||
private ActivityStarter mActivityStarter;
|
||||
@Mock
|
||||
private QSLogger mQSLogger;
|
||||
private UiEventLogger mUiEventLogger = new UiEventLoggerFake();
|
||||
@Mock
|
||||
private QuickAccessWalletClient mQuickAccessWalletClient;
|
||||
@Mock
|
||||
private KeyguardStateController mKeyguardStateController;
|
||||
@Mock
|
||||
private PackageManager mPackageManager;
|
||||
@Mock
|
||||
private SecureSettings mSecureSettings;
|
||||
@Mock
|
||||
private FeatureFlags mFeatureFlags;
|
||||
|
||||
private TestableLooper mTestableLooper;
|
||||
private QuickAccessWalletTile mTile;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
|
||||
mTestableLooper = TestableLooper.get(this);
|
||||
|
||||
when(mHost.getContext()).thenReturn(mContext);
|
||||
when(mHost.getUiEventLogger()).thenReturn(mUiEventLogger);
|
||||
when(mFeatureFlags.isQuickAccessWalletEnabled()).thenReturn(true);
|
||||
|
||||
mTile = new QuickAccessWalletTile(
|
||||
mHost,
|
||||
mTestableLooper.getLooper(),
|
||||
new Handler(mTestableLooper.getLooper()),
|
||||
new FalsingManagerFake(),
|
||||
mMetricsLogger,
|
||||
mStatusBarStateController,
|
||||
mActivityStarter,
|
||||
mQSLogger,
|
||||
mQuickAccessWalletClient,
|
||||
mKeyguardStateController,
|
||||
mPackageManager,
|
||||
mSecureSettings,
|
||||
mFeatureFlags);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNewTile() {
|
||||
assertFalse(mTile.newTileState().handlesLongClick);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_featureFlagIsOff() {
|
||||
when(mFeatureFlags.isQuickAccessWalletEnabled()).thenReturn(false);
|
||||
assertFalse(mTile.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_qawServiceNotAvailable() {
|
||||
when(mQuickAccessWalletClient.isWalletServiceAvailable()).thenReturn(false);
|
||||
assertFalse(mTile.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsAvailable_qawServiceAvailable() {
|
||||
when(mPackageManager.hasSystemFeature(FEATURE_NFC_HOST_CARD_EMULATION)).thenReturn(true);
|
||||
when(mPackageManager.hasSystemFeature("org.chromium.arc")).thenReturn(false);
|
||||
when(mSecureSettings.getString(NFC_PAYMENT_DEFAULT_COMPONENT)).thenReturn("Component");
|
||||
|
||||
assertTrue(mTile.isAvailable());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleClick_openGPay() {
|
||||
Intent intent = new Intent("WalletIntent");
|
||||
when(mQuickAccessWalletClient.createWalletIntent()).thenReturn(intent);
|
||||
mTile.handleClick();
|
||||
|
||||
verify(mActivityStarter, times(1))
|
||||
.postStartActivityDismissingKeyguard(eq(intent), anyInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleUpdateState_updateLabelAndIcon() {
|
||||
QSTile.Icon icon = QSTileImpl.ResourceIcon.get(R.drawable.ic_qs_wallet);
|
||||
QSTile.State state = new QSTile.State();
|
||||
when(mQuickAccessWalletClient.getServiceLabel()).thenReturn("QuickAccessWallet");
|
||||
|
||||
mTile.handleUpdateState(state, new Object());
|
||||
|
||||
assertEquals("QuickAccessWallet", state.label.toString());
|
||||
assertTrue(state.label.toString().contentEquals(state.contentDescription));
|
||||
assertEquals(icon, state.icon);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleUpdateState_deviceLocked_tileInactive() {
|
||||
QSTile.State state = new QSTile.State();
|
||||
when(mKeyguardStateController.isUnlocked()).thenReturn(false);
|
||||
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
|
||||
|
||||
mTile.handleUpdateState(state, new Object());
|
||||
|
||||
assertEquals(Tile.STATE_INACTIVE, state.state);
|
||||
assertNull(state.stateDescription);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleUpdateState_deviceLocked_tileActive() {
|
||||
QSTile.State state = new QSTile.State();
|
||||
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
|
||||
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(true);
|
||||
|
||||
mTile.handleUpdateState(state, new Object());
|
||||
|
||||
assertEquals(Tile.STATE_ACTIVE, state.state);
|
||||
assertTrue(state.secondaryLabel.toString().contentEquals(state.stateDescription));
|
||||
assertEquals(
|
||||
getContext().getString(R.string.wallet_secondary_label),
|
||||
state.secondaryLabel.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHandleUpdateState_qawFeatureUnavailable_tileUnavailable() {
|
||||
QSTile.State state = new QSTile.State();
|
||||
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
|
||||
when(mQuickAccessWalletClient.isWalletFeatureAvailable()).thenReturn(false);
|
||||
|
||||
mTile.handleUpdateState(state, new Object());
|
||||
|
||||
assertEquals(Tile.STATE_UNAVAILABLE, state.state);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user