• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.plugin.globalactions.wallet;
18 
19 import static android.service.quickaccesswallet.QuickAccessWalletService.SERVICE_INTERFACE;
20 
21 import static com.google.common.truth.Truth.assertThat;
22 
23 import static org.robolectric.Shadows.shadowOf;
24 
25 import android.Manifest;
26 import android.app.ActivityManager;
27 import android.content.ComponentName;
28 import android.content.ContentResolver;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.pm.ApplicationInfo;
32 import android.content.pm.PackageInfo;
33 import android.content.pm.PackageManager;
34 import android.content.pm.ResolveInfo;
35 import android.content.pm.ServiceInfo;
36 import android.provider.Settings;
37 import android.service.quickaccesswallet.QuickAccessWalletClient;
38 
39 import androidx.test.core.app.ApplicationProvider;
40 
41 import com.android.internal.widget.LockPatternUtils;
42 
43 import org.junit.Before;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 import org.mockito.MockitoAnnotations;
47 import org.robolectric.RobolectricTestRunner;
48 import org.robolectric.RuntimeEnvironment;
49 import org.robolectric.annotation.Config;
50 import org.robolectric.annotation.Implementation;
51 import org.robolectric.annotation.Implements;
52 import org.robolectric.annotation.Resetter;
53 import org.robolectric.shadow.api.Shadow;
54 import org.robolectric.shadows.ShadowLog;
55 
56 /**
57  * Ensures compatibility between the {@link QuickAccessWalletClient} and the plugin
58  */
59 @RunWith(RobolectricTestRunner.class)
60 @Config(shadows = {
61         QuickAccessWalletClientTest.ShadowActivityManager.class,
62         QuickAccessWalletClientTest.ShadowLockPatternUtils.class})
63 public class QuickAccessWalletClientTest {
64 
65     private final Context mContext = ApplicationProvider.getApplicationContext();
66     private QuickAccessWalletClient mWalletClient;
67 
68     @Before
setUp()69     public void setUp() {
70         MockitoAnnotations.initMocks(this);
71         ShadowLog.stream = System.out;
72     }
73 
74     @Test
isWalletServiceAvailable_serviceAvailable_returnsTrue()75     public void isWalletServiceAvailable_serviceAvailable_returnsTrue() {
76         setDefaultPaymentApp(mContext.getPackageName());
77         registerWalletService();
78 
79         mWalletClient = QuickAccessWalletClient.create(mContext);
80 
81         assertThat(mWalletClient.isWalletServiceAvailable()).isTrue();
82     }
83 
84     @Test
isWalletServiceAvailable_returnsFalseIfServiceUnavailable()85     public void isWalletServiceAvailable_returnsFalseIfServiceUnavailable() {
86         setDefaultPaymentApp(mContext.getPackageName());
87 
88         mWalletClient = QuickAccessWalletClient.create(mContext);
89 
90         assertThat(mWalletClient.isWalletServiceAvailable()).isFalse();
91     }
92 
93     @Test
isWalletServiceAvailable_returnsFalseIfNfcPaymentAppIsAnotherApp()94     public void isWalletServiceAvailable_returnsFalseIfNfcPaymentAppIsAnotherApp() {
95         setDefaultPaymentApp("foo.bar");
96         registerWalletService();
97 
98         mWalletClient = QuickAccessWalletClient.create(mContext);
99 
100         assertThat(mWalletClient.isWalletServiceAvailable()).isFalse();
101     }
102 
103     @Test
isWalletFeatureAvailable_happyCase()104     public void isWalletFeatureAvailable_happyCase() {
105         setDefaultPaymentApp(mContext.getPackageName());
106         registerWalletService();
107         WalletPluginService.updateSettingsFeatureAvailability(mContext, true);
108         ContentResolver cr = mContext.getContentResolver();
109         Settings.Secure.putInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 1);
110 
111         mWalletClient = QuickAccessWalletClient.create(mContext);
112 
113         assertThat(mWalletClient.isWalletFeatureAvailable()).isTrue();
114     }
115 
116     @Test
isWalletFeatureAvailable_wrongUser()117     public void isWalletFeatureAvailable_wrongUser() {
118         setDefaultPaymentApp(mContext.getPackageName());
119         registerWalletService();
120         WalletPluginService.updateSettingsFeatureAvailability(mContext, true);
121         ContentResolver cr = mContext.getContentResolver();
122         Settings.Secure.putInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 1);
123         ShadowActivityManager.setCurrentUser(11);
124 
125         mWalletClient = QuickAccessWalletClient.create(mContext);
126 
127         assertThat(mWalletClient.isWalletFeatureAvailable()).isFalse();
128     }
129 
130     @Test
isWalletFeatureAvailable_userSetupIncomplete()131     public void isWalletFeatureAvailable_userSetupIncomplete() {
132         setDefaultPaymentApp(mContext.getPackageName());
133         registerWalletService();
134         WalletPluginService.updateSettingsFeatureAvailability(mContext, true);
135         // do not set user setup complete
136 
137         mWalletClient = QuickAccessWalletClient.create(mContext);
138 
139         assertThat(mWalletClient.isWalletFeatureAvailable()).isFalse();
140     }
141 
142     @Test
isWalletFeatureAvailable_globalActionsPanelDisabled()143     public void isWalletFeatureAvailable_globalActionsPanelDisabled() {
144         setDefaultPaymentApp(mContext.getPackageName());
145         registerWalletService();
146         WalletPluginService.updateSettingsFeatureAvailability(mContext, true);
147         ContentResolver cr = mContext.getContentResolver();
148         Settings.Secure.putInt(cr,
149                 Settings.Secure.GLOBAL_ACTIONS_PANEL_ENABLED, 0);
150         Settings.Secure.putInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 1);
151 
152         mWalletClient = QuickAccessWalletClient.create(mContext);
153 
154         assertThat(mWalletClient.isWalletFeatureAvailable()).isFalse();
155     }
156 
157     @Test
isWalletFeatureAvailable_userInLockdown()158     public void isWalletFeatureAvailable_userInLockdown() {
159         setDefaultPaymentApp(mContext.getPackageName());
160         registerWalletService();
161         WalletPluginService.updateSettingsFeatureAvailability(mContext, true);
162         ContentResolver cr = mContext.getContentResolver();
163         Settings.Secure.putInt(cr, Settings.Secure.USER_SETUP_COMPLETE, 1);
164         ShadowLockPatternUtils.sIsUserInLockdown = true;
165 
166         mWalletClient = QuickAccessWalletClient.create(mContext);
167 
168         assertThat(mWalletClient.isWalletFeatureAvailable()).isFalse();
169     }
170 
171     @Test
isWalletFeatureAvailableWhenDeviceLocked()172     public void isWalletFeatureAvailableWhenDeviceLocked() {
173         ContentResolver cr = mContext.getContentResolver();
174         mWalletClient = QuickAccessWalletClient.create(mContext);
175 
176         Settings.Secure.putInt(cr, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 1);
177 
178         assertThat(mWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).isTrue();
179 
180         Settings.Secure.putInt(cr, Settings.Secure.POWER_MENU_LOCKED_SHOW_CONTENT, 0);
181 
182         assertThat(mWalletClient.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
183     }
184 
setDefaultPaymentApp(String pkg)185     private void setDefaultPaymentApp(String pkg) {
186         ComponentName nfcComponent = new ComponentName(pkg, "WalletService");
187         Settings.Secure.putString(mContext.getContentResolver(), "nfc_payment_default_component",
188                 nfcComponent.flattenToString());
189     }
190 
registerWalletService()191     private void registerWalletService() {
192         Intent queryIntent = new Intent(SERVICE_INTERFACE).setPackage(mContext.getPackageName());
193         ServiceInfo serviceInfo = new ServiceInfo();
194         serviceInfo.exported = true;
195         serviceInfo.applicationInfo = new ApplicationInfo();
196         serviceInfo.applicationInfo.packageName = mContext.getPackageName();
197         serviceInfo.name = "QuickAccessWalletService";
198         serviceInfo.permission = Manifest.permission.BIND_QUICK_ACCESS_WALLET_SERVICE;
199         ResolveInfo resolveInfo = new ResolveInfo();
200         resolveInfo.serviceInfo = serviceInfo;
201         PackageManager rpm = mContext.getPackageManager();
202         PackageInfo packageInfo = new PackageInfo();
203         packageInfo.packageName = mContext.getPackageName();
204         packageInfo.services = new ServiceInfo[]{serviceInfo};
205         shadowOf(rpm).addResolveInfoForIntent(queryIntent, resolveInfo);
206     }
207 
208     @Implements(LockPatternUtils.class)
209     public static class ShadowLockPatternUtils {
210         private static boolean sIsUserInLockdown = false;
211 
212         @Implementation
isUserInLockdown(int userId)213         public boolean isUserInLockdown(int userId) {
214             return sIsUserInLockdown;
215         }
216     }
217 
218     @Implements(ActivityManager.class)
219     public static class ShadowActivityManager {
220         private static int sCurrentUserId = 0;
221 
222         @Resetter
reset()223         public void reset() {
224             sCurrentUserId = 0;
225         }
226 
227         @Implementation
getCurrentUser()228         protected static int getCurrentUser() {
229             return sCurrentUserId;
230         }
231 
setCurrentUser(int userId)232         public static void setCurrentUser(int userId) {
233             sCurrentUserId = userId;
234         }
235 
getShadow()236         public static ShadowActivityManager getShadow() {
237             return (ShadowActivityManager) Shadow.extract(
238                     RuntimeEnvironment.application.getSystemService(ActivityManager.class));
239         }
240     }
241 
242 }
243