Files
app_Settings/src/com/android/settings/datausage/DataSaverBackend.java
Matthew Fritze c6211c8829 Fix DataSaverBackend objects created on background threads
Add the main looper to the handler created with each
DataSaverBackend to avoid crashes when the objects are
created on background threads.

Bug: 62022517
Test: make RunSettingsRoboTests
Change-Id: Ie5ffabbfbe7660761527b3ecd51e6bc5a43c1ace
2017-08-08 19:03:43 -07:00

217 lines
7.5 KiB
Java

/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package com.android.settings.datausage;
import android.content.Context;
import android.net.INetworkPolicyListener;
import android.net.NetworkPolicyManager;
import android.os.Handler;
import android.os.Looper;
import android.os.RemoteException;
import android.util.SparseIntArray;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.settings.core.instrumentation.MetricsFeatureProvider;
import com.android.settings.overlay.FeatureFactory;
import java.util.ArrayList;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
public class DataSaverBackend {
private static final String TAG = "DataSaverBackend";
private final Context mContext;
private final MetricsFeatureProvider mMetricsFeatureProvider;
private final Handler mHandler = new Handler(Looper.getMainLooper());
private final NetworkPolicyManager mPolicyManager;
private final ArrayList<Listener> mListeners = new ArrayList<>();
private SparseIntArray mUidPolicies = new SparseIntArray();
private boolean mWhitelistInitialized;
private boolean mBlacklistInitialized;
// TODO: Staticize into only one.
public DataSaverBackend(Context context) {
mContext = context;
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mPolicyManager = NetworkPolicyManager.from(context);
}
public void addListener(Listener listener) {
mListeners.add(listener);
if (mListeners.size() == 1) {
mPolicyManager.registerListener(mPolicyListener);
}
listener.onDataSaverChanged(isDataSaverEnabled());
}
public void remListener(Listener listener) {
mListeners.remove(listener);
if (mListeners.size() == 0) {
mPolicyManager.unregisterListener(mPolicyListener);
}
}
public boolean isDataSaverEnabled() {
return mPolicyManager.getRestrictBackground();
}
public void setDataSaverEnabled(boolean enabled) {
mPolicyManager.setRestrictBackground(enabled);
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_DATA_SAVER_MODE, enabled ? 1 : 0);
}
public void refreshWhitelist() {
loadWhitelist();
}
public void setIsWhitelisted(int uid, String packageName, boolean whitelisted) {
final int policy = whitelisted ? POLICY_ALLOW_METERED_BACKGROUND : POLICY_NONE;
mPolicyManager.setUidPolicy(uid, policy);
mUidPolicies.put(uid, policy);
if (whitelisted) {
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_DATA_SAVER_WHITELIST, packageName);
}
}
public boolean isWhitelisted(int uid) {
loadWhitelist();
return mUidPolicies.get(uid, POLICY_NONE) == POLICY_ALLOW_METERED_BACKGROUND;
}
public int getWhitelistedCount() {
int count = 0;
loadWhitelist();
for (int i = 0; i < mUidPolicies.size(); i++) {
if (mUidPolicies.valueAt(i) == POLICY_ALLOW_METERED_BACKGROUND) {
count++;
}
}
return count;
}
private void loadWhitelist() {
if (mWhitelistInitialized) return;
for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_ALLOW_METERED_BACKGROUND)) {
mUidPolicies.put(uid, POLICY_ALLOW_METERED_BACKGROUND);
}
mWhitelistInitialized = true;
}
public void refreshBlacklist() {
loadBlacklist();
}
public void setIsBlacklisted(int uid, String packageName, boolean blacklisted) {
final int policy = blacklisted ? POLICY_REJECT_METERED_BACKGROUND : POLICY_NONE;
mPolicyManager.setUidPolicy(uid, policy);
mUidPolicies.put(uid, policy);
if (blacklisted) {
mMetricsFeatureProvider.action(
mContext, MetricsEvent.ACTION_DATA_SAVER_BLACKLIST, packageName);
}
}
public boolean isBlacklisted(int uid) {
loadBlacklist();
return mUidPolicies.get(uid, POLICY_NONE) == POLICY_REJECT_METERED_BACKGROUND;
}
private void loadBlacklist() {
if (mBlacklistInitialized) return;
for (int uid : mPolicyManager.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND)) {
mUidPolicies.put(uid, POLICY_REJECT_METERED_BACKGROUND);
}
mBlacklistInitialized = true;
}
private void handleRestrictBackgroundChanged(boolean isDataSaving) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onDataSaverChanged(isDataSaving);
}
}
private void handleWhitelistChanged(int uid, boolean isWhitelisted) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onWhitelistStatusChanged(uid, isWhitelisted);
}
}
private void handleBlacklistChanged(int uid, boolean isBlacklisted) {
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onBlacklistStatusChanged(uid, isBlacklisted);
}
}
private void handleUidPoliciesChanged(int uid, int newPolicy) {
loadWhitelist();
loadBlacklist();
final int oldPolicy = mUidPolicies.get(uid, POLICY_NONE);
if (newPolicy == POLICY_NONE) {
mUidPolicies.delete(uid);
} else {
mUidPolicies.put(uid, newPolicy);
}
final boolean wasWhitelisted = oldPolicy == POLICY_ALLOW_METERED_BACKGROUND;
final boolean wasBlacklisted = oldPolicy == POLICY_REJECT_METERED_BACKGROUND;
final boolean isWhitelisted = newPolicy == POLICY_ALLOW_METERED_BACKGROUND;
final boolean isBlacklisted = newPolicy == POLICY_REJECT_METERED_BACKGROUND;
if (wasWhitelisted != isWhitelisted) {
handleWhitelistChanged(uid, isWhitelisted);
}
if (wasBlacklisted != isBlacklisted) {
handleBlacklistChanged(uid, isBlacklisted);
}
}
private final INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() {
@Override
public void onUidRulesChanged(int uid, int uidRules) throws RemoteException {
}
@Override
public void onUidPoliciesChanged(final int uid, final int uidPolicies) {
mHandler.post(() -> handleUidPoliciesChanged(uid, uidPolicies));
}
@Override
public void onMeteredIfacesChanged(String[] strings) throws RemoteException {
}
@Override
public void onRestrictBackgroundChanged(final boolean isDataSaving) throws RemoteException {
mHandler.post(() -> handleRestrictBackgroundChanged(isDataSaving));
}
};
public interface Listener {
void onDataSaverChanged(boolean isDataSaving);
void onWhitelistStatusChanged(int uid, boolean isWhitelisted);
void onBlacklistStatusChanged(int uid, boolean isBlacklisted);
}
}