• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 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 android.net.util;
18 
19 import android.content.BroadcastReceiver;
20 import android.content.ContentResolver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.database.ContentObserver;
25 import android.net.Uri;
26 import android.os.Handler;
27 import android.os.Message;
28 import android.os.UserHandle;
29 import android.provider.Settings;
30 import android.util.Slog;
31 
32 import com.android.internal.annotations.VisibleForTesting;
33 import com.android.internal.R;
34 
35 import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
36 
37 /**
38  * A class to encapsulate management of the "Smart Networking" capability of
39  * avoiding bad Wi-Fi when, for example upstream connectivity is lost or
40  * certain critical link failures occur.
41  *
42  * This enables the device to switch to another form of connectivity, like
43  * mobile, if it's available and working.
44  *
45  * The Runnable |cb|, if given, is called on the supplied Handler's thread
46  * whether the computed "avoid bad wifi" value changes.
47  *
48  * Disabling this reverts the device to a level of networking sophistication
49  * circa 2012-13 by disabling disparate code paths each of which contribute to
50  * maintaining continuous, working Internet connectivity.
51  *
52  * @hide
53  */
54 public class AvoidBadWifiTracker {
55     private static String TAG = AvoidBadWifiTracker.class.getSimpleName();
56 
57     private final Context mContext;
58     private final Handler mHandler;
59     private final Runnable mReevaluateRunnable;
60     private final Uri mUri;
61     private final ContentResolver mResolver;
62     private final SettingObserver mSettingObserver;
63     private final BroadcastReceiver mBroadcastReceiver;
64 
65     private volatile boolean mAvoidBadWifi = true;
66 
AvoidBadWifiTracker(Context ctx, Handler handler)67     public AvoidBadWifiTracker(Context ctx, Handler handler) {
68         this(ctx, handler, null);
69     }
70 
AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb)71     public AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb) {
72         mContext = ctx;
73         mHandler = handler;
74         mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
75         mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
76         mResolver = mContext.getContentResolver();
77         mSettingObserver = new SettingObserver();
78         mBroadcastReceiver = new BroadcastReceiver() {
79             @Override
80             public void onReceive(Context context, Intent intent) {
81                 reevaluate();
82             }
83         };
84 
85         update();
86     }
87 
start()88     public void start() {
89         mResolver.registerContentObserver(mUri, false, mSettingObserver);
90 
91         final IntentFilter intentFilter = new IntentFilter();
92         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
93         mContext.registerReceiverAsUser(
94                 mBroadcastReceiver, UserHandle.ALL, intentFilter, null, null);
95 
96         reevaluate();
97     }
98 
shutdown()99     public void shutdown() {
100         mResolver.unregisterContentObserver(mSettingObserver);
101 
102         mContext.unregisterReceiver(mBroadcastReceiver);
103     }
104 
currentValue()105     public boolean currentValue() {
106         return mAvoidBadWifi;
107     }
108 
109     /**
110      * Whether the device or carrier configuration disables avoiding bad wifi by default.
111      */
configRestrictsAvoidBadWifi()112     public boolean configRestrictsAvoidBadWifi() {
113         return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
114     }
115 
116     /**
117      * Whether we should display a notification when wifi becomes unvalidated.
118      */
shouldNotifyWifiUnvalidated()119     public boolean shouldNotifyWifiUnvalidated() {
120         return configRestrictsAvoidBadWifi() && getSettingsValue() == null;
121     }
122 
getSettingsValue()123     public String getSettingsValue() {
124         return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
125     }
126 
127     @VisibleForTesting
reevaluate()128     public void reevaluate() {
129         mHandler.post(mReevaluateRunnable);
130     }
131 
update()132     public boolean update() {
133         final boolean settingAvoidBadWifi = "1".equals(getSettingsValue());
134         final boolean prev = mAvoidBadWifi;
135         mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
136         return mAvoidBadWifi != prev;
137     }
138 
139     private class SettingObserver extends ContentObserver {
SettingObserver()140         public SettingObserver() {
141             super(null);
142         }
143 
144         @Override
onChange(boolean selfChange)145         public void onChange(boolean selfChange) {
146             Slog.wtf(TAG, "Should never be reached.");
147         }
148 
149         @Override
onChange(boolean selfChange, Uri uri)150         public void onChange(boolean selfChange, Uri uri) {
151             if (!mUri.equals(uri)) return;
152             reevaluate();
153         }
154     }
155 }
156