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")
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(
......
......@@ -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 {
......
......@@ -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(_ < _)
import scala.collection.JavaConversions._
val packageManager: PackageManager = context.getPackageManager
val appList = packageManager.getInstalledApplications(0)
class ListEntry {
var box: CheckBox = null
var text: TextView = null
var icon: ImageView = null
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
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
val proxiedApps = proxiedAppString.split('|').sortWith(_ < _)
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
/* 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 {
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) {
......
......@@ -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)
......
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