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 {
......
/* 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