Commit 32561d39 authored by Max Lv's avatar Max Lv

update Google Analytics and Tag Manager

parent c96dde86
libraryDependencies ++= Seq(
"com.google.android" % "support-v4" % "r12",
"com.google.android.analytics" % "analytics" % "2.0beta4",
"dnsjava" % "dnsjava" % "2.1.5",
"com.google.android.admob" % "admob" % "6.3.1"
"com.google.android" % "analytics" % "3.01",
"com.google.android" % "admob" % "6.4.1",
"dnsjava" % "dnsjava" % "2.1.5"
)
libraryDependencies ++= Seq(
......
......@@ -2,8 +2,4 @@ import sbtandroid.AndroidPlugin._
keyalias := "travis"
publicServer := "127.0.0.1"
publicPorts := "443"
publicMethod := "rc4"
containerId := "GTM-XXXX"
......@@ -15,7 +15,7 @@ object General {
name := "shadowsocks",
version := App.version,
versionCode := App.versionCode,
scalaVersion := "2.9.2",
scalaVersion := "2.10.3",
compileOrder := CompileOrder.JavaThenScala,
platformName := "android-16",
resolvers += "madeye-maven" at "http://madeye-maven-repository.googlecode.com/git",
......
......@@ -39,7 +39,7 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
}
private def checkWithinBounds(toValidate: SortedSet[IpAddressRange]): Boolean = {
return (toValidate.firstKey.first >= first && toValidate.lastKey.last <= last)
toValidate.firstKey.first >= first && toValidate.lastKey.last <= last
}
/**
......@@ -52,9 +52,9 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
// get the first range of free addresses, and take the first address of that range
val range: IpAddressRange = freeRanges.firstKey
val toAllocate: IpAddress = range.first
return doAllocate(toAllocate, range)
doAllocate(toAllocate, range)
} else {
return (this, None)
(this, None)
}
}
......@@ -84,13 +84,13 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
// the range we need is either the first of the tail, or the last of the head, or it doesn't exist
if (!head.isEmpty && head.lastKey.contains(toAllocate)) {
return Some(head.lastKey)
Some(head.lastKey)
}
else if (!tail.isEmpty && tail.firstKey.contains(toAllocate)) {
return Some(tail.firstKey)
Some(tail.firstKey)
}
else {
return None
None
}
}
......@@ -103,7 +103,7 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
val newRanges = range - toAllocate
// note: the cast to SortedSet is a workaround until scala 2.8 (http://stackoverflow.com/questions/1271426/scala-immutable-sortedset-are-not-stable-on-deletion)
val remainingRanges = (freeRanges ++ newRanges).asInstanceOf[SortedSet[IpAddressRange]] - range
return (new IpAddressPool(this.first, this.last, remainingRanges.asInstanceOf[SortedSet[IpAddressRange]]), Some(toAllocate))
(new IpAddressPool(this.first, this.last, remainingRanges.asInstanceOf[SortedSet[IpAddressRange]]), Some(toAllocate))
}
/**
......@@ -115,7 +115,7 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
if (!contains(address))
throw new IllegalArgumentException("can not deallocate address which is not contained in the range of the pool [" + address + "]")
return new IpAddressPool(first, last, addAddressToFreeRanges(address))
new IpAddressPool(first, last, addAddressToFreeRanges(address))
}
/**
......@@ -128,24 +128,24 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
if (freeRangeBeforeAddress.isEmpty && freeRangeAfterAddress.isEmpty) {
// no match -> nothing to "defragment"
return freeRanges + new IpAddressRange(address, address)
freeRanges + new IpAddressRange(address, address)
} else {
if (!freeRangeBeforeAddress.isEmpty && !freeRangeAfterAddress.isEmpty) {
// first and last match -> merge the 2 existing ranges
return (freeRanges -
(freeRanges -
freeRangeBeforeAddress.toSeq(0) -
freeRangeAfterAddress.toSeq(0) +
new IpAddressRange(freeRangeBeforeAddress.toSeq(0).first, freeRangeAfterAddress.toSeq(0).last)).
asInstanceOf[SortedSet[IpAddressRange]] // workaround, see above
} else if (!freeRangeBeforeAddress.isEmpty) {
// append
return (freeRanges -
(freeRanges -
freeRangeBeforeAddress.toSeq(0) +
(freeRangeBeforeAddress.toSeq(0) + address)).
asInstanceOf[SortedSet[IpAddressRange]] // workaround, see above
} else {
// prepend
return (freeRanges -
(freeRanges -
freeRangeAfterAddress.toSeq(0) +
(freeRangeAfterAddress.toSeq(0) + address)).
asInstanceOf[SortedSet[IpAddressRange]] // workaround, see above
......@@ -153,7 +153,7 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
}
}
def isExhausted(): Boolean = {
def isExhausted: Boolean = {
freeRanges.isEmpty
}
......@@ -187,7 +187,7 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
* @return ranges of allocated addresses in the pool
* @note the pool implementation keeps track of the free addresses, so this operation is more expensive than the freeRanges() one
*/
def allocatedRanges(): List[IpAddressRange] = {
def allocatedRanges: List[IpAddressRange] = {
if (freeRanges.isEmpty) {
// one big range of allocated addresses
List[IpAddressRange](new IpAddressRange(first, last))
......@@ -203,14 +203,14 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
for (freeRange <- freeRanges) {
currentEnd = freeRange.first
if (currentEnd != currentStart) { // occurs if first free range starts at the beginning of the pool
allocatedRanges + new IpAddressRange(currentStart, currentEnd - 1)
allocatedRanges.append(new IpAddressRange(currentStart, currentEnd - 1))
}
currentStart = freeRange.last + 1
}
if (currentStart <= last) { // occurs if the last free range didn't reach until the end of the pool
allocatedRanges + new IpAddressRange(currentStart, last)
allocatedRanges.append(new IpAddressRange(currentStart, last))
}
return allocatedRanges.toList
allocatedRanges.toList
}
......@@ -227,7 +227,7 @@ class IpAddressPool private(override val first: IpAddress, override val last: Ip
}
}
override def toString(): String = {
override def toString: String = {
"IpAddressPool " + super.toString + " with free ranges " + freeRanges.toString
}
......
......@@ -30,9 +30,9 @@ class IpAddressRange(val first: IpAddress, val last: IpAddress) extends Ordered[
last.value - first.value + 1
}
def addresses(): Stream[IpAddress] = {
def addresses: Stream[IpAddress] = {
if (first < last) {
Stream.cons(first, new IpAddressRange(first + 1, last).addresses())
Stream.cons(first, new IpAddressRange(first + 1, last).addresses)
} else {
Stream.cons(first, Stream.empty)
}
......
......@@ -256,12 +256,12 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
protected override def onStart() {
super.onStart()
EasyTracker.getInstance.activityStart(this)
EasyTracker.getInstance(this).activityStart(this)
}
protected override def onStop() {
super.onStop()
EasyTracker.getInstance.activityStop(this)
EasyTracker.getInstance(this).activityStop(this)
}
def saveAppSettings(context: Context) {
......
......@@ -46,7 +46,7 @@ import android.content.pm.PackageManager
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
import com.google.analytics.tracking.android.EasyTracker
import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker}
import java.io._
import android.net.VpnService
import org.apache.http.conn.util.InetAddressUtils
......@@ -188,6 +188,19 @@ class ShadowVpnService extends VpnService {
config = Extra.get(intent)
spawn {
if (config.proxy == "198.199.101.152") {
val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer
if (container == null) {
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
stopSelf()
handler.sendEmptyMessageDelayed(MSG_CONNECT_FAIL, 500)
return
} else {
config = Config.getPublicConfig(container, config)
}
}
killProcesses()
// Resolve server address
......@@ -236,15 +249,10 @@ class ShadowVpnService extends VpnService {
def startVpn() {
val proxy_address = new IpAddress(config.proxy)
val private_networks = Array[IpNetwork](
new IpNetwork("127.0.0.0/8"),
new IpNetwork("10.0.0.0/8"),
new IpNetwork("172.16.0.0/12"),
new IpNetwork("192.168.0.0/16")
)
val private_networks = Array[IpNetwork](new IpNetwork("127.0.0.0/8"),
new IpNetwork("10.0.0.0/8"), new IpNetwork("172.16.0.0/12"), new IpNetwork("192.168.0.0/16"))
val builder = new Builder()
builder
......@@ -258,10 +266,9 @@ class ShadowVpnService extends VpnService {
} else if (config.isGFWList) {
val gfwList = getResources.getStringArray(R.array.gfw_list)
gfwList.foreach(addr => {
val network = new IpNetwork(addr)
val network = new IpNetwork(addr)
if (!network.contains(proxy_address)) {
builder.addRoute(network.address.toString, network.mask.prefixLength)
Log.d(Shadowsocks.TAG, "add route: " + addr)
}
})
} else {
......@@ -269,7 +276,7 @@ class ShadowVpnService extends VpnService {
val network = new IpNetwork(i.toString + ".0.0.0/8")
if (!network.contains(proxy_address) &&
private_networks.forall(range => !network.contains(range))) {
builder.addRoute(i + ".0.0.0", 8)
builder.addRoute(i + ".0.0.0", 8)
} else {
for (j <- 0 to 255) {
val subNetwork = new IpNetwork(i.toString + "." + j.toString + ".0.0/16")
......@@ -313,7 +320,8 @@ class ShadowVpnService extends VpnService {
+ "--tunmtu %d "
+ "--loglevel 3 "
+ "--pid %stun2socks.pid")
.format(PRIVATE_VLAN.format("2"), PRIVATE_VLAN.format("1"), config.localPort, fd, VPN_MTU, BASE)
.format(PRIVATE_VLAN.format("2"), PRIVATE_VLAN.format("1"), config.localPort, fd, VPN_MTU,
BASE)
if (BuildConfig.DEBUG) Log.d(TAG, cmd)
System.exec(cmd)
}
......@@ -357,8 +365,14 @@ class ShadowVpnService extends VpnService {
override def onCreate() {
super.onCreate()
EasyTracker.getTracker.setStartSession(true)
EasyTracker.getTracker.sendEvent(TAG, "start", getVersionName, 0L)
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "start", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "start")
.build())
notificationManager = getSystemService(Context.NOTIFICATION_SERVICE)
.asInstanceOf[NotificationManager]
......@@ -379,7 +393,14 @@ class ShadowVpnService extends VpnService {
killProcesses()
changeState(State.STOPPED)
EasyTracker.getTracker.sendEvent(TAG, "stop", getVersionName, 0L)
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "stop", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "stop")
.build())
if (receiver != null) {
unregisterReceiver(receiver)
receiver = null
......@@ -393,8 +414,6 @@ class ShadowVpnService extends VpnService {
/** Called when the activity is closed. */
override def onDestroy() {
EasyTracker.getTracker.setStartSession(false)
EasyTracker.getTracker.sendEvent(TAG, "stop", getVersionName, 0L)
destroy()
super.onDestroy()
}
......
......@@ -47,7 +47,7 @@ import android.preference._
import android.util.Log
import android.view._
import android.widget._
import com.google.analytics.tracking.android.EasyTracker
import com.google.analytics.tracking.android.{MapBuilder, EasyTracker}
import de.keyboardsurfer.android.widget.crouton.Crouton
import de.keyboardsurfer.android.widget.crouton.Style
import java.io._
......@@ -78,6 +78,8 @@ import scala.Option
import android.view.ViewGroup.LayoutParams
import com.github.shadowsocks.database.Item
import com.github.shadowsocks.database.Category
import com.google.tagmanager.{Container, ContainerOpener, TagManager}
import com.google.tagmanager.ContainerOpener.{Notifier, OpenType}
class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int)
extends BaseImageDownloader(context, connectTimeout, readTimeout) {
......@@ -666,18 +668,21 @@ class Shadowsocks
buf += new Category("Settings")
buf += new Item(-100, getString(R.string.recovery), android.R.drawable.ic_menu_revert, _ => {
EasyTracker.getTracker.sendEvent(Shadowsocks.TAG, "reset", getVersionName, 0L)
EasyTracker.getInstance(this).send(
MapBuilder.createEvent(Shadowsocks.TAG, "reset", getVersionName, null).build())
recovery()
})
buf +=
new Item(-200, getString(R.string.flush_dnscache), android.R.drawable.ic_menu_delete, _ => {
EasyTracker.getTracker.sendEvent(Shadowsocks.TAG, "flush_dnscache", getVersionName, 0L)
EasyTracker.getInstance(this).send(
MapBuilder.createEvent(Shadowsocks.TAG, "flush_dnscache", getVersionName, null).build())
flushDnsCache()
})
buf += new Item(-300, getString(R.string.about), android.R.drawable.ic_menu_info_details, _ => {
EasyTracker.getTracker.sendEvent(Shadowsocks.TAG, "about", getVersionName, 0L)
EasyTracker.getInstance(this).send(
MapBuilder.createEvent(Shadowsocks.TAG, "about", getVersionName, null).build())
showAbout()
})
......@@ -687,7 +692,8 @@ class Shadowsocks
override def onOptionsItemSelected(item: MenuItem): Boolean = {
item.getItemId match {
case android.R.id.home => {
EasyTracker.getTracker.sendEvent(Shadowsocks.TAG, "home", getVersionName, 0L)
EasyTracker.getInstance(this).send(
MapBuilder.createEvent(Shadowsocks.TAG, "home", getVersionName, null).build())
drawer.toggleMenu()
return true
}
......@@ -769,12 +775,12 @@ class Shadowsocks
override def onStart() {
super.onStart()
EasyTracker.getInstance.activityStart(this)
EasyTracker.getInstance(this).activityStart(this)
}
override def onStop() {
super.onStop()
EasyTracker.getInstance.activityStop(this)
EasyTracker.getInstance(this).activityStop(this)
clearDialog()
}
......
......@@ -39,14 +39,20 @@
package com.github.shadowsocks
import android.app.Application
import com.google.analytics.tracking.android.EasyTracker
import com.github.shadowsocks.database.{ProfileManager, DBHelper}
import com.github.shadowsocks.database.DBHelper
import com.google.tagmanager.{Container, ContainerOpener, TagManager}
import com.google.tagmanager.ContainerOpener.{Notifier, OpenType}
class ShadowsocksApplication extends Application {
lazy val dbHelper = new DBHelper(this)
var tagContainer: Container = null
override def onCreate() {
EasyTracker.getInstance.setContext(this)
val tm = TagManager.getInstance(this)
ContainerOpener.openContainer(tm, BuildConfig.CONTAINER_ID, OpenType.PREFER_FRESH, null, new Notifier {
override def containerAvailable(container: Container) {
tagContainer = container
}
})
}
}
......@@ -49,7 +49,7 @@ import android.content.pm.PackageManager
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
import com.google.analytics.tracking.android.EasyTracker
import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker}
import java.io._
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
......@@ -224,6 +224,19 @@ class ShadowsocksService extends Service {
}
spawn {
if (config.proxy == "198.199.101.152") {
val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer
if (container == null) {
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
stopSelf()
handler.sendEmptyMessageDelayed(MSG_CONNECT_FAIL, 500)
return
} else {
config = Config.getPublicConfig(container, config)
}
}
killProcesses()
var resolved: Boolean = false
......@@ -374,8 +387,14 @@ class ShadowsocksService extends Service {
override def onCreate() {
super.onCreate()
EasyTracker.getTracker.setStartSession(true)
EasyTracker.getTracker.sendEvent(TAG, "start", getVersionName, 0L)
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "start", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "start")
.build())
notificationManager = this
.getSystemService(Context.NOTIFICATION_SERVICE)
.asInstanceOf[NotificationManager]
......@@ -422,8 +441,14 @@ class ShadowsocksService extends Service {
// clean up context
changeState(State.STOPPED)
EasyTracker.getTracker.setStartSession(false)
EasyTracker.getTracker.sendEvent(TAG, "stop", getVersionName, 0L)
EasyTracker
.getInstance(this)
.send(MapBuilder
.createEvent(TAG, "stop", getVersionName, 0L)
.set(Fields.SESSION_CONTROL, "stop")
.build())
stopForegroundCompat(1)
if (receiver != null) {
unregisterReceiver(receiver)
......
......@@ -48,12 +48,12 @@ import java.net.{UnknownHostException, InetAddress, NetworkInterface}
import org.apache.http.conn.util.InetAddressUtils
import scala.collection.mutable.ArrayBuffer
import org.xbill.DNS._
import scala.Some
import android.graphics._
import android.app.ActivityManager
import android.os.Build
import android.provider.Settings
import scala.Some
import com.google.tagmanager.Container
object Config {
val SHADOWSOCKS = "{\"server\": [%s], \"server_port\": %d, \"local_port\": %d, \"password\": %s, \"timeout\": %d}"
......@@ -110,11 +110,21 @@ object Config {
p.close()
}
}
def getPublicConfig(container: Container, config: Config): Config = {
val host = container.getString("host")
val port = util.Random.shuffle(container.getString("port").split(',').toSeq).toSeq(0).toInt
val method = container.getString("method")
val password = container.getString("password")
new Config(config.isGlobalProxy, config.isGFWList, config.isBypassApps, config.isTrafficStat,
config.profileName, host, password, method, port, config.localPort, config.proxiedAppString)
}
}
case class Config(isGlobalProxy: Boolean, isGFWList: Boolean, isBypassApps: Boolean, isTrafficStat: Boolean,
profileName: String, var proxy: String, sitekey: String, encMethod: String, remotePort: Int,
localPort: Int, proxiedAppString: String)
case class Config(isGlobalProxy: Boolean, isGFWList: Boolean, isBypassApps: Boolean,
isTrafficStat: Boolean, profileName: String, var proxy: String, sitekey: String,
encMethod: String, remotePort: Int, localPort: Int, proxiedAppString: String)
object Key {
val profileId = "profileId"
......@@ -196,8 +206,8 @@ object Extra {
val localPort = intent.getIntExtra(Key.localPort, 1984)
val proxiedString = intent.getStringExtra(Key.proxied)
new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, profileName, proxy, sitekey, encMethod, remotePort,
localPort, proxiedString)
new Config(isGlobalProxy, isGFWList, isBypassApps, isTrafficStat, profileName, proxy, sitekey,
encMethod, remotePort, localPort, proxiedString)
}
def put(settings: SharedPreferences, intent: Intent) {
......@@ -206,33 +216,20 @@ object Extra {
val isBypassApps = settings.getBoolean(Key.isBypassApps, false)
val isTrafficStat = settings.getBoolean(Key.isTrafficStat, false)
val profileName = settings.getString(Key.profileName, "default")
val proxy = settings.getString(Key.proxy, "127.0.0.1") match {
case "198.199.101.152" => BuildConfig.SERVER
case s: String => s
case _ => "127.0.0.1"
}
val proxy = settings.getString(Key.proxy, "127.0.0.1")
val sitekey = settings.getString(Key.sitekey, "default")
val encMethod = {
if (proxy == BuildConfig.SERVER) {
BuildConfig.METHOD
} else {
settings.getString(Key.encMethod, "table")
}
}
val encMethod = settings.getString(Key.encMethod, "table")
val remotePort: Int = try {
if (proxy == BuildConfig.SERVER) {
scala.util.Random.shuffle(BuildConfig.PORTS.toSeq).toSeq(0)
} else {
Integer.valueOf(settings.getString(Key.remotePort, "1984"))
}
settings.getString(Key.remotePort, "1984").toInt
} catch {
case ex: NumberFormatException => {
1984
}
}
val localProt: Int = try {
Integer.valueOf(settings.getString(Key.localPort, "1984"))
settings.getString(Key.localPort, "1984").toInt
} catch {
case ex: NumberFormatException => {
1984
......@@ -283,19 +280,18 @@ object Utils {
* round or floor depending on whether you are using offsets(floor) or
* widths(round)
*/
def dpToPx (context: Context, dp: Float): Float = {
def dpToPx(context: Context, dp: Float): Float = {
val density = context.getResources.getDisplayMetrics.density
dp * density
}
def pxToDp (context: Context, px: Float): Float = {
def pxToDp(context: Context, px: Float): Float = {
val density = context.getResources.getDisplayMetrics.density
px / density
}
def getBitmap(text: String, width: Int, height: Int, background: Int): Bitmap = {
val bitmap = Bitmap.createBitmap(width,
height, Bitmap.Config.ARGB_8888)
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val size = bitmap.getHeight / 4
val canvas = new Canvas(bitmap)
canvas.drawColor(background)
......@@ -304,7 +300,8 @@ object Utils {
paint.setTextSize(size)
val bounds = new Rect()
paint.getTextBounds(text, 0, text.length, bounds)
canvas.drawText(text, (bitmap.getWidth - bounds.width()) / 2,
canvas
.drawText(text, (bitmap.getWidth - bounds.width()) / 2,
bitmap.getHeight - (bitmap.getHeight - bounds.height()) / 2, paint)
bitmap
}
......@@ -323,8 +320,7 @@ object Utils {
Utils.runRootCommand("settings put global airplane_mode_on 1\n"
+ "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state true\n"
+ "settings put global airplane_mode_on 0\n"
+ "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n"
)
+ "am broadcast -a android.intent.action.AIRPLANE_MODE --ez state false\n")
}
private def toggleBelowApiLevel17(context: Context) {
......@@ -792,6 +788,7 @@ object Utils {
}
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment