• 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 SettingObserver mSettingObserver;
61     private volatile boolean mAvoidBadWifi = true;
62 
AvoidBadWifiTracker(Context ctx, Handler handler)63     public AvoidBadWifiTracker(Context ctx, Handler handler) {
64         this(ctx, handler, null);
65     }
66 
AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb)67     public AvoidBadWifiTracker(Context ctx, Handler handler, Runnable cb) {
68         mContext = ctx;
69         mHandler = handler;
70         mReevaluateRunnable = () -> { if (update() && cb != null) cb.run(); };
71         mSettingObserver = new SettingObserver();
72 
73         final IntentFilter intentFilter = new IntentFilter();
74         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
75         mContext.registerReceiverAsUser(new BroadcastReceiver() {
76             public void onReceive(Context context, Intent intent) {
77                 reevaluate();
78             }
79         }, UserHandle.ALL, intentFilter, null, null);
80 
81         update();
82     }
83 
currentValue()84     public boolean currentValue() {
85         return mAvoidBadWifi;
86     }
87 
88     /**
89      * Whether the device or carrier configuration disables avoiding bad wifi by default.
90      */
configRestrictsAvoidBadWifi()91     public boolean configRestrictsAvoidBadWifi() {
92         return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
93     }
94 
95     /**
96      * Whether we should display a notification when wifi becomes unvalidated.
97      */
shouldNotifyWifiUnvalidated()98     public boolean shouldNotifyWifiUnvalidated() {
99         return configRestrictsAvoidBadWifi() && getSettingsValue() == null;
100     }
101 
getSettingsValue()102     public String getSettingsValue() {
103         final ContentResolver resolver = mContext.getContentResolver();
104         return Settings.Global.getString(resolver, NETWORK_AVOID_BAD_WIFI);
105     }
106 
107     @VisibleForTesting
reevaluate()108     public void reevaluate() {
109         mHandler.post(mReevaluateRunnable);
110     }
111 
update()112     public boolean update() {
113         final boolean settingAvoidBadWifi = "1".equals(getSettingsValue());
114         final boolean prev = mAvoidBadWifi;
115         mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
116         return mAvoidBadWifi != prev;
117     }
118 
119     private class SettingObserver extends ContentObserver {
120         private final Uri mUri = Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI);
121 
SettingObserver()122         public SettingObserver() {
123             super(null);
124             final ContentResolver resolver = mContext.getContentResolver();
125             resolver.registerContentObserver(mUri, false, this);
126         }
127 
128         @Override
onChange(boolean selfChange)129         public void onChange(boolean selfChange) {
130             Slog.wtf(TAG, "Should never be reached.");
131         }
132 
133         @Override
onChange(boolean selfChange, Uri uri)134         public void onChange(boolean selfChange, Uri uri) {
135             if (!mUri.equals(uri)) return;
136             reevaluate();
137         }
138     }
139 }
140