1 /*
2  * Copyright (C) 2023 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.settings.nfc;
18 
19 import static com.android.settingslib.applications.ApplicationsState.AppEntry;
20 import static com.android.settingslib.applications.ApplicationsState.AppFilter;
21 
22 import android.app.ActivityManager;
23 import android.content.Context;
24 import android.nfc.NfcAdapter;
25 import android.os.UserHandle;
26 import android.os.UserManager;
27 import android.util.Log;
28 
29 import com.android.settings.applications.AppStateBaseBridge;
30 import com.android.settingslib.applications.ApplicationsState;
31 
32 import java.util.HashMap;
33 import java.util.List;
34 import java.util.Map;
35 
36 /**
37  * Filter to display only in the Tag preference listed Apps on Nfc Tag Apps page.
38  */
39 public class AppStateNfcTagAppsBridge extends AppStateBaseBridge{
40 
41     private static final String TAG = "AppStateNfcTagAppsBridge";
42 
43     private final Context mContext;
44     private final NfcAdapter mNfcAdapter;
45     // preference list cache
46     private static Map<Integer, Map<String, Boolean>> sList = new HashMap<>();
47 
AppStateNfcTagAppsBridge(Context context, ApplicationsState appState, Callback callback)48     public AppStateNfcTagAppsBridge(Context context, ApplicationsState appState,
49             Callback callback) {
50         super(appState, callback);
51         mContext = context;
52         mNfcAdapter = NfcAdapter.getDefaultAdapter(mContext);
53         if (mNfcAdapter != null && mNfcAdapter.isTagIntentAppPreferenceSupported()) {
54             UserManager um = mContext.createContextAsUser(
55                     UserHandle.of(ActivityManager.getCurrentUser()), 0)
56                     .getSystemService(UserManager.class);
57             List<UserHandle> luh = um.getEnabledProfiles();
58             for (UserHandle uh : luh) {
59                 int userId = uh.getIdentifier();
60                 sList.put(userId, mNfcAdapter.getTagIntentAppPreferenceForUser(userId));
61             }
62         }
63     }
64 
65     /**
66      * Update the system and cached tag app preference lists.
67      */
updateApplist(int userId, String pkg, boolean allowed)68     public boolean updateApplist(int userId, String pkg, boolean allowed) {
69         if (mNfcAdapter.setTagIntentAppPreferenceForUser(
70                 userId, pkg, allowed) == NfcAdapter.TAG_INTENT_APP_PREF_RESULT_SUCCESS) {
71             sList.put(userId, mNfcAdapter.getTagIntentAppPreferenceForUser(userId));
72             return true;
73         } else {
74             return false;
75         }
76     }
77 
78     @Override
loadAllExtraInfo()79     protected void loadAllExtraInfo() {
80         final List<ApplicationsState.AppEntry> allApps = mAppSession.getAllApps();
81         for (int i = 0; i < allApps.size(); i++) {
82             ApplicationsState.AppEntry app = allApps.get(i);
83             this.updateExtraInfo(app, app.info.packageName, app.info.uid);
84         }
85     }
86 
87     @Override
updateExtraInfo(AppEntry app, String pkg, int uid)88     protected void updateExtraInfo(AppEntry app, String pkg, int uid) {
89         // Display package if is in the app preference list.
90         int userId = UserHandle.getUserId(uid);
91         Map<String, Boolean> map = sList.getOrDefault(userId, new HashMap<>());
92         if (map.containsKey(pkg)) {
93             app.extraInfo = new NfcTagAppState(/* exist */ true, /* allowed */ map.get(pkg));
94         } else {
95             app.extraInfo = new NfcTagAppState(/* exist */ false, /* allowed */ false);
96         }
97     }
98 
99     /**
100      * Class to denote the nfc tag app preference state of the AppEntry
101      */
102     public static class NfcTagAppState {
103         private boolean mIsExisted;
104         private boolean mIsAllowed;
105 
NfcTagAppState(boolean exist, boolean allowed)106         public NfcTagAppState(boolean exist, boolean allowed) {
107             mIsExisted = exist;
108             mIsAllowed = allowed;
109         }
110 
isExisted()111         public boolean isExisted() {
112             return mIsExisted;
113         }
114 
isAllowed()115         public boolean isAllowed() {
116             return mIsAllowed;
117         }
118     }
119 
120     public static final AppFilter FILTER_APPS_NFC_TAG =
121             new AppFilter() {
122                 @Override
123                 public void init() {
124                 }
125 
126                 @Override
127                 public boolean filterApp(AppEntry entry) {
128                     if (entry.extraInfo == null) {
129                         Log.d(TAG, "[" + entry.info.packageName + "]" + " has No extra info.");
130                         return false;
131                     }
132                     NfcTagAppState state = (NfcTagAppState) entry.extraInfo;
133                     return state.isExisted();
134                 }
135             };
136 }
137