• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.server.nearby.fastpair.halfsheet;
18 
19 
20 import static com.android.server.nearby.fastpair.blocklist.Blocklist.BlocklistState.ACTIVE;
21 import static com.android.server.nearby.fastpair.blocklist.Blocklist.BlocklistState.DISMISSED;
22 import static com.android.server.nearby.fastpair.blocklist.Blocklist.BlocklistState.DO_NOT_SHOW_AGAIN;
23 import static com.android.server.nearby.fastpair.blocklist.Blocklist.BlocklistState.DO_NOT_SHOW_AGAIN_LONG;
24 
25 import android.util.Log;
26 import android.util.LruCache;
27 
28 import androidx.annotation.VisibleForTesting;
29 
30 import com.android.server.nearby.fastpair.blocklist.Blocklist;
31 import com.android.server.nearby.fastpair.blocklist.BlocklistElement;
32 import com.android.server.nearby.util.Clock;
33 import com.android.server.nearby.util.DefaultClock;
34 
35 
36 /**
37  * Maintains a list of half sheet id to tell whether the half sheet should be suppressed or not.
38  *
39  * <p>When user cancel half sheet, the ble address related half sheet should be in block list and
40  * after certain duration of time half sheet can show again.
41  */
42 public class FastPairHalfSheetBlocklist extends LruCache<Integer, BlocklistElement>
43         implements Blocklist {
44     private static final String TAG = "HalfSheetBlocklist";
45     // Number of entries in the FastPair blocklist
46     private static final int FAST_PAIR_BLOCKLIST_CACHE_SIZE = 16;
47     // Duration between first half sheet dismiss and second half sheet shows: 2 seconds
48     private static final int FAST_PAIR_HALF_SHEET_DISMISS_COOL_DOWN_MILLIS = 2000;
49     // The timeout to ban half sheet after user trigger the ban logic even number of time : 1 day
50     private static final int DURATION_RESURFACE_HALFSHEET_EVEN_NUMBER_BAN_MILLI_SECONDS = 86400000;
51     // Timeout for DISMISSED entries in the blocklist to expire : 1 min
52     private static final int FAST_PAIR_BLOCKLIST_DISMISSED_HALF_SHEET_TIMEOUT_MILLIS = 60000;
53     // The timeout for entries in the blocklist to expire : 1 day
54     private static final int STATE_EXPIRATION_MILLI_SECONDS = 86400000;
55     private long mEndTimeBanAllItems;
56     private final Clock mClock;
57 
58 
FastPairHalfSheetBlocklist()59     public FastPairHalfSheetBlocklist() {
60         // Reuses the size limit from notification cache.
61         // Number of entries in the FastPair blocklist
62         super(FAST_PAIR_BLOCKLIST_CACHE_SIZE);
63         mClock = new DefaultClock();
64     }
65 
66     @VisibleForTesting
FastPairHalfSheetBlocklist(int size, Clock clock)67     FastPairHalfSheetBlocklist(int size, Clock clock) {
68         super(size);
69         mClock = clock;
70     }
71 
72     /**
73      * Checks whether need to show HalfSheet or not.
74      *
75      * <p> When the HalfSheet {@link BlocklistState} is DISMISS, there is a little cool down period
76      * to allow half sheet to reshow.
77      * If the HalfSheet {@link BlocklistState} is DO_NOT_SHOW_AGAIN, within durationMilliSeconds
78      * from banned start time, the function will return true
79      * otherwise it will return false if the status is expired
80      * If the HalfSheet {@link BlocklistState} is DO_NOT_SHOW_AGAIN_LONG, the half sheet will be
81      * baned for a longer duration.
82      *
83      * @param id {@link com.android.nearby.halfsheet.HalfSheetActivity} id
84      * @param durationMilliSeconds the time duration from item is banned to now
85      * @return whether the HalfSheet is blocked to show
86      */
87     @Override
isBlocklisted(int id, int durationMilliSeconds)88     public boolean isBlocklisted(int id, int durationMilliSeconds) {
89         if (shouldBanAllItem()) {
90             return true;
91         }
92         BlocklistElement entry = get(id);
93         if (entry == null) {
94             return false;
95         }
96         if (entry.getState().equals(DO_NOT_SHOW_AGAIN)) {
97             Log.d(TAG, "BlocklistState: DO_NOT_SHOW_AGAIN");
98             return mClock.elapsedRealtime() < entry.getTimeStamp() + durationMilliSeconds;
99         }
100         if (entry.getState().equals(DO_NOT_SHOW_AGAIN_LONG)) {
101             Log.d(TAG, "BlocklistState: DO_NOT_SHOW_AGAIN_LONG ");
102             return mClock.elapsedRealtime()
103                     < entry.getTimeStamp()
104                     + DURATION_RESURFACE_HALFSHEET_EVEN_NUMBER_BAN_MILLI_SECONDS;
105         }
106 
107         if (entry.getState().equals(ACTIVE)) {
108             Log.d(TAG, "BlocklistState: ACTIVE");
109             return false;
110         }
111         // Get some cool down period for dismiss state
112         if (entry.getState().equals(DISMISSED)) {
113             Log.d(TAG, "BlocklistState: DISMISSED");
114             return mClock.elapsedRealtime()
115                     < entry.getTimeStamp() + FAST_PAIR_HALF_SHEET_DISMISS_COOL_DOWN_MILLIS;
116         }
117         if (dismissStateHasExpired(entry)) {
118             Log.d(TAG, "stateHasExpired: True");
119             return false;
120         }
121         return true;
122     }
123 
124     @Override
removeBlocklist(int id)125     public boolean removeBlocklist(int id) {
126         BlocklistElement oldValue = remove(id);
127         return oldValue != null;
128     }
129 
130     /**
131      * Updates the HalfSheet blocklist state
132      *
133      * <p>When the new {@link BlocklistState} has higher priority then old {@link BlocklistState} or
134      * the old {@link BlocklistState} status is expired,the function will update the status.
135      *
136      * @param id HalfSheet id
137      * @param state Blocklist state
138      * @return update status successful or not
139      */
140     @Override
updateState(int id, BlocklistState state)141     public boolean updateState(int id, BlocklistState state) {
142         BlocklistElement entry = get(id);
143         if (entry == null || state.hasHigherPriorityThan(entry.getState())
144                 || dismissStateHasExpired(entry)) {
145             Log.d(TAG, "updateState: " + state);
146             put(id, new BlocklistElement(state, mClock.elapsedRealtime()));
147             return true;
148         }
149         return false;
150     }
151 
152     /** Enables lower state to override the higher value state. */
forceUpdateState(int id, BlocklistState state)153     public void forceUpdateState(int id, BlocklistState state) {
154         put(id, new BlocklistElement(state, mClock.elapsedRealtime()));
155     }
156 
157     /** Resets certain device ban state to active. */
158     @Override
resetBlockState(int id)159     public void resetBlockState(int id) {
160         BlocklistElement entry = get(id);
161         if (entry != null) {
162             put(id, new BlocklistElement(ACTIVE, mClock.elapsedRealtime()));
163         }
164     }
165 
166     /** Checks whether certain device state has expired. */
isStateExpired(int id)167     public boolean isStateExpired(int id) {
168         BlocklistElement entry = get(id);
169         if (entry != null) {
170             return mClock.elapsedRealtime() > entry.getTimeStamp() + STATE_EXPIRATION_MILLI_SECONDS;
171         }
172         return false;
173     }
174 
dismissStateHasExpired(BlocklistElement entry)175     private boolean dismissStateHasExpired(BlocklistElement entry) {
176         return mClock.elapsedRealtime()
177                 > entry.getTimeStamp() + FAST_PAIR_BLOCKLIST_DISMISSED_HALF_SHEET_TIMEOUT_MILLIS;
178     }
179 
180     /**
181      * Updates the end time that all half sheet will be banned.
182      */
banAllItem(long banDurationTimeMillis)183     void banAllItem(long banDurationTimeMillis) {
184         long endTime = mClock.elapsedRealtime() + banDurationTimeMillis;
185         if (endTime > mEndTimeBanAllItems) {
186             mEndTimeBanAllItems = endTime;
187         }
188     }
189 
shouldBanAllItem()190     private boolean shouldBanAllItem() {
191         return mClock.elapsedRealtime() < mEndTimeBanAllItems;
192     }
193 }
194