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 @@ - - - - + - - - - - - - - - - - - - - + - \ 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 = {