Commit 527d8f40 authored by Max Lv's avatar Max Lv

refine app manager

parent 1fafe1e2
...@@ -5,7 +5,8 @@ javacOptions in doc ++= Seq("-source", "1.6") ...@@ -5,7 +5,8 @@ javacOptions in doc ++= Seq("-source", "1.6")
libraryDependencies ++= Seq( libraryDependencies ++= Seq(
"com.google.android" % "support-v4" % "r12", "com.google.android" % "support-v4" % "r12",
"com.google.android.analytics" % "analytics" % "2.0beta4", "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( libraryDependencies ++= Seq(
......
...@@ -5,8 +5,8 @@ import org.scalasbt.androidplugin._ ...@@ -5,8 +5,8 @@ import org.scalasbt.androidplugin._
import org.scalasbt.androidplugin.AndroidKeys._ import org.scalasbt.androidplugin.AndroidKeys._
object App { object App {
val version = "1.4.3" val version = "1.4.4"
val versionCode = 25 val versionCode = 26
} }
object General { object General {
......
...@@ -38,18 +38,15 @@ ...@@ -38,18 +38,15 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.app.Activity
import android.app.ProgressDialog import android.app.ProgressDialog
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.ApplicationInfo import android.content.pm.{ApplicationInfo, PackageManager}
import android.content.pm.PackageManager import android.graphics.{Bitmap, PixelFormat}
import android.graphics.PixelFormat
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.os.Message import android.os.Message
import android.preference.PreferenceManager import android.preference.PreferenceManager
import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.View.OnClickListener import android.view.View.OnClickListener
import android.view.ViewGroup import android.view.ViewGroup
...@@ -67,7 +64,12 @@ import android.widget.ListView ...@@ -67,7 +64,12 @@ import android.widget.ListView
import android.widget.TextView import android.widget.TextView
import com.actionbarsherlock.app.SherlockActivity import com.actionbarsherlock.app.SherlockActivity
import java.util.StringTokenizer 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 { object AppManager {
...@@ -82,44 +84,24 @@ object AppManager { ...@@ -82,44 +84,24 @@ object AppManager {
implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a) implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new ObjectArrayTools(a)
def getProxiedApps(context: Context): Array[ProxiedApp] = { def getProxiedApps(context: Context): Array[ProxiedApp] = {
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val proxiedAppString = prefs.getString(PREFS_KEY_PROXYED, "") val proxiedAppString = prefs.getString(PREFS_KEY_PROXYED, "")
val st: StringTokenizer = new StringTokenizer(proxiedAppString, "|") val proxiedApps = proxiedAppString.split('|').sortWith(_ < _)
val proxiedApps = new Array[String](st.countTokens)
var idx = 0 import scala.collection.JavaConversions._
while (st.hasMoreTokens) {
proxiedApps(idx) = st.nextToken() val packageManager: PackageManager = context.getPackageManager
idx += 1 val appList = packageManager.getInstalledApplications(0)
}
proxiedApps.sortWith(_ < _) appList.filter(_.uid >= 10000).map {
val pMgr: PackageManager = context.getPackageManager case a => {
val lAppInfo = pMgr.getInstalledApplications(0) val uid = a.uid
val itAppInfo = lAppInfo.iterator val userName = uid.toString
val result = new ArrayBuffer[ProxiedApp] val proxied = proxiedApps.binarySearch(userName) >= 0
var aInfo: ApplicationInfo = null new ProxiedApp(uid, userName, proxied)
while (itAppInfo.hasNext) { }
aInfo = itAppInfo.next }.toArray
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
}
class ListEntry {
var box: CheckBox = null
var text: TextView = null
var icon: ImageView = null
} }
} }
...@@ -128,84 +110,69 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -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) implicit def anyrefarray_tools[T <: AnyRef](a: Array[T]) = new AppManager.ObjectArrayTools(a)
val MSG_LOAD_START = 1 def loadApps(context: Context): Array[ProxiedApp] = {
val MSG_LOAD_FINISH = 2
def initApps(context: Context) {
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
val proxiedAppString = prefs.getString(AppManager.PREFS_KEY_PROXYED, "") val proxiedAppString = prefs.getString(AppManager.PREFS_KEY_PROXYED, "")
val st: StringTokenizer = new StringTokenizer(proxiedAppString, "|") val proxiedApps = proxiedAppString.split('|').sortWith(_ < _)
var proxiedApps = new Array[String](st.countTokens)
var idx = 0 import scala.collection.JavaConversions._
while (st.hasMoreTokens) {
proxiedApps(idx) = st.nextToken() val packageManager: PackageManager = context.getPackageManager
idx += 1 val appList = packageManager.getInstalledApplications(0)
}
proxiedApps = proxiedApps.sortWith(_ < _) appList.filter (a => a.uid >= 10000
val pMgr: PackageManager = context.getPackageManager && packageManager.getApplicationLabel(a) != null
val lAppInfo = pMgr.getInstalledApplications(0) && packageManager.getApplicationIcon(a) != null).map { a =>
val itAppInfo = lAppInfo.iterator val uid = a.uid
val result = new ArrayBuffer[ProxiedApp] val userName = uid.toString
var aInfo: ApplicationInfo = null val name = packageManager.getApplicationLabel(a).toString
val proxied = (proxiedApps binarySearch userName) >= 0
while (itAppInfo.hasNext) { new ProxiedApp(uid, name, proxied)
aInfo = itAppInfo.next }.toArray
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
} }
def loadApps() { def loadApps() {
initApps(this) apps = loadApps(this).sortWith((a, b) => {
apps = apps.sortWith((a, b) => { if (a == null || b == null || a.name == null || b.name == null) true
if (a == null || b == null || a.getName == null || b.getName == null) true else if (a.proxied == b.proxied) a.name < b.name
else if (a.isProxied == b.isProxied) a.getName < b.getName else if (a.proxied) true
else if (a.isProxied) true
else false else false
}) })
val inflater: LayoutInflater = getLayoutInflater
adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) { adapter = new ArrayAdapter[ProxiedApp](this, R.layout.layout_apps_item, R.id.itemtext, apps) {
override def getView(position: Int, view: View, parent: ViewGroup): View = { override def getView(position: Int, view: View, parent: ViewGroup): View = {
var convertView = view var convertView = view
var entry: AppManager.ListEntry = null var entry: ListEntry = null
if (convertView == null) { if (convertView == null) {
convertView = inflater.inflate(R.layout.layout_apps_item, parent, false) convertView = getLayoutInflater.inflate(R.layout.layout_apps_item, parent, false)
entry = new AppManager.ListEntry val icon = convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView]
entry.icon = convertView.findViewById(R.id.itemicon).asInstanceOf[ImageView] val box = convertView.findViewById(R.id.itemcheck).asInstanceOf[CheckBox]
entry.box = convertView.findViewById(R.id.itemcheck).asInstanceOf[CheckBox] val text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView]
entry.text = convertView.findViewById(R.id.itemtext).asInstanceOf[TextView] entry = new ListEntry(box, text, icon)
entry.text.setOnClickListener(AppManager.this) entry.text.setOnClickListener(AppManager.this)
entry.text.setOnClickListener(AppManager.this) entry.text.setOnClickListener(AppManager.this)
convertView.setTag(entry) convertView.setTag(entry)
entry.box.setOnCheckedChangeListener(AppManager.this) entry.box.setOnCheckedChangeListener(AppManager.this)
} }
else { else {
entry = convertView.getTag.asInstanceOf[AppManager.ListEntry] entry = convertView.getTag.asInstanceOf[ListEntry]
} }
val app: ProxiedApp = apps(position) val app: ProxiedApp = apps(position)
entry.icon.setTag(app.getUid) val options =
imageLoader.DisplayImage(app.getUid, convertView.getContext.asInstanceOf[Activity], entry.icon) new DisplayImageOptions.Builder().showStubImage(STUB)
entry.text.setText(app.getName) .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 val box: CheckBox = entry.box
box.setTag(app) box.setTag(app)
box.setChecked(app.isProxied) box.setChecked(app.proxied)
entry.text.setTag(box) entry.text.setTag(box)
convertView convertView
} }
...@@ -217,7 +184,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -217,7 +184,7 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
def onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) { def onCheckedChanged(buttonView: CompoundButton, isChecked: Boolean) {
val app: ProxiedApp = buttonView.getTag.asInstanceOf[ProxiedApp] val app: ProxiedApp = buttonView.getTag.asInstanceOf[ProxiedApp]
if (app != null) { if (app != null) {
app.setProxyed(isChecked) app.proxied = isChecked
} }
saveAppSettings(this) saveAppSettings(this)
} }
...@@ -226,8 +193,8 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -226,8 +193,8 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
val cbox: CheckBox = v.getTag.asInstanceOf[CheckBox] val cbox: CheckBox = v.getTag.asInstanceOf[CheckBox]
val app: ProxiedApp = cbox.getTag.asInstanceOf[ProxiedApp] val app: ProxiedApp = cbox.getTag.asInstanceOf[ProxiedApp]
if (app != null) { if (app != null) {
app.setProxyed(!app.isProxied) app.proxied = !app.proxied
cbox.setChecked(app.isProxied) cbox.setChecked(app.proxied)
} }
saveAppSettings(this) saveAppSettings(this)
} }
...@@ -235,9 +202,14 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -235,9 +202,14 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
protected override def onCreate(savedInstanceState: Bundle) { protected override def onCreate(savedInstanceState: Bundle) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
this.setContentView(R.layout.layout_apps) this.setContentView(R.layout.layout_apps)
this.imageLoader = ImageLoader.getImageLoader(this)
this.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView] 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)) 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() { protected override def onResume() {
...@@ -260,12 +232,11 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -260,12 +232,11 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
if (apps == null) return if (apps == null) return
val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this) val prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
val proxiedApps = new StringBuilder val proxiedApps = new StringBuilder
apps.foreach(app => { apps.foreach(app =>
if (app.isProxied) { if (app.proxied) {
proxiedApps ++= app.getUsername proxiedApps ++= app.uid.toString
proxiedApps += '|' proxiedApps += '|'
} }
}
) )
val edit: SharedPreferences.Editor = prefs.edit val edit: SharedPreferences.Editor = prefs.edit
edit.putString(AppManager.PREFS_KEY_PROXYED, proxiedApps.toString()) edit.putString(AppManager.PREFS_KEY_PROXYED, proxiedApps.toString())
...@@ -282,9 +253,9 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -282,9 +253,9 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
appListView.setOnScrollListener(new AbsListView.OnScrollListener { appListView.setOnScrollListener(new AbsListView.OnScrollListener {
def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) { def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
if (visible) { if (visible) {
val name: String = apps(firstVisibleItem).getName val name: String = apps(firstVisibleItem).name
if (name != null && name.length > 1) { if (name != null && name.length > 1) {
overlay.setText(apps(firstVisibleItem).getName.substring(0, 1)) overlay.setText(apps(firstVisibleItem).name.substring(0, 1))
} }
else { else {
overlay.setText("*") overlay.setText("*")
...@@ -310,11 +281,34 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl ...@@ -310,11 +281,34 @@ class AppManager extends SherlockActivity with OnCheckedChangeListener with OnCl
super.handleMessage(msg) 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 apps: Array[ProxiedApp] = null
var appListView: ListView = null var appListView: ListView = null
var overlay: TextView = null var overlay: TextView = null
var progressDialog: ProgressDialog = null var progressDialog: ProgressDialog = null
var adapter: ListAdapter = null var adapter: ListAdapter = null
var imageLoader: ImageLoader = null
var appsLoaded: Boolean = false 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
/* Shadowsocks - A shadowsocks client for Android
* Copyright (C) 2012 <max.c.lv@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
* ___====-_ _-====___
* _--^^^#####// \\#####^^^--_
* _-^##########// ( ) \\##########^-_
* -############// |\^^/| \\############-
* _/############// (@::@) \\############\_
* /#############(( \\// ))#############\
* -###############\\ (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
/* Shadowsocks - A shadowsocks client for Android
* Copyright (C) 2012 <max.c.lv@gmail.com>
*
* 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 <http://www.gnu.org/licenses/>.
*
*
* ___====-_ _-====___
* _--^^^#####// \\#####^^^--_
* _-^##########// ( ) \\##########^-_
* -############// |\^^/| \\############-
* _/############// (@::@) \\############\_
* /#############(( \\// ))#############\
* -###############\\ (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
...@@ -433,8 +433,8 @@ class ShadowsocksService extends Service { ...@@ -433,8 +433,8 @@ class ShadowsocksService extends Service {
if (apps == null || apps.length <= 0) apps = AppManager.getProxiedApps(this) if (apps == null || apps.length <= 0) apps = AppManager.getProxiedApps(this)
val uidSet: mutable.HashSet[Int] = new mutable.HashSet[Int] val uidSet: mutable.HashSet[Int] = new mutable.HashSet[Int]
for (app <- apps) { for (app <- apps) {
if (app.isProxied) { if (app.proxied) {
uidSet.add(app.getUid) uidSet.add(app.uid)
} }
} }
for (uid <- uidSet) { for (uid <- uidSet) {
......
...@@ -40,7 +40,7 @@ package com.github.shadowsocks ...@@ -40,7 +40,7 @@ package com.github.shadowsocks
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.drawable.Drawable import android.graphics.drawable.{BitmapDrawable, Drawable}
import android.os.Environment import android.os.Environment
import android.util.Log import android.util.Log
import java.io._ import java.io._
...@@ -49,6 +49,7 @@ import org.apache.http.conn.util.InetAddressUtils ...@@ -49,6 +49,7 @@ import org.apache.http.conn.util.InetAddressUtils
import scala.collection.mutable.ArrayBuffer import scala.collection.mutable.ArrayBuffer
import org.xbill.DNS._ import org.xbill.DNS._
import scala.Some import scala.Some
import android.graphics.{Canvas, Bitmap}
object Utils { object Utils {
...@@ -245,12 +246,28 @@ 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 = { def getAppIcon(c: Context, uid: Int): Drawable = {
val pm: PackageManager = c.getPackageManager val pm: PackageManager = c.getPackageManager
var appIcon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon) var appIcon: Drawable = c.getResources.getDrawable(android.R.drawable.sym_def_app_icon)
val packages: Array[String] = pm.getPackagesForUid(uid) val packages: Array[String] = pm.getPackagesForUid(uid)
if (packages != null) { if (packages != null) {
if (packages.length == 1) { if (packages.length >= 1) {
try { try {
val appInfo: ApplicationInfo = pm.getApplicationInfo(packages(0), 0) val appInfo: ApplicationInfo = pm.getApplicationInfo(packages(0), 0)
appIcon = pm.getApplicationIcon(appInfo) appIcon = pm.getApplicationIcon(appInfo)
......
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