diff --git a/build.sbt b/build.sbt
index db6b98f4..157aa391 100644
--- a/build.sbt
+++ b/build.sbt
@@ -15,7 +15,6 @@ resolvers += "JRAF" at "http://JRAF.org/static/maven/2"
resolvers += "madeye private releases" at "http://madeye-maven-repository.googlecode.com/git/"
libraryDependencies ++= Seq(
- "com.google.android" % "analytics" % "3.01",
"dnsjava" % "dnsjava" % "2.1.5",
"org.scalaj" %% "scalaj-http" % "0.3.10",
"commons-net" % "commons-net" % "3.3",
@@ -23,10 +22,8 @@ libraryDependencies ++= Seq(
)
libraryDependencies ++= Seq(
- aar("com.actionbarsherlock" % "actionbarsherlock" % "4.4.0") exclude("com.google.android", "support-v4"),
"net.simonvt.menudrawer" % "menudrawer" % "3.0.6",
- "org.jraf" % "android-switch-backport" % "1.3.1",
- "com.google.android.gms" % "play-services" % "4.4.52",
+ "com.google.android.gms" % "play-services" % "5.2.08",
"com.android.support" % "support-v4" % "19.1.0"
)
diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml
index 3c368e13..0ac6e3f2 100644
--- a/src/main/AndroidManifest.xml
+++ b/src/main/AndroidManifest.xml
@@ -15,10 +15,11 @@
android:required="false"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/main/res/values/analytics.xml b/src/main/res/values/analytics.xml
deleted file mode 100755
index 3ae34114..00000000
--- a/src/main/res/values/analytics.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
- UA-37082941-1
-
-
- true
-
-
- true
-
-
- 604800
-
diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml
index c9f62e57..0b4a3cf9 100644
--- a/src/main/res/values/colors.xml
+++ b/src/main/res/values/colors.xml
@@ -1,18 +1,4 @@
-
diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml
index 3382923c..2ffd80d8 100644
--- a/src/main/res/values/styles.xml
+++ b/src/main/res/values/styles.xml
@@ -16,20 +16,11 @@
-
-
-
-
diff --git a/src/main/res/values/styles_shadow.xml b/src/main/res/values/styles_shadow.xml
index c8ae87a0..870da93d 100755
--- a/src/main/res/values/styles_shadow.xml
+++ b/src/main/res/values/styles_shadow.xml
@@ -19,77 +19,64 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
\ No newline at end of file
diff --git a/src/main/res/xml/tracker.xml b/src/main/res/xml/tracker.xml
new file mode 100644
index 00000000..1d1784c6
--- /dev/null
+++ b/src/main/res/xml/tracker.xml
@@ -0,0 +1,18 @@
+
+
+
+ 604800
+
+
+ true
+
+
+
+ Shadowsocks ScreenView
+
+
+ Shadowsocks EcommerceView
+
+
+ UA-37082941-1
+
\ No newline at end of file
diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala
index 6623c840..fc8d63ed 100644
--- a/src/main/scala/com/github/shadowsocks/AppManager.scala
+++ b/src/main/scala/com/github/shadowsocks/AppManager.scala
@@ -68,7 +68,6 @@ import com.nostra13.universalimageloader.core.download.BaseImageDownloader
import java.io.{ByteArrayOutputStream, ByteArrayInputStream, InputStream}
import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration}
import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer
-import com.google.analytics.tracking.android.EasyTracker
import org.jraf.android.backport.switchwidget.Switch
import com.github.shadowsocks.utils.{Utils, Scheme, Key}
@@ -255,16 +254,6 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
}.start()
}
- protected override def onStart() {
- super.onStart()
- EasyTracker.getInstance(this).activityStart(this)
- }
-
- protected override def onStop() {
- super.onStop()
- EasyTracker.getInstance(this).activityStop(this)
- }
-
def saveAppSettings(context: Context) {
if (apps == null) return
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala
index 062742d9..7f98b010 100644
--- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala
+++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala
@@ -54,18 +54,16 @@ import android.util.{DisplayMetrics, Log}
import android.view._
import android.webkit.{WebView, WebViewClient}
import android.widget._
-import com.actionbarsherlock.app.SherlockPreferenceActivity
import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback}
import com.github.shadowsocks.database._
import com.github.shadowsocks.preferences.{PasswordEditTextPreference, ProfileEditTextPreference, SummaryEditTextPreference}
import com.github.shadowsocks.utils._
-import com.google.analytics.tracking.android.{EasyTracker, MapBuilder}
import com.google.android.gms.ads.{AdRequest, AdSize, AdView}
+import com.google.android.gms.analytics.HitBuilders
import com.google.zxing.integration.android.IntentIntegrator
import com.nostra13.universalimageloader.core.download.BaseImageDownloader
import de.keyboardsurfer.android.widget.crouton.{Configuration, Crouton, Style}
import net.simonvt.menudrawer.MenuDrawer
-import org.jraf.android.backport.switchwidget.Switch
import scala.collection.mutable.{ArrayBuffer, ListBuffer}
import scala.concurrent.ops._
@@ -169,7 +167,7 @@ object Shadowsocks {
}
class Shadowsocks
- extends SherlockPreferenceActivity
+ extends PreferenceActivity
with CompoundButton.OnCheckedChangeListener
with MenuAdapter.MenuListener {
@@ -236,7 +234,8 @@ class Shadowsocks
lazy val profileManager =
new ProfileManager(settings, getApplication.asInstanceOf[ShadowsocksApplication].dbHelper)
- val handler = new Handler()
+ private lazy val handler = new Handler()
+ private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isSinglePane: Boolean = {
if (singlePane == -1) {
@@ -481,10 +480,10 @@ class Shadowsocks
val tf: Typeface = Typefaces.get(this, "fonts/Iceland.ttf")
if (tf != null) title.setTypeface(tf)
switchButton = switchLayout.findViewById(R.id.switchButton).asInstanceOf[Switch]
- getSupportActionBar.setCustomView(switchLayout)
- getSupportActionBar.setDisplayShowTitleEnabled(false)
- getSupportActionBar.setDisplayShowCustomEnabled(true)
- getSupportActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
+ getActionBar.setCustomView(switchLayout)
+ getActionBar.setDisplayShowTitleEnabled(false)
+ getActionBar.setDisplayShowCustomEnabled(true)
+ getActionBar.setIcon(R.drawable.ic_stat_shadowsocks)
// Register broadcast receiver
registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS))
@@ -683,32 +682,40 @@ class Shadowsocks
buf += new Category(getString(R.string.settings))
buf += new Item(-100, getString(R.string.recovery), android.R.drawable.ic_menu_revert, _ => {
- EasyTracker
- .getInstance(this)
- .send(MapBuilder.createEvent(Shadowsocks.TAG, "reset", getVersionName, null).build())
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(Shadowsocks.TAG)
+ .setAction("reset")
+ .setLabel(getVersionName)
+ .build())
recovery()
})
buf +=
new Item(-200, getString(R.string.flush_dnscache), android.R.drawable.ic_menu_delete, _ => {
- EasyTracker
- .getInstance(this)
- .send(
- MapBuilder.createEvent(Shadowsocks.TAG, "flush_dnscache", getVersionName, null).build())
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(Shadowsocks.TAG)
+ .setAction("flush_dnscache")
+ .setLabel(getVersionName)
+ .build())
flushDnsCache()
})
buf += new Item(-300, getString(R.string.about), android.R.drawable.ic_menu_info_details, _ => {
- EasyTracker
- .getInstance(this)
- .send(MapBuilder.createEvent(Shadowsocks.TAG, "about", getVersionName, null).build())
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(Shadowsocks.TAG)
+ .setAction("about")
+ .setLabel(getVersionName)
+ .build())
showAbout()
})
buf.toList
}
- override def onOptionsItemSelected(item: com.actionbarsherlock.view.MenuItem): Boolean = {
+ override def onOptionsItemSelected(item: MenuItem): Boolean = {
item.getItemId match {
case android.R.id.home =>
drawer.toggleMenu()
@@ -776,12 +783,10 @@ class Shadowsocks
override def onStart() {
super.onStart()
- EasyTracker.getInstance(this).activityStart(this)
}
override def onStop() {
super.onStop()
- EasyTracker.getInstance(this).activityStop(this)
clearDialog()
}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala
index 4f208d91..f757278c 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala
@@ -39,8 +39,14 @@
package com.github.shadowsocks
+import java.util.concurrent.TimeUnit
+
import android.app.Application
import com.github.shadowsocks.database.DBHelper
+import com.google.android.gms.analytics.{GoogleAnalytics, Tracker}
+import com.google.android.gms.common.api.ResultCallback
+import com.google.android.gms.tagmanager.Container.FunctionCallMacroCallback
+import com.google.android.gms.tagmanager.{ContainerHolder, TagManager, Container}
import com.google.tagmanager.{Container, ContainerOpener, TagManager}
import com.google.tagmanager.ContainerOpener.{Notifier, OpenType}
import com.google.tagmanager.Container.FunctionCallMacroHandler
@@ -50,15 +56,21 @@ import com.github.shadowsocks.utils.Utils
class ShadowsocksApplication extends Application {
lazy val dbHelper = new DBHelper(this)
lazy val SIG_FUNC = "getSignature"
- var tagContainer: Container = null
+ var containerHolder: ContainerHolder = null
+ lazy val tracker = GoogleAnalytics.getInstance(this).newTracker(R.xml.tracker)
override def onCreate() {
val tm = TagManager.getInstance(this)
- ContainerOpener.openContainer(tm, "GTM-NT8WS8", OpenType.PREFER_NON_DEFAULT, null, new Notifier {
- override def containerAvailable(container: Container) {
- tagContainer = container
- container.registerFunctionCallMacroHandler(SIG_FUNC, new FunctionCallMacroHandler {
- def getValue(functionName: String, parameters: util.Map[String, AnyRef]): AnyRef = {
+ val pending = tm.loadContainerPreferNonDefault("GTM-NT8WS8", R.raw.gtm_default_container)
+ val callback = new ResultCallback[ContainerHolder] {
+ override def onResult(holder: ContainerHolder): Unit = {
+ if (!containerHolder.getStatus.isSuccess) {
+ return
+ }
+ containerHolder = holder
+ val container = holder.getContainer
+ container.registerFunctionCallMacroCallback(SIG_FUNC, new FunctionCallMacroCallback {
+ override def getValue(functionName: String, parameters: util.Map[String, AnyRef]): AnyRef = {
if (functionName == SIG_FUNC) {
Utils.getSignature(getApplicationContext)
}
@@ -66,6 +78,7 @@ class ShadowsocksApplication extends Application {
}
})
}
- })
+ }
+ pending.setResultCallback(callback, 2, TimeUnit.SECONDS)
}
}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
index fb541639..08d46bc8 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala
@@ -49,9 +49,9 @@ import android.content.pm.PackageManager
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
-import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker}
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Method
+import com.google.android.gms.analytics.HitBuilders
import org.apache.http.conn.util.InetAddressUtils
import scala.collection._
import java.util.{TimerTask, Timer}
@@ -100,7 +100,7 @@ class ShadowsocksNatService extends Service with BaseService {
private var timer: Timer = null
private val TIMER_INTERVAL = 2
- val handler: Handler = new Handler()
+ private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isACLEnabled: Boolean = {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
@@ -454,12 +454,12 @@ class ShadowsocksNatService extends Service with BaseService {
}
registerReceiver(receiver, filter)
- // start tracker
- EasyTracker
- .getInstance(this)
- .send(MapBuilder
- .createEvent(TAG, "start", getVersionName, 0L)
- .set(Fields.SESSION_CONTROL, "start")
+
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(TAG)
+ .setAction("start")
+ .setLabel(getVersionName)
.build())
changeState(State.CONNECTING)
@@ -496,9 +496,9 @@ class ShadowsocksNatService extends Service with BaseService {
spawn {
if (config.proxy == "198.199.101.152") {
- val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer
+ val holder = application.containerHolder
try {
- config = ConfigUtils.getPublicConfig(getBaseContext, container, config)
+ config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch {
case ex: Exception =>
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
@@ -542,12 +542,11 @@ class ShadowsocksNatService extends Service with BaseService {
// change the state
changeState(State.STOPPED)
- // stop the tracker
- EasyTracker
- .getInstance(this)
- .send(MapBuilder
- .createEvent(TAG, "stop", getVersionName, 0L)
- .set(Fields.SESSION_CONTROL, "stop")
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(TAG)
+ .setAction("stop")
+ .setLabel(getVersionName)
.build())
// reset timer
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala
index 7efe4254..c2b052f3 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala
@@ -138,7 +138,7 @@ class ShadowsocksRunnerActivity extends Activity {
deattachService()
if (receiver != null) {
unregisterReceiver(receiver)
- receiver = null;
+ receiver = null
}
}
diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
index 1836e8f5..4376164b 100644
--- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
+++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala
@@ -39,25 +39,24 @@
package com.github.shadowsocks
+import java.io.File
+import java.net.InetAddress
+
import android.app._
import android.content._
-import android.content.pm.PackageInfo
-import android.content.pm.PackageManager
+import android.content.pm.{PackageInfo, PackageManager}
+import android.net.VpnService
import android.os._
import android.support.v4.app.NotificationCompat
import android.util.Log
-import com.google.analytics.tracking.android.{Fields, MapBuilder, EasyTracker}
-import android.net.VpnService
-import org.apache.http.conn.util.InetAddressUtils
-import android.os.Message
-import scala.concurrent.ops._
-import org.apache.commons.net.util.SubnetUtils
+import com.github.shadowsocks.aidl.Config
import com.github.shadowsocks.utils._
-import scala.Some
-import com.github.shadowsocks.aidl.{IShadowsocksService, Config}
+import com.google.android.gms.analytics.HitBuilders
+import org.apache.commons.net.util.SubnetUtils
+import org.apache.http.conn.util.InetAddressUtils
+
import scala.collection.mutable.ArrayBuffer
-import java.io.File
-import java.net.InetAddress
+import scala.concurrent.ops._
class ShadowsocksVpnService extends VpnService with BaseService {
@@ -73,7 +72,7 @@ class ShadowsocksVpnService extends VpnService with BaseService {
var apps: Array[ProxiedApp] = null
var config: Config = null
- val handler: Handler = new Handler()
+ private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication]
def isByass(net: SubnetUtils): Boolean = {
val info = net.getInfo
@@ -272,12 +271,11 @@ class ShadowsocksVpnService extends VpnService with BaseService {
return
}
- // start the tracker
- EasyTracker
- .getInstance(this)
- .send(MapBuilder
- .createEvent(TAG, "start", getVersionName, 0L)
- .set(Fields.SESSION_CONTROL, "start")
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(TAG)
+ .setAction("start")
+ .setLabel(getVersionName)
.build())
// register close receiver
@@ -294,9 +292,9 @@ class ShadowsocksVpnService extends VpnService with BaseService {
spawn {
if (config.proxy == "198.199.101.152") {
- val container = getApplication.asInstanceOf[ShadowsocksApplication].tagContainer
+ val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder
try {
- config = ConfigUtils.getPublicConfig(getBaseContext, container, config)
+ config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config)
} catch {
case ex: Exception =>
notifyAlert(getString(R.string.forward_fail), getString(R.string.service_failed))
@@ -338,12 +336,11 @@ class ShadowsocksVpnService extends VpnService with BaseService {
// channge the state
changeState(State.STOPPED)
- // stop the tracker
- EasyTracker
- .getInstance(this)
- .send(MapBuilder
- .createEvent(TAG, "stop", getVersionName, 0L)
- .set(Fields.SESSION_CONTROL, "stop")
+ // send event
+ application.tracker.send(new HitBuilders.EventBuilder()
+ .setCategory(TAG)
+ .setAction("stop")
+ .setLabel(getVersionName)
.build())
// reset VPN
diff --git a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
index 6a50eba4..bef47468 100644
--- a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
+++ b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala
@@ -41,7 +41,7 @@ package com.github.shadowsocks.utils
import android.content.{SharedPreferences, Context}
import com.github.shadowsocks.ShadowsocksApplication
-import com.google.tagmanager.Container
+import com.google.android.gms.tagmanager.Container
import scalaj.http.{HttpOptions, Http}
import com.github.shadowsocks.aidl.Config
@@ -143,8 +143,8 @@ object ConfigUtils {
}
def refresh(context: Context) {
- val container = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].tagContainer
- if (container != null) container.refresh()
+ val holder = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].containerHolder
+ if (holder != null) holder.refresh()
}
def getPublicConfig(context: Context, container: Container, config: Config): Config = {