Initial commit
19
.gitignore
vendored
@ -1,12 +1,7 @@
|
|||||||
*.class
|
.gradle
|
||||||
|
/local.properties
|
||||||
# Mobile Tools for Java (J2ME)
|
/.idea/workspace.xml
|
||||||
.mtj.tmp/
|
/.idea/libraries
|
||||||
|
.DS_Store
|
||||||
# Package Files #
|
/build
|
||||||
*.jar
|
/captures
|
||||||
*.war
|
|
||||||
*.ear
|
|
||||||
|
|
||||||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
|
|
||||||
hs_err_pid*
|
|
||||||
|
7
README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
Speedo - Network Speed Monitor
|
||||||
|
=============================================================================
|
||||||
|
|
||||||
|
Speedo is an extremely small app that shows the network speed as an icon in the status bar.
|
||||||
|
|
||||||
|
It does one thing and aims to do it well without any excessive bloat. Speedo has a minimal memory footprint and is primarily active while the screen is on.
|
||||||
|
|
19
Speedo.iml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.linked.project.id="Speedo" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="java-gradle" name="Java-Gradle">
|
||||||
|
<configuration>
|
||||||
|
<option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" />
|
||||||
|
<option name="BUILDABLE" value="false" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true">
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.gradle" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
1
app/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/build
|
96
app/app.iml
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module external.linked.project.id=":app" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Speedo" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
|
||||||
|
<component name="FacetManager">
|
||||||
|
<facet type="android-gradle" name="Android-Gradle">
|
||||||
|
<configuration>
|
||||||
|
<option name="GRADLE_PROJECT_PATH" value=":app" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
<facet type="android" name="Android">
|
||||||
|
<configuration>
|
||||||
|
<option name="SELECTED_BUILD_VARIANT" value="debug" />
|
||||||
|
<option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
|
||||||
|
<option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
|
||||||
|
<option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
|
||||||
|
<option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
|
||||||
|
<option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" />
|
||||||
|
<afterSyncTasks>
|
||||||
|
<task>generateDebugAndroidTestSources</task>
|
||||||
|
<task>generateDebugSources</task>
|
||||||
|
</afterSyncTasks>
|
||||||
|
<option name="ALLOW_USER_CONFIGURATION" value="false" />
|
||||||
|
<option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
|
||||||
|
<option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
|
||||||
|
<option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
|
||||||
|
<option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
|
||||||
|
</configuration>
|
||||||
|
</facet>
|
||||||
|
</component>
|
||||||
|
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false">
|
||||||
|
<output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
|
||||||
|
<output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
|
||||||
|
<exclude-output />
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/22.1.1/jars" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/outputs" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/build/tmp" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Android API 22 Platform" jdkType="Android SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
<orderEntry type="library" exported="" name="support-v4-22.1.1" level="project" />
|
||||||
|
<orderEntry type="library" exported="" name="support-annotations-22.1.1" level="project" />
|
||||||
|
<orderEntry type="module" module-name="colorPicker" exported="" />
|
||||||
|
</component>
|
||||||
|
</module>
|
26
app/build.gradle
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
|
android {
|
||||||
|
compileSdkVersion 22
|
||||||
|
buildToolsVersion "22.0.0"
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
applicationId "com.mridang.speedo"
|
||||||
|
minSdkVersion 14
|
||||||
|
targetSdkVersion 22
|
||||||
|
versionCode 1
|
||||||
|
versionName "1.0"
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
minifyEnabled false
|
||||||
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||||
|
compile 'com.android.support:support-v4:22.1.1'
|
||||||
|
compile project(':colorPicker')
|
||||||
|
}
|
17
app/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Add project specific ProGuard rules here.
|
||||||
|
# By default, the flags in this file are appended to flags specified
|
||||||
|
# in /Users/mridangagarwalla/Downloads/adt-bundle-mac-x86_64-20140702/sdk/tools/proguard/proguard-android.txt
|
||||||
|
# You can edit the include path and order by changing the proguardFiles
|
||||||
|
# directive in build.gradle.
|
||||||
|
#
|
||||||
|
# For more details, see
|
||||||
|
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||||
|
|
||||||
|
# Add any project specific keep options here:
|
||||||
|
|
||||||
|
# If your project uses WebView with JS, uncomment the following
|
||||||
|
# and specify the fully qualified class name to the JavaScript interface
|
||||||
|
# class:
|
||||||
|
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||||
|
# public *;
|
||||||
|
#}
|
43
app/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest
|
||||||
|
package="com.mridang.speedo"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
|
||||||
|
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
|
||||||
|
<application
|
||||||
|
android:allowBackup="true"
|
||||||
|
android:icon="@mipmap/ic_launcher"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:theme="@style/AppTheme">
|
||||||
|
<activity
|
||||||
|
android:name=".SettingsActivity"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
tools:ignore="ExportedPreferenceActivity">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
|
<service
|
||||||
|
android:name=".TrafficService"
|
||||||
|
android:enabled="true"/>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".BootReceiver"
|
||||||
|
android:enabled="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||||
|
</intent-filter>
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
||||||
|
<data android:scheme="package"/>
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
BIN
app/src/main/ic_launcher-web.png
Normal file
After Width: | Height: | Size: 30 KiB |
23
app/src/main/java/com/mridang/speedo/BootReceiver.java
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package com.mridang.speedo;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Broadcast receiver class to help start the traffic monitoring service when the phone boots up only
|
||||||
|
if the service is enabled.
|
||||||
|
*/
|
||||||
|
public class BootReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Receiver method for the phone boot that starts the traffic monitoring service
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context appContext, Intent bootIntent) {
|
||||||
|
if (PreferenceManager.getDefaultSharedPreferences(appContext).getBoolean("enabled", true)) {
|
||||||
|
appContext.startService(new Intent(appContext, TrafficService.class));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
114
app/src/main/java/com/mridang/speedo/SettingsActivity.java
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
package com.mridang.speedo;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.preference.Preference;
|
||||||
|
import android.preference.PreferenceActivity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Settings activity that allows the user to start or stop the service and also change the polling
|
||||||
|
interval
|
||||||
|
*/
|
||||||
|
public class SettingsActivity extends PreferenceActivity {
|
||||||
|
|
||||||
|
private boolean isBounded;
|
||||||
|
private TrafficService backgroundService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Connection class between the activity and the service to be able to invoke service methods
|
||||||
|
*/
|
||||||
|
private final ServiceConnection mConnection = new ServiceConnection() {
|
||||||
|
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
isBounded = false;
|
||||||
|
backgroundService = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
isBounded = true;
|
||||||
|
TrafficService.LocalBinder mLocalBinder = (TrafficService.LocalBinder) service;
|
||||||
|
backgroundService = mLocalBinder.getServerInstance();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
OnStart method of the activity that establishes a connection with the service by binding to it
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onStart() {
|
||||||
|
super.onStart();
|
||||||
|
Intent serviceIntent = new Intent(getApplicationContext(), TrafficService.class);
|
||||||
|
startService(serviceIntent);
|
||||||
|
bindService(serviceIntent, mConnection, BIND_AUTO_CREATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
OnStop method of the activity that destroys the connection with the service by unbinding from
|
||||||
|
it
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void onStop() {
|
||||||
|
super.onStop();
|
||||||
|
if (isBounded) {
|
||||||
|
unbindService(mConnection);
|
||||||
|
isBounded = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Post create method that bind each of the preferences to a listener so that updating the
|
||||||
|
preferences will fire the listeners to trigger updates to the notification
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
@Override
|
||||||
|
protected void onPostCreate(Bundle savedInstanceState) {
|
||||||
|
super.onPostCreate(savedInstanceState);
|
||||||
|
addPreferencesFromResource(R.xml.preferences);
|
||||||
|
|
||||||
|
findPreference("enabled").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference change listener that handles the starting and the stopping of the service
|
||||||
|
* depending on whether the the switch is toggled or not.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
|
||||||
|
if ((Boolean) newValue) {
|
||||||
|
backgroundService.showNotification();
|
||||||
|
} else {
|
||||||
|
backgroundService.hideNotification();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
findPreference("lockscreen").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference change listener that handles whether the notification should be displayed
|
||||||
|
* on the lockscreen depending on whether the the switch is toggled or not.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
|
||||||
|
backgroundService.visibilityPublic((Boolean) newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
findPreference("color").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Preference change listener that handles whether the notification should be displayed
|
||||||
|
* on the lockscreen depending on whether the the switch is toggled or not.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean onPreferenceChange(Preference enabledPreference, Object newValue) {
|
||||||
|
backgroundService.setColor((Integer) newValue);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
360
app/src/main/java/com/mridang/speedo/TrafficService.java
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
package com.mridang.speedo;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.app.NotificationManager;
|
||||||
|
import android.app.PendingIntent;
|
||||||
|
import android.app.Service;
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.net.ConnectivityManager;
|
||||||
|
import android.net.NetworkInfo;
|
||||||
|
import android.net.TrafficStats;
|
||||||
|
import android.net.wifi.WifiInfo;
|
||||||
|
import android.net.wifi.WifiManager;
|
||||||
|
import android.os.Binder;
|
||||||
|
import android.os.Handler;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.preference.PreferenceManager;
|
||||||
|
import android.support.v4.app.NotificationCompat;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
|
import android.text.format.Formatter;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Main service class that monitors the network speed and updates the notification every second
|
||||||
|
*/
|
||||||
|
public class TrafficService extends Service {
|
||||||
|
|
||||||
|
/**
|
||||||
|
Custom binder class used for allowing the preference activity to bind to this service so that it
|
||||||
|
may be configured on the fly
|
||||||
|
*/
|
||||||
|
public class LocalBinder extends Binder {
|
||||||
|
|
||||||
|
public TrafficService getServerInstance() {
|
||||||
|
return TrafficService.this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
The instance of the binder class used by the activity
|
||||||
|
*/
|
||||||
|
private final IBinder mBinder = new LocalBinder();
|
||||||
|
/**
|
||||||
|
The constant defining the identifier of the notification that is to be shown
|
||||||
|
*/
|
||||||
|
private static final int ID = 9000;
|
||||||
|
/**
|
||||||
|
The identifier if the component that open from the settings activity
|
||||||
|
*/
|
||||||
|
private static final String CMP = "com.android.settings.Settings$DataUsageSummaryActivity";
|
||||||
|
|
||||||
|
/**
|
||||||
|
The handler class that runs every second to update the notification with the network speed. It
|
||||||
|
also runs every minute to save the amount of data-transferred to the preferences.
|
||||||
|
*/
|
||||||
|
private static class NotificationHandler extends Handler {
|
||||||
|
|
||||||
|
/**
|
||||||
|
The value of the amount of data transferred in the previous invocation of the method
|
||||||
|
*/
|
||||||
|
private long lngPrevious = 0L;
|
||||||
|
/**
|
||||||
|
The instance of the context of the parent service
|
||||||
|
*/
|
||||||
|
private final Context ctxContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Simple constructor to initialize the initial value of the previous
|
||||||
|
*/
|
||||||
|
@SuppressLint("CommitPrefEdits")
|
||||||
|
public NotificationHandler(Context ctxContext) {
|
||||||
|
this.ctxContext = ctxContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Handler method that updates the notification icon with the current speed. It is a very
|
||||||
|
hackish method. We have icons for 1 KB/s to 999 KB/s and 1.0 MB/s to 99.9 MB/s. Every time
|
||||||
|
the method is invoked, we get the amount of data transferred. By subtracting this value with
|
||||||
|
the previous value, we get the delta. Since this method is invoked every second, this delta
|
||||||
|
value indicates the b/s. However, we need to convert this value into KB/s for values under 1
|
||||||
|
MB/s and we need to convert the value to MB/s for values over 1 MB/s. Since all our icon
|
||||||
|
images are numbered sequentially we can assume that the R class generated will contain the
|
||||||
|
integer references of the drawables in the sequential order.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void handleMessage(Message msgMessage) {
|
||||||
|
|
||||||
|
TrafficService.hndNotifier.sendEmptyMessageDelayed(1, 1000L);
|
||||||
|
|
||||||
|
long lngCurrent = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();
|
||||||
|
int lngSpeed = (int) (lngCurrent - lngPrevious);
|
||||||
|
lngPrevious = lngCurrent;
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (lngSpeed < 1024) {
|
||||||
|
TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000);
|
||||||
|
} else if (lngSpeed < 1048576L) {
|
||||||
|
|
||||||
|
TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000 + (int) (lngSpeed / 1024L));
|
||||||
|
if (lngSpeed > 1022976) {
|
||||||
|
TrafficService.notBuilder.setSmallIcon(R.drawable.wkb000 + 1000);
|
||||||
|
}
|
||||||
|
} else if (lngSpeed <= 10485760) {
|
||||||
|
TrafficService.notBuilder.setSmallIcon(990 + R.drawable.wkb000
|
||||||
|
+ (int) (0.5D + (double) (10F * ((float) lngSpeed / 1048576F))));
|
||||||
|
} else if (lngSpeed <= 103809024) {
|
||||||
|
TrafficService.notBuilder.setSmallIcon(1080 + R.drawable.wkb000
|
||||||
|
+ (int) (0.5D + (double) ((float) lngSpeed / 1048576F)));
|
||||||
|
} else {
|
||||||
|
TrafficService.notBuilder.setSmallIcon(1180 + R.drawable.wkb000);
|
||||||
|
}
|
||||||
|
|
||||||
|
Long lngTotal = TrafficStats.getTotalRxBytes() + TrafficStats.getTotalTxBytes();
|
||||||
|
String strTotal = Formatter.formatFileSize(this.ctxContext, lngTotal);
|
||||||
|
TrafficService.notBuilder.setContentInfo(strTotal);
|
||||||
|
TrafficService.mgrNotifications.notify(ID, TrafficService.notBuilder.build());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Log.e("NotificationHandler", "Error creating notification for speed " + lngSpeed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
The instance of the handler that updates the notification
|
||||||
|
*/
|
||||||
|
private static NotificationHandler hndNotifier;
|
||||||
|
/**
|
||||||
|
The instance of the manager of the connectivity services
|
||||||
|
*/
|
||||||
|
private static ConnectivityManager mgrConnectivity;
|
||||||
|
/**
|
||||||
|
The instance of the manager of the notification services
|
||||||
|
*/
|
||||||
|
private static NotificationManager mgrNotifications;
|
||||||
|
/**
|
||||||
|
The instance of the manager of the wireless services
|
||||||
|
*/
|
||||||
|
private static WifiManager mgrWireless;
|
||||||
|
/**
|
||||||
|
The instance of the manager of the telephony services
|
||||||
|
*/
|
||||||
|
private static TelephonyManager mgrTelephony;
|
||||||
|
/**
|
||||||
|
The instance of the notification builder to rebuild the notification
|
||||||
|
*/
|
||||||
|
private static NotificationCompat.Builder notBuilder;
|
||||||
|
/**
|
||||||
|
The instance of the broadcast receiver to handle intents
|
||||||
|
*/
|
||||||
|
private BroadcastReceiver recScreen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Initializes the service by getting instances of service managers and mainly setting up the
|
||||||
|
receiver to receive all the necessary intents that this service is supposed to handle.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
|
||||||
|
Log.i("HardwareService", "Creating the hardware service");
|
||||||
|
super.onCreate();
|
||||||
|
final SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
|
||||||
|
|
||||||
|
Intent ittSettings = new Intent();
|
||||||
|
ittSettings.setComponent(new ComponentName("com.android.settings", CMP));
|
||||||
|
PendingIntent pitSettings = PendingIntent.getActivity(this, 0, ittSettings, 0);
|
||||||
|
notBuilder = new NotificationCompat.Builder(this);
|
||||||
|
notBuilder.setSmallIcon(R.drawable.wkb000);
|
||||||
|
notBuilder.setContentIntent(pitSettings);
|
||||||
|
notBuilder.setOngoing(true);
|
||||||
|
notBuilder.setWhen(0);
|
||||||
|
notBuilder.setOnlyAlertOnce(true);
|
||||||
|
notBuilder.setPriority(Integer.MAX_VALUE);
|
||||||
|
notBuilder.setCategory(NotificationCompat.CATEGORY_SERVICE);
|
||||||
|
setColor(settings.getInt("color", Color.TRANSPARENT));
|
||||||
|
visibilityPublic(settings.getBoolean("lockscreen", true));
|
||||||
|
|
||||||
|
Log.d("HardwareService", "Setting up the service manager and the broadcast receiver");
|
||||||
|
mgrConnectivity = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
|
||||||
|
mgrNotifications = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
|
||||||
|
mgrWireless = (WifiManager) getSystemService(Context.WIFI_SERVICE);
|
||||||
|
mgrTelephony = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
|
||||||
|
hndNotifier = new NotificationHandler(getApplicationContext());
|
||||||
|
|
||||||
|
if (settings.getBoolean("enabled", true)) {
|
||||||
|
Log.d("HardwareService", "Screen on; showing the notification");
|
||||||
|
hndNotifier.sendEmptyMessage(1);
|
||||||
|
}
|
||||||
|
recScreen = new BroadcastReceiver() {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the screen-on and the screen off intents to enable or disable the notification.
|
||||||
|
* We don't want to show the notification if the screen is off.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context ctcContext, Intent ittIntent) {
|
||||||
|
|
||||||
|
if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_OFF)) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Screen off; hiding the notification");
|
||||||
|
hndNotifier.removeMessages(1);
|
||||||
|
mgrNotifications.cancel(ID);
|
||||||
|
} else if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_SCREEN_ON)) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Screen on; showing the notification");
|
||||||
|
connectivityUpdate();
|
||||||
|
} else if (ittIntent.getAction().equalsIgnoreCase(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
|
||||||
|
|
||||||
|
if (ittIntent.getBooleanExtra("state", false)) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Airplane mode; hiding the notification");
|
||||||
|
hndNotifier.removeMessages(1);
|
||||||
|
hndNotifier.sendEmptyMessage(1);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Airplane mode; showing the notification");
|
||||||
|
connectivityUpdate();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Connectivity change; updating the notification");
|
||||||
|
connectivityUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
IntentFilter ittScreen = new IntentFilter();
|
||||||
|
ittScreen.addAction(Intent.ACTION_SCREEN_ON);
|
||||||
|
ittScreen.addAction(Intent.ACTION_SCREEN_OFF);
|
||||||
|
ittScreen.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
|
||||||
|
ittScreen.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
|
||||||
|
registerReceiver(recScreen, ittScreen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Updates the notification with the new connectivity information. This method determines the type
|
||||||
|
of connectivity and updates the notification with the network type and name. If there is no
|
||||||
|
information about the active network, this will suppress the notification.
|
||||||
|
*/
|
||||||
|
private void connectivityUpdate() {
|
||||||
|
|
||||||
|
NetworkInfo nifNetwork = mgrConnectivity.getActiveNetworkInfo();
|
||||||
|
if (nifNetwork != null && nifNetwork.isConnectedOrConnecting()) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Network connected; showing the notification");
|
||||||
|
if (nifNetwork.getType() == ConnectivityManager.TYPE_WIFI) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Connected to a wireless network");
|
||||||
|
WifiInfo wifInfo = mgrWireless.getConnectionInfo();
|
||||||
|
if (wifInfo != null && !wifInfo.getSSID().trim().isEmpty()) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", wifInfo.getSSID());
|
||||||
|
notBuilder.setContentTitle(getString(R.string.wireless));
|
||||||
|
notBuilder.setContentText(wifInfo.getSSID().replaceAll("^\"|\"$", ""));
|
||||||
|
showNotification();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Unknown network without SSID");
|
||||||
|
hideNotification();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Connected to a cellular network");
|
||||||
|
if (!mgrTelephony.getNetworkOperatorName().trim().isEmpty()) {
|
||||||
|
|
||||||
|
Log.d("TrafficService", mgrTelephony.getNetworkOperatorName());
|
||||||
|
notBuilder.setContentTitle(getString(R.string.cellular));
|
||||||
|
notBuilder.setContentText(mgrTelephony.getNetworkOperatorName());
|
||||||
|
showNotification();
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Unknown network without IMSI");
|
||||||
|
hideNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
Log.d("TrafficService", "Network disconnected; hiding the notification");
|
||||||
|
hideNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Called when the service is being stopped. It doesn't do much except clear the message queue of
|
||||||
|
the handler, hides the notification and unregisters the receivers.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void onDestroy() {
|
||||||
|
|
||||||
|
Log.d("HardwareService", "Stopping the hardware service");
|
||||||
|
unregisterReceiver(recScreen);
|
||||||
|
hndNotifier.removeMessages(1);
|
||||||
|
mgrNotifications.cancel(ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper method that shows the notification by sending the handler a message and building the
|
||||||
|
notification. This is invoked when the preference is toggled.
|
||||||
|
*/
|
||||||
|
public void showNotification() {
|
||||||
|
|
||||||
|
Log.d("HardwareService", "Showing the notification");
|
||||||
|
mgrNotifications.notify(ID, notBuilder.build());
|
||||||
|
hndNotifier.removeMessages(1);
|
||||||
|
hndNotifier.sendEmptyMessage(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper method that hides the notification by clearing the handler messages and cancelling the
|
||||||
|
notification. This is invoked when the preference is toggled.
|
||||||
|
*/
|
||||||
|
public void hideNotification() {
|
||||||
|
|
||||||
|
Log.d("HardwareService", "Hiding the notification");
|
||||||
|
mgrNotifications.cancel(ID);
|
||||||
|
hndNotifier.removeMessages(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper method that toggles the visibility of the notification on the locksreen depending on the
|
||||||
|
value of the preference in the activity
|
||||||
|
|
||||||
|
@param visibility A boolean value indicating whether the notification should be visible on the
|
||||||
|
lockscreen
|
||||||
|
*/
|
||||||
|
public void visibilityPublic(Boolean visibility) {
|
||||||
|
if (visibility) {
|
||||||
|
notBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
|
||||||
|
} else {
|
||||||
|
notBuilder.setVisibility(NotificationCompat.VISIBILITY_SECRET);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Helper method that sets the background color of the notification icon by parsing the RGB value
|
||||||
|
into an int.
|
||||||
|
|
||||||
|
@param color The internal int representation of the RGB color to set as the background colour
|
||||||
|
*/
|
||||||
|
public void setColor(Integer color) {
|
||||||
|
notBuilder.setColor(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Binder method to allow the settings activity to bind to the service so the notification can be
|
||||||
|
configured and updated while the activity is being toggles.
|
||||||
|
|
||||||
|
@see android.app.Service#onBind(android.content.Intent)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intReason) {
|
||||||
|
return mBinder;
|
||||||
|
}
|
||||||
|
}
|
BIN
app/src/main/res/drawable-hdpi/wkb000.png
Normal file
After Width: | Height: | Size: 441 B |
BIN
app/src/main/res/drawable-hdpi/wkb001.png
Normal file
After Width: | Height: | Size: 375 B |
BIN
app/src/main/res/drawable-hdpi/wkb002.png
Normal file
After Width: | Height: | Size: 434 B |
BIN
app/src/main/res/drawable-hdpi/wkb003.png
Normal file
After Width: | Height: | Size: 455 B |
BIN
app/src/main/res/drawable-hdpi/wkb004.png
Normal file
After Width: | Height: | Size: 421 B |
BIN
app/src/main/res/drawable-hdpi/wkb005.png
Normal file
After Width: | Height: | Size: 442 B |
BIN
app/src/main/res/drawable-hdpi/wkb006.png
Normal file
After Width: | Height: | Size: 456 B |
BIN
app/src/main/res/drawable-hdpi/wkb007.png
Normal file
After Width: | Height: | Size: 416 B |
BIN
app/src/main/res/drawable-hdpi/wkb008.png
Normal file
After Width: | Height: | Size: 442 B |
BIN
app/src/main/res/drawable-hdpi/wkb009.png
Normal file
After Width: | Height: | Size: 460 B |
BIN
app/src/main/res/drawable-hdpi/wkb010.png
Normal file
After Width: | Height: | Size: 499 B |
BIN
app/src/main/res/drawable-hdpi/wkb011.png
Normal file
After Width: | Height: | Size: 437 B |
BIN
app/src/main/res/drawable-hdpi/wkb012.png
Normal file
After Width: | Height: | Size: 507 B |
BIN
app/src/main/res/drawable-hdpi/wkb013.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
app/src/main/res/drawable-hdpi/wkb014.png
Normal file
After Width: | Height: | Size: 469 B |
BIN
app/src/main/res/drawable-hdpi/wkb015.png
Normal file
After Width: | Height: | Size: 498 B |
BIN
app/src/main/res/drawable-hdpi/wkb016.png
Normal file
After Width: | Height: | Size: 507 B |
BIN
app/src/main/res/drawable-hdpi/wkb017.png
Normal file
After Width: | Height: | Size: 465 B |
BIN
app/src/main/res/drawable-hdpi/wkb018.png
Normal file
After Width: | Height: | Size: 514 B |
BIN
app/src/main/res/drawable-hdpi/wkb019.png
Normal file
After Width: | Height: | Size: 516 B |
BIN
app/src/main/res/drawable-hdpi/wkb020.png
Normal file
After Width: | Height: | Size: 523 B |
BIN
app/src/main/res/drawable-hdpi/wkb021.png
Normal file
After Width: | Height: | Size: 493 B |
BIN
app/src/main/res/drawable-hdpi/wkb022.png
Normal file
After Width: | Height: | Size: 505 B |
BIN
app/src/main/res/drawable-hdpi/wkb023.png
Normal file
After Width: | Height: | Size: 540 B |
BIN
app/src/main/res/drawable-hdpi/wkb024.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
app/src/main/res/drawable-hdpi/wkb025.png
Normal file
After Width: | Height: | Size: 521 B |
BIN
app/src/main/res/drawable-hdpi/wkb026.png
Normal file
After Width: | Height: | Size: 532 B |
BIN
app/src/main/res/drawable-hdpi/wkb027.png
Normal file
After Width: | Height: | Size: 497 B |
BIN
app/src/main/res/drawable-hdpi/wkb028.png
Normal file
After Width: | Height: | Size: 531 B |
BIN
app/src/main/res/drawable-hdpi/wkb029.png
Normal file
After Width: | Height: | Size: 536 B |
BIN
app/src/main/res/drawable-hdpi/wkb030.png
Normal file
After Width: | Height: | Size: 542 B |
BIN
app/src/main/res/drawable-hdpi/wkb031.png
Normal file
After Width: | Height: | Size: 501 B |
BIN
app/src/main/res/drawable-hdpi/wkb032.png
Normal file
After Width: | Height: | Size: 548 B |
BIN
app/src/main/res/drawable-hdpi/wkb033.png
Normal file
After Width: | Height: | Size: 562 B |
BIN
app/src/main/res/drawable-hdpi/wkb034.png
Normal file
After Width: | Height: | Size: 531 B |
BIN
app/src/main/res/drawable-hdpi/wkb035.png
Normal file
After Width: | Height: | Size: 540 B |
BIN
app/src/main/res/drawable-hdpi/wkb036.png
Normal file
After Width: | Height: | Size: 552 B |
BIN
app/src/main/res/drawable-hdpi/wkb037.png
Normal file
After Width: | Height: | Size: 522 B |
BIN
app/src/main/res/drawable-hdpi/wkb038.png
Normal file
After Width: | Height: | Size: 557 B |
BIN
app/src/main/res/drawable-hdpi/wkb039.png
Normal file
After Width: | Height: | Size: 544 B |
BIN
app/src/main/res/drawable-hdpi/wkb040.png
Normal file
After Width: | Height: | Size: 501 B |
BIN
app/src/main/res/drawable-hdpi/wkb041.png
Normal file
After Width: | Height: | Size: 471 B |
BIN
app/src/main/res/drawable-hdpi/wkb042.png
Normal file
After Width: | Height: | Size: 509 B |
BIN
app/src/main/res/drawable-hdpi/wkb043.png
Normal file
After Width: | Height: | Size: 520 B |
BIN
app/src/main/res/drawable-hdpi/wkb044.png
Normal file
After Width: | Height: | Size: 484 B |
BIN
app/src/main/res/drawable-hdpi/wkb045.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
app/src/main/res/drawable-hdpi/wkb046.png
Normal file
After Width: | Height: | Size: 524 B |
BIN
app/src/main/res/drawable-hdpi/wkb047.png
Normal file
After Width: | Height: | Size: 486 B |
BIN
app/src/main/res/drawable-hdpi/wkb048.png
Normal file
After Width: | Height: | Size: 518 B |
BIN
app/src/main/res/drawable-hdpi/wkb049.png
Normal file
After Width: | Height: | Size: 510 B |
BIN
app/src/main/res/drawable-hdpi/wkb050.png
Normal file
After Width: | Height: | Size: 524 B |
BIN
app/src/main/res/drawable-hdpi/wkb051.png
Normal file
After Width: | Height: | Size: 489 B |
BIN
app/src/main/res/drawable-hdpi/wkb052.png
Normal file
After Width: | Height: | Size: 527 B |
BIN
app/src/main/res/drawable-hdpi/wkb053.png
Normal file
After Width: | Height: | Size: 545 B |
BIN
app/src/main/res/drawable-hdpi/wkb054.png
Normal file
After Width: | Height: | Size: 499 B |
BIN
app/src/main/res/drawable-hdpi/wkb055.png
Normal file
After Width: | Height: | Size: 513 B |
BIN
app/src/main/res/drawable-hdpi/wkb056.png
Normal file
After Width: | Height: | Size: 542 B |
BIN
app/src/main/res/drawable-hdpi/wkb057.png
Normal file
After Width: | Height: | Size: 498 B |
BIN
app/src/main/res/drawable-hdpi/wkb058.png
Normal file
After Width: | Height: | Size: 539 B |
BIN
app/src/main/res/drawable-hdpi/wkb059.png
Normal file
After Width: | Height: | Size: 533 B |
BIN
app/src/main/res/drawable-hdpi/wkb060.png
Normal file
After Width: | Height: | Size: 527 B |
BIN
app/src/main/res/drawable-hdpi/wkb061.png
Normal file
After Width: | Height: | Size: 508 B |
BIN
app/src/main/res/drawable-hdpi/wkb062.png
Normal file
After Width: | Height: | Size: 534 B |
BIN
app/src/main/res/drawable-hdpi/wkb063.png
Normal file
After Width: | Height: | Size: 552 B |
BIN
app/src/main/res/drawable-hdpi/wkb064.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
app/src/main/res/drawable-hdpi/wkb065.png
Normal file
After Width: | Height: | Size: 541 B |
BIN
app/src/main/res/drawable-hdpi/wkb066.png
Normal file
After Width: | Height: | Size: 545 B |
BIN
app/src/main/res/drawable-hdpi/wkb067.png
Normal file
After Width: | Height: | Size: 529 B |
BIN
app/src/main/res/drawable-hdpi/wkb068.png
Normal file
After Width: | Height: | Size: 552 B |
BIN
app/src/main/res/drawable-hdpi/wkb069.png
Normal file
After Width: | Height: | Size: 541 B |
BIN
app/src/main/res/drawable-hdpi/wkb070.png
Normal file
After Width: | Height: | Size: 503 B |
BIN
app/src/main/res/drawable-hdpi/wkb071.png
Normal file
After Width: | Height: | Size: 467 B |
BIN
app/src/main/res/drawable-hdpi/wkb072.png
Normal file
After Width: | Height: | Size: 506 B |
BIN
app/src/main/res/drawable-hdpi/wkb073.png
Normal file
After Width: | Height: | Size: 529 B |
BIN
app/src/main/res/drawable-hdpi/wkb074.png
Normal file
After Width: | Height: | Size: 482 B |
BIN
app/src/main/res/drawable-hdpi/wkb075.png
Normal file
After Width: | Height: | Size: 500 B |
BIN
app/src/main/res/drawable-hdpi/wkb076.png
Normal file
After Width: | Height: | Size: 520 B |
BIN
app/src/main/res/drawable-hdpi/wkb077.png
Normal file
After Width: | Height: | Size: 456 B |
BIN
app/src/main/res/drawable-hdpi/wkb078.png
Normal file
After Width: | Height: | Size: 527 B |
BIN
app/src/main/res/drawable-hdpi/wkb079.png
Normal file
After Width: | Height: | Size: 519 B |
BIN
app/src/main/res/drawable-hdpi/wkb080.png
Normal file
After Width: | Height: | Size: 526 B |
BIN
app/src/main/res/drawable-hdpi/wkb081.png
Normal file
After Width: | Height: | Size: 504 B |
BIN
app/src/main/res/drawable-hdpi/wkb082.png
Normal file
After Width: | Height: | Size: 543 B |
BIN
app/src/main/res/drawable-hdpi/wkb083.png
Normal file
After Width: | Height: | Size: 535 B |
BIN
app/src/main/res/drawable-hdpi/wkb084.png
Normal file
After Width: | Height: | Size: 514 B |
BIN
app/src/main/res/drawable-hdpi/wkb085.png
Normal file
After Width: | Height: | Size: 539 B |
BIN
app/src/main/res/drawable-hdpi/wkb086.png
Normal file
After Width: | Height: | Size: 539 B |
BIN
app/src/main/res/drawable-hdpi/wkb087.png
Normal file
After Width: | Height: | Size: 522 B |