1a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach/*
2a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * Copyright 2017 The Android Open Source Project
3a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach *
4a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * Licensed under the Apache License, Version 2.0 (the "License");
5a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * you may not use this file except in compliance with the License.
6a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * You may obtain a copy of the License at
7a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach *
8a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach *      http://www.apache.org/licenses/LICENSE-2.0
9a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach *
10a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * Unless required by applicable law or agreed to in writing, software
11a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * distributed under the License is distributed on an "AS IS" BASIS,
12a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * See the License for the specific language governing permissions and
14a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * limitations under the License.
15a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach */
16a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
17a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachpackage com.android.server.wifi;
18a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
1917139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbachimport static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED;
2017139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach
21a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachimport android.content.Context;
22a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachimport android.database.ContentObserver;
23115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport android.net.wifi.ScanResult;
24115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport android.net.wifi.WifiConfiguration;
25115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport android.net.wifi.WifiScanner;
26a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachimport android.os.Handler;
27a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachimport android.os.Looper;
28a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachimport android.provider.Settings;
29115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport android.util.Log;
30a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
31a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachimport com.android.internal.annotations.VisibleForTesting;
32a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
3304263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbachimport java.io.FileDescriptor;
3404263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbachimport java.io.PrintWriter;
35b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbachimport java.util.Arrays;
36b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbachimport java.util.Collection;
37115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport java.util.HashSet;
38115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport java.util.List;
39115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbachimport java.util.Set;
404f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbachimport java.util.stream.Collectors;
41115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
4204263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach
43a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach/**
44a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * WakeupController is responsible managing Auto Wifi.
45a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach *
46a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach * <p>It determines if and when to re-enable wifi after it has been turned off by the user.
47a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach */
48a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbachpublic class WakeupController {
49a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
50115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    private static final String TAG = "WakeupController";
51115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
5232152cdeeefb4d8cc9a1137232892e5360ae1f5bEric Schwarzenbach    private static final boolean USE_PLATFORM_WIFI_WAKE = true;
53a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
54a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    private final Context mContext;
55a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    private final Handler mHandler;
56a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    private final FrameworkFacade mFrameworkFacade;
57a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    private final ContentObserver mContentObserver;
58a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    private final WakeupLock mWakeupLock;
59b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach    private final WakeupEvaluator mWakeupEvaluator;
609d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach    private final WakeupOnboarding mWakeupOnboarding;
61a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    private final WifiConfigManager mWifiConfigManager;
62115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    private final WifiInjector mWifiInjector;
63aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach    private final WakeupConfigStoreData mWakeupConfigStoreData;
6412d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach    private final WifiWakeMetrics mWifiWakeMetrics;
65115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
66115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    private final WifiScanner.ScanListener mScanListener = new WifiScanner.ScanListener() {
67115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        @Override
68115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        public void onPeriodChanged(int periodInMs) {
69115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            // no-op
70115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
71115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
72115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        @Override
73115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        public void onResults(WifiScanner.ScanData[] results) {
74b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach            if (results.length == 1 && results[0].isAllChannelsScanned()) {
75f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach                handleScanResults(filterDfsScanResults(Arrays.asList(results[0].getResults())));
76b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach            }
77115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
78115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
79115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        @Override
80115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        public void onFullResult(ScanResult fullScanResult) {
81115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            // no-op
82115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
83115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
84115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        @Override
85115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        public void onSuccess() {
86115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            // no-op
87115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
88115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
89115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        @Override
90115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        public void onFailure(int reason, String description) {
91115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            Log.e(TAG, "ScanListener onFailure: " + reason + ": " + description);
92115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
93115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    };
94a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
95a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    /** Whether this feature is enabled in Settings. */
96a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    private boolean mWifiWakeupEnabled;
97a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
98a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    /** Whether the WakeupController is currently active. */
99a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    private boolean mIsActive = false;
100a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach
10112d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach    /** The number of scans that have been handled by the controller since last {@link #reset()}. */
10212d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach    private int mNumScansHandled = 0;
10312d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach
104eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach    /** Whether Wifi verbose logging is enabled. */
105eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach    private boolean mVerboseLoggingEnabled;
106eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach
107a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    public WakeupController(
108a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach            Context context,
109a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach            Looper looper,
110a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            WakeupLock wakeupLock,
111b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach            WakeupEvaluator wakeupEvaluator,
1129d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach            WakeupOnboarding wakeupOnboarding,
113a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            WifiConfigManager wifiConfigManager,
114a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            WifiConfigStore wifiConfigStore,
11512d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach            WifiWakeMetrics wifiWakeMetrics,
116115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            WifiInjector wifiInjector,
117a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach            FrameworkFacade frameworkFacade) {
118a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach        mContext = context;
119a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach        mHandler = new Handler(looper);
120a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        mWakeupLock = wakeupLock;
121b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        mWakeupEvaluator = wakeupEvaluator;
1229d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach        mWakeupOnboarding = wakeupOnboarding;
123a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        mWifiConfigManager = wifiConfigManager;
12412d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        mWifiWakeMetrics = wifiWakeMetrics;
125a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach        mFrameworkFacade = frameworkFacade;
126115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        mWifiInjector = wifiInjector;
127a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach        mContentObserver = new ContentObserver(mHandler) {
128a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach            @Override
129a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach            public void onChange(boolean selfChange) {
1305aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach                readWifiWakeupEnabledFromSettings();
1315aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach                mWakeupOnboarding.setOnboarded();
132a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach            }
133a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach        };
134a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach        mFrameworkFacade.registerContentObserver(mContext, Settings.Global.getUriFor(
135a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach                Settings.Global.WIFI_WAKEUP_ENABLED), true, mContentObserver);
1365aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach        readWifiWakeupEnabledFromSettings();
137a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach
138a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        // registering the store data here has the effect of reading the persisted value of the
139a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        // data sources after system boot finishes
140aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach        mWakeupConfigStoreData = new WakeupConfigStoreData(
1419d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach                new IsActiveDataSource(),
1425aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach                mWakeupOnboarding.getIsOnboadedDataSource(),
1435aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach                mWakeupOnboarding.getNotificationsDataSource(),
1449d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach                mWakeupLock.getDataSource());
145aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach        wifiConfigStore.registerStoreData(mWakeupConfigStoreData);
146a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    }
147a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach
1485aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach    private void readWifiWakeupEnabledFromSettings() {
1495aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach        mWifiWakeupEnabled = mFrameworkFacade.getIntegerSetting(
1505aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach                mContext, Settings.Global.WIFI_WAKEUP_ENABLED, 0) == 1;
1515aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach        Log.d(TAG, "WifiWake " + (mWifiWakeupEnabled ? "enabled" : "disabled"));
1525aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach    }
1535aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach
154a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    private void setActive(boolean isActive) {
155a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        if (mIsActive != isActive) {
156b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach            Log.d(TAG, "Setting active to " + isActive);
157a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            mIsActive = isActive;
158a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            mWifiConfigManager.saveToStore(false /* forceWrite */);
159a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        }
160a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    }
161a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach
162a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    /**
163115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * Starts listening for incoming scans.
164115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     *
165115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * <p>Should only be called upon entering ScanMode. WakeupController registers its listener with
166115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * the WifiScanner. If the WakeupController is already active, then it returns early. Otherwise
167115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * it performs its initialization steps and sets {@link #mIsActive} to true.
168115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     */
169115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    public void start() {
170b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        Log.d(TAG, "start()");
171115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        mWifiInjector.getWifiScanner().registerScanListener(mScanListener);
172115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
173dca47232ea69a4501318b4dfb69db69e1216694fEric Schwarzenbach        // If already active, we don't want to restart the session, so return early.
174115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        if (mIsActive) {
175dca47232ea69a4501318b4dfb69db69e1216694fEric Schwarzenbach            mWifiWakeMetrics.recordIgnoredStart();
176115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            return;
177115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
178115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        setActive(true);
179115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
180aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach        // ensure feature is enabled and store data has been read before performing work
181b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        if (isEnabled()) {
1829d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach            mWakeupOnboarding.maybeShowNotification();
18312d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach
184f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach            List<ScanResult> scanResults =
185f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach                    filterDfsScanResults(mWifiInjector.getWifiScanner().getSingleScanResults());
186f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach            Set<ScanResultMatchInfo> matchInfos = toMatchInfos(scanResults);
187f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach            matchInfos.retainAll(getGoodSavedNetworks());
188f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach
189eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            if (mVerboseLoggingEnabled) {
190f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach                Log.d(TAG, "Saved networks in most recent scan:" + matchInfos);
191eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            }
192eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach
193f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach            mWifiWakeMetrics.recordStartEvent(matchInfos.size());
194f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach            mWakeupLock.setLock(matchInfos);
1954f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach            // TODO(b/77291248): request low latency scan here
196115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
197115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    }
1985aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach
199115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    /**
200115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * Stops listening for scans.
201115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     *
202115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * <p>Should only be called upon leaving ScanMode. It deregisters the listener from
203115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     * WifiScanner.
204115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach     */
205115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    public void stop() {
206b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        Log.d(TAG, "stop()");
207115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        mWifiInjector.getWifiScanner().deregisterScanListener(mScanListener);
2089d60c0ff94757e8862f167f6de54789fe2e1bab2Eric Schwarzenbach        mWakeupOnboarding.onStop();
209115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    }
210115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
211115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    /** Resets the WakeupController, setting {@link #mIsActive} to false. */
212115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    public void reset() {
213b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        Log.d(TAG, "reset()");
21412d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        mWifiWakeMetrics.recordResetEvent(mNumScansHandled);
21512d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        mNumScansHandled = 0;
216115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        setActive(false);
217115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    }
218115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
219eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach    /** Sets verbose logging flag based on verbose level. */
220eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach    public void enableVerboseLogging(int verbose) {
221eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach        mVerboseLoggingEnabled = verbose > 0;
222eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach        mWakeupLock.enableVerboseLogging(mVerboseLoggingEnabled);
223eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach    }
224eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach
225f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach    /** Returns a list of ScanResults with DFS channels removed. */
226f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach    private List<ScanResult> filterDfsScanResults(Collection<ScanResult> scanResults) {
2274f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        int[] dfsChannels = mWifiInjector.getWifiNative()
2284f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach                .getChannelsForBand(WifiScanner.WIFI_BAND_5_GHZ_DFS_ONLY);
2294f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        if (dfsChannels == null) {
2304f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach            dfsChannels = new int[0];
231115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
232115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
2334f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        final Set<Integer> dfsChannelSet = Arrays.stream(dfsChannels).boxed()
2344f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach                .collect(Collectors.toSet());
2354f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach
2364f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        return scanResults.stream()
2374f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach                .filter(scanResult -> !dfsChannelSet.contains(scanResult.frequency))
238f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach                .collect(Collectors.toList());
239115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    }
240115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
241f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach    /** Returns a filtered set of saved networks from WifiConfigManager. */
242115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    private Set<ScanResultMatchInfo> getGoodSavedNetworks() {
243115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        List<WifiConfiguration> savedNetworks = mWifiConfigManager.getSavedNetworks();
244115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
245115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        Set<ScanResultMatchInfo> goodSavedNetworks = new HashSet<>(savedNetworks.size());
246115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        for (WifiConfiguration config : savedNetworks) {
247115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            if (isWideAreaNetwork(config)
248115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach                    || config.hasNoInternetAccess()
249115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach                    || config.noInternetAccessExpected
250115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach                    || !config.getNetworkSelectionStatus().getHasEverConnected()) {
251115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach                continue;
252115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            }
253115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach            goodSavedNetworks.add(ScanResultMatchInfo.fromWifiConfiguration(config));
254115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        }
255115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
256115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        return goodSavedNetworks;
257115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    }
258115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
259115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    //TODO(b/69271702) implement WAN filtering
2604f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach    private static boolean isWideAreaNetwork(WifiConfiguration config) {
261115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach        return false;
262115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    }
263115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach
264115c8923f9cfee8052c03eb5c92359d4156a86b2Eric Schwarzenbach    /**
265b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach     * Handles incoming scan results.
266b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach     *
2674f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     * <p>The controller updates the WakeupLock with the incoming scan results. If WakeupLock is not
2684f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     * yet fully initialized, it adds the current scanResults to the lock and returns. If WakeupLock
2694f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     * is initialized but not empty, the controller updates the lock with the current scan. If it is
2704f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     * both initialized and empty, it evaluates scan results for a match with saved networks. If a
2714f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     * match exists, it enables wifi.
272a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach     *
273aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     * <p>The feature must be enabled and the store data must be loaded in order for the controller
274aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     * to handle scan results.
275aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     *
276b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach     * @param scanResults The scan results with which to update the controller
277a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach     */
278b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach    private void handleScanResults(Collection<ScanResult> scanResults) {
279b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        if (!isEnabled()) {
280eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            Log.d(TAG, "Attempted to handleScanResults while not enabled");
281b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach            return;
282b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        }
283b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach
2845aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach        // only count scan as handled if isEnabled
2854f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        mNumScansHandled++;
2864f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        if (mVerboseLoggingEnabled) {
2874f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach            Log.d(TAG, "Incoming scan #" + mNumScansHandled);
2884f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        }
289b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach
2905aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach        // need to show notification here in case user turns phone on while wifi is off
2915aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach        mWakeupOnboarding.maybeShowNotification();
2925aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach
293f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach        // filter out unsaved networks
294f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach        Set<ScanResultMatchInfo> goodSavedNetworks = getGoodSavedNetworks();
295f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach        Set<ScanResultMatchInfo> matchInfos = toMatchInfos(scanResults);
296f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach        matchInfos.retainAll(goodSavedNetworks);
2975aad8ece7e38a80db917d49b5245f6b8c6dca273Eric Schwarzenbach
298f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach        mWakeupLock.update(matchInfos);
2994f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        if (!mWakeupLock.isUnlocked()) {
3004f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach            return;
301b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        }
302b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach
303f18cd43a78de639b3680a0e881d90d02ae57decdEric Schwarzenbach        ScanResult network = mWakeupEvaluator.findViableNetwork(scanResults, goodSavedNetworks);
304b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach
305b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        if (network != null) {
306eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            Log.d(TAG, "Enabling wifi for network: " + network.SSID);
30717139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach            enableWifi();
308b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        }
309b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach    }
310b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach
31117139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach    /**
3124f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     * Converts ScanResults to ScanResultMatchInfos.
3134f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach     */
3144f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach    private static Set<ScanResultMatchInfo> toMatchInfos(Collection<ScanResult> scanResults) {
3154f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach        return scanResults.stream()
3164f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach                .map(ScanResultMatchInfo::fromScanResult)
3174f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach                .collect(Collectors.toSet());
3184f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach    }
3194f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach
3204f894bd0f4b378972d10f64390ab710da54d5cc6Eric Schwarzenbach    /**
32117139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach     * Enables wifi.
32217139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach     *
32317139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach     * <p>This method ignores all checks and assumes that {@link WifiStateMachine} is currently
32417139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach     * in ScanModeState.
32517139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach     */
32617139823e3dbbcdb46f1e586427297d72a5a0e66Eric Schwarzenbach    private void enableWifi() {
327eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach        if (USE_PLATFORM_WIFI_WAKE) {
328eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            // TODO(b/72180295): ensure that there is no race condition with WifiServiceImpl here
329eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            if (mWifiInjector.getWifiSettingsStore().handleWifiToggled(true /* wifiEnabled */)) {
330eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach                mWifiInjector.getWifiController().sendMessage(CMD_WIFI_TOGGLED);
331eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach                mWifiWakeMetrics.recordWakeupEvent(mNumScansHandled);
332eaa590a3216ed7bf971c67a43ae68ed6e3ad1ce1Eric Schwarzenbach            }
333b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach        }
334b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach    }
335b6b9c915c200d71da56026d8c3aeec9c243a933aEric Schwarzenbach
336aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach    /**
337aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     * Whether the feature is currently enabled.
338aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     *
339aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     * <p>This method checks both the Settings value and the store data to ensure that it has been
340aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     * read.
341aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach     */
342a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    @VisibleForTesting
343a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    boolean isEnabled() {
344aa872c243eb5b27beaefe1360b69a46ceb016b56Eric Schwarzenbach        return mWifiWakeupEnabled && mWakeupConfigStoreData.hasBeenRead();
345a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach    }
346a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach
34704263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach    /** Dumps wakeup controller state. */
34804263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
34904263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach        pw.println("Dump of WakeupController");
35004263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach        pw.println("USE_PLATFORM_WIFI_WAKE: " + USE_PLATFORM_WIFI_WAKE);
35112d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        pw.println("mWifiWakeupEnabled: " + mWifiWakeupEnabled);
35212d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        pw.println("isOnboarded: " + mWakeupOnboarding.isOnboarded());
35312d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        pw.println("configStore hasBeenRead: " + mWakeupConfigStoreData.hasBeenRead());
35404263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach        pw.println("mIsActive: " + mIsActive);
35512d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach        pw.println("mNumScansHandled: " + mNumScansHandled);
35612d31e7fea8e5c17dddc0ab433c26c31a3bf2550Eric Schwarzenbach
35704263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach        mWakeupLock.dump(fd, pw, args);
35804263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach    }
35904263765dc4bb2a74722d69db56c5b42e7fb1bc9Eric Schwarzenbach
360a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    private class IsActiveDataSource implements WakeupConfigStoreData.DataSource<Boolean> {
361a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach
362a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        @Override
363a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        public Boolean getData() {
364a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            return mIsActive;
365a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        }
366a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach
367a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        @Override
368a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        public void setData(Boolean data) {
369a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach            mIsActive = data;
370a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach        }
371a57806da53f2eadcf12475892ae3a0e0e58d98cdEric Schwarzenbach    }
372a55e8d795bba5aa66f692cffa8fa28e3b4174546Eric Schwarzenbach}
373