1 /*
2  * Copyright 2016, 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.managedprovisioning.task.wifi;
18 
19 import static com.android.internal.util.Preconditions.checkNotNull;
20 
21 import android.content.Context;
22 import android.net.ConnectivityManager;
23 import android.net.ConnectivityManager.NetworkCallback;
24 import android.net.Network;
25 import android.net.NetworkCapabilities;
26 
27 import com.android.managedprovisioning.common.ProvisionLogger;
28 
29 /**
30  * Monitor the state of the data network. Invoke a callback when the network is connected.
31  *
32  * The callback may be called multiple times for the same network as its status changes.
33  */
34 public class NetworkMonitor {
35 
36     /** State notification callback. Expect some duplicate notifications. */
37     public interface NetworkConnectedCallback {
onNetworkConnected()38         void onNetworkConnected();
39     }
40 
41     private final Context mContext;
42     private final boolean mWaitForValidated;
43 
44     private NetworkConnectedCallback mCallback = null;
45 
46     /**
47      * Start watching the network. Immediately invokes the callback method to report the
48      * current default network if any, and then invokes callback methods over time as the default
49      * network changes.
50      *
51      * @param context to use for intent observers and such
52      */
NetworkMonitor(Context context, boolean waitForValidated)53     public NetworkMonitor(Context context, boolean waitForValidated) {
54         mContext = checkNotNull(context);
55         mWaitForValidated = waitForValidated;
56     }
57 
58     /**
59      * Start listening for connectivity changes.
60      * @param callback Callback to inform about those changes.
61      */
startListening(NetworkConnectedCallback callback)62     public synchronized void startListening(NetworkConnectedCallback callback) {
63         mCallback = checkNotNull(callback);
64         // TODO: this code has always kept track of the default network, but it should probably
65         // instead use registerNetworkCallback or even requestNetwork with a specific
66         // NetworkRequest.Builder#addTransportType transport depending on the caller. For example,
67         // ConnectMobileNetworkTask should file a request for TRANSPORT_CELLULAR instead of waiting
68         // for any network to be available. When requestNetwork is not used, cellular data is also
69         // not guaranteed to connect after being enabled if another network is already available.
70         mContext.getSystemService(ConnectivityManager.class)
71                 .registerDefaultNetworkCallback(mConnectivityCallback);
72     }
73 
74     /**
75      * Stop listening for connectivity changes.
76      */
stopListening()77     public synchronized void stopListening() {
78         if (mCallback == null) {
79             return;
80         }
81 
82         mCallback = null;
83         mContext.getSystemService(ConnectivityManager.class)
84                 .unregisterNetworkCallback(mConnectivityCallback);
85     }
86 
87     private final NetworkCallback mConnectivityCallback = new NetworkCallback() {
88         private boolean mBlocked;
89         private boolean mValidated;
90 
91         @Override
92         public void onAvailable(Network network) {
93             // Default network switched to a new network. Set internal state to values that will
94             // not cause a callback to be sent. onBlockedStatusChanged and onCapabilitiesChanged
95             // will be called immediately after (then later on changes).
96             mBlocked = true;
97             mValidated = false;
98         }
99 
100         @Override
101         public void onBlockedStatusChanged(Network network, boolean blocked) {
102             if (mBlocked == blocked) {
103                 return;
104             }
105             ProvisionLogger.logd("NetworkMonitor.onBlockedStatusChanged: " + network
106                     + " blocked=" + blocked);
107             mBlocked = blocked;
108             maybeSendCallback();
109         }
110 
111         @Override
112         public void onCapabilitiesChanged(Network network, NetworkCapabilities caps) {
113             final boolean validated = caps.hasCapability(
114                     NetworkCapabilities.NET_CAPABILITY_VALIDATED);
115             if (!mWaitForValidated || mValidated == validated) {
116                 return;
117             }
118             ProvisionLogger.logd("NetworkMonitor.onCapabilitiesChanged: " + network
119                     + " validated=" + validated);
120             mValidated = validated;
121             maybeSendCallback();
122         }
123 
124         private void maybeSendCallback() {
125             // Receiving blocked=false is the equivalent to legacy behavior that would verify
126             // getActiveNetworkInfo().isConnected()
127             if (mBlocked || (mWaitForValidated && !mValidated)) {
128                 return;
129             }
130             synchronized (NetworkMonitor.this) {
131                 if (mCallback != null) {
132                     mCallback.onNetworkConnected();
133                 }
134             }
135         }
136     };
137 }
138