lineage-sdk: Add Network Traffic [2/3]

Changes made since the original implementation from older branches:

*) Forward-ported to Oreo and adapted to Lineage SDK (bgcngm).

*) Implement LineageStatusBarItem interfaces to receive visibility
   and color tint information (bgcngm / sam3000).

*) Move from fw/b to lineage-sdk (sam3000).

*) Increase refresh interval from 1s to 2s (sam3000).

*) Don't generate messages when the statusbar isn't visible (sam3000).

*) Allow for choice of unit to be kb/s or Mb/s (and kB/s and MB/s). This
   deprecates threshold selection for autohide (sam3000).

*) Add an option for whether units should be shown in the
   statusbar (sam3000).

*) Various other simplifications (sam3000).

*) Added vector drawables (courtesy of kover).

Change-Id: Ia5aadc3f03a7b434a047accbd7d53f4aa44c77fb
This commit is contained in:
Jon Haus
2014-12-06 17:19:23 +01:00
committed by Dan Pasanen
parent 27a44cc178
commit 7ea84eb2f9
8 changed files with 555 additions and 1 deletions

View File

@@ -1,5 +1,6 @@
/**
* Copyright (c) 2015, The CyanogenMod Project
* Copyright (C) 2015-2016 The CyanogenMod Project
* Copyright (C) 2017-2018 The LineageOS Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -2910,6 +2911,47 @@ public final class LineageSettings {
*/
public static final String LOCK_SCREEN_WEATHER_ENABLED = "lock_screen_weather_enabled";
/**
* Network traffic indicator mode
* 0 = Don't show network traffic indicator
* 1 = Display up-stream traffic only
* 2 = Display down-stream traffic only
* 3 = Display both up- and down-stream traffic
* @hide
*/
public static final String NETWORK_TRAFFIC_MODE = "network_traffic_mode";
/** @hide */
public static final Validator NETWORK_TRAFFIC_MODE_VALIDATOR =
new InclusiveIntegerRangeValidator(0, 3);
/**
* Whether or not to hide the network traffic indicator when there is no activity
* @hide
*/
public static final String NETWORK_TRAFFIC_AUTOHIDE = "network_traffic_autohide";
/** @hide */
public static final Validator NETWORK_TRAFFIC_AUTOHIDE_VALIDATOR = sBooleanValidator;
/**
* Measurement unit preference for network traffic
* @hide
*/
public static final String NETWORK_TRAFFIC_UNITS = "network_traffic_units";
/** @hide */
public static final Validator NETWORK_TRAFFIC_UNITS_VALIDATOR =
new InclusiveIntegerRangeValidator(0, 3);
/**
* Whether or not to show measurement units in the network traffic indiciator
* @hide
*/
public static final String NETWORK_TRAFFIC_SHOW_UNITS = "network_traffic_show_units";
/** @hide */
public static final Validator NETWORK_TRAFFIC_SHOW_UNITS_VALIDATOR = sBooleanValidator;
// endregion
@@ -3016,6 +3058,10 @@ public final class LineageSettings {
static {
VALIDATORS.put(PROTECTED_COMPONENTS, PROTECTED_COMPONENTS_VALIDATOR);
VALIDATORS.put(PROTECTED_COMPONENT_MANAGERS, PROTECTED_COMPONENTS_MANAGER_VALIDATOR);
VALIDATORS.put(NETWORK_TRAFFIC_MODE, NETWORK_TRAFFIC_MODE_VALIDATOR);
VALIDATORS.put(NETWORK_TRAFFIC_AUTOHIDE, NETWORK_TRAFFIC_AUTOHIDE_VALIDATOR);
VALIDATORS.put(NETWORK_TRAFFIC_UNITS, NETWORK_TRAFFIC_UNITS_VALIDATOR);
VALIDATORS.put(NETWORK_TRAFFIC_SHOW_UNITS, NETWORK_TRAFFIC_SHOW_UNITS_VALIDATOR);
}
/**

View File

@@ -0,0 +1,371 @@
/**
* Copyright (C) 2017-2018 The LineageOS 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 org.lineageos.internal.statusbar;
import android.animation.ArgbEvaluator;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.net.ConnectivityManager;
import android.net.TrafficStats;
import android.os.Handler;
import android.os.UserHandle;
import android.os.Message;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.widget.TextView;
import lineageos.providers.LineageSettings;
import org.lineageos.platform.internal.R;
public class NetworkTraffic extends TextView {
private static final String TAG = "NetworkTraffic";
private static final int MODE_DISABLED = 0;
private static final int MODE_UPSTREAM_ONLY = 1;
private static final int MODE_DOWNSTREAM_ONLY = 2;
private static final int MODE_UPSTREAM_AND_DOWNSTREAM = 3;
private static final int MESSAGE_TYPE_PERIODIC_REFRESH = 0;
private static final int MESSAGE_TYPE_UPDATE_VIEW = 1;
private static final int REFRESH_INTERVAL = 2000;
private static final int UNITS_KILOBITS = 0;
private static final int UNITS_MEGABITS = 1;
private static final int UNITS_KILOBYTES = 2;
private static final int UNITS_MEGABYTES = 3;
// Thresholds themselves are always defined in kbps
private static final long AUTOHIDE_THRESHOLD_KILOBITS = 10;
private static final long AUTOHIDE_THRESHOLD_MEGABITS = 100;
private static final long AUTOHIDE_THRESHOLD_KILOBYTES = 8;
private static final long AUTOHIDE_THRESHOLD_MEGABYTES = 80;
private int mMode = MODE_DISABLED;
private boolean mNetworkTrafficIsVisible;
private long mTxKbps;
private long mRxKbps;
private long mLastTxBytesTotal;
private long mLastRxBytesTotal;
private long mLastUpdateTime;
private int mTextSizeSingle;
private int mTextSizeMulti;
private boolean mAutoHide;
private long mAutoHideThreshold;
private int mUnits;
private boolean mShowUnits;
private int mDarkModeFillColor;
private int mLightModeFillColor;
private int mIconTint = Color.WHITE;
private SettingsObserver mObserver;
private Drawable mDrawable;
public NetworkTraffic(Context context) {
this(context, null);
}
public NetworkTraffic(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NetworkTraffic(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
final Resources resources = getResources();
mTextSizeSingle = resources.getDimensionPixelSize(R.dimen.net_traffic_single_text_size);
mTextSizeMulti = resources.getDimensionPixelSize(R.dimen.net_traffic_multi_text_size);
mNetworkTrafficIsVisible = false;
mObserver = new SettingsObserver(mTrafficHandler);
}
private LineageStatusBarItem.DarkReceiver mDarkReceiver =
new LineageStatusBarItem.DarkReceiver() {
public void onDarkChanged(Rect area, float darkIntensity, int tint) {
mIconTint = (int) ArgbEvaluator.getInstance().evaluate(darkIntensity,
mLightModeFillColor, mDarkModeFillColor);
setTextColor(mIconTint);
updateTrafficDrawableColor();
}
public void setFillColors(int darkColor, int lightColor) {
mDarkModeFillColor = darkColor;
mLightModeFillColor = lightColor;
}
};
private LineageStatusBarItem.VisibilityReceiver mVisibilityReceiver =
new LineageStatusBarItem.VisibilityReceiver() {
public void onVisibilityChanged(boolean isVisible) {
if (mNetworkTrafficIsVisible != isVisible) {
mNetworkTrafficIsVisible = isVisible;
updateViewState();
}
}
};
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
LineageStatusBarItem.Manager manager =
LineageStatusBarItem.findManager((View) this);
manager.addDarkReceiver(mDarkReceiver);
manager.addVisibilityReceiver(mVisibilityReceiver);
mContext.registerReceiver(mIntentReceiver,
new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mObserver.observe();
updateSettings();
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mContext.unregisterReceiver(mIntentReceiver);
mObserver.unobserve();
}
private Handler mTrafficHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
long now = SystemClock.elapsedRealtime();
long timeDelta = now - mLastUpdateTime;
if (msg.what == MESSAGE_TYPE_PERIODIC_REFRESH
&& timeDelta >= REFRESH_INTERVAL * 0.95f) {
// Update counters
mLastUpdateTime = now;
long txBytes = TrafficStats.getTotalTxBytes() - mLastTxBytesTotal;
long rxBytes = TrafficStats.getTotalRxBytes() - mLastRxBytesTotal;
mTxKbps = (long) (txBytes * 8f / (timeDelta / 1000f) / 1000f);
mRxKbps = (long) (rxBytes * 8f / (timeDelta / 1000f) / 1000f);
mLastTxBytesTotal += txBytes;
mLastRxBytesTotal += rxBytes;
}
final boolean enabled = mMode != MODE_DISABLED && isConnectionAvailable();
final boolean showUpstream =
mMode == MODE_UPSTREAM_ONLY || mMode == MODE_UPSTREAM_AND_DOWNSTREAM;
final boolean showDownstream =
mMode == MODE_DOWNSTREAM_ONLY || mMode == MODE_UPSTREAM_AND_DOWNSTREAM;
final boolean shouldHide = mAutoHide && (!showUpstream || mTxKbps < mAutoHideThreshold)
&& (!showDownstream || mRxKbps < mAutoHideThreshold);
if (!enabled || shouldHide) {
setText("");
setVisibility(GONE);
} else {
// Get information for uplink ready so the line return can be added
StringBuilder output = new StringBuilder();
if (showUpstream) {
output.append(formatOutput(mTxKbps));
}
// Ensure text size is where it needs to be
int textSize;
if (showUpstream && showDownstream) {
output.append("\n");
textSize = mTextSizeMulti;
} else {
textSize = mTextSizeSingle;
}
// Add information for downlink if it's called for
if (showDownstream) {
output.append(formatOutput(mRxKbps));
}
// Update view if there's anything new to show
if (!output.toString().contentEquals(getText())) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, (float) textSize);
setText(output.toString());
}
setVisibility(VISIBLE);
}
// Schedule periodic refresh
mTrafficHandler.removeMessages(MESSAGE_TYPE_PERIODIC_REFRESH);
if (enabled && mNetworkTrafficIsVisible) {
mTrafficHandler.sendEmptyMessageDelayed(MESSAGE_TYPE_PERIODIC_REFRESH,
REFRESH_INTERVAL);
}
}
private String formatOutput(long kbps) {
final String value;
final String unit;
switch (mUnits) {
case UNITS_KILOBITS:
value = String.format("%d", kbps);
unit = mContext.getString(R.string.kilobitspersecond_short);
break;
case UNITS_MEGABITS:
value = String.format("%.1f", (float) kbps / 1000);
unit = mContext.getString(R.string.megabitspersecond_short);
break;
case UNITS_KILOBYTES:
value = String.format("%d", kbps / 8);
unit = mContext.getString(R.string.kilobytespersecond_short);
break;
case UNITS_MEGABYTES:
value = String.format("%.2f", (float) kbps / 8000);
unit = mContext.getString(R.string.megabytespersecond_short);
break;
default:
value = "unknown";
unit = "unknown";
break;
}
if (mShowUnits) {
return value + " " + unit;
} else {
return value;
}
}
};
private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
updateViewState();
}
}
};
class SettingsObserver extends ContentObserver {
SettingsObserver(Handler handler) {
super(handler);
}
void observe() {
ContentResolver resolver = mContext.getContentResolver();
resolver.registerContentObserver(LineageSettings.Secure.getUriFor(
LineageSettings.Secure.NETWORK_TRAFFIC_MODE),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.Secure.getUriFor(
LineageSettings.Secure.NETWORK_TRAFFIC_AUTOHIDE),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.Secure.getUriFor(
LineageSettings.Secure.NETWORK_TRAFFIC_UNITS),
false, this, UserHandle.USER_ALL);
resolver.registerContentObserver(LineageSettings.Secure.getUriFor(
LineageSettings.Secure.NETWORK_TRAFFIC_SHOW_UNITS),
false, this, UserHandle.USER_ALL);
}
void unobserve() {
mContext.getContentResolver().unregisterContentObserver(this);
}
@Override
public void onChange(boolean selfChange) {
updateSettings();
}
}
private boolean isConnectionAvailable() {
ConnectivityManager cm =
(ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
return cm.getActiveNetworkInfo() != null;
}
private void updateSettings() {
ContentResolver resolver = mContext.getContentResolver();
mMode = LineageSettings.Secure.getIntForUser(resolver,
LineageSettings.Secure.NETWORK_TRAFFIC_MODE, 0, UserHandle.USER_CURRENT);
mAutoHide = LineageSettings.Secure.getIntForUser(resolver,
LineageSettings.Secure.NETWORK_TRAFFIC_AUTOHIDE, 0, UserHandle.USER_CURRENT) == 1;
mUnits = LineageSettings.Secure.getIntForUser(resolver,
LineageSettings.Secure.NETWORK_TRAFFIC_UNITS, /* Mbps */ 1,
UserHandle.USER_CURRENT);
switch (mUnits) {
case UNITS_KILOBITS:
mAutoHideThreshold = AUTOHIDE_THRESHOLD_KILOBITS;
break;
case UNITS_MEGABITS:
mAutoHideThreshold = AUTOHIDE_THRESHOLD_MEGABITS;
break;
case UNITS_KILOBYTES:
mAutoHideThreshold = AUTOHIDE_THRESHOLD_KILOBYTES;
break;
case UNITS_MEGABYTES:
mAutoHideThreshold = AUTOHIDE_THRESHOLD_MEGABYTES;
break;
default:
mAutoHideThreshold = 0;
break;
}
mShowUnits = LineageSettings.Secure.getIntForUser(resolver,
LineageSettings.Secure.NETWORK_TRAFFIC_SHOW_UNITS, 1,
UserHandle.USER_CURRENT) == 1;
if (mMode != MODE_DISABLED) {
updateTrafficDrawable();
}
updateViewState();
}
private void updateViewState() {
mTrafficHandler.sendEmptyMessage(MESSAGE_TYPE_UPDATE_VIEW);
}
private void clearHandlerCallbacks() {
mTrafficHandler.removeMessages(MESSAGE_TYPE_PERIODIC_REFRESH);
mTrafficHandler.removeMessages(MESSAGE_TYPE_UPDATE_VIEW);
}
private void updateTrafficDrawable() {
final int drawableResId;
if (mMode == MODE_UPSTREAM_AND_DOWNSTREAM) {
drawableResId = R.drawable.stat_sys_network_traffic_updown;
} else if (mMode == MODE_UPSTREAM_ONLY) {
drawableResId = R.drawable.stat_sys_network_traffic_up;
} else if (mMode == MODE_DOWNSTREAM_ONLY) {
drawableResId = R.drawable.stat_sys_network_traffic_down;
} else {
drawableResId = 0;
}
mDrawable = drawableResId != 0 ? getResources().getDrawable(drawableResId) : null;
setCompoundDrawablesWithIntrinsicBounds(null, null, mDrawable, null);
updateTrafficDrawableColor();
}
private void updateTrafficDrawableColor() {
if (mDrawable != null) {
mDrawable.setColorFilter(mIconTint, PorterDuff.Mode.SRC_ATOP);
}
}
}