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.settings.wifi;
18 
19 import android.content.Context;
20 import android.net.wifi.WifiManager;
21 import android.os.Handler;
22 import android.os.HandlerThread;
23 import android.os.Looper;
24 import android.os.PersistableBundle;
25 import android.os.Process;
26 import android.os.SimpleClock;
27 import android.os.SystemClock;
28 import android.telephony.CarrierConfigManager;
29 import android.util.Log;
30 
31 import androidx.annotation.NonNull;
32 import androidx.annotation.Nullable;
33 import androidx.lifecycle.Lifecycle;
34 import androidx.lifecycle.LifecycleObserver;
35 import androidx.lifecycle.OnLifecycleEvent;
36 
37 import com.android.internal.annotations.VisibleForTesting;
38 import com.android.settings.overlay.FeatureFactory;
39 import com.android.wifitrackerlib.MergedCarrierEntry;
40 import com.android.wifitrackerlib.WifiEntry;
41 import com.android.wifitrackerlib.WifiPickerTracker;
42 
43 import java.time.Clock;
44 import java.time.ZoneOffset;
45 
46 public class WifiPickerTrackerHelper implements LifecycleObserver {
47 
48     private static final String TAG = "WifiPickerTrackerHelper";
49 
50     // Max age of tracked WifiEntries
51     private static final long MAX_SCAN_AGE_MILLIS = 15_000;
52     // Interval between initiating WifiPickerTracker scans
53     private static final long SCAN_INTERVAL_MILLIS = 10_000;
54     // Clock used for evaluating the age of scans
55     private static final Clock ELAPSED_REALTIME_CLOCK = new SimpleClock(ZoneOffset.UTC) {
56         @Override
57         public long millis() {
58             return SystemClock.elapsedRealtime();
59         }
60     };
61 
62     protected WifiPickerTracker mWifiPickerTracker;
63     // Worker thread used for WifiPickerTracker work
64     protected HandlerThread mWorkerThread;
65 
66     protected final WifiManager mWifiManager;
67     protected final CarrierConfigManager mCarrierConfigManager;
68 
WifiPickerTrackerHelper(@onNull Lifecycle lifecycle, @NonNull Context context, @Nullable WifiPickerTracker.WifiPickerTrackerCallback listener)69     public WifiPickerTrackerHelper(@NonNull Lifecycle lifecycle, @NonNull Context context,
70             @Nullable WifiPickerTracker.WifiPickerTrackerCallback listener) {
71         if (lifecycle == null) {
72             throw new IllegalArgumentException("lifecycle must be non-null.");
73         }
74         lifecycle.addObserver(this);
75         mWorkerThread = new HandlerThread(TAG
76                 + "{" + Integer.toHexString(System.identityHashCode(this)) + "}",
77                 Process.THREAD_PRIORITY_BACKGROUND);
78         mWorkerThread.start();
79 
80         mWifiPickerTracker = FeatureFactory.getFactory(context)
81                 .getWifiTrackerLibProvider()
82                 .createWifiPickerTracker(lifecycle, context,
83                 new Handler(Looper.getMainLooper()),
84                 mWorkerThread.getThreadHandler(),
85                 ELAPSED_REALTIME_CLOCK,
86                 MAX_SCAN_AGE_MILLIS,
87                 SCAN_INTERVAL_MILLIS,
88                 listener);
89 
90         mWifiManager = context.getSystemService(WifiManager.class);
91         mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class);
92     }
93 
94     /** @OnLifecycleEvent(ON_DESTROY) */
95     @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
onDestroy()96     public void onDestroy() {
97         mWorkerThread.quit();
98     }
99 
100     /** Return the WifiPickerTracker class */
getWifiPickerTracker()101     public @NonNull WifiPickerTracker getWifiPickerTracker() {
102         return mWifiPickerTracker;
103     }
104 
105     /** Return the enabled/disabled state of the carrier network provision */
isCarrierNetworkProvisionEnabled(int subId)106     public boolean isCarrierNetworkProvisionEnabled(int subId) {
107         final PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId);
108         if (config == null) {
109             Log.e(TAG, "Could not get carrier config, subId:" + subId);
110             return false;
111         }
112         final boolean enabled = config.getBoolean(
113                 CarrierConfigManager.KEY_CARRIER_PROVISIONS_WIFI_MERGED_NETWORKS_BOOL);
114         Log.i(TAG, "isCarrierNetworkProvisionEnabled:" + enabled);
115         return enabled;
116     }
117 
118     /** Return the enabled/disabled state of the carrier network */
isCarrierNetworkEnabled(int subId)119     public boolean isCarrierNetworkEnabled(int subId) {
120         return mWifiManager.isCarrierNetworkOffloadEnabled(subId, true /* merged */);
121     }
122 
123     /** Enables/disables the carrier network */
setCarrierNetworkEnabled(boolean enabled)124     public void setCarrierNetworkEnabled(boolean enabled) {
125         final MergedCarrierEntry mergedCarrierEntry = mWifiPickerTracker.getMergedCarrierEntry();
126         if (mergedCarrierEntry == null) {
127             return;
128         }
129         mergedCarrierEntry.setEnabled(enabled);
130     }
131 
132     /** Connect to the carrier network */
connectCarrierNetwork(@ullable WifiEntry.ConnectCallback callback)133     public boolean connectCarrierNetwork(@Nullable WifiEntry.ConnectCallback callback) {
134         final MergedCarrierEntry mergedCarrierEntry = mWifiPickerTracker.getMergedCarrierEntry();
135         if (mergedCarrierEntry == null || !mergedCarrierEntry.canConnect()) {
136             return false;
137         }
138         mergedCarrierEntry.connect(callback);
139         return true;
140     }
141 
142     /** Confirms connection of the carrier network connected with the internet access */
isCarrierNetworkActive()143     public boolean isCarrierNetworkActive() {
144         final MergedCarrierEntry mergedCarrierEntry = mWifiPickerTracker.getMergedCarrierEntry();
145         return (mergedCarrierEntry != null && mergedCarrierEntry.isDefaultNetwork());
146     }
147 
148     /** Return the carrier network ssid */
getCarrierNetworkSsid()149     public String getCarrierNetworkSsid() {
150         final MergedCarrierEntry mergedCarrierEntry = mWifiPickerTracker.getMergedCarrierEntry();
151         if (mergedCarrierEntry == null) {
152             return null;
153         }
154         return mergedCarrierEntry.getSsid();
155     }
156 
157     @VisibleForTesting
setWifiPickerTracker(@onNull WifiPickerTracker wifiPickerTracker)158     void setWifiPickerTracker(@NonNull WifiPickerTracker wifiPickerTracker) {
159         mWifiPickerTracker = wifiPickerTracker;
160     }
161 
162     @VisibleForTesting
setWorkerThread(@onNull HandlerThread workerThread)163     void setWorkerThread(@NonNull HandlerThread workerThread) {
164         mWorkerThread = workerThread;
165     }
166 }
167