• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.wallet.controller;
18 
19 import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
20 import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
21 
22 import android.content.Context;
23 import android.database.ContentObserver;
24 import android.provider.Settings;
25 import android.service.quickaccesswallet.GetWalletCardsRequest;
26 import android.service.quickaccesswallet.QuickAccessWalletClient;
27 import android.service.quickaccesswallet.QuickAccessWalletClientImpl;
28 import android.util.Log;
29 
30 import com.android.systemui.R;
31 import com.android.systemui.dagger.SysUISingleton;
32 import com.android.systemui.dagger.qualifiers.Main;
33 import com.android.systemui.util.settings.SecureSettings;
34 import com.android.systemui.util.time.SystemClock;
35 
36 import java.util.concurrent.Executor;
37 import java.util.concurrent.TimeUnit;
38 
39 import javax.inject.Inject;
40 
41 /**
42  * Controller to handle communication between SystemUI and Quick Access Wallet Client.
43  */
44 @SysUISingleton
45 public class QuickAccessWalletController {
46 
47     /**
48      * Event for the wallet status change, e.g. the default payment app change and the wallet
49      * preference change.
50      */
51     public enum WalletChangeEvent {
52         DEFAULT_PAYMENT_APP_CHANGE,
53         WALLET_PREFERENCE_CHANGE,
54     }
55 
56     private static final String TAG = "QAWController";
57     private static final long RECREATION_TIME_WINDOW = TimeUnit.MINUTES.toMillis(10L);
58     private final Context mContext;
59     private final Executor mExecutor;
60     private final SecureSettings mSecureSettings;
61     private final SystemClock mClock;
62 
63     private QuickAccessWalletClient mQuickAccessWalletClient;
64     private ContentObserver mWalletPreferenceObserver;
65     private ContentObserver mDefaultPaymentAppObserver;
66     private int mWalletPreferenceChangeEvents = 0;
67     private int mDefaultPaymentAppChangeEvents = 0;
68     private boolean mWalletEnabled = false;
69     private long mQawClientCreatedTimeMillis;
70 
71     @Inject
QuickAccessWalletController( Context context, @Main Executor executor, SecureSettings secureSettings, QuickAccessWalletClient quickAccessWalletClient, SystemClock clock)72     public QuickAccessWalletController(
73             Context context,
74             @Main Executor executor,
75             SecureSettings secureSettings,
76             QuickAccessWalletClient quickAccessWalletClient,
77             SystemClock clock) {
78         mContext = context;
79         mExecutor = executor;
80         mSecureSettings = secureSettings;
81         mQuickAccessWalletClient = quickAccessWalletClient;
82         mClock = clock;
83         mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
84     }
85 
86     /**
87      * Returns true if the Quick Access Wallet service & feature is available.
88      */
isWalletEnabled()89     public boolean isWalletEnabled() {
90         return mWalletEnabled;
91     }
92 
93     /**
94      * Returns the current instance of {@link QuickAccessWalletClient} in the controller.
95      */
getWalletClient()96     public QuickAccessWalletClient getWalletClient() {
97         return mQuickAccessWalletClient;
98     }
99 
100     /**
101      * Setup the wallet change observers per {@link WalletChangeEvent}
102      *
103      * @param cardsRetriever a callback that retrieves the wallet cards
104      * @param events {@link WalletChangeEvent} need to be handled.
105      */
setupWalletChangeObservers( QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever, WalletChangeEvent... events)106     public void setupWalletChangeObservers(
107             QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever,
108             WalletChangeEvent... events) {
109         for (WalletChangeEvent event : events) {
110             if (event == WALLET_PREFERENCE_CHANGE) {
111                 setupWalletPreferenceObserver();
112             } else if (event == DEFAULT_PAYMENT_APP_CHANGE) {
113                 setupDefaultPaymentAppObserver(cardsRetriever);
114             }
115         }
116     }
117 
118     /**
119      * Unregister wallet change observers per {@link WalletChangeEvent} if needed.
120      *
121      */
unregisterWalletChangeObservers(WalletChangeEvent... events)122     public void unregisterWalletChangeObservers(WalletChangeEvent... events) {
123         for (WalletChangeEvent event : events) {
124             if (event == WALLET_PREFERENCE_CHANGE && mWalletPreferenceObserver != null) {
125                 mWalletPreferenceChangeEvents--;
126                 if (mWalletPreferenceChangeEvents == 0) {
127                     mSecureSettings.unregisterContentObserver(mWalletPreferenceObserver);
128                 }
129             } else if (event == DEFAULT_PAYMENT_APP_CHANGE && mDefaultPaymentAppObserver != null) {
130                 mDefaultPaymentAppChangeEvents--;
131                 if (mDefaultPaymentAppChangeEvents == 0) {
132                     mSecureSettings.unregisterContentObserver(mDefaultPaymentAppObserver);
133                 }
134             }
135         }
136     }
137 
138     /**
139      * Update the "show wallet" preference.
140      */
updateWalletPreference()141     public void updateWalletPreference() {
142         mWalletEnabled = mQuickAccessWalletClient.isWalletServiceAvailable()
143                 && mQuickAccessWalletClient.isWalletFeatureAvailable()
144                 && mQuickAccessWalletClient.isWalletFeatureAvailableWhenDeviceLocked();
145     }
146 
147     /**
148      * Query the wallet cards from {@link QuickAccessWalletClient}.
149      *
150      * @param cardsRetriever a callback to retrieve wallet cards.
151      */
queryWalletCards( QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever)152     public void queryWalletCards(
153             QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
154         if (mClock.elapsedRealtime() - mQawClientCreatedTimeMillis
155                 > RECREATION_TIME_WINDOW) {
156             Log.i(TAG, "Re-creating the QAW client to avoid stale.");
157             reCreateWalletClient();
158         }
159         if (!mQuickAccessWalletClient.isWalletFeatureAvailable()) {
160             Log.d(TAG, "QuickAccessWallet feature is not available.");
161             return;
162         }
163         int cardWidth =
164                 mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_width);
165         int cardHeight =
166                 mContext.getResources().getDimensionPixelSize(R.dimen.wallet_tile_card_view_height);
167         int iconSizePx = mContext.getResources().getDimensionPixelSize(R.dimen.wallet_icon_size);
168         GetWalletCardsRequest request =
169                 new GetWalletCardsRequest(cardWidth, cardHeight, iconSizePx, /* maxCards= */ 1);
170         mQuickAccessWalletClient.getWalletCards(mExecutor, request, cardsRetriever);
171     }
172 
173     /**
174      * Re-create the {@link QuickAccessWalletClient} of the controller.
175      */
reCreateWalletClient()176     public void reCreateWalletClient() {
177         mQuickAccessWalletClient = QuickAccessWalletClient.create(mContext);
178         mQawClientCreatedTimeMillis = mClock.elapsedRealtime();
179     }
180 
setupDefaultPaymentAppObserver( QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever)181     private void setupDefaultPaymentAppObserver(
182             QuickAccessWalletClient.OnWalletCardsRetrievedCallback cardsRetriever) {
183         if (mDefaultPaymentAppObserver == null) {
184             mDefaultPaymentAppObserver = new ContentObserver(null /* handler */) {
185                 @Override
186                 public void onChange(boolean selfChange) {
187                     mExecutor.execute(() -> {
188                         reCreateWalletClient();
189                         updateWalletPreference();
190                         queryWalletCards(cardsRetriever);
191                     });
192                 }
193             };
194 
195             mSecureSettings.registerContentObserver(
196                     Settings.Secure.getUriFor(Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT),
197                     false /* notifyForDescendants */,
198                     mDefaultPaymentAppObserver);
199         }
200         mDefaultPaymentAppChangeEvents++;
201     }
202 
setupWalletPreferenceObserver()203     private void setupWalletPreferenceObserver() {
204         if (mWalletPreferenceObserver == null) {
205             mWalletPreferenceObserver = new ContentObserver(null /* handler */) {
206                 @Override
207                 public void onChange(boolean selfChange) {
208                     mExecutor.execute(() -> {
209                         updateWalletPreference();
210                     });
211                 }
212             };
213 
214             mSecureSettings.registerContentObserver(
215                     Settings.Secure.getUriFor(QuickAccessWalletClientImpl.SETTING_KEY),
216                     false /* notifyForDescendants */,
217                     mWalletPreferenceObserver);
218         }
219         mWalletPreferenceChangeEvents++;
220     }
221 }
222