OSDN Git Service

Merge "docs: Add documentation for equals() method" into qt-dev
[android-x86/frameworks-base.git] / core / java / android / net / util / MultinetworkPolicyTracker.java
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.ConnectivityManager;
26 import android.net.Uri;
27 import android.os.Handler;
28 import android.os.Message;
29 import android.os.UserHandle;
30 import android.provider.Settings;
31 import android.util.Slog;
32
33 import java.util.Arrays;
34 import java.util.List;
35
36 import com.android.internal.annotations.VisibleForTesting;
37 import com.android.internal.R;
38
39 import static android.provider.Settings.Global.NETWORK_AVOID_BAD_WIFI;
40 import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
41
42 /**
43  * A class to encapsulate management of the "Smart Networking" capability of
44  * avoiding bad Wi-Fi when, for example upstream connectivity is lost or
45  * certain critical link failures occur.
46  *
47  * This enables the device to switch to another form of connectivity, like
48  * mobile, if it's available and working.
49  *
50  * The Runnable |avoidBadWifiCallback|, if given, is posted to the supplied
51  * Handler' whenever the computed "avoid bad wifi" value changes.
52  *
53  * Disabling this reverts the device to a level of networking sophistication
54  * circa 2012-13 by disabling disparate code paths each of which contribute to
55  * maintaining continuous, working Internet connectivity.
56  *
57  * @hide
58  */
59 public class MultinetworkPolicyTracker {
60     private static String TAG = MultinetworkPolicyTracker.class.getSimpleName();
61
62     private final Context mContext;
63     private final Handler mHandler;
64     private final Runnable mReevaluateRunnable;
65     private final List<Uri> mSettingsUris;
66     private final ContentResolver mResolver;
67     private final SettingObserver mSettingObserver;
68     private final BroadcastReceiver mBroadcastReceiver;
69
70     private volatile boolean mAvoidBadWifi = true;
71     private volatile int mMeteredMultipathPreference;
72
73     public MultinetworkPolicyTracker(Context ctx, Handler handler) {
74         this(ctx, handler, null);
75     }
76
77     public MultinetworkPolicyTracker(Context ctx, Handler handler, Runnable avoidBadWifiCallback) {
78         mContext = ctx;
79         mHandler = handler;
80         mReevaluateRunnable = () -> {
81             if (updateAvoidBadWifi() && avoidBadWifiCallback != null) {
82                 avoidBadWifiCallback.run();
83             }
84             updateMeteredMultipathPreference();
85         };
86         mSettingsUris = Arrays.asList(
87             Settings.Global.getUriFor(NETWORK_AVOID_BAD_WIFI),
88             Settings.Global.getUriFor(NETWORK_METERED_MULTIPATH_PREFERENCE));
89         mResolver = mContext.getContentResolver();
90         mSettingObserver = new SettingObserver();
91         mBroadcastReceiver = new BroadcastReceiver() {
92             @Override
93             public void onReceive(Context context, Intent intent) {
94                 reevaluate();
95             }
96         };
97
98         updateAvoidBadWifi();
99         updateMeteredMultipathPreference();
100     }
101
102     public void start() {
103         for (Uri uri : mSettingsUris) {
104             mResolver.registerContentObserver(uri, false, mSettingObserver);
105         }
106
107         final IntentFilter intentFilter = new IntentFilter();
108         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
109         mContext.registerReceiverAsUser(
110                 mBroadcastReceiver, UserHandle.ALL, intentFilter, null, null);
111
112         reevaluate();
113     }
114
115     public void shutdown() {
116         mResolver.unregisterContentObserver(mSettingObserver);
117
118         mContext.unregisterReceiver(mBroadcastReceiver);
119     }
120
121     public boolean getAvoidBadWifi() {
122         return mAvoidBadWifi;
123     }
124
125     // TODO: move this to MultipathPolicyTracker.
126     public int getMeteredMultipathPreference() {
127         return mMeteredMultipathPreference;
128     }
129
130     /**
131      * Whether the device or carrier configuration disables avoiding bad wifi by default.
132      */
133     public boolean configRestrictsAvoidBadWifi() {
134         return (mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi) == 0);
135     }
136
137     /**
138      * Whether we should display a notification when wifi becomes unvalidated.
139      */
140     public boolean shouldNotifyWifiUnvalidated() {
141         return configRestrictsAvoidBadWifi() && getAvoidBadWifiSetting() == null;
142     }
143
144     public String getAvoidBadWifiSetting() {
145         return Settings.Global.getString(mResolver, NETWORK_AVOID_BAD_WIFI);
146     }
147
148     @VisibleForTesting
149     public void reevaluate() {
150         mHandler.post(mReevaluateRunnable);
151     }
152
153     public boolean updateAvoidBadWifi() {
154         final boolean settingAvoidBadWifi = "1".equals(getAvoidBadWifiSetting());
155         final boolean prev = mAvoidBadWifi;
156         mAvoidBadWifi = settingAvoidBadWifi || !configRestrictsAvoidBadWifi();
157         return mAvoidBadWifi != prev;
158     }
159
160     /**
161      * The default (device and carrier-dependent) value for metered multipath preference.
162      */
163     public int configMeteredMultipathPreference() {
164         return mContext.getResources().getInteger(
165                 R.integer.config_networkMeteredMultipathPreference);
166     }
167
168     public void updateMeteredMultipathPreference() {
169         String setting = Settings.Global.getString(mResolver, NETWORK_METERED_MULTIPATH_PREFERENCE);
170         try {
171             mMeteredMultipathPreference = Integer.parseInt(setting);
172         } catch (NumberFormatException e) {
173             mMeteredMultipathPreference = configMeteredMultipathPreference();
174         }
175     }
176
177     private class SettingObserver extends ContentObserver {
178         public SettingObserver() {
179             super(null);
180         }
181
182         @Override
183         public void onChange(boolean selfChange) {
184             Slog.wtf(TAG, "Should never be reached.");
185         }
186
187         @Override
188         public void onChange(boolean selfChange, Uri uri) {
189             if (!mSettingsUris.contains(uri)) {
190                 Slog.wtf(TAG, "Unexpected settings observation: " + uri);
191             }
192             reevaluate();
193         }
194     }
195 }