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

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="18dp"
android:viewportWidth="14"
android:viewportHeight="18">
<path
android:name="down"
android:fillColor="#FFFFFFFF"
android:pathData="M9,16l3-3h-2V8H8v5H6L9,16z" />
<path
android:name="up"
android:fillColor="#4DFFFFFF"
android:pathData="M5,2L2,5h2v5h2V5h2L5,2z" />
</vector>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="18dp"
android:viewportWidth="14"
android:viewportHeight="18">
<path
android:name="down"
android:fillColor="#4DFFFFFF"
android:pathData="M9,16l3-3h-2V8H8v5H6L9,16z" />
<path
android:name="up"
android:fillColor="#FFFFFFFF"
android:pathData="M5,2L2,5h2v5h2V5h2L5,2z" />
</vector>

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2017 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.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="14dp"
android:height="18dp"
android:viewportWidth="14"
android:viewportHeight="18">
<path
android:name="down"
android:fillColor="#FFFFFFFF"
android:pathData="M9,16l3-3h-2V8H8v5H6L9,16z" />
<path
android:name="up"
android:fillColor="#FFFFFFFF"
android:pathData="M5,2L2,5h2v5h2V5h2L5,2z" />
</vector>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2014 The CyanogenMod Project
Copyright (C) 2017 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.
-->
<resources>
<dimen name="net_traffic_single_text_size">14sp</dimen>
<dimen name="net_traffic_multi_text_size">8sp</dimen>
</resources>

View File

@@ -151,4 +151,10 @@
<!-- Long-press back kill application -->
<string name="app_killed_message">Application killed</string>
<!-- Status bar network traffic monitor strings -->
<string name="kilobitspersecond_short">kb/s</string>
<string name="megabitspersecond_short">Mb/s</string>
<string name="kilobytespersecond_short">kB/s</string>
<string name="megabytespersecond_short">MB/s</string>
</resources>

View File

@@ -139,4 +139,15 @@
<!-- Power menu -->
<java-symbol type="array" name="config_restartActionsList" />
<!-- Status bar network traffic monitor -->
<java-symbol type="drawable" name="stat_sys_network_traffic_down" />
<java-symbol type="drawable" name="stat_sys_network_traffic_up" />
<java-symbol type="drawable" name="stat_sys_network_traffic_updown" />
<java-symbol type="dimen" name="net_traffic_single_text_size" />
<java-symbol type="dimen" name="net_traffic_multi_text_size" />
<java-symbol type="string" name="kilobitspersecond_short" />
<java-symbol type="string" name="megabitspersecond_short" />
<java-symbol type="string" name="kilobytespersecond_short" />
<java-symbol type="string" name="megabytespersecond_short" />
</resources>

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);
}
}
}