From 527d8f40662c1405e27107b8f78622e2cf631f34 Mon Sep 17 00:00:00 2001 From: Max Lv Date: Mon, 13 May 2013 15:36:46 +0800 Subject: [PATCH] refine app manager --- build.sbt | 3 +- project/Build.scala | 4 +- .../com/github/shadowsocks/AppManager.scala | 210 +++++++++-------- .../com/github/shadowsocks/ImageLoader.scala | 215 ------------------ .../com/github/shadowsocks/ProxiedApp.scala | 107 --------- .../shadowsocks/ShadowsocksService.scala | 4 +- .../scala/com/github/shadowsocks/Utils.scala | 21 +- 7 files changed, 127 insertions(+), 437 deletions(-) delete mode 100644 src/main/scala/com/github/shadowsocks/ImageLoader.scala delete mode 100644 src/main/scala/com/github/shadowsocks/ProxiedApp.scala diff --git a/build.sbt b/build.sbt index 72f04389..6a8543f3 100644 --- a/build.sbt +++ b/build.sbt @@ -5,7 +5,8 @@ javacOptions in doc ++= Seq("-source", "1.6") libraryDependencies ++= Seq( "com.google.android" % "support-v4" % "r12", "com.google.android.analytics" % "analytics" % "2.0beta4", - "dnsjava" % "dnsjava" % "2.1.5" + "dnsjava" % "dnsjava" % "2.1.5", + "com.nostra13.universalimageloader" % "universal-image-loader" % "1.8.4" ) libraryDependencies ++= Seq( diff --git a/project/Build.scala b/project/Build.scala index 1115f532..18a0e674 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -5,8 +5,8 @@ import org.scalasbt.androidplugin._ import org.scalasbt.androidplugin.AndroidKeys._ object App { - val version = "1.4.3" - val versionCode = 25 + val version = "1.4.4" + val versionCode = 26 } object General { diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala index be5b963a..eef664cf 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -38,18 +38,15 @@ package com.github.shadowsocks -import android.app.Activity import android.app.ProgressDialog import android.content.Context import android.content.SharedPreferences -import android.content.pm.ApplicationInfo -import android.content.pm.PackageManager -import android.graphics.PixelFormat +import android.content.pm.{ApplicationInfo, PackageManager} +import android.graphics.{Bitmap, PixelFormat} import android.os.Bundle import android.os.Handler import android.os.Message import android.preference.PreferenceManager -import android.view.LayoutInflater import android.view.View import android.view.View.OnClickListener import android.view.ViewGroup @@ -67,7 +64,12 @@ import android.widget.ListView import android.widget.TextView import com.actionbarsherlock.app.SherlockActivity import java.util.StringTokenizer -import scala.collection.mutable.ArrayBuffer +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 + +case class ProxiedApp(uid: Int, name: String, var proxied: Boolean) object AppManager { @@ -82,44 +84,24 @@ object AppManager { implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a) def getProxiedApps(context: Context): Array[ProxiedApp] = { + val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) val proxiedAppString = prefs.getString(PREFS_KEY_PROXYED, "") - val st: StringTokenizer = new StringTokenizer(proxiedAppString, "|") - val proxiedApps = new Array[String](st.countTokens) - var idx = 0 - while (st.hasMoreTokens) { - proxiedApps(idx) = st.nextToken() - idx += 1 - } - proxiedApps.sortWith(_ < _) - val pMgr: PackageManager = context.getPackageManager - val lAppInfo = pMgr.getInstalledApplications(0) - val itAppInfo = lAppInfo.iterator - val result = new ArrayBuffer[ProxiedApp] - var aInfo: ApplicationInfo = null - while (itAppInfo.hasNext) { - aInfo = itAppInfo.next - if (aInfo.uid >= 10000) { - val app: ProxiedApp = new ProxiedApp - app.setUid(aInfo.uid) - app.setUsername(pMgr.getNameForUid(app.getUid)) - if (aInfo.packageName != null && (aInfo.packageName == "com.github.shadowsocks")) { - app.setProxyed(true) - } else if (proxiedApps.binarySearch(app.getUsername) >= 0) { - app.setProxyed(true) - } else { - app.setProxyed(false) - } - result += app - } - } - result.toArray - } + val proxiedApps = proxiedAppString.split('|').sortWith(_ < _) - class ListEntry { - var box: CheckBox = null - var text: TextView = null - var icon: ImageView = null + import scala.collection.JavaConversions._ + + val packageManager: PackageManager = context.getPackageManager + val appList = packageManager.getInstalledApplications(0) + + appList.filter(_.uid >= 10000).map { + case a => { + val uid = a.uid + val userName = uid.toString + val proxied = proxiedApps.binarySearch(userName) >= 0 + new ProxiedApp(uid, userName, proxied) + } + }.toArray } } @@ -128,84 +110,69 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new AppManager.ObjectArrayTools(a) - val MSG_LOAD_START = 1 - val MSG_LOAD_FINISH = 2 - - def initApps(context: Context) { + def loadApps(context: Context): Array[ProxiedApp] = { val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) val proxiedAppString = prefs.getString(AppManager.PREFS_KEY_PROXYED, "") - val st: StringTokenizer = new StringTokenizer(proxiedAppString, "|") - var proxiedApps = new Array[String](st.countTokens) - var idx = 0 - while (st.hasMoreTokens) { - proxiedApps(idx) = st.nextToken() - idx += 1 - } - proxiedApps = proxiedApps.sortWith(_ < _) - val pMgr: PackageManager = context.getPackageManager - val lAppInfo = pMgr.getInstalledApplications(0) - val itAppInfo = lAppInfo.iterator - val result = new ArrayBuffer[ProxiedApp] - var aInfo: ApplicationInfo = null + val proxiedApps = proxiedAppString.split('|').sortWith(_ < _) - while (itAppInfo.hasNext) { - aInfo = itAppInfo.next - aInfo match { - case null => {} - case a if a.uid < 10000 => {} - case a if a.processName == null => {} - case a if pMgr.getApplicationLabel(a) == null => {} - case a if (pMgr.getApplicationLabel(aInfo).toString == "") => {} - case a if pMgr.getApplicationIcon(aInfo) == null => {} - case _ => { - val tApp: ProxiedApp = new ProxiedApp - tApp.setEnabled(aInfo.enabled) - tApp.setUid(aInfo.uid) - tApp.setUsername(pMgr.getNameForUid(tApp.getUid)) - tApp.setProcname(aInfo.processName) - tApp.setName(pMgr.getApplicationLabel(aInfo).toString) - tApp.setProxyed((proxiedApps binarySearch tApp.getUsername) >= 0) - result += tApp - } - } - } - apps = result.toArray + import scala.collection.JavaConversions._ + + val packageManager: PackageManager = context.getPackageManager + val appList = packageManager.getInstalledApplications(0) + + appList.filter (a => a.uid >= 10000 + && packageManager.getApplicationLabel(a) != null + && packageManager.getApplicationIcon(a) != null).map { a => + val uid = a.uid + val userName = uid.toString + val name = packageManager.getApplicationLabel(a).toString + val proxied = (proxiedApps binarySearch userName) >= 0 + new ProxiedApp(uid, name, proxied) + }.toArray } def loadApps() { - initApps(this) - apps = apps.sortWith((a, b) => { - if (a == null || b == null || a.getName == null || b.getName == null) true - else if (a.isProxied == b.isProxied) a.getName < b.getName - else if (a.isProxied) true + apps = loadApps(this).sortWith((a, b) => { + if (a == null || b == null || a.name == null || b.name == null) true + else if (a.proxied == b.proxied) a.name < b.name + else if (a.proxied) true else false }) - val inflater: LayoutInflater = getLayoutInflater adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) { override def getView(position: Int, view: View, parent: ViewGroup): View = { var convertView = view - var entry: AppManager.ListEntry = null + var entry: ListEntry = null if (convertView == null) { - convertView = inflater.inflate(R.layout.layout_apps_item, parent, false) - entry = new AppManager.ListEntry - entry.icon = convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView] - entry.box = convertView.findViewById(R.id.itemcheck).asInstanceOf[CheckBox] - entry.text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView] + convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false) + val icon = convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView] + val box = convertView.findViewById(R.id.itemcheck).asInstanceOf[CheckBox] + val text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView] + entry = new ListEntry(box, text, icon) entry.text.setOnClickListener(AppManager.this) entry.text.setOnClickListener(AppManager.this) convertView.setTag(entry) entry.box.setOnCheckedChangeListener(AppManager.this) } else { - entry = convertView.getTag.asInstanceOf[AppManager.ListEntry] + entry = convertView.getTag.asInstanceOf[ListEntry] } + val app: ProxiedApp = apps(position) - entry.icon.setTag(app.getUid) - imageLoader.DisplayImage(app.getUid, convertView.getContext.asInstanceOf[Activity], entry.icon) - entry.text.setText(app.getName) + val options = + new DisplayImageOptions.Builder().showStubImage(STUB) + .showImageForEmptyUri(STUB) + .showImageOnFail(STUB) + .resetViewBeforeLoading() + .cacheInMemory() + .cacheOnDisc() + .displayer(new FadeInBitmapDisplayer(300)) + .build() + ImageLoader.getInstance().displayImage("app://" + app.uid, entry.icon, options) + + entry.text.setText(app.name) val box: CheckBox = entry.box box.setTag(app) - box.setChecked(app.isProxied) + box.setChecked(app.proxied) entry.text.setTag(box) convertView } @@ -217,7 +184,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl def onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { val app: ProxiedApp = buttonView.getTag.asInstanceOf[ProxiedApp] if (app != null) { - app.setProxyed(isChecked) + app.proxied = isChecked } saveAppSettings(this) } @@ -226,8 +193,8 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl val cbox: CheckBox = v.getTag.asInstanceOf[CheckBox] val app: ProxiedApp = cbox.getTag.asInstanceOf[ProxiedApp] if (app != null) { - app.setProxyed(!app.isProxied) - cbox.setChecked(app.isProxied) + app.proxied = !app.proxied + cbox.setChecked(app.proxied) } saveAppSettings(this) } @@ -235,9 +202,14 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl protected override def onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) this.setContentView(R.layout.layout_apps) - this.imageLoader = ImageLoader.getImageLoader(this) this.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView] getWindowManager.addView(overlay, new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, PixelFormat.TRANSLUCENT)) + + val config = + new ImageLoaderConfiguration.Builder(this).imageDownloader( + new AppIconDownloader(this)).build() + ImageLoader.getInstance().init(config) + } protected override def onResume() { @@ -260,12 +232,11 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl if (apps == null) return val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val proxiedApps = new StringBuilder - apps.foreach(app => { - if (app.isProxied) { - proxiedApps ++= app.getUsername + apps.foreach(app => + if (app.proxied) { + proxiedApps ++= app.uid.toString proxiedApps += '|' } - } ) val edit: SharedPreferences.Editor = prefs.edit edit.putString(AppManager.PREFS_KEY_PROXYED, proxiedApps.toString()) @@ -282,9 +253,9 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl appListView.setOnScrollListener(new AbsListView.OnScrollListener { def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) { if (visible) { - val name: String = apps(firstVisibleItem).getName + val name: String = apps(firstVisibleItem).name if (name != null && name.length > 1) { - overlay.setText(apps(firstVisibleItem).getName.substring(0, 1)) + overlay.setText(apps(firstVisibleItem).name.substring(0, 1)) } else { overlay.setText("*") @@ -310,11 +281,34 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl super.handleMessage(msg) } } + + class AppIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int) + extends BaseImageDownloader(context, connectTimeout, readTimeout) { + + def this(context: Context) { this(context, 0, 0) } + + override def getStreamFromOtherSource(imageUri: String, extra: AnyRef): InputStream = { + val uid = imageUri.substring(SCHEME.length).toInt + val drawable = Utils.getAppIcon(getBaseContext, uid) + val bitmap = Utils.drawableToBitmap(drawable) + + val os = new ByteArrayOutputStream() + bitmap.compress(Bitmap.CompressFormat.PNG, 100, os) + new ByteArrayInputStream(os.toByteArray) + } + } + + case class ListEntry(box: CheckBox, text: TextView, icon: ImageView) + var apps: Array[ProxiedApp] = null var appListView: ListView = null var overlay: TextView = null var progressDialog: ProgressDialog = null var adapter: ListAdapter = null - var imageLoader: ImageLoader = null var appsLoaded: Boolean = false + + val MSG_LOAD_START = 1 + val MSG_LOAD_FINISH = 2 + val SCHEME = "app://" + val STUB = android.R.drawable.sym_def_app_icon } \ No newline at end of file diff --git a/src/main/scala/com/github/shadowsocks/ImageLoader.scala b/src/main/scala/com/github/shadowsocks/ImageLoader.scala deleted file mode 100644 index a24baac4..00000000 --- a/src/main/scala/com/github/shadowsocks/ImageLoader.scala +++ /dev/null @@ -1,215 +0,0 @@ -/* Shadowsocks - A shadowsocks client for Android - * Copyright (C) 2012 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * - * ___====-_ _-====___ - * _--^^^#####// \\#####^^^--_ - * _-^##########// ( ) \\##########^-_ - * -############// |\^^/| \\############- - * _/############// (@::@) \\############\_ - * /#############(( \\// ))#############\ - * -###############\\ (oo) //###############- - * -#################\\ / VV \ //#################- - * -###################\\/ \//###################- - * _#/|##########/\######( /\ )######/\##########|\#_ - * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| - * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' - * ` ` ` ` / | | | | \ ' ' ' ' - * ( | | | | ) - * __\ | | | | /__ - * (vvv(VVV)(VVV)vvv) - * - * HERE BE DRAGONS - * - */ -package com.github.shadowsocks - -import android.app.Activity -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.drawable.BitmapDrawable -import android.widget.ImageView -import java.io.File -import java.io.FileInputStream -import java.io.FileNotFoundException -import scala.collection.mutable - -object ImageLoader { - def getImageLoader(context: Context): ImageLoader = { - if (il == null) { - il = new ImageLoader(context) - } - il - } - - class PhotosQueue { - def clean(image: ImageView) { - photosToLoad synchronized { - { - photosToLoad filterNot (photo => photo.imageView eq image) - } - } - } - - val photosToLoad: mutable.Stack[PhotoToLoad] = new mutable.Stack[PhotoToLoad] - } - - class PhotoToLoad { - def this(u: Int, i: ImageView) { - this() - uid = u - imageView = i - } - - var uid: Int = 0 - var imageView: ImageView = null - } - - class BitmapDisplayer(bitmap: Bitmap, imageView: ImageView) extends Runnable { - def run() { - if (bitmap != null) { - imageView.setImageBitmap(bitmap) - } - else { - imageView.setImageResource(stub_id) - } - } - } - - var il: ImageLoader = null - val stub_id: Int = android.R.drawable.sym_def_app_icon -} - -class ImageLoader { - def this(c: Context) { - this() - photoLoaderThread.setPriority(Thread.NORM_PRIORITY - 1) - context = c - cacheDir = context.getCacheDir - } - - def clearCache() { - cache.clear() - val files: Array[File] = cacheDir.listFiles - for (f <- files) f.delete - } - - private def decodeFile(f: File): Bitmap = { - try { - val o: BitmapFactory.Options = new BitmapFactory.Options - o.inJustDecodeBounds = true - BitmapFactory.decodeStream(new FileInputStream(f), null, o) - val REQUIRED_SIZE: Int = 70 - var width_tmp: Int = o.outWidth - var height_tmp: Int = o.outHeight - var scale: Int = 1 - while (true) { - if (width_tmp / 2 >= REQUIRED_SIZE && height_tmp / 2 >= REQUIRED_SIZE) { - width_tmp /= 2 - height_tmp /= 2 - scale *= 2 - } - } - val o2: BitmapFactory.Options = new BitmapFactory.Options - o2.inSampleSize = scale - return BitmapFactory.decodeStream(new FileInputStream(f), null, o2) - } - catch { - case ignored: FileNotFoundException => { - } - } - null - } - - def DisplayImage(uid: Int, activity: Activity, imageView: ImageView) { - cache.get(uid) map { - bitmap => imageView.setImageBitmap(bitmap) - } getOrElse { - queuePhoto(uid, activity, imageView) - imageView.setImageResource(ImageLoader.stub_id) - } - } - - private def getBitmap(uid: Int): Bitmap = { - val filename = String.valueOf(uid) - val f: File = new File(cacheDir, filename) - val b: Bitmap = decodeFile(f) - if (b != null) return b - try { - val icon: BitmapDrawable = Utils.getAppIcon(context, uid).asInstanceOf[BitmapDrawable] - icon.getBitmap - } - catch { - case ex: Exception => { - return null - } - } - } - - def queuePhoto(uid: Int, activity: Activity, imageView: ImageView) { - photosQueue.clean(imageView) - val p: ImageLoader.PhotoToLoad = new ImageLoader.PhotoToLoad(uid, imageView) - photosQueue.photosToLoad synchronized { - photosQueue.photosToLoad.push(p) - photosQueue.photosToLoad.notifyAll() - } - if (photoLoaderThread.getState eq Thread.State.NEW) photoLoaderThread.start() - } - - def stopThread() { - photoLoaderThread.interrupt() - } - - val photosQueue: ImageLoader.PhotosQueue = new ImageLoader.PhotosQueue - val photoLoaderThread: PhotosLoader = new PhotosLoader - var cache: mutable.HashMap[Int, Bitmap] = new mutable.HashMap[Int, Bitmap] - var cacheDir: File = null - var context: Context = null - - class PhotosLoader extends Thread { - override def run() { - try { - while (true) { - if (photosQueue.photosToLoad.size == 0) { - photosQueue.photosToLoad synchronized { - photosQueue.photosToLoad.wait() - } - } - if (photosQueue.photosToLoad.size != 0) { - var photoToLoad: ImageLoader.PhotoToLoad = null - photosQueue.photosToLoad synchronized { - photoToLoad = photosQueue.photosToLoad.pop() - } - val bmp: Bitmap = getBitmap(photoToLoad.uid) - cache.put(photoToLoad.uid, bmp) - val tag: AnyRef = photoToLoad.imageView.getTag - if (tag != null && tag.asInstanceOf[Int] == photoToLoad.uid) { - val bd: ImageLoader.BitmapDisplayer = new ImageLoader.BitmapDisplayer(bmp, photoToLoad.imageView) - val a: Activity = photoToLoad.imageView.getContext.asInstanceOf[Activity] - a.runOnUiThread(bd) - } - } - if (Thread.interrupted) return - } - } - catch { - case e: InterruptedException => { - } - } - } - } -} \ No newline at end of file diff --git a/src/main/scala/com/github/shadowsocks/ProxiedApp.scala b/src/main/scala/com/github/shadowsocks/ProxiedApp.scala deleted file mode 100644 index a30315d1..00000000 --- a/src/main/scala/com/github/shadowsocks/ProxiedApp.scala +++ /dev/null @@ -1,107 +0,0 @@ -/* Shadowsocks - A shadowsocks client for Android - * Copyright (C) 2012 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - * - * - * ___====-_ _-====___ - * _--^^^#####// \\#####^^^--_ - * _-^##########// ( ) \\##########^-_ - * -############// |\^^/| \\############- - * _/############// (@::@) \\############\_ - * /#############(( \\// ))#############\ - * -###############\\ (oo) //###############- - * -#################\\ / VV \ //#################- - * -###################\\/ \//###################- - * _#/|##########/\######( /\ )######/\##########|\#_ - * |/ |#/\#/\#/\/ \#/\##\ | | /##/\#/ \/\#/\#/\#| \| - * ` |/ V V ` V \#\| | | |/#/ V ' V V \| ' - * ` ` ` ` / | | | | \ ' ' ' ' - * ( | | | | ) - * __\ | | | | /__ - * (vvv(VVV)(VVV)vvv) - * - * HERE BE DRAGONS - * - */ -package com.github.shadowsocks - -class ProxiedApp { - /** @return the name */ - def getName: String = { - name - } - - /** @param name the name to set */ - def setName(name: String) { - this.name = name - } - - /** @return the procname */ - def getProcname: String = { - procname - } - - /** @param procname the procname to set */ - def setProcname(procname: String) { - this.procname = procname - } - - /** @return the uid */ - def getUid: Int = { - uid - } - - /** @param uid the uid to set */ - def setUid(uid: Int) { - this.uid = uid - } - - /** @return the username */ - def getUsername: String = { - username - } - - /** @param username the username to set */ - def setUsername(username: String) { - this.username = username - } - - /** @return the enabled */ - def isEnabled: Boolean = { - enabled - } - - /** @param enabled the enabled to set */ - def setEnabled(enabled: Boolean) { - this.enabled = enabled - } - - /** @return the proxied */ - def isProxied: Boolean = { - proxied - } - - /** @param proxied the proxied to set */ - def setProxyed(proxied: Boolean) { - this.proxied = proxied - } - - private var enabled: Boolean = false - private var uid: Int = 0 - private var username: String = null - private var procname: String = null - private var name: String = null - private var proxied: Boolean = false -} \ No newline at end of file diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala index 4055485b..0016692e 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksService.scala @@ -433,8 +433,8 @@ class ShadowsocksService extends Service { if (apps == null || apps.length <= 0) apps = AppManager.getProxiedApps(this) val uidSet: mutable.HashSet[Int] = new mutable.HashSet[Int] for (app <- apps) { - if (app.isProxied) { - uidSet.add(app.getUid) + if (app.proxied) { + uidSet.add(app.uid) } } for (uid <- uidSet) { diff --git a/src/main/scala/com/github/shadowsocks/Utils.scala b/src/main/scala/com/github/shadowsocks/Utils.scala index 890dc3f3..ed6fdd7c 100644 --- a/src/main/scala/com/github/shadowsocks/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/Utils.scala @@ -40,7 +40,7 @@ package com.github.shadowsocks import android.content.Context import android.content.pm.ApplicationInfo import android.content.pm.PackageManager -import android.graphics.drawable.Drawable +import android.graphics.drawable.{BitmapDrawable, Drawable} import android.os.Environment import android.util.Log import java.io._ @@ -49,6 +49,7 @@ import org.apache.http.conn.util.InetAddressUtils import scala.collection.mutable.ArrayBuffer import org.xbill.DNS._ import scala.Some +import android.graphics.{Canvas, Bitmap} object Utils { @@ -245,12 +246,28 @@ object Utils { } } + def drawableToBitmap (drawable: Drawable): Bitmap = { + if (drawable.isInstanceOf[BitmapDrawable]) { + return drawable.asInstanceOf[BitmapDrawable].getBitmap + } + + val width = if (drawable.getIntrinsicWidth > 0) drawable.getIntrinsicWidth else 1 + val height = if (drawable.getIntrinsicWidth > 0) drawable.getIntrinsicWidth else 1 + + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888) + val canvas = new Canvas(bitmap) + drawable.setBounds(0, 0, canvas.getWidth, canvas.getHeight) + drawable.draw(canvas) + + bitmap + } + def getAppIcon(c: Context, uid: Int): Drawable = { val pm: PackageManager = c.getPackageManager var appIcon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon) val packages: Array[String] = pm.getPackagesForUid(uid) if (packages != null) { - if (packages.length == 1) { + if (packages.length >= 1) { try { val appInfo: ApplicationInfo = pm.getApplicationInfo(packages(0), 0) appIcon = pm.getApplicationIcon(appInfo)