1 /*
2  * Copyright (C) 2020 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.wifitrackerlib;
18 
19 import static android.net.wifi.WifiInfo.DEFAULT_MAC_ADDRESS;
20 import static android.net.wifi.WifiInfo.sanitizeSsid;
21 
22 import static com.android.wifitrackerlib.Utils.getVerboseLoggingDescription;
23 
24 import android.content.Context;
25 import android.net.NetworkInfo;
26 import android.net.wifi.WifiInfo;
27 import android.net.wifi.WifiManager;
28 import android.net.wifi.WifiNetworkScoreCache;
29 import android.os.Handler;
30 import android.text.TextUtils;
31 import android.widget.Toast;
32 
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 import androidx.annotation.WorkerThread;
36 
37 import java.util.StringJoiner;
38 
39 /**
40  * WifiEntry representation of merged carrier network, uniquely identified by subscription id.
41  */
42 public class MergedCarrierEntry extends WifiEntry {
43     static final String KEY_PREFIX = "MergedCarrierEntry:";
44 
45     private final int mSubscriptionId;
46     @NonNull private final String mKey;
47     @NonNull private final Context mContext;
48     boolean mIsCellDefaultRoute;
49 
MergedCarrierEntry(@onNull Handler callbackHandler, @NonNull WifiManager wifiManager, @NonNull WifiNetworkScoreCache scoreCache, boolean forSavedNetworksPage, @NonNull Context context, int subscriptionId)50     MergedCarrierEntry(@NonNull Handler callbackHandler,
51             @NonNull WifiManager wifiManager,
52             @NonNull WifiNetworkScoreCache scoreCache,
53             boolean forSavedNetworksPage,
54             @NonNull Context context,
55             int subscriptionId) throws IllegalArgumentException {
56         super(callbackHandler, wifiManager, scoreCache, forSavedNetworksPage);
57         mContext = context;
58         mSubscriptionId = subscriptionId;
59         mKey = KEY_PREFIX + subscriptionId;
60     }
61 
62     @Override
getKey()63     public String getKey() {
64         return mKey;
65     }
66 
67     @Override
getSummary(boolean concise)68     public String getSummary(boolean concise) {
69         StringJoiner sj = new StringJoiner(mContext.getString(
70                 R.string.wifitrackerlib_summary_separator));
71         if (!concise) {
72             final String verboseLoggingDescription = getVerboseLoggingDescription(this);
73             if (!TextUtils.isEmpty(verboseLoggingDescription)) {
74                 sj.add(verboseLoggingDescription);
75             }
76         }
77         return sj.toString();
78     }
79 
80     @Override
getSsid()81     public synchronized String getSsid() {
82         if (mWifiInfo != null) {
83             return sanitizeSsid(mWifiInfo.getSSID());
84         }
85         return null;
86     }
87 
88     @Override
getMacAddress()89     public synchronized String getMacAddress() {
90         if (mWifiInfo != null) {
91             final String wifiInfoMac = mWifiInfo.getMacAddress();
92             if (!TextUtils.isEmpty(wifiInfoMac)
93                     && !TextUtils.equals(wifiInfoMac, DEFAULT_MAC_ADDRESS)) {
94                 return wifiInfoMac;
95             }
96         }
97         return null;
98     }
99 
100     @Override
canConnect()101     public synchronized boolean canConnect() {
102         return getConnectedState() == CONNECTED_STATE_DISCONNECTED && !mIsCellDefaultRoute;
103     }
104 
105     /**
106      * Connect to this merged carrier network and show the "Wi-Fi won't autoconnect for now" toast.
107      * @param callback callback for the connect result
108      */
109     @Override
connect(@ullable ConnectCallback callback)110     public synchronized void connect(@Nullable ConnectCallback callback) {
111         connect(callback, true);
112     }
113 
114     /**
115      * Connect to this merged carrier network.
116      * @param callback callback for the connect result
117      * @param showToast show the "Wi-Fi won't autoconnect for now" toast if {@code true}
118      */
connect(@ullable ConnectCallback callback, boolean showToast)119     public synchronized void connect(@Nullable ConnectCallback callback, boolean showToast) {
120         mConnectCallback = callback;
121         mWifiManager.startRestrictingAutoJoinToSubscriptionId(mSubscriptionId);
122         if (showToast) {
123             Toast.makeText(mContext, R.string.wifitrackerlib_wifi_wont_autoconnect_for_now,
124                     Toast.LENGTH_SHORT).show();
125         }
126         if (mConnectCallback != null) {
127             mCallbackHandler.post(() -> {
128                 final ConnectCallback connectCallback = mConnectCallback;
129                 if (connectCallback != null) {
130                     connectCallback.onConnectResult(ConnectCallback.CONNECT_STATUS_SUCCESS);
131                 }
132             });
133         }
134     }
135 
136     @Override
canDisconnect()137     public boolean canDisconnect() {
138         return getConnectedState() == CONNECTED_STATE_CONNECTED;
139     }
140 
141     @Override
disconnect(@ullable DisconnectCallback callback)142     public synchronized void disconnect(@Nullable DisconnectCallback callback) {
143         mDisconnectCallback = callback;
144         mWifiManager.stopRestrictingAutoJoinToSubscriptionId();
145         mWifiManager.startScan();
146         if (mDisconnectCallback != null) {
147             mCallbackHandler.post(() -> {
148                 final DisconnectCallback disconnectCallback = mDisconnectCallback;
149                 if (disconnectCallback != null) {
150                     disconnectCallback.onDisconnectResult(
151                             DisconnectCallback.DISCONNECT_STATUS_SUCCESS);
152                 }
153             });
154         }
155     }
156 
157     @WorkerThread
connectionInfoMatches(@onNull WifiInfo wifiInfo, @NonNull NetworkInfo networkInfo)158     protected boolean connectionInfoMatches(@NonNull WifiInfo wifiInfo,
159             @NonNull NetworkInfo networkInfo) {
160         return wifiInfo.isCarrierMerged() && mSubscriptionId == wifiInfo.getSubscriptionId();
161     }
162 
163     /** Returns whether or not carrier network offload is enabled for this subscription **/
isEnabled()164     public boolean isEnabled() {
165         return mWifiManager.isCarrierNetworkOffloadEnabled(mSubscriptionId, true);
166     }
167 
168     /** Enables/disables the carrier network */
setEnabled(boolean enabled)169     public void setEnabled(boolean enabled) {
170         mWifiManager.setCarrierNetworkOffloadEnabled(mSubscriptionId, true, enabled);
171         if (!enabled) {
172             mWifiManager.stopRestrictingAutoJoinToSubscriptionId();
173             mWifiManager.startScan();
174         }
175     }
176 
getSubscriptionId()177     /* package */ int getSubscriptionId() {
178         return mSubscriptionId;
179     }
180 
updateIsCellDefaultRoute(boolean isCellDefaultRoute)181     /* package */ synchronized void updateIsCellDefaultRoute(boolean isCellDefaultRoute) {
182         mIsCellDefaultRoute = isCellDefaultRoute;
183         notifyOnUpdated();
184     }
185 }
186