From 51e155c940b2c35bb1d68910af3bc65d19d63183 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 01:58:36 +0800 Subject: [PATCH 01/10] Add more material design (3) --- build.sbt | 9 +- src/main/AndroidManifest.xml | 21 +- src/main/jni/shadowsocks-libev | 2 +- src/main/res/layout/layout_profiles.xml | 11 + src/main/res/layout/layout_profiles_item.xml | 34 ++ src/main/res/layout/menu_row_category.xml | 5 - src/main/res/layout/menu_row_item.xml | 5 - src/main/res/layout/toolbar_light_dark.xml | 1 - src/main/res/menu/add_profile_methods.xml | 20 + src/main/res/values-zh/strings.xml | 21 +- src/main/res/values/strings.xml | 27 +- src/main/res/values/styles.xml | 57 +- src/main/res/xml/pref_all.xml | 56 +- .../com/github/shadowsocks/AppManager.scala | 30 +- .../github/shadowsocks/ParserActivity.scala | 6 +- .../shadowsocks/ProfileManagerActivity.scala | 176 ++++++ .../com/github/shadowsocks/Shadowsocks.scala | 509 +++--------------- .../shadowsocks/ShadowsocksApplication.scala | 42 +- .../shadowsocks/ShadowsocksNatService.scala | 28 +- .../shadowsocks/ShadowsocksSettings.scala | 14 +- .../shadowsocks/ShadowsocksVpnService.scala | 23 +- .../shadowsocks/database/MenuAdapter.scala | 179 ------ .../ProfileEditTextPreference.scala | 78 --- .../shadowsocks/utils/ConfigUtils.scala | 10 +- .../github/shadowsocks/utils/Constants.scala | 2 - .../com/github/shadowsocks/utils/Utils.scala | 3 + 26 files changed, 473 insertions(+), 896 deletions(-) create mode 100644 src/main/res/layout/layout_profiles.xml create mode 100644 src/main/res/layout/layout_profiles_item.xml delete mode 100644 src/main/res/layout/menu_row_category.xml delete mode 100644 src/main/res/layout/menu_row_item.xml create mode 100644 src/main/res/menu/add_profile_methods.xml create mode 100644 src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala delete mode 100644 src/main/scala/com/github/shadowsocks/database/MenuAdapter.scala delete mode 100644 src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala diff --git a/build.sbt b/build.sbt index 3abae4dd..5327bbdc 100644 --- a/build.sbt +++ b/build.sbt @@ -29,13 +29,10 @@ libraryDependencies ++= Seq( "com.github.kevinsawicki" % "http-request" % "6.0", "commons-net" % "commons-net" % "3.3", "com.google.zxing" % "android-integration" % "3.2.1", - "com.joanzapata.android" % "android-iconify" % "1.0.11", "net.glxn.qrgen" % "android" % "2.0", - "net.simonvt.menudrawer" % "menudrawer" % "3.0.6", "com.google.android.gms" % "play-services-base" % "8.1.0", "com.google.android.gms" % "play-services-ads" % "8.1.0", "com.google.android.gms" % "play-services-analytics" % "8.1.0", - "com.android.support" % "support-v4" % "23.1.0", "com.android.support" % "design" % "23.1.0", "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01", "com.nostra13.universalimageloader" % "universal-image-loader" % "1.9.4", @@ -46,13 +43,9 @@ libraryDependencies ++= Seq( proguardOptions in Android ++= Seq("-keep class android.support.v4.app.** { *; }", "-keep interface android.support.v4.app.** { *; }", "-keep class android.support.v7.widget.Toolbar { (...); }", - "-keep class com.actionbarsherlock.** { *; }", - "-keep interface com.actionbarsherlock.** { *; }", "-keep class org.jraf.android.backport.** { *; }", "-keep class com.github.shadowsocks.** { *; }", "-keep class * extends com.j256.ormlite.** { *; }", - "-keep class com.joanzapata.** { *; }", "-keepattributes *Annotation*", "-dontwarn com.google.android.gms.internal.zzhu", - "-dontwarn org.xbill.**", - "-dontwarn com.actionbarsherlock.**") + "-dontwarn org.xbill.**") diff --git a/src/main/AndroidManifest.xml b/src/main/AndroidManifest.xml index 787cd862..e03bc12c 100644 --- a/src/main/AndroidManifest.xml +++ b/src/main/AndroidManifest.xml @@ -22,7 +22,8 @@ android:hardwareAccelerated="true" android:icon="@drawable/ic_launcher" android:backupAgent=".ShadowsocksBackupAgent" - android:label="@string/app_name"> + android:label="@string/app_name" + android:theme="@style/Theme.Material"> @@ -36,7 +37,6 @@ @@ -63,10 +63,21 @@ + android:parentActivityName=".Shadowsocks" + android:exported="false"> + + + + + + + diff --git a/src/main/jni/shadowsocks-libev b/src/main/jni/shadowsocks-libev index 095aa749..890e880d 160000 --- a/src/main/jni/shadowsocks-libev +++ b/src/main/jni/shadowsocks-libev @@ -1 +1 @@ -Subproject commit 095aa7490cb39d513180d1f756e6751107511f98 +Subproject commit 890e880dc61ad4f2e9a340a78c797c4aabee6429 diff --git a/src/main/res/layout/layout_profiles.xml b/src/main/res/layout/layout_profiles.xml new file mode 100644 index 00000000..a98f4674 --- /dev/null +++ b/src/main/res/layout/layout_profiles.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/src/main/res/layout/layout_profiles_item.xml b/src/main/res/layout/layout_profiles_item.xml new file mode 100644 index 00000000..1d15e2bf --- /dev/null +++ b/src/main/res/layout/layout_profiles_item.xml @@ -0,0 +1,34 @@ + + + + + + + diff --git a/src/main/res/layout/menu_row_category.xml b/src/main/res/layout/menu_row_category.xml deleted file mode 100644 index c89e5d96..00000000 --- a/src/main/res/layout/menu_row_category.xml +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/src/main/res/layout/menu_row_item.xml b/src/main/res/layout/menu_row_item.xml deleted file mode 100644 index af2c4b38..00000000 --- a/src/main/res/layout/menu_row_item.xml +++ /dev/null @@ -1,5 +0,0 @@ - - \ No newline at end of file diff --git a/src/main/res/layout/toolbar_light_dark.xml b/src/main/res/layout/toolbar_light_dark.xml index b3b7a02b..ae61afe4 100644 --- a/src/main/res/layout/toolbar_light_dark.xml +++ b/src/main/res/layout/toolbar_light_dark.xml @@ -7,6 +7,5 @@ android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" - app:titleTextAppearance="@style/Toolbar.TitleText" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" android:id="@+id/toolbar" /> diff --git a/src/main/res/menu/add_profile_methods.xml b/src/main/res/menu/add_profile_methods.xml new file mode 100644 index 00000000..3749a324 --- /dev/null +++ b/src/main/res/menu/add_profile_methods.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index 195090d5..03bba9c3 100755 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -3,9 +3,6 @@ 影梭 shadowsocks - 服务控制 - 代理开关 - 启动/关闭后台服务 服务器设置 配置文件 配置文件名称 @@ -39,26 +36,18 @@ 在通知栏上显示当前上下行速率 后台服务已开始运行。 已连接到「%s」 - 当前速率:%d KB/s - 后台服务启动失败。 - 后台服务已停止。 - 后台服务已停止。 无法连接远程服务器 停止服务 正在关闭... 后台服务启动失败:%s - 确定 关闭 本地端口号应大于1024 端口号不能为空 代理服务器地址不能为空 - 检测到意外退出,状态已被重置。 连接 正在初始化... 重置中... 正在加载... - 是 - 否 配置文件 设置选项 删除此配置文件「%s」? @@ -84,10 +73,8 @@ 为影梭添加此配置文件? - - 扫描二维码 - 手动设置 - + 扫描二维码 + 手动设置 全局 @@ -101,6 +88,8 @@ 导出失败 导入成功 导入失败 - 错误 + + 已删除 + 撤销 diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 0fa48668..49211bb4 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -4,15 +4,14 @@ Shadowsocks shadowsocks - - Service Controller - Proxy Switch - Enable / Disable Proxy + + Global Settings + Profile + Switch to another profile Server Settings - Profile - Profile name + Profile name Server Hostname or IP of the remote server Remote Port @@ -54,26 +53,18 @@ Shadowsocks started. Connected to "%s" - Current Rate: %d KB/s - Shadowsocks failed to start. - Shadowsocks stopped. - Shadowsocks stopped. Failed to connect the remote server Stop the service Shutting down... %s Turn on NAT mode. Turn off NAT mode. - ERROR - OK Close The local port number should be greater than 1024 Port should not be empty Proxy should not be empty - An unexpected exit detected, the context has been reset. - Connect Initializing… Resetting… @@ -101,9 +92,9 @@ Add this Shadowsocks Profile? - - Scan QR code - Manual Settings - + Scan QR code + Manual Settings + Removed + Undo diff --git a/src/main/res/values/styles.xml b/src/main/res/values/styles.xml index 7cc7ff33..efa07058 100644 --- a/src/main/res/values/styles.xml +++ b/src/main/res/values/styles.xml @@ -1,22 +1,8 @@ - - - - - - - - - - - diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml index c4df91c0..b81b41ab 100644 --- a/src/main/res/xml/pref_all.xml +++ b/src/main/res/xml/pref_all.xml @@ -2,50 +2,58 @@ + + + + + + + + + + + + - - + android:title="@string/profile_name"/> - + android:title="@string/proxy"/> - + android:title="@string/remote_port"/> - + android:title="@string/port"/> - + android:title="@string/sitekey"/> - + android:title="@string/enc_method"/> @@ -58,21 +66,18 @@ app:entries="@array/route_entry" app:entryValues="@array/route_value" app:summary="%s" - android:title="@string/route_list"> - + android:title="@string/route_list"/> - + android:title="@string/ipv6"/> - + android:title="@string/auto_set_proxy"/> - + android:title="@string/udp_dns"/> - - - + android:title="@string/onetime_auth"/> diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala index 88004783..5c20fd95 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -39,32 +39,26 @@ package com.github.shadowsocks -import android.app.{Activity, ProgressDialog} -import android.content.ClipboardManager -import android.content.ClipData -import android.content.Context -import android.content.SharedPreferences +import java.io.{ByteArrayInputStream, ByteArrayOutputStream, InputStream} + +import android.app.ProgressDialog +import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} import android.content.pm.PackageManager import android.graphics.{Bitmap, PixelFormat} -import android.os.Bundle -import android.os.Handler +import android.os.{Bundle, Handler} import android.preference.PreferenceManager +import android.support.v7.app.AppCompatActivity import android.support.v7.widget.Toolbar -import android.view.Menu -import android.view.MenuItem -import android.view.View import android.view.View.OnClickListener -import android.view.ViewGroup import android.view.ViewGroup.LayoutParams -import android.view.WindowManager -import android.widget._ +import android.view.{Menu, MenuItem, View, ViewGroup, WindowManager} import android.widget.AbsListView.OnScrollListener import android.widget.CompoundButton.OnCheckedChangeListener -import com.nostra13.universalimageloader.core.download.BaseImageDownloader -import java.io.{ByteArrayOutputStream, ByteArrayInputStream, InputStream} -import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration} +import android.widget._ +import com.github.shadowsocks.utils.{Key, Scheme, Utils} import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer -import com.github.shadowsocks.utils.{Utils, Scheme, Key} +import com.nostra13.universalimageloader.core.download.BaseImageDownloader +import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -105,7 +99,7 @@ object AppManager { } } -class AppManager extends Activity with OnCheckedChangeListener with OnClickListener { +class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnClickListener { val MSG_LOAD_START = 1 val MSG_LOAD_FINISH = 2 diff --git a/src/main/scala/com/github/shadowsocks/ParserActivity.scala b/src/main/scala/com/github/shadowsocks/ParserActivity.scala index 59911e27..ba102adc 100644 --- a/src/main/scala/com/github/shadowsocks/ParserActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ParserActivity.scala @@ -57,14 +57,14 @@ class ParserActivity extends Activity { new AlertDialog.Builder(this) .setTitle(R.string.add_profile_dialog) .setCancelable(false) - .setPositiveButton(R.string.yes, ((dialog: DialogInterface, id: Int) => { + .setPositiveButton(android.R.string.yes, ((dialog: DialogInterface, id: Int) => { Parser.parse(data) match { case Some(profile) => addProfile(profile) case _ => // ignore } dialog.dismiss() }): DialogInterface.OnClickListener) - .setNegativeButton(R.string.no, ((dialog: DialogInterface, id: Int) => { + .setNegativeButton(android.R.string.no, ((dialog: DialogInterface, id: Int) => { dialog.dismiss() finish() }): DialogInterface.OnClickListener) @@ -90,7 +90,7 @@ class ParserActivity extends Activity { h.postDelayed(() => { val profileManager = new ProfileManager(PreferenceManager.getDefaultSharedPreferences(getBaseContext), - getApplication.asInstanceOf[ShadowsocksApplication].dbHelper) + ShadowsocksApplication.dbHelper) profileManager.createOrUpdateProfile(profile) profileManager.reload(profile.id) h.sendEmptyMessage(0) diff --git a/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala new file mode 100644 index 00000000..1f2d9583 --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/ProfileManagerActivity.scala @@ -0,0 +1,176 @@ +package com.github.shadowsocks + +import android.app.AlertDialog +import android.content.{DialogInterface, Intent} +import android.os.Bundle +import android.support.design.widget.Snackbar +import android.support.v7.app.AppCompatActivity +import android.support.v7.widget.RecyclerView.ViewHolder +import android.support.v7.widget.Toolbar.OnMenuItemClickListener +import android.support.v7.widget.helper.ItemTouchHelper +import android.support.v7.widget.helper.ItemTouchHelper.SimpleCallback +import android.support.v7.widget.{DefaultItemAnimator, LinearLayoutManager, RecyclerView, Toolbar} +import android.view.View.{OnAttachStateChangeListener, OnClickListener} +import android.view.{LayoutInflater, MenuItem, View, ViewGroup} +import android.widget.{LinearLayout, ImageView, CheckedTextView, Toast} +import com.github.shadowsocks.database.Profile +import com.github.shadowsocks.utils.{Parser, Utils} +import com.google.zxing.integration.android.IntentIntegrator +import net.glxn.qrgen.android.QRCode + +import scala.collection.mutable.ArrayBuffer + +/** + * @author Mygod + */ +class ProfileManagerActivity extends AppCompatActivity with OnMenuItemClickListener { + private class ProfileViewHolder(val view: View) extends RecyclerView.ViewHolder(view) with View.OnClickListener { + private var item: Profile = _ + private val text = itemView.findViewById(android.R.id.text1).asInstanceOf[CheckedTextView] + itemView.setOnClickListener(this) + + { + val qrcode = itemView.findViewById(R.id.qrcode) + qrcode.setOnClickListener((v: View) => { + val image = new ImageView(ProfileManagerActivity.this) + image.setLayoutParams(new LinearLayout.LayoutParams(-1, -1)) + val qrcode = QRCode.from(Parser.generate(item)) + .withSize(Utils.dpToPx(ProfileManagerActivity.this, 250), Utils.dpToPx(ProfileManagerActivity.this, 250)) + .asInstanceOf[QRCode] + image.setImageBitmap(qrcode.bitmap()) + + new AlertDialog.Builder(ProfileManagerActivity.this) + .setCancelable(true) + .setNegativeButton(getString(R.string.close), + ((dialog: DialogInterface, id: Int) => dialog.cancel()): DialogInterface.OnClickListener) + .setView(image) + .create() + .show() + }) + qrcode.setOnLongClickListener((v: View) => { + Utils.positionToast(Toast.makeText(ProfileManagerActivity.this, R.string.qrcode, Toast.LENGTH_SHORT), qrcode, + getWindow, 0, Utils.dpToPx(ProfileManagerActivity.this, 8)).show + true + }) + } + + def bind(item: Profile) { + text.setText(item.name) + text.setChecked(item.id == ShadowsocksApplication.profileId) + this.item = item + } + + def onClick(v: View) = { + ShadowsocksApplication.profileId(item.id) + finish + } + } + + private class ProfilesAdapter extends RecyclerView.Adapter[ProfileViewHolder] { + private val recycleBin = new ArrayBuffer[(Int, Profile)] + private var profiles = new ArrayBuffer[Profile] + profiles ++= ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List[Profile]()) + + def getItemCount = profiles.length + + def onBindViewHolder(vh: ProfileViewHolder, i: Int) = vh.bind(profiles(i)) + + def onCreateViewHolder(vg: ViewGroup, i: Int) = + new ProfileViewHolder(LayoutInflater.from(vg.getContext).inflate(R.layout.layout_profiles_item, vg, false)) + + def add(item: Profile) { + removedSnackbar.dismiss + commitRemoves + val pos = getItemCount + if (ShadowsocksApplication.profileManager.createOrUpdateProfile(item)) { + profiles += item + notifyItemInserted(pos) + } + } + + def remove(pos: Int) { + recycleBin.append((pos, profiles(pos))) + profiles.remove(pos) + notifyItemRemoved(pos) + } + def undoRemoves { + for ((index, item) <- recycleBin.reverseIterator) { + profiles.insert(index, item) + notifyItemInserted(index) + } + recycleBin.clear + } + def commitRemoves { + for ((index, item) <- recycleBin) { + ShadowsocksApplication.profileManager.delProfile(item.id) + if (item.id == ShadowsocksApplication.profileId) ShadowsocksApplication.profileId(-1) + } + recycleBin.clear + } + } + + private lazy val profilesAdapter = new ProfilesAdapter + private var removedSnackbar: Snackbar = _ + + override def onCreate(savedInstanceState: Bundle) { + super.onCreate(savedInstanceState) + setContentView(R.layout.layout_profiles) + + val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] + toolbar.setTitle(R.string.profiles) + toolbar.setNavigationIcon(R.drawable.abc_ic_ab_back_mtrl_am_alpha) + toolbar.setNavigationOnClickListener((v: View) => { + val intent = getParentActivityIntent + if (intent == null) finish else navigateUpTo(intent) + }) + toolbar.inflateMenu(R.menu.add_profile_methods) + toolbar.setOnMenuItemClickListener(this) + + val profilesList = findViewById(R.id.profilesList).asInstanceOf[RecyclerView] + profilesList.setLayoutManager(new LinearLayoutManager(this)) + profilesList.setItemAnimator(new DefaultItemAnimator) + profilesList.setAdapter(profilesAdapter) + removedSnackbar = Snackbar.make(findViewById(android.R.id.content), R.string.removed, Snackbar.LENGTH_LONG) + .setAction(R.string.undo, ((v: View) => profilesAdapter.undoRemoves): OnClickListener) + removedSnackbar.getView.addOnAttachStateChangeListener(new OnAttachStateChangeListener { + def onViewDetachedFromWindow(v: View) = profilesAdapter.commitRemoves + def onViewAttachedToWindow(v: View) = () + }) + new ItemTouchHelper(new SimpleCallback(0, ItemTouchHelper.START | ItemTouchHelper.END) { + def onSwiped(viewHolder: ViewHolder, direction: Int) = { + profilesAdapter.remove(viewHolder.getAdapterPosition) + removedSnackbar.show + } + def onMove(recyclerView: RecyclerView, viewHolder: ViewHolder, target: ViewHolder) = false // TODO? + }).attachToRecyclerView(profilesList) + } + + override def onDestroy { + super.onDestroy + profilesAdapter.commitRemoves + } + + override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { + val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) + if (scanResult != null) Parser.parse(scanResult.getContents) match { + case Some(profile) => profilesAdapter.add(profile) + case _ => // ignore + } + } + + def onMenuItemClick(item: MenuItem) = item.getItemId match { + case R.id.scan_qr_code => + val integrator = new IntentIntegrator(this) + val list = new java.util.ArrayList(IntentIntegrator.TARGET_ALL_KNOWN) + list.add("tw.com.quickmark") + integrator.setTargetApplications(list) + integrator.initiateScan() + true + case R.id.manual_settings => + ShadowsocksApplication.profileManager.reload(-1) + ShadowsocksApplication.profileId(ShadowsocksApplication.profileManager.save.id) + finish + true + case _ => false + } +} diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index c1497c39..48cc5999 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -45,35 +45,28 @@ import java.util.Locale import android.app.backup.BackupManager import android.app.{Activity, AlertDialog, ProgressDialog} import android.content._ -import android.content.pm.{PackageInfo, PackageManager} import android.content.res.AssetManager import android.graphics.{Bitmap, Color, Typeface} import android.net.{Uri, VpnService} import android.os._ -import android.preference.{Preference, PreferenceManager, SwitchPreference} -import android.support.v4.content.ContextCompat +import android.preference.{Preference, SwitchPreference} import android.support.design.widget.{FloatingActionButton, Snackbar} +import android.support.v4.content.ContextCompat import android.support.v7.app.AppCompatActivity import android.support.v7.widget.Toolbar -import android.util.{DisplayMetrics, Log} +import android.util.Log import android.view.{View, ViewGroup, ViewParent} import android.webkit.{WebView, WebViewClient} import android.widget._ import com.github.jorgecastilloprz.FABProgressCircle import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback} import com.github.shadowsocks.database._ -import com.github.shadowsocks.preferences.{DropDownPreference, PasswordEditTextPreference, ProfileEditTextPreference, SummaryEditTextPreference} +import com.github.shadowsocks.preferences.{DropDownPreference, PasswordEditTextPreference, SummaryEditTextPreference} import com.github.shadowsocks.utils._ 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.joanzapata.android.iconify.IconDrawable -import com.joanzapata.android.iconify.Iconify.IconValue import com.nostra13.universalimageloader.core.download.BaseImageDownloader -import net.glxn.qrgen.android.QRCode -import net.simonvt.menudrawer.MenuDrawer -import scala.collection.mutable.{ArrayBuffer, ListBuffer} +import scala.collection.mutable.ArrayBuffer import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future @@ -86,7 +79,7 @@ class ProfileIconDownloader(context: Context, connectTimeout: Int, readTimeout: override def getStreamFromOtherSource(imageUri: String, extra: AnyRef): InputStream = { val text = imageUri.substring(Scheme.PROFILE.length) - val size = Utils.dpToPx(context, 16).toInt + val size = Utils.dpToPx(context, 16) val idx = text.getBytes.last % 6 val color = Seq(Color.MAGENTA, Color.GREEN, Color.YELLOW, Color.BLUE, Color.DKGRAY, Color.CYAN)( idx) @@ -126,12 +119,10 @@ object Shadowsocks { val REQUEST_CONNECT = 1 val PREFS_NAME = "Shadowsocks" - val PROXY_PREFS = Array(Key.profileName, Key.proxy, Key.remotePort, Key.localPort, Key.sitekey, - Key.encMethod) - val FEATRUE_PREFS = Array(Key.route, Key.isGlobalProxy, Key.proxyedApps, - Key.isUdpDns, Key.isAuth, Key.isIpv6, Key.isAutoConnect) - - val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL, Executable.TUN2SOCKS) + val PROXY_PREFS = Array(Key.proxy, Key.remotePort, Key.localPort, Key.sitekey, Key.encMethod) + val FEATURE_PREFS = Array(Key.route, Key.isGlobalProxy, Key.proxyedApps, Key.isUdpDns, Key.isAuth, Key.isIpv6) + val EXECUTABLES = Array(Executable.PDNSD, Executable.REDSOCKS, Executable.SS_TUNNEL, Executable.SS_LOCAL, + Executable.TUN2SOCKS) // Helper functions def updateDropDownPreference(pref: Preference, value: String) { @@ -148,18 +139,13 @@ object Shadowsocks { pref.asInstanceOf[SummaryEditTextPreference].setText(value) } - def updateProfileEditTextPreference(pref: Preference, value: String) { - pref.asInstanceOf[ProfileEditTextPreference].resetSummary(value) - pref.asInstanceOf[ProfileEditTextPreference].setText(value) - } - def updateSwitchPreference(pref: Preference, value: Boolean) { pref.asInstanceOf[SwitchPreference].setChecked(value) } def updatePreference(pref: Preference, name: String, profile: Profile) { name match { - case Key.profileName => updateProfileEditTextPreference(pref, profile.name) + case Key.profileName => updateSummaryEditTextPreference(pref, profile.name) case Key.proxy => updateSummaryEditTextPreference(pref, profile.host) case Key.remotePort => updateSummaryEditTextPreference(pref, profile.remotePort.toString) case Key.localPort => updateSummaryEditTextPreference(pref, profile.localPort.toString) @@ -176,14 +162,8 @@ object Shadowsocks { } class Shadowsocks - extends AppCompatActivity - with MenuAdapter.MenuListener { - - // Flags - val MSG_CRASH_RECOVER: Int = 1 - val STATE_MENUDRAWER = "com.github.shadowsocks.menuDrawer" - val STATE_ACTIVE_VIEW_ID = "com.github.shadowsocks.activeViewId" - var singlePane: Int = -1 + extends AppCompatActivity { + import Shadowsocks._ // Variables private var serviceStarted = false @@ -217,8 +197,8 @@ class Shadowsocks if (fab != null) fab.setEnabled(true) stateUpdate() - if (!status.getBoolean(getVersionName, false)) { - status.edit.putBoolean(getVersionName, true).apply() + if (!status.getBoolean(ShadowsocksApplication.getVersionName, false)) { + status.edit.putBoolean(ShadowsocksApplication.getVersionName, true).apply() recovery() } } @@ -236,33 +216,12 @@ class Shadowsocks private lazy val preferences = getFragmentManager.findFragmentById(android.R.id.content).asInstanceOf[ShadowsocksSettings] - lazy val settings = PreferenceManager.getDefaultSharedPreferences(this) - lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) - private lazy val preferenceReceiver = new PreferenceBroadcastReceiver - private lazy val drawer = MenuDrawer.attach(this) - private lazy val menuAdapter = new MenuAdapter(this, getMenuList) - private lazy val listView = new ListView(this) - private lazy val profileManager = - new ProfileManager(settings, getApplication.asInstanceOf[ShadowsocksApplication].dbHelper) - private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication] + private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) private lazy val greyTint = ContextCompat.getColorStateList(this, R.color.material_blue_grey_700) private lazy val greenTint = ContextCompat.getColorStateList(this, R.color.material_green_600) var handler = new Handler() - def isSinglePane: Boolean = { - if (singlePane == -1) { - val metrics = new DisplayMetrics() - getWindowManager.getDefaultDisplay.getMetrics(metrics) - val widthPixels = metrics.widthPixels - val scaleFactor = metrics.density - val widthDp = widthPixels / scaleFactor - - singlePane = if (widthDp <= 720) 1 else 0 - } - singlePane == 1 - } - private def changeSwitch(checked: Boolean) { serviceStarted = checked fab.setImageResource(if (checked) R.drawable.ic_cloud else R.drawable.ic_cloud_off) @@ -359,18 +318,6 @@ class Shadowsocks Console.runRootCommand(Utils.getIptables + " -t nat -F OUTPUT") } - private def getVersionName: String = { - var version: String = null - try { - val pi: PackageInfo = getPackageManager.getPackageInfo(getPackageName, 0) - version = pi.versionName - } catch { - case e: PackageManager.NameNotFoundException => - version = "Package name not found" - } - version - } - def isTextEmpty(s: String, msg: String): Boolean = { if (s != null && s.length > 0) return false Snackbar.make(getWindow.getDecorView.findViewById(android.R.id.content), msg, Snackbar.LENGTH_LONG).show @@ -413,74 +360,58 @@ class Shadowsocks } } - def initAdView() { - if (settings.getString(Key.proxy, "") == "198.199.101.152") { - val layoutView = { - if (Build.VERSION.SDK_INT > 10) { - drawer.getContentContainer.getChildAt(0) - } else { - getLayoutView(drawer.getContentContainer.getParent) - } - } - if (layoutView != null) { - val adView = new AdView(this) - adView.setAdUnitId("ca-app-pub-9097031975646651/7760346322") - adView.setAdSize(AdSize.SMART_BANNER) - layoutView.asInstanceOf[ViewGroup].addView(adView, 0) - adView.loadAd(new AdRequest.Builder().build()) - } - } - } - - override def setContentView(layoutResId: Int) { - drawer.setContentView(layoutResId) - initAdView() - onContentChanged() - } - override def onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) setContentView(R.layout.layout_main) + if (ShadowsocksApplication.proxy == "198.199.101.152") { + val adView = new AdView(this) + adView.setAdUnitId("ca-app-pub-9097031975646651/7760346322") + adView.setAdSize(AdSize.SMART_BANNER) + preferences.getView.asInstanceOf[ViewGroup].addView(adView, 0) // TODO: test + adView.loadAd(new AdRequest.Builder().build()) + } // Update the profile - if (!status.getBoolean(getVersionName, false)) { - currentProfile = profileManager.create() + if (!status.getBoolean(ShadowsocksApplication.getVersionName, false)) { + currentProfile = ShadowsocksApplication.profileManager.create() } // Initialize the profile currentProfile = { - profileManager.getProfile(settings.getInt(Key.profileId, -1)) getOrElse currentProfile - } - - // Initialize drawer - menuAdapter.setActiveId(settings.getInt(Key.profileId, -1)) - menuAdapter.setListener(this) - listView.setAdapter(menuAdapter) - drawer.setMenuView(listView) - - if (Utils.isLollipopOrAbove) { - drawer.setDrawerIndicatorEnabled(false) - } else { - // The drawable that replaces the up indicator in the action bar - drawer.setSlideDrawable(R.drawable.ic_drawer) - // Whether the previous drawable should be shown - drawer.setDrawerIndicatorEnabled(true) - } - - if (!isSinglePane) { - drawer.openMenu(false) + ShadowsocksApplication.currentProfile getOrElse currentProfile } // Initialize action bar val toolbar = findViewById(R.id.toolbar).asInstanceOf[Toolbar] - toolbar.setTitle(getTitle) + toolbar.setTitle(getString(R.string.screen_name)) + toolbar.setTitleTextAppearance(toolbar.getContext, R.style.Toolbar_Logo) val field = classOf[Toolbar].getDeclaredField("mTitleTextView") field.setAccessible(true) val title: TextView = field.get(toolbar).asInstanceOf[TextView] val tf: Typeface = Typefaces.get(this, "fonts/Iceland.ttf") if (tf != null) title.setTypeface(tf) + title.setOnClickListener((view: View) => { + ShadowsocksApplication.track(TAG, "about") + showAbout() + }) + title.setOnLongClickListener((v: View) => { + if (Utils.isLollipopOrAbove && bgService != null + && (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) { + val natEnabled = !status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove) + status.edit().putBoolean(Key.isNAT, natEnabled).apply() + deattachService() + attachService() + if (!Utils.isLollipopOrAbove) setPreferenceEnabled(State.isAvailable(bgService.getState)) + Toast.makeText(getBaseContext, if (natEnabled) R.string.enable_nat else R.string.disable_nat, Toast.LENGTH_LONG) + .show() + true + } else { + false + } + }) + fab = findViewById(R.id.fab).asInstanceOf[FloatingActionButton] fabProgressCircle = findViewById(R.id.fabProgressCircle).asInstanceOf[FABProgressCircle] fab.setOnClickListener((v: View) => { @@ -503,29 +434,9 @@ class Shadowsocks }) fab.setOnLongClickListener((v: View) => { Utils.positionToast(Toast.makeText(this, if (serviceStarted) R.string.stop else R.string.connect, - Toast.LENGTH_SHORT), fab, getWindow, 0, Utils.dpToPx(this, 8).toInt).show + Toast.LENGTH_SHORT), fab, getWindow, 0, Utils.dpToPx(this, 8)).show true }) - toolbar.setNavigationIcon(R.drawable.ic_drawer) - toolbar.setNavigationOnClickListener((v: View) => drawer.toggleMenu()) - title.setOnLongClickListener((v: View) => { - if (Utils.isLollipopOrAbove && bgService != null - && (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) { - val natEnabled = !status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove) - status.edit().putBoolean(Key.isNAT, natEnabled).apply() - deattachService() - attachService() - if (!Utils.isLollipopOrAbove) setPreferenceEnabled(State.isAvailable(bgService.getState)) - Toast.makeText(getBaseContext, if (natEnabled) R.string.enable_nat else R.string.disable_nat, Toast.LENGTH_LONG) - .show() - true - } else { - false - } - }) - - // Register broadcast receiver - registerReceiver(preferenceReceiver, new IntentFilter(Action.UPDATE_PREFS)) // Bind to the service handler.post(() => { @@ -555,222 +466,29 @@ class Shadowsocks } } - override def onRestoreInstanceState(inState: Bundle) { - super.onRestoreInstanceState(inState) - drawer.restoreState(inState.getParcelable(STATE_MENUDRAWER)) - } - - override def onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putParcelable(STATE_MENUDRAWER, drawer.saveState()) - outState.putInt(STATE_ACTIVE_VIEW_ID, currentProfile.id) - } - - override def onBackPressed() { - val drawerState = drawer.getDrawerState - if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING) { - drawer.closeMenu() - return - } - super.onBackPressed() - } - - override def onActiveViewChanged(v: View, pos: Int) { - drawer.setActiveView(v, pos) - } - - def newProfile(id: Int) { - - val builder = new AlertDialog.Builder(this) - builder - .setTitle(R.string.add_profile) - .setItems(R.array.add_profile_methods, ((dialog: DialogInterface, which: Int) => which match { - case 0 => - dialog.dismiss() - val h = showProgress(R.string.loading) - h.postDelayed(() => { - val integrator = new IntentIntegrator(Shadowsocks.this) - val list = new java.util.ArrayList(IntentIntegrator.TARGET_ALL_KNOWN) - list.add("tw.com.quickmark") - integrator.setTargetApplications(list) - integrator.initiateScan() - h.sendEmptyMessage(0) - }, 600) - case 1 => - dialog.dismiss() - addProfile(id) - case _ => - }): DialogInterface.OnClickListener) - builder.create().show() - } - def reloadProfile() { - drawer.closeMenu(true) + currentProfile = ShadowsocksApplication.currentProfile match { + case Some(profile) => profile // updated + case None => // removed + val profiles = ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List[Profile]()) + ShadowsocksApplication.profileId(if (profiles.isEmpty) -1 else profiles.head.id) + ShadowsocksApplication.currentProfile getOrElse currentProfile + } - val h = showProgress(R.string.loading) - - handler.postDelayed(() => { - currentProfile = { - profileManager.getProfile(settings.getInt(Key.profileId, -1)) getOrElse currentProfile - } - menuAdapter.updateList(getMenuList, currentProfile.id) - - updatePreferenceScreen() - - h.sendEmptyMessage(0) - }, 600) + updatePreferenceScreen() } def addProfile(profile: Profile) { - drawer.closeMenu(true) + currentProfile = profile + ShadowsocksApplication.profileManager.createOrUpdateProfile(currentProfile) + ShadowsocksApplication.profileManager.reload(currentProfile.id) - val h = showProgress(R.string.loading) - - handler.postDelayed(() => { - currentProfile = profile - profileManager.createOrUpdateProfile(currentProfile) - profileManager.reload(currentProfile.id) - menuAdapter.updateList(getMenuList, currentProfile.id) - - updatePreferenceScreen() - - h.sendEmptyMessage(0) - }, 600) - } - - def addProfile(id: Int) { - drawer.closeMenu(true) - - val h = showProgress(R.string.loading) - - handler.postDelayed(() => { - currentProfile = profileManager.reload(id) - profileManager.save() - menuAdapter.updateList(getMenuList, currentProfile.id) - - updatePreferenceScreen() - - h.sendEmptyMessage(0) - }, 600) - } - - def updateProfile(id: Int) { - drawer.closeMenu(true) - - val h = showProgress(R.string.loading) - - handler.postDelayed(() => { - currentProfile = profileManager.reload(id) - menuAdapter.setActiveId(id) - menuAdapter.notifyDataSetChanged() - - updatePreferenceScreen() - - h.sendEmptyMessage(0) - }, 600) - } - - def delProfile(id: Int): Boolean = { - drawer.closeMenu(true) - - val profile = profileManager.getProfile(id) - - if (profile.isEmpty) return false - - new AlertDialog.Builder(this) - .setMessage(String.format(Locale.ENGLISH, getString(R.string.remove_profile), profile.get.name)) - .setCancelable(false) - .setNegativeButton(R.string.no, - ((dialog: DialogInterface, i: Int) => dialog.cancel()): DialogInterface.OnClickListener) - .setPositiveButton(R.string.yes, ((dialog: DialogInterface, i: Int) => { - profileManager.delProfile(id) - val profileId = { - val profiles = profileManager.getAllProfiles.getOrElse(List[Profile]()) - if (profiles.isEmpty) -1 else profiles.head.id - } - currentProfile = profileManager.load(profileId) - menuAdapter.updateList(getMenuList, currentProfile.id) - - updatePreferenceScreen() - - dialog.dismiss() - }): DialogInterface.OnClickListener) - .create() - .show() - - true - } - - def getProfileList: List[Item] = { - val list = profileManager.getAllProfiles getOrElse List[Profile]() - list.map(p => new IconItem(p.id, p.name, -1, updateProfile, delProfile)) - } - - def getMenuList: List[Any] = { - - val buf = new ListBuffer[Any]() - - buf += new Category(getString(R.string.profiles)) - - buf ++= getProfileList - - buf += - new DrawableItem(-400, getString(R.string.add_profile), new IconDrawable(this, IconValue.fa_plus_circle) - .colorRes(android.R.color.darker_gray).sizeDp(26), newProfile) - - buf += new Category(getString(R.string.settings)) - - buf += new DrawableItem(-100, getString(R.string.recovery), new IconDrawable(this, IconValue.fa_recycle) - .colorRes(android.R.color.darker_gray).sizeDp(26), _ => { - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(Shadowsocks.TAG) - .setAction("reset") - .setLabel(getVersionName) - .build()) - recovery() - }) - - buf += - new DrawableItem(-200, getString(R.string.flush_dnscache), new IconDrawable(this, IconValue.fa_refresh) - .colorRes(android.R.color.darker_gray).sizeDp(26), _ => { - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(Shadowsocks.TAG) - .setAction("flush_dnscache") - .setLabel(getVersionName) - .build()) - flushDnsCache() - }) - - buf += - new DrawableItem(-300, getString(R.string.qrcode), new IconDrawable(this, IconValue.fa_qrcode) - .colorRes(android.R.color.darker_gray).sizeDp(26), _ => { - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(Shadowsocks.TAG) - .setAction("qrcode") - .setLabel(getVersionName) - .build()) - showQrCode() - }) - - buf += new DrawableItem(-400, getString(R.string.about), new IconDrawable(this, IconValue.fa_info_circle) - .colorRes(android.R.color.darker_gray).sizeDp(26), _ => { - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(Shadowsocks.TAG) - .setAction("about") - .setLabel(getVersionName) - .build()) - showAbout() - }) - - buf.toList + updatePreferenceScreen() } protected override def onPause() { super.onPause() + ShadowsocksApplication.profileManager.save prepared = false } @@ -778,19 +496,19 @@ class Shadowsocks if (bgService != null) { bgService.getState match { case State.CONNECTING => - fab.setBackgroundTintList(greyTint); + fab.setBackgroundTintList(greyTint) fabProgressCircle.show() changeSwitch(checked = true) case State.CONNECTED => - fab.setBackgroundTintList(greenTint); + fab.setBackgroundTintList(greenTint) fabProgressCircle.hide() changeSwitch(checked = true) case State.STOPPING => - fab.setBackgroundTintList(greyTint); + fab.setBackgroundTintList(greyTint) fabProgressCircle.show() changeSwitch(checked = false) case _ => - fab.setBackgroundTintList(greyTint); + fab.setBackgroundTintList(greyTint) fabProgressCircle.hide() changeSwitch(checked = false) } @@ -803,10 +521,8 @@ class Shadowsocks stateUpdate() ConfigUtils.refresh(this) - // Check if profile list changed - val id = settings.getInt(Key.profileId, -1) - if (id != -1 && id != currentProfile.id) - reloadProfile() + // Check if current profile changed + if (ShadowsocksApplication.profileId != currentProfile.id) reloadProfile() } private def setPreferenceEnabled(enabled: Boolean) { @@ -816,7 +532,7 @@ class Shadowsocks pref.setEnabled(enabled) } } - for (name <- Shadowsocks.FEATRUE_PREFS) { + for (name <- Shadowsocks.FEATURE_PREFS) { val pref = preferences.findPreference(name) if (pref != null) { if (Seq(Key.isGlobalProxy, Key.proxyedApps) @@ -831,11 +547,12 @@ class Shadowsocks private def updatePreferenceScreen() { val profile = currentProfile + Shadowsocks.updatePreference(preferences.findPreference(Key.profileName), Key.profileName, profile) for (name <- Shadowsocks.PROXY_PREFS) { val pref = preferences.findPreference(name) Shadowsocks.updatePreference(pref, name, profile) } - for (name <- Shadowsocks.FEATRUE_PREFS) { + for (name <- Shadowsocks.FEATURE_PREFS) { val pref = preferences.findPreference(name) Shadowsocks.updatePreference(pref, name, profile) } @@ -853,7 +570,6 @@ class Shadowsocks override def onDestroy() { super.onDestroy() deattachService() - unregisterReceiver(preferenceReceiver) new BackupManager(this).dataChanged() handler.removeCallbacksAndMessages(null) } @@ -881,13 +597,12 @@ class Shadowsocks } def reset() { - crashRecovery() install() } - private def recovery() { + def recovery() { serviceStop() val h = showProgress(R.string.recovering) Future { @@ -896,26 +611,7 @@ class Shadowsocks } } - private def dp2px(dp: Int): Int = - Math.round(dp * (getBaseContext.getResources.getDisplayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)) - - private def showQrCode() { - val image = new ImageView(this) - image.setLayoutParams(new LinearLayout.LayoutParams(-1, -1)) - val qrcode = QRCode.from(Parser.generate(currentProfile)) - .withSize(dp2px(250), dp2px(250)).asInstanceOf[QRCode] - image.setImageBitmap(qrcode.bitmap()) - - new AlertDialog.Builder(this) - .setCancelable(true) - .setNegativeButton(getString(R.string.close), - ((dialog: DialogInterface, id: Int) => dialog.cancel()): DialogInterface.OnClickListener) - .setView(image) - .create() - .show() - } - - private def flushDnsCache() { + def flushDnsCache() { val h = showProgress(R.string.flushing) Future { Utils.toggleAirplaneMode(getBaseContext) @@ -923,23 +619,13 @@ class Shadowsocks } } - override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { - val scanResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, data) - if (scanResult != null) { - Parser.parse(scanResult.getContents) match { - case Some(profile) => addProfile(profile) - case _ => // ignore - } - } else { - resultCode match { - case Activity.RESULT_OK => - prepared = true - serviceStart() - case _ => - cancelStart() - Log.e(Shadowsocks.TAG, "Failed to start VpnService") - } - } + override def onActivityResult(requestCode: Int, resultCode: Int, data: Intent) = resultCode match { + case Activity.RESULT_OK => + prepared = true + serviceStart() + case _ => + cancelStart() + Log.e(Shadowsocks.TAG, "Failed to start VpnService") } var isRoot: Option[Boolean] = None @@ -953,12 +639,12 @@ class Shadowsocks } def checkText(key: String): Boolean = { - val text = settings.getString(key, "") + val text = ShadowsocksApplication.settings.getString(key, "") !isTextEmpty(text, getString(R.string.proxy_empty)) } def checkNumber(key: String, low: Boolean): Boolean = { - val text = settings.getString(key, "") + val text = ShadowsocksApplication.settings.getString(key, "") if (isTextEmpty(text, getString(R.string.port_empty))) return false try { val port: Int = Integer.valueOf(text) @@ -978,7 +664,7 @@ class Shadowsocks /** Called when connect button is clicked. */ def serviceStart() { - bgService.start(ConfigUtils.load(settings)) + bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) if (isVpnEnabled) { changeSwitch(checked = false) @@ -986,7 +672,6 @@ class Shadowsocks } private def showAbout() { - val web = new WebView(this) web.loadUrl("file:///android_asset/pages/about.html") web.setWebViewClient(new WebViewClient() { @@ -996,18 +681,10 @@ class Shadowsocks } }) - var versionName = "" - try { - versionName = getPackageManager.getPackageInfo(getPackageName, 0).versionName - } catch { - case ex: PackageManager.NameNotFoundException => - versionName = "" - } - new AlertDialog.Builder(this) - .setTitle(getString(R.string.about_title).formatLocal(Locale.ENGLISH, versionName)) + .setTitle(getString(R.string.about_title).formatLocal(Locale.ENGLISH, ShadowsocksApplication.getVersionName)) .setCancelable(false) - .setNegativeButton(getString(R.string.ok_iknow), + .setNegativeButton(getString(android.R.string.ok), ((dialog: DialogInterface, id: Int) => dialog.cancel()): DialogInterface.OnClickListener) .setView(web) .create() @@ -1026,13 +703,13 @@ class Shadowsocks handler.post(() => if (state != s) { s match { case State.CONNECTING => - fab.setBackgroundTintList(greyTint); + fab.setBackgroundTintList(greyTint) fab.setImageResource(R.drawable.ic_cloud_queue) fab.setEnabled(false) fabProgressCircle.show() setPreferenceEnabled(enabled = false) case State.CONNECTED => - fab.setBackgroundTintList(greenTint); + fab.setBackgroundTintList(greenTint) if (state == State.CONNECTING) { fabProgressCircle.beginFinalAnimation() } else { @@ -1042,7 +719,7 @@ class Shadowsocks changeSwitch(checked = true) setPreferenceEnabled(enabled = false) case State.STOPPED => - fab.setBackgroundTintList(greyTint); + fab.setBackgroundTintList(greyTint) handler.postDelayed(() => fabProgressCircle.hide(), 1000) fab.setEnabled(true) changeSwitch(checked = false) @@ -1050,7 +727,7 @@ class Shadowsocks getString(R.string.vpn_error).formatLocal(Locale.ENGLISH, m), Snackbar.LENGTH_LONG).show setPreferenceEnabled(enabled = true) case State.STOPPING => - fab.setBackgroundTintList(greyTint); + fab.setBackgroundTintList(greyTint) fab.setImageResource(R.drawable.ic_cloud_queue) fab.setEnabled(false) fabProgressCircle.show() @@ -1059,12 +736,4 @@ class Shadowsocks state = s }) } - - class PreferenceBroadcastReceiver extends BroadcastReceiver { - override def onReceive(context: Context, intent: Intent) { - currentProfile = profileManager.save() - menuAdapter.updateList(getMenuList, currentProfile.id) - } - } - } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala index ebb22de3..5d85788b 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala @@ -43,19 +43,47 @@ import java.util import java.util.concurrent.TimeUnit import android.app.Application -import com.github.shadowsocks.database.DBHelper -import com.github.shadowsocks.utils.Utils -import com.google.android.gms.analytics.GoogleAnalytics +import android.content.pm.PackageManager +import android.preference.PreferenceManager +import com.github.shadowsocks.database.{DBHelper, ProfileManager} +import com.github.shadowsocks.utils.{Key, Utils} +import com.google.android.gms.analytics.{HitBuilders, GoogleAnalytics} import com.google.android.gms.common.api.ResultCallback import com.google.android.gms.tagmanager.{ContainerHolder, TagManager} +object ShadowsocksApplication { + var instance: ShadowsocksApplication = _ + lazy val dbHelper = new DBHelper(instance) + final val SIG_FUNC = "getSignature" + var containerHolder: ContainerHolder = _ + lazy val tracker = GoogleAnalytics.getInstance(instance).newTracker(R.xml.tracker) + lazy val settings = PreferenceManager.getDefaultSharedPreferences(instance) + lazy val profileManager = new ProfileManager(settings, dbHelper) + + def getVersionName = try { + instance.getPackageManager.getPackageInfo(instance.getPackageName, 0).versionName + } catch { + case _: PackageManager.NameNotFoundException => "Package name not found" + case _: Throwable => null + } + + // send event + def track(category: String, action: String) = tracker.send(new HitBuilders.EventBuilder() + .setAction(action) + .setLabel(getVersionName) + .build()) + + def profileId = settings.getInt(Key.profileId, -1) + def profileId(i: Int) = settings.edit.putInt(Key.profileId, i).apply + def proxy = settings.getString(Key.proxy, "") + def currentProfile = profileManager.getProfile(profileId) +} + class ShadowsocksApplication extends Application { - lazy val dbHelper = new DBHelper(this) - lazy val SIG_FUNC = "getSignature" - var containerHolder: ContainerHolder = null - lazy val tracker = GoogleAnalytics.getInstance(this).newTracker(R.xml.tracker) + import ShadowsocksApplication._ override def onCreate() { + ShadowsocksApplication.instance = this val tm = TagManager.getInstance(this) val pending = tm.loadContainerPreferNonDefault("GTM-NT8WS8", R.raw.gtm_default_container) val callback = new ResultCallback[ContainerHolder] { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index 6029337c..1ea60a5f 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -40,22 +40,20 @@ package com.github.shadowsocks import java.io.File -import java.lang.reflect.{InvocationTargetException, Method} import java.net.{Inet6Address, InetAddress} import java.util.Locale import android.app._ import android.content._ import android.content.pm.{PackageInfo, PackageManager} -import android.net.{Network, ConnectivityManager} +import android.net.{ConnectivityManager, Network} import android.os._ import android.support.v4.app.NotificationCompat import android.support.v4.content.ContextCompat -import android.util.{SparseArray, Log} +import android.util.{Log, SparseArray} import android.widget.Toast import com.github.shadowsocks.aidl.Config import com.github.shadowsocks.utils._ -import com.google.android.gms.analytics.HitBuilders import scala.collection._ import scala.collection.mutable.ArrayBuffer @@ -77,8 +75,6 @@ class ShadowsocksNatService extends Service with BaseService { var apps: Array[ProxiedApp] = null val myUid = Process.myUid() - private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication] - private val dnsAddressCache = new SparseArray[String] def getNetId(network: Network): Int = { @@ -254,8 +250,8 @@ class ShadowsocksNatService extends Service with BaseService { def startDnsDaemon() { val conf = if (config.route == Route.BYPASS_CHN) { - val reject = ConfigUtils.getRejectList(getContext, application) - val blackList = ConfigUtils.getBlackList(getContext, application) + val reject = ConfigUtils.getRejectList(getContext) + val blackList = ConfigUtils.getBlackList(getContext) ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "127.0.0.1", 8153, Path.BASE + "pdnsd-nat.pid", reject, blackList, 8163, "") } else { @@ -457,19 +453,14 @@ class ShadowsocksNatService extends Service with BaseService { registerReceiver(lockReceiver, screenFilter) } - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(TAG) - .setAction("start") - .setLabel(getVersionName) - .build()) + ShadowsocksApplication.track(TAG, "start") changeState(State.CONNECTING) Future { if (config.proxy == "198.199.101.152") { - val holder = application.containerHolder + val holder = ShadowsocksApplication.containerHolder try { config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config) } catch { @@ -531,12 +522,7 @@ class ShadowsocksNatService extends Service with BaseService { } } - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(TAG) - .setAction("stop") - .setLabel(getVersionName) - .build()) + ShadowsocksApplication.track(TAG, "stop") // reset NAT killProcesses() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index 30ce662e..db746897 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -1,12 +1,24 @@ package com.github.shadowsocks import android.os.Bundle -import android.preference.PreferenceFragment +import android.preference.{Preference, PreferenceFragment} // TODO: Move related logic here class ShadowsocksSettings extends PreferenceFragment { + private lazy val activity = getActivity.asInstanceOf[Shadowsocks] + override def onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) addPreferencesFromResource(R.xml.pref_all) + findPreference("recovery").setOnPreferenceClickListener((preference: Preference) => { + ShadowsocksApplication.track(Shadowsocks.TAG, "reset") + activity.recovery() + true + }) + findPreference("flush_dnscache").setOnPreferenceClickListener((preference: Preference) => { + ShadowsocksApplication.track(Shadowsocks.TAG, "flush_dnscache") + activity.flushDnsCache() + true + }) } } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 72e9449d..ba14253f 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -53,7 +53,6 @@ import android.util.Log import android.widget.Toast import com.github.shadowsocks.aidl.Config import com.github.shadowsocks.utils._ -import com.google.android.gms.analytics.HitBuilders import org.apache.commons.net.util.SubnetUtils import scala.collection.mutable @@ -62,8 +61,6 @@ import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future class ShadowsocksVpnService extends VpnService with BaseService { - - private lazy val application = getApplication.asInstanceOf[ShadowsocksApplication] val TAG = "ShadowsocksVpnService" val VPN_MTU = 1500 val PRIVATE_VLAN = "26.26.26.%s" @@ -152,12 +149,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { // channge the state changeState(State.STOPPING) - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(TAG) - .setAction("stop") - .setLabel(getVersionName) - .build()) + ShadowsocksApplication.track(TAG, "stop") // reset VPN killProcesses() @@ -231,18 +223,13 @@ class ShadowsocksVpnService extends VpnService with BaseService { return } - // send event - application.tracker.send(new HitBuilders.EventBuilder() - .setCategory(TAG) - .setAction("start") - .setLabel(getVersionName) - .build()) + ShadowsocksApplication.track(TAG, "start") changeState(State.CONNECTING) Future { if (config.proxy == "198.199.101.152") { - val holder = getApplication.asInstanceOf[ShadowsocksApplication].containerHolder + val holder = ShadowsocksApplication.containerHolder try { config = ConfigUtils.getPublicConfig(getBaseContext, holder.getContainer, config) } catch { @@ -371,8 +358,8 @@ class ShadowsocksVpnService extends VpnService with BaseService { val ipv6 = if (config.isIpv6) "" else "reject = ::/0;" val conf = { if (config.route == Route.BYPASS_CHN) { - val reject = ConfigUtils.getRejectList(getContext, application) - val blackList = ConfigUtils.getBlackList(getContext, application) + val reject = ConfigUtils.getRejectList(getContext) + val blackList = ConfigUtils.getBlackList(getContext) ConfigUtils.PDNSD_DIRECT.formatLocal(Locale.ENGLISH, "0.0.0.0", 8153, Path.BASE + "pdnsd-vpn.pid", reject, blackList, 8163, ipv6) } else { diff --git a/src/main/scala/com/github/shadowsocks/database/MenuAdapter.scala b/src/main/scala/com/github/shadowsocks/database/MenuAdapter.scala deleted file mode 100644 index e7d7463d..00000000 --- a/src/main/scala/com/github/shadowsocks/database/MenuAdapter.scala +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Shadowsocks - A shadowsocks client for Android - * Copyright (C) 2014 - * - * 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.database - -import android.content.Context -import android.graphics.drawable.Drawable -import android.view.{LayoutInflater, View, ViewGroup} -import android.widget.{BaseAdapter, TextView} -import com.github.shadowsocks.R - -abstract class Item { - def id: Int - def title: String - def click: Int => Unit - def longClick: Int => Boolean -} - -case class IconItem(id: Int, title: String, iconRes: Int, - click: Int => Unit, longClick: Int => Boolean = _ => false) - extends Item - -case class DrawableItem(id: Int, title: String, iconRes: Drawable, - click: Int => Unit, longClick: Int => Boolean = _ => false) - extends Item - -case class Category(title: String) - -object MenuAdapter { - - trait MenuListener { - def onActiveViewChanged(v: View, pos: Int) - } - - val UNDEFINED = -1 - val CATEGORY = 0 - val ITEM = 1 -} - -class MenuAdapter(context: Context, var items: List[Any]) extends BaseAdapter { - - def setListener(listener: MenuAdapter.MenuListener) { - this.listener = listener - } - - def setActiveId(activeId: Int) { - this.activeId = activeId - } - - @Override def getCount: Int = { - items.size - } - - @Override def getItem(position: Int): Object = { - items(position).asInstanceOf[Object] - } - - @Override def getItemId(position: Int): Long = { - position - } - - @Override override def getItemViewType(position: Int): Int = { - getItem(position) match { - case Category => MenuAdapter.CATEGORY - case IconItem => MenuAdapter.ITEM - case DrawableItem => MenuAdapter.ITEM - case _ => MenuAdapter.UNDEFINED - } - } - - @Override override def getViewTypeCount: Int = { - 3 - } - - @Override override def isEnabled(position: Int): Boolean = { - getItemViewType(position) != MenuAdapter.UNDEFINED - } - - @Override override def areAllItemsEnabled: Boolean = { - false - } - - @Override def getView(position: Int, convertView: View, parent: ViewGroup): View = { - var v: View = convertView - val item = getItem(position) - item match { - case value: Category => - if (v == null) { - v = LayoutInflater.from(context).inflate(R.layout.menu_row_category, parent, false) - } - v.asInstanceOf[TextView].setText(value.title) - case value: Item => - if (v == null) { - v = LayoutInflater.from(context).inflate(R.layout.menu_row_item, parent, false) - } - val tv: TextView = v.asInstanceOf[TextView] - tv.setText(value.title) - - value match { - case iconItem: IconItem => - if (iconItem.iconRes != -1) { - tv.setCompoundDrawablesWithIntrinsicBounds(iconItem.iconRes, 0, 0, 0) - } - case drawableItem: DrawableItem => - if (drawableItem.iconRes != null) { - tv.setCompoundDrawablesWithIntrinsicBounds(drawableItem.iconRes, null, null, null) - } - } - - tv.setOnClickListener((view: View) => { - val item = view.getTag(R.id.mdItem).asInstanceOf[Item] - item.click(item.id) - }) - tv.setOnLongClickListener((view: View) => { - val item = view.getTag(R.id.mdItem).asInstanceOf[Item] - item.longClick(item.id) - }) - - v.setTag(R.id.mdItem, value) - - if (value.id == activeId) { - if (listener != null) listener.onActiveViewChanged(v, position) - } - - case _ => - } - v.setTag(R.id.mdActiveViewPosition, position) - - - v - } - - def updateList(list: List[Any], activeId: Int) { - items = list - this.activeId = activeId - notifyDataSetChanged() - } - - private var listener: MenuAdapter.MenuListener = null - private var activeId: Int = -1 -} - - diff --git a/src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala b/src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala deleted file mode 100644 index 1ca8ecc3..00000000 --- a/src/main/scala/com/github/shadowsocks/preferences/ProfileEditTextPreference.scala +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Shadowsocks - A shadowsocks client for Android - * Copyright (C) 2013 - * - * 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.preferences - -import android.content.{Intent, Context} -import android.preference.EditTextPreference -import android.util.AttributeSet -import com.github.shadowsocks.utils.Action - -class ProfileEditTextPreference(context: Context, attrs: AttributeSet, defStyle: Int) - extends EditTextPreference(context, attrs, defStyle) { - - def this(context: Context, attrs: AttributeSet) = { - this(context, attrs, android.R.attr.editTextPreferenceStyle) - mDefaultSummary = getSummary - } - - override def setText(text: String) { - super.setText(text) - setSummary(text) - } - - override def setSummary(summary: CharSequence) { - if (summary.toString.isEmpty) { - super.setSummary(mDefaultSummary) - } else { - super.setSummary(summary) - } - context.sendBroadcast(new Intent(Action.UPDATE_PREFS)) - } - - def resetSummary(summary: CharSequence) { - if (summary.toString.isEmpty) { - super.setSummary(mDefaultSummary) - } else { - super.setSummary(summary) - } - } - - private var mDefaultSummary: CharSequence = getSummary -} diff --git a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala index 8f57476d..774c355b 100644 --- a/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/ConfigUtils.scala @@ -198,14 +198,14 @@ object ConfigUtils { } def refresh(context: Context) { - val holder = context.getApplicationContext.asInstanceOf[ShadowsocksApplication].containerHolder + val holder = ShadowsocksApplication.containerHolder if (holder != null) holder.refresh() } - def getRejectList(context: Context, app: ShadowsocksApplication): String = { + def getRejectList(context: Context): String = { val default = context.getString(R.string.reject) try { - val container = app.containerHolder.getContainer + val container = ShadowsocksApplication.containerHolder.getContainer val update = container.getString("reject") if (update == null || update.isEmpty) default else update } catch { @@ -213,10 +213,10 @@ object ConfigUtils { } } - def getBlackList(context: Context, app: ShadowsocksApplication): String = { + def getBlackList(context: Context): String = { val default = context.getString(R.string.black_list) try { - val container = app.containerHolder.getContainer + val container = ShadowsocksApplication.containerHolder.getContainer val update = container.getString("black_list") if (update == null || update.isEmpty) default else update } catch { diff --git a/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/src/main/scala/com/github/shadowsocks/utils/Constants.scala index 3d812e9b..e4a9de80 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Constants.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Constants.scala @@ -111,8 +111,6 @@ object State { object Action { val SERVICE = "com.github.shadowsocks.SERVICE" val CLOSE = "com.github.shadowsocks.CLOSE" - val UPDATE_FRAGMENT = "com.github.shadowsocks.ACTION_UPDATE_FRAGMENT" - val UPDATE_PREFS = "com.github.shadowsocks.ACTION_UPDATE_PREFS" } object Route { diff --git a/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/src/main/scala/com/github/shadowsocks/utils/Utils.scala index 85b14a47..e80012a4 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Utils.scala @@ -92,6 +92,9 @@ object Utils { new String(Base64.encode(mdg.digest, 0)) } + def dpToPx(context: Context, dp: Int): Int = + Math.round(dp * (context.getResources.getDisplayMetrics.xdpi / DisplayMetrics.DENSITY_DEFAULT)) + /* * round or floor depending on whether you are using offsets(floor) or * widths(round) From b505ff3705c998706e035addc7cab7ecca38841f Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 02:46:55 +0800 Subject: [PATCH 02/10] Move NAT/VPN switch to a more user-friendly place --- src/main/res/values-zh/strings.xml | 13 +++---- src/main/res/values/strings.xml | 7 ++-- src/main/res/xml/pref_all.xml | 4 +- .../com/github/shadowsocks/Shadowsocks.scala | 38 +++++-------------- .../shadowsocks/ShadowsocksApplication.scala | 7 +++- .../shadowsocks/ShadowsocksReceiver.scala | 21 ++-------- .../ShadowsocksRunnerActivity.scala | 25 ++++-------- .../ShadowsocksRunnerService.scala | 19 ++-------- .../shadowsocks/ShadowsocksSettings.scala | 7 ++++ .../preferences/NatSwitchPreference.scala | 27 +++++++++++++ .../github/shadowsocks/utils/Constants.scala | 1 - 11 files changed, 75 insertions(+), 94 deletions(-) create mode 100644 src/main/scala/com/github/shadowsocks/preferences/NatSwitchPreference.scala diff --git a/src/main/res/values-zh/strings.xml b/src/main/res/values-zh/strings.xml index 03bba9c3..54343ba6 100755 --- a/src/main/res/values-zh/strings.xml +++ b/src/main/res/values-zh/strings.xml @@ -38,16 +38,16 @@ 已连接到「%s」 无法连接远程服务器 停止服务 - 正在关闭... + 正在关闭…… 后台服务启动失败:%s 关闭 本地端口号应大于1024 端口号不能为空 代理服务器地址不能为空 连接 - 正在初始化... - 重置中... - 正在加载... + 正在初始化…… + 重置中…… + 正在加载…… 配置文件 设置选项 删除此配置文件「%s」? @@ -55,13 +55,10 @@ 关于 影梭(shadowsocks)%s 刷新 DNS 缓存 - 刷新中... + 刷新中…… 二维码 添加配置文件 - 启用 NAT 模式. - 禁用 NAT 模式. - UDP 转发 由远程服务器转发 UDP 协议的数据包 diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 49211bb4..73ccaec1 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -8,6 +8,9 @@ Global Settings Profile Switch to another profile + NAT mode + Use NAT/VPN mode. + NAT mode is disabled without root. Server Settings @@ -55,10 +58,8 @@ Connected to "%s" Failed to connect the remote server Stop the service - Shutting down... + Shutting down… %s - Turn on NAT mode. - Turn off NAT mode. Close diff --git a/src/main/res/xml/pref_all.xml b/src/main/res/xml/pref_all.xml index b81b41ab..29e54dd2 100644 --- a/src/main/res/xml/pref_all.xml +++ b/src/main/res/xml/pref_all.xml @@ -7,7 +7,9 @@ - + { - if (Utils.isLollipopOrAbove && bgService != null - && (bgService.getState == State.INIT || bgService.getState == State.STOPPED)) { - val natEnabled = !status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove) - status.edit().putBoolean(Key.isNAT, natEnabled).apply() - deattachService() - attachService() - if (!Utils.isLollipopOrAbove) setPreferenceEnabled(State.isAvailable(bgService.getState)) - Toast.makeText(getBaseContext, if (natEnabled) R.string.enable_nat else R.string.disable_nat, Toast.LENGTH_LONG) - .show() - true - } else { - false - } - }) fab = findViewById(R.id.fab).asInstanceOf[FloatingActionButton] fabProgressCircle = findViewById(R.id.fabProgressCircle).asInstanceOf[FABProgressCircle] @@ -446,7 +430,8 @@ class Shadowsocks def attachService() { if (bgService == null) { - val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService] + val s = if (ShadowsocksApplication.isVpnEnabled) classOf[ShadowsocksVpnService] + else classOf[ShadowsocksNatService] val intent = new Intent(this, s) intent.setAction(Action.SERVICE) bindService(intent, connection, Context.BIND_AUTO_CREATE) @@ -526,6 +511,7 @@ class Shadowsocks } private def setPreferenceEnabled(enabled: Boolean) { + preferences.findPreference(Key.isNAT).setEnabled(enabled) for (name <- Shadowsocks.PROXY_PREFS) { val pref = preferences.findPreference(name) if (pref != null) { @@ -537,7 +523,7 @@ class Shadowsocks if (pref != null) { if (Seq(Key.isGlobalProxy, Key.proxyedApps) .contains(name)) { - pref.setEnabled(enabled && (Utils.isLollipopOrAbove || !isVpnEnabled)) + pref.setEnabled(enabled && (Utils.isLollipopOrAbove || !ShadowsocksApplication.isVpnEnabled)) } else { pref.setEnabled(enabled) } @@ -628,12 +614,6 @@ class Shadowsocks Log.e(Shadowsocks.TAG, "Failed to start VpnService") } - var isRoot: Option[Boolean] = None - def isVpnEnabled: Boolean = { - if (isRoot.isEmpty) isRoot = Some(Console.isRoot) - !(isRoot.get && status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove)) - } - def serviceStop() { if (bgService != null) bgService.stop() } @@ -666,7 +646,7 @@ class Shadowsocks def serviceStart() { bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) - if (isVpnEnabled) { + if (ShadowsocksApplication.isVpnEnabled) { changeSwitch(checked = false) } } diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala index 5d85788b..d507b88f 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala @@ -46,8 +46,8 @@ import android.app.Application import android.content.pm.PackageManager import android.preference.PreferenceManager import com.github.shadowsocks.database.{DBHelper, ProfileManager} -import com.github.shadowsocks.utils.{Key, Utils} -import com.google.android.gms.analytics.{HitBuilders, GoogleAnalytics} +import com.github.shadowsocks.utils.{Console, Key, Utils} +import com.google.android.gms.analytics.{GoogleAnalytics, HitBuilders} import com.google.android.gms.common.api.ResultCallback import com.google.android.gms.tagmanager.{ContainerHolder, TagManager} @@ -60,6 +60,9 @@ object ShadowsocksApplication { lazy val settings = PreferenceManager.getDefaultSharedPreferences(instance) lazy val profileManager = new ProfileManager(settings, dbHelper) + val isRoot = Console.isRoot + def isVpnEnabled = !(isRoot && settings.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove)) + def getVersionName = try { instance.getPackageManager.getPackageInfo(instance.getPackageName, 0).versionName } catch { diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala index 6c2a3532..8d1643ca 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksReceiver.scala @@ -39,12 +39,7 @@ package com.github.shadowsocks -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.SharedPreferences -import android.content.pm.PackageManager -import android.preference.PreferenceManager +import android.content.{BroadcastReceiver, Context, Intent} import com.github.shadowsocks.utils._ class ShadowsocksReceiver extends BroadcastReceiver { @@ -52,18 +47,8 @@ class ShadowsocksReceiver extends BroadcastReceiver { val TAG = "Shadowsocks" def onReceive(context: Context, intent: Intent) { - val settings: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - val status = context.getSharedPreferences(Key.status, Context.MODE_PRIVATE) - - var versionName: String = null - try { - versionName = context.getPackageManager.getPackageInfo(context.getPackageName, 0).versionName - } catch { - case e: PackageManager.NameNotFoundException => - versionName = "NONE" - } - val isAutoConnect: Boolean = settings.getBoolean(Key.isAutoConnect, false) - val isInstalled: Boolean = status.getBoolean(versionName, false) + val isAutoConnect: Boolean = ShadowsocksApplication.settings.getBoolean(Key.isAutoConnect, false) + val isInstalled: Boolean = ShadowsocksApplication.settings.getBoolean(ShadowsocksApplication.getVersionName, false) if (isAutoConnect && isInstalled) { if (Utils.isLollipopOrAbove) { val intent = new Intent(context, classOf[ShadowsocksRunnerService]) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala index 7b2d3817..137912f7 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerActivity.scala @@ -40,19 +40,15 @@ package com.github.shadowsocks import android.app.{Activity, KeyguardManager} -import android.os._ -import android.net.VpnService import android.content._ +import android.net.VpnService +import android.os._ import android.util.Log -import android.preference.PreferenceManager -import com.github.shadowsocks.utils._ import com.github.shadowsocks.aidl.IShadowsocksService +import com.github.shadowsocks.utils._ class ShadowsocksRunnerActivity extends Activity { - private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this) - private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) - val handler = new Handler() val connection = new ServiceConnection { override def onServiceConnected(name: ComponentName, service: IBinder) { @@ -65,18 +61,12 @@ class ShadowsocksRunnerActivity extends Activity { } // Variables - var isRoot: Option[Boolean] = None var bgService: IShadowsocksService = _ var receiver:BroadcastReceiver = _ - def isVpnEnabled: Boolean = { - if (isRoot.isEmpty) isRoot = Some(Console.isRoot) - !(isRoot.get && status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove)) - } - def startBackgroundService() { - if (isVpnEnabled) { + if (ShadowsocksApplication.isVpnEnabled) { val intent = VpnService.prepare(ShadowsocksRunnerActivity.this) if (intent != null) { startActivityForResult(intent, Shadowsocks.REQUEST_CONNECT) @@ -84,14 +74,15 @@ class ShadowsocksRunnerActivity extends Activity { onActivityResult(Shadowsocks.REQUEST_CONNECT, Activity.RESULT_OK, null) } } else { - bgService.start(ConfigUtils.load(settings)) + bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) finish() } } def attachService() { if (bgService == null) { - val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService] + val s = if (ShadowsocksApplication.isVpnEnabled) classOf[ShadowsocksVpnService] + else classOf[ShadowsocksNatService] val intent = new Intent(this, s) intent.setAction(Action.SERVICE) bindService(intent, connection, Context.BIND_AUTO_CREATE) @@ -137,7 +128,7 @@ class ShadowsocksRunnerActivity extends Activity { resultCode match { case Activity.RESULT_OK => if (bgService != null) { - bgService.start(ConfigUtils.load(settings)) + bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) } case _ => Log.e(Shadowsocks.TAG, "Failed to start VpnService") diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala index e27168f2..8a271746 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksRunnerService.scala @@ -43,15 +43,10 @@ import android.app.Service import android.content._ import android.net.VpnService import android.os._ -import android.preference.PreferenceManager import com.github.shadowsocks.aidl.IShadowsocksService import com.github.shadowsocks.utils._ class ShadowsocksRunnerService extends Service { - - private lazy val settings = PreferenceManager.getDefaultSharedPreferences(this) - private lazy val status = getSharedPreferences(Key.status, Context.MODE_PRIVATE) - val handler = new Handler() val connection = new ServiceConnection { override def onServiceConnected(name: ComponentName, service: IBinder) { @@ -64,35 +59,29 @@ class ShadowsocksRunnerService extends Service { } // Variables - var isRoot: Option[Boolean] = None var bgService: IShadowsocksService = _ - def isVpnEnabled: Boolean = { - if (isRoot.isEmpty) isRoot = Some(Console.isRoot) - !(isRoot.get && status.getBoolean(Key.isNAT, !Utils.isLollipopOrAbove)) - } - override def onBind(intent: Intent): IBinder = { null } def startBackgroundService() { - if (isVpnEnabled) { + if (ShadowsocksApplication.isVpnEnabled) { val intent = VpnService.prepare(ShadowsocksRunnerService.this) if (intent == null) { if (bgService != null) { - bgService.start(ConfigUtils.load(settings)) + bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) } } } else { - bgService.start(ConfigUtils.load(settings)) + bgService.start(ConfigUtils.load(ShadowsocksApplication.settings)) } stopSelf() } def attachService() { if (bgService == null) { - val s = if (!isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService] + val s = if (!ShadowsocksApplication.isVpnEnabled) classOf[ShadowsocksNatService] else classOf[ShadowsocksVpnService] val intent = new Intent(this, s) intent.setAction(Action.SERVICE) bindService(intent, connection, Context.BIND_AUTO_CREATE) diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index db746897..2b170f54 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -2,6 +2,7 @@ package com.github.shadowsocks import android.os.Bundle import android.preference.{Preference, PreferenceFragment} +import com.github.shadowsocks.utils.Key // TODO: Move related logic here class ShadowsocksSettings extends PreferenceFragment { @@ -10,6 +11,12 @@ class ShadowsocksSettings extends PreferenceFragment { override def onCreate(savedInstanceState: Bundle) { super.onCreate(savedInstanceState) addPreferencesFromResource(R.xml.pref_all) + findPreference(Key.isNAT).setOnPreferenceChangeListener((preference: Preference, newValue: Any) => + if (ShadowsocksApplication.isRoot) activity.handler.post(() => { + activity.deattachService() + activity.attachService() + true + }) else false) findPreference("recovery").setOnPreferenceClickListener((preference: Preference) => { ShadowsocksApplication.track(Shadowsocks.TAG, "reset") activity.recovery() diff --git a/src/main/scala/com/github/shadowsocks/preferences/NatSwitchPreference.scala b/src/main/scala/com/github/shadowsocks/preferences/NatSwitchPreference.scala new file mode 100644 index 00000000..2bd38d27 --- /dev/null +++ b/src/main/scala/com/github/shadowsocks/preferences/NatSwitchPreference.scala @@ -0,0 +1,27 @@ +package com.github.shadowsocks.preferences + +import android.content.Context +import android.content.res.TypedArray +import android.preference.SwitchPreference +import android.util.AttributeSet +import com.github.shadowsocks.{R, ShadowsocksApplication} + +/** + * TODO: No animations? + * @author Mygod + */ +final class NatSwitchPreference(context: Context, attrs: AttributeSet) extends SwitchPreference(context, attrs) { + private var disabled = false + + override def isEnabled = super.isEnabled && !disabled + + override def onGetDefaultValue(a: TypedArray, index: Int) = { + val result = ShadowsocksApplication.isVpnEnabled + if (!ShadowsocksApplication.isRoot) { + disabled = true + setEnabled(false) + setSummary(R.string.nat_summary_no_root) + } + result.asInstanceOf[AnyRef] + } +} diff --git a/src/main/scala/com/github/shadowsocks/utils/Constants.scala b/src/main/scala/com/github/shadowsocks/utils/Constants.scala index e4a9de80..1b1f621e 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Constants.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Constants.scala @@ -66,7 +66,6 @@ object Key { val proxied = "Proxyed" val isNAT = "isNAT" - val status = "status" val proxyedApps = "proxyedApps" val route = "route" From 91fd69f250b73550a0121f70984eaa6c3254342f Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 02:50:22 +0800 Subject: [PATCH 03/10] Adjust FAB color brightness --- src/main/res/values/colors.xml | 2 +- src/main/scala/com/github/shadowsocks/Shadowsocks.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index 157d3c4a..95094338 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -12,7 +12,7 @@ #00000000 #FF555555 - #43A047 + #388E3C #90A4AE #607D8B #455A64 diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 06872c54..72e5bf3e 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -217,7 +217,7 @@ class Shadowsocks private lazy val preferences = getFragmentManager.findFragmentById(android.R.id.content).asInstanceOf[ShadowsocksSettings] private lazy val greyTint = ContextCompat.getColorStateList(this, R.color.material_blue_grey_700) - private lazy val greenTint = ContextCompat.getColorStateList(this, R.color.material_green_600) + private lazy val greenTint = ContextCompat.getColorStateList(this, R.color.material_green_700) var handler = new Handler() From b0c0058cb0c128224729f52997baf106eebe6f38 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 03:03:28 +0800 Subject: [PATCH 04/10] Replace placeholder icons --- .../res/drawable-anydpi-v21/ic_content_add.xml | 9 +++++++++ .../res/drawable-anydpi-v21/ic_social_share.xml | 9 +++++++++ src/main/res/drawable-hdpi/ic_content_add.png | Bin 0 -> 127 bytes src/main/res/drawable-hdpi/ic_social_share.png | Bin 0 -> 398 bytes src/main/res/drawable-mdpi/ic_content_add.png | Bin 0 -> 88 bytes src/main/res/drawable-mdpi/ic_social_share.png | Bin 0 -> 262 bytes src/main/res/drawable-xhdpi/ic_content_add.png | Bin 0 -> 97 bytes src/main/res/drawable-xhdpi/ic_social_share.png | Bin 0 -> 483 bytes src/main/res/drawable-xxhdpi/ic_content_add.png | Bin 0 -> 97 bytes src/main/res/drawable-xxhdpi/ic_social_share.png | Bin 0 -> 675 bytes src/main/res/drawable-xxxhdpi/ic_content_add.png | Bin 0 -> 102 bytes src/main/res/drawable-xxxhdpi/ic_social_share.png | Bin 0 -> 888 bytes src/main/res/layout/layout_profiles_item.xml | 3 +-- src/main/res/menu/add_profile_methods.xml | 6 +++--- 14 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 src/main/res/drawable-anydpi-v21/ic_content_add.xml create mode 100644 src/main/res/drawable-anydpi-v21/ic_social_share.xml create mode 100644 src/main/res/drawable-hdpi/ic_content_add.png create mode 100644 src/main/res/drawable-hdpi/ic_social_share.png create mode 100644 src/main/res/drawable-mdpi/ic_content_add.png create mode 100644 src/main/res/drawable-mdpi/ic_social_share.png create mode 100644 src/main/res/drawable-xhdpi/ic_content_add.png create mode 100644 src/main/res/drawable-xhdpi/ic_social_share.png create mode 100644 src/main/res/drawable-xxhdpi/ic_content_add.png create mode 100644 src/main/res/drawable-xxhdpi/ic_social_share.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_content_add.png create mode 100644 src/main/res/drawable-xxxhdpi/ic_social_share.png diff --git a/src/main/res/drawable-anydpi-v21/ic_content_add.xml b/src/main/res/drawable-anydpi-v21/ic_content_add.xml new file mode 100644 index 00000000..b9b8eca8 --- /dev/null +++ b/src/main/res/drawable-anydpi-v21/ic_content_add.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/main/res/drawable-anydpi-v21/ic_social_share.xml b/src/main/res/drawable-anydpi-v21/ic_social_share.xml new file mode 100644 index 00000000..e3fe874d --- /dev/null +++ b/src/main/res/drawable-anydpi-v21/ic_social_share.xml @@ -0,0 +1,9 @@ + + + diff --git a/src/main/res/drawable-hdpi/ic_content_add.png b/src/main/res/drawable-hdpi/ic_content_add.png new file mode 100644 index 0000000000000000000000000000000000000000..694179bd46b685e55da1b4dde2575bde0b2bfd64 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;o2QFoh{y5d1PRu~4CX)Hf7s8+ zA**4&;-NiZFkHm}@zHRp0w0bW3B~m|KP-%}=Y-wz_ zDsv+1vMM)4)(sUp?ux8SiZxz|tk1fN9Pr475L!RBytVTR>~P(h5H{SmS7YR>FP5B8 z;GETT{!7OcX!H%zSx1c0$Op4J{#e&gq=xRKr}5owI~5rUd5=vh)QGG%POH!tS$$Oo zBI}AOCq>qZGpdY)yr-rV>sk`2C+4jSVcoo4iZ!mf<~W%0EX{s2rvvrQdYi_U(|on< z2HJFKAKGuyqIXs-I;_|}57K93O)FAkJr#PEMb@eb6*_K-teL;{7nxP%l*pP^Wt;ce sC7MvFXDm{m9HrhN_q^V0!9o9q-!{wmnqcRJ!2kdN07*qoM6N<$f+kh3$p8QV literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_content_add.png b/src/main/res/drawable-mdpi/ic_content_add.png new file mode 100644 index 0000000000000000000000000000000000000000..3856041d702e80237afa394e0900d507f67e0a8f GIT binary patch literal 88 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1c~2L|5R22v2@_&aj!VDzSo@fq7N>%r!;1bAd`3JYD@<);T3K0RTZ}7R&$u literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-mdpi/ic_social_share.png b/src/main/res/drawable-mdpi/ic_social_share.png new file mode 100644 index 0000000000000000000000000000000000000000..f02d360aa290e52f16769babe8a7b73fc8133d37 GIT binary patch literal 262 zcmV+h0r~!kP)z!E9V%weI_yd=Fl&Tqx@ zU4J%T|887QWvJ8?(v!Z|6;kD3AYj^i4*F^|tb3C3I)1h6LNc`Bz(8Nem>Ns1e8+Vqcw#ZP2I2i_O(=!b4$Wz9T^!pHYaS+ zndHTmJ$G*HYN%0I^&sW#2$=MogKHr-Ik*(k&cUXT!nUi=wG{ry2jCQLp-zXh2LJ#7 M07*qoM6N<$fU7)bX8PvpMCyj1<@L zk_wJ!3Plg>lVDHjd_C9D?zol5B&k{u#QWlcjS^iJqOG}YYxl0>XNS9cyuR_zENF`V zL^YY57oxS@wViYo^MZIwM)XOxQ>%0x?{xgp-Z&vypCOZ$d^P#|I@U}HMUNbiU60c~ z6f0KT&@a1w*R2#wK02dEcKbaPil)^-UBkSVhPrf)d;Q1fdtc~iLRGR}!xn{j#$~b1 zn6?mYP$o6+gh*quX$g^LyS-pWHVq-tsBG#&qyZUC2&L}Hs%pG6z9PFpV`j}5HQ+C_ Z?icFHxy#pVb)^6R002ovPDHLkV1k48;SK-* literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_content_add.png b/src/main/res/drawable-xxhdpi/ic_content_add.png new file mode 100644 index 0000000000000000000000000000000000000000..0fdced8fce76a0f9a527388935adecebf63d0dae GIT binary patch literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^9w5vJBp7O^^}Pa8OeH~n!3+##lh0ZJc~YJ(jv*C{ s$r5`OFVdQ&MBb@07vc`*Z=?k literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxhdpi/ic_social_share.png b/src/main/res/drawable-xxhdpi/ic_social_share.png new file mode 100644 index 0000000000000000000000000000000000000000..784933ad55a011a9b829767844969f36ecd98b80 GIT binary patch literal 675 zcmV;U0$lxxP)UZPF>#3%k9#08-1VeKX7y3y)WkyiA4SZF@~9C4WBJmnPCX0 z4zY{`TA~+6`Y9urmFRP`J7pxKlKw8mSVjmhhq7VB(jcm45lbGb)(}etRQZUd3aYBj zwxF+wr95hqT&Ij!%AjPVwmX&vP;ii!NL{_7;o5nKkJMF>12j~Oi~K+Wz2{fRa*okZ zNBMvR`p!9G?B}idu^PKOT|8ym_`}>|Cp80j6!58#C&K^@)XEJ?NTBEJ!->-rkU%S( zz=aK6bWB+xg`IvdW7 zD%@pS~Mow4tCcWJy2G*_n05h-vIn4hi&{y~G$}-F#he1O2C?)6Rf~wFc~mVRmgbu6lTD*4jaWL5s!q#2`%N3lZX@Aw6Lm>) zNJwvp<3K0bkmYpXNPT$m`Z~Df*BafCZDwc^5i{T978G? xlN*`>5BzUTIj7P7-(I3-fns}2dtZ?oBSS_(`pg9u0+k>GJYD@<);T3K0RZru9Krwq literal 0 HcmV?d00001 diff --git a/src/main/res/drawable-xxxhdpi/ic_social_share.png b/src/main/res/drawable-xxxhdpi/ic_social_share.png new file mode 100644 index 0000000000000000000000000000000000000000..5a8544ce5d6c8bf471c8fbd54cf4f88254ea9ccb GIT binary patch literal 888 zcmV-;1Bd*HP)9LMqRypZ5w`JO>))98$f6)oE2rdCPO(4t&OEy|HVqeUTEVJbno>6L`orcEYB zO@<!#gj`DvJ3WY+U zOXmgB9rTlB8$sA6%WE_c81+o!A$fUBQ49J#&EJTj15zm0gJ7>4#oCY}dJ?5-IY5eN zpBhw}M2c)2g=+DTB0D3FI(>*kub|EX;?NxGY$6V=qfQQS=oocQ5r>XYXB~0qXVl3e z4tVzmNT;dsiN1Pi)h5PviagRT!#CK8B$bZVC8K2!qANxqb ze#NtY#_=pZYi128*dhH~rkNeY&<>B`tGoCTF*HdH08qt9fnCb+E*1Ewj3MJ(e#-+~ zR7EGBvc?{}{Kz!VQ|a$qwzFkC7SC}5s@=!e##izkZb7x%_y94q$UP_!vCL%;d&aNH zC-7Aruae<6&hXeGLoabIdX!b`T>2=%Bwm5@oF)bU+{qV~xs2nhR?GF%E-l>5TjY#$ z*@VwtMyz>kYo5!e5PQ1kGR{6?PWxQK$A~#ab7_#^3~}m^0WPCPFJegBTpG+H4$TMs z?(%xj?=Ew}e*kqhf_{YNg8mYBBTjun9ja7wia2$|>y)C%hlq0X|_d z%}}r7A-edCpE%%<>&)^3Q7%gIgYj>?Z%_*QmGGkRxNVXm0{T@jVtnnFXe1CCSu$?c zC>7{OgcO^`%dnRyK|kxfF7pWa614L+0CA`db%qd! z22p1macB&6(m{WK;h-O(4#c4p>Li?IGzvlf-`xdNN+Lzpgi=#T5q*SO<*Xp~_>M9Z zt7h5$>vKEGU1h>@c*+QbhsfaN4d(()1WJrH1{phVkQ7lup-?CkD#AaVcIHkIiEiWo O0000 - diff --git a/src/main/res/menu/add_profile_methods.xml b/src/main/res/menu/add_profile_methods.xml index 3749a324..6d080c8f 100644 --- a/src/main/res/menu/add_profile_methods.xml +++ b/src/main/res/menu/add_profile_methods.xml @@ -1,8 +1,8 @@ - - + From fc7c423695364a26c7e6dc00ff94eced9f085b12 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 03:13:31 +0800 Subject: [PATCH 05/10] Remove redundant resources --- .../ab_bottom_solid_shadow.9.png | Bin 193 -> 0 bytes .../res/drawable-hdpi/ab_solid_shadow.9.png | Bin 198 -> 0 bytes .../ab_stacked_solid_shadow.9.png | Bin 199 -> 0 bytes .../drawable-hdpi/ab_texture_tile_shadow.png | Bin 129 -> 0 bytes .../drawable-hdpi/ab_transparent_shadow.9.png | Bin 205 -> 0 bytes .../btn_cab_done_default_shadow.9.png | Bin 111 -> 0 bytes .../btn_cab_done_focused_shadow.9.png | Bin 118 -> 0 bytes .../btn_cab_done_pressed_shadow.9.png | Bin 125 -> 0 bytes .../cab_background_bottom_shadow.9.png | Bin 206 -> 0 bytes .../cab_background_top_shadow.9.png | Bin 206 -> 0 bytes src/main/res/drawable-hdpi/ic_drawer.png | Bin 2864 -> 0 bytes .../drawable-hdpi/list_focused_shadow.9.png | Bin 145 -> 0 bytes .../drawable-hdpi/list_pressed_shadow.9.png | Bin 113 -> 0 bytes .../md__category_background.9.png | Bin 173 -> 0 bytes src/main/res/drawable-hdpi/menu_arrow.png | Bin 1578 -> 0 bytes .../menu_dropdown_panel_shadow.9.png | Bin 1233 -> 0 bytes .../drawable-hdpi/progress_bg_shadow.9.png | Bin 133 -> 0 bytes .../progress_primary_shadow.9.png | Bin 800 -> 0 bytes .../progress_secondary_shadow.9.png | Bin 139 -> 0 bytes .../spinner_ab_default_shadow.9.png | Bin 376 -> 0 bytes .../spinner_ab_disabled_shadow.9.png | Bin 358 -> 0 bytes .../spinner_ab_focused_shadow.9.png | Bin 568 -> 0 bytes .../spinner_ab_pressed_shadow.9.png | Bin 461 -> 0 bytes .../tab_selected_focused_shadow.9.png | Bin 107 -> 0 bytes .../tab_selected_pressed_shadow.9.png | Bin 107 -> 0 bytes .../drawable-hdpi/tab_selected_shadow.9.png | Bin 101 -> 0 bytes .../tab_unselected_focused_shadow.9.png | Bin 100 -> 0 bytes .../tab_unselected_pressed_shadow.9.png | Bin 100 -> 0 bytes .../drawable-hdpi/tab_unselected_shadow.9.png | Bin 103 -> 0 bytes .../ab_bottom_solid_shadow.9.png | Bin 156 -> 0 bytes .../res/drawable-mdpi/ab_solid_shadow.9.png | Bin 166 -> 0 bytes .../ab_stacked_solid_shadow.9.png | Bin 166 -> 0 bytes .../drawable-mdpi/ab_texture_tile_shadow.png | Bin 105 -> 0 bytes .../drawable-mdpi/ab_transparent_shadow.9.png | Bin 164 -> 0 bytes .../btn_cab_done_default_shadow.9.png | Bin 106 -> 0 bytes .../btn_cab_done_focused_shadow.9.png | Bin 114 -> 0 bytes .../btn_cab_done_pressed_shadow.9.png | Bin 134 -> 0 bytes .../cab_background_bottom_shadow.9.png | Bin 157 -> 0 bytes .../cab_background_top_shadow.9.png | Bin 155 -> 0 bytes src/main/res/drawable-mdpi/ic_drawer.png | Bin 2853 -> 0 bytes .../drawable-mdpi/list_focused_shadow.9.png | Bin 120 -> 0 bytes .../drawable-mdpi/list_pressed_shadow.9.png | Bin 110 -> 0 bytes .../md__category_background.9.png | Bin 165 -> 0 bytes src/main/res/drawable-mdpi/menu_arrow.png | Bin 869 -> 0 bytes .../menu_dropdown_panel_shadow.9.png | Bin 822 -> 0 bytes .../drawable-mdpi/progress_bg_shadow.9.png | Bin 126 -> 0 bytes .../progress_primary_shadow.9.png | Bin 501 -> 0 bytes .../progress_secondary_shadow.9.png | Bin 126 -> 0 bytes .../spinner_ab_default_shadow.9.png | Bin 314 -> 0 bytes .../spinner_ab_disabled_shadow.9.png | Bin 308 -> 0 bytes .../spinner_ab_focused_shadow.9.png | Bin 407 -> 0 bytes .../spinner_ab_pressed_shadow.9.png | Bin 351 -> 0 bytes .../tab_selected_focused_shadow.9.png | Bin 104 -> 0 bytes .../tab_selected_pressed_shadow.9.png | Bin 104 -> 0 bytes .../drawable-mdpi/tab_selected_shadow.9.png | Bin 97 -> 0 bytes .../tab_unselected_focused_shadow.9.png | Bin 98 -> 0 bytes .../tab_unselected_pressed_shadow.9.png | Bin 97 -> 0 bytes .../drawable-mdpi/tab_unselected_shadow.9.png | Bin 107 -> 0 bytes .../ab_bottom_solid_shadow.9.png | Bin 251 -> 0 bytes .../res/drawable-xhdpi/ab_solid_shadow.9.png | Bin 259 -> 0 bytes .../ab_stacked_solid_shadow.9.png | Bin 256 -> 0 bytes .../drawable-xhdpi/ab_texture_tile_shadow.png | Bin 123 -> 0 bytes .../ab_transparent_shadow.9.png | Bin 269 -> 0 bytes .../btn_cab_done_default_shadow.9.png | Bin 122 -> 0 bytes .../btn_cab_done_focused_shadow.9.png | Bin 125 -> 0 bytes .../btn_cab_done_pressed_shadow.9.png | Bin 129 -> 0 bytes .../cab_background_bottom_shadow.9.png | Bin 266 -> 0 bytes .../cab_background_top_shadow.9.png | Bin 267 -> 0 bytes src/main/res/drawable-xhdpi/ic_drawer.png | Bin 2908 -> 0 bytes .../drawable-xhdpi/list_focused_shadow.9.png | Bin 149 -> 0 bytes .../drawable-xhdpi/list_pressed_shadow.9.png | Bin 114 -> 0 bytes .../md__category_background.9.png | Bin 179 -> 0 bytes src/main/res/drawable-xhdpi/menu_arrow.png | Bin 1723 -> 0 bytes .../menu_dropdown_panel_shadow.9.png | Bin 1865 -> 0 bytes .../drawable-xhdpi/progress_bg_shadow.9.png | Bin 134 -> 0 bytes .../progress_primary_shadow.9.png | Bin 1076 -> 0 bytes .../progress_secondary_shadow.9.png | Bin 134 -> 0 bytes .../spinner_ab_default_shadow.9.png | Bin 476 -> 0 bytes .../spinner_ab_disabled_shadow.9.png | Bin 457 -> 0 bytes .../spinner_ab_focused_shadow.9.png | Bin 725 -> 0 bytes .../spinner_ab_pressed_shadow.9.png | Bin 603 -> 0 bytes .../tab_selected_focused_shadow.9.png | Bin 111 -> 0 bytes .../tab_selected_pressed_shadow.9.png | Bin 111 -> 0 bytes .../drawable-xhdpi/tab_selected_shadow.9.png | Bin 105 -> 0 bytes .../tab_unselected_focused_shadow.9.png | Bin 101 -> 0 bytes .../tab_unselected_pressed_shadow.9.png | Bin 101 -> 0 bytes .../tab_unselected_shadow.9.png | Bin 116 -> 0 bytes .../ab_bottom_solid_shadow.9.png | Bin 357 -> 0 bytes .../res/drawable-xxhdpi/ab_solid_shadow.9.png | Bin 351 -> 0 bytes .../ab_stacked_solid_shadow.9.png | Bin 350 -> 0 bytes .../ab_texture_tile_shadow.png | Bin 255 -> 0 bytes .../ab_transparent_shadow.9.png | Bin 352 -> 0 bytes .../btn_cab_done_default_shadow.9.png | Bin 140 -> 0 bytes .../btn_cab_done_focused_shadow.9.png | Bin 131 -> 0 bytes .../btn_cab_done_pressed_shadow.9.png | Bin 148 -> 0 bytes .../cab_background_bottom_shadow.9.png | Bin 372 -> 0 bytes .../cab_background_top_shadow.9.png | Bin 360 -> 0 bytes src/main/res/drawable-xxhdpi/ic_drawer.png | Bin 2955 -> 0 bytes .../drawable-xxhdpi/list_focused_shadow.9.png | Bin 163 -> 0 bytes .../drawable-xxhdpi/list_pressed_shadow.9.png | Bin 137 -> 0 bytes .../menu_dropdown_panel_shadow.9.png | Bin 3948 -> 0 bytes .../drawable-xxhdpi/progress_bg_shadow.9.png | Bin 156 -> 0 bytes .../progress_primary_shadow.9.png | Bin 1674 -> 0 bytes .../progress_secondary_shadow.9.png | Bin 157 -> 0 bytes .../spinner_ab_default_shadow.9.png | Bin 480 -> 0 bytes .../spinner_ab_disabled_shadow.9.png | Bin 481 -> 0 bytes .../spinner_ab_focused_shadow.9.png | Bin 805 -> 0 bytes .../spinner_ab_pressed_shadow.9.png | Bin 744 -> 0 bytes .../tab_selected_focused_shadow.9.png | Bin 116 -> 0 bytes .../tab_selected_pressed_shadow.9.png | Bin 116 -> 0 bytes .../drawable-xxhdpi/tab_selected_shadow.9.png | Bin 110 -> 0 bytes .../tab_unselected_focused_shadow.9.png | Bin 102 -> 0 bytes .../tab_unselected_pressed_shadow.9.png | Bin 102 -> 0 bytes .../tab_unselected_shadow.9.png | Bin 110 -> 0 bytes .../ab_background_textured_shadow.xml | 21 ---------- src/main/res/drawable/btn_cab_done_shadow.xml | 27 ------------- .../drawable/progress_horizontal_shadow.xml | 35 ----------------- .../drawable/selectable_background_shadow.xml | 25 ------------ .../drawable/spinner_background_ab_shadow.xml | 28 ------------- .../res/drawable/tab_indicator_ab_shadow.xml | 37 ------------------ src/main/res/layout/main.xml | 11 ------ src/main/res/values/colors.xml | 10 ----- src/main/res/values/ids.xml | 28 ------------- .../shadowsocks/ShadowsocksSettings.scala | 1 - 124 files changed, 223 deletions(-) delete mode 100755 src/main/res/drawable-hdpi/ab_bottom_solid_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/ab_solid_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/ab_stacked_solid_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/ab_texture_tile_shadow.png delete mode 100755 src/main/res/drawable-hdpi/ab_transparent_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/btn_cab_done_default_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/btn_cab_done_focused_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/btn_cab_done_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/cab_background_bottom_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/cab_background_top_shadow.9.png delete mode 100644 src/main/res/drawable-hdpi/ic_drawer.png delete mode 100755 src/main/res/drawable-hdpi/list_focused_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/list_pressed_shadow.9.png delete mode 100644 src/main/res/drawable-hdpi/md__category_background.9.png delete mode 100644 src/main/res/drawable-hdpi/menu_arrow.png delete mode 100755 src/main/res/drawable-hdpi/menu_dropdown_panel_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/progress_bg_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/progress_primary_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/progress_secondary_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/spinner_ab_default_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/spinner_ab_disabled_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/spinner_ab_focused_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/spinner_ab_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/tab_selected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/tab_selected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/tab_selected_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/tab_unselected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/tab_unselected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-hdpi/tab_unselected_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/ab_bottom_solid_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/ab_solid_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/ab_stacked_solid_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/ab_texture_tile_shadow.png delete mode 100755 src/main/res/drawable-mdpi/ab_transparent_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/btn_cab_done_default_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/btn_cab_done_focused_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/btn_cab_done_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/cab_background_bottom_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/cab_background_top_shadow.9.png delete mode 100644 src/main/res/drawable-mdpi/ic_drawer.png delete mode 100755 src/main/res/drawable-mdpi/list_focused_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/list_pressed_shadow.9.png delete mode 100644 src/main/res/drawable-mdpi/md__category_background.9.png delete mode 100644 src/main/res/drawable-mdpi/menu_arrow.png delete mode 100755 src/main/res/drawable-mdpi/menu_dropdown_panel_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/progress_bg_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/progress_primary_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/progress_secondary_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/spinner_ab_default_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/spinner_ab_disabled_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/spinner_ab_focused_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/spinner_ab_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/tab_selected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/tab_selected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/tab_selected_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/tab_unselected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/tab_unselected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-mdpi/tab_unselected_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/ab_bottom_solid_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/ab_solid_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/ab_stacked_solid_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/ab_texture_tile_shadow.png delete mode 100755 src/main/res/drawable-xhdpi/ab_transparent_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/btn_cab_done_default_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/btn_cab_done_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/btn_cab_done_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/cab_background_bottom_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/cab_background_top_shadow.9.png delete mode 100644 src/main/res/drawable-xhdpi/ic_drawer.png delete mode 100755 src/main/res/drawable-xhdpi/list_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/list_pressed_shadow.9.png delete mode 100644 src/main/res/drawable-xhdpi/md__category_background.9.png delete mode 100644 src/main/res/drawable-xhdpi/menu_arrow.png delete mode 100755 src/main/res/drawable-xhdpi/menu_dropdown_panel_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/progress_bg_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/progress_primary_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/progress_secondary_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/spinner_ab_default_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/spinner_ab_disabled_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/spinner_ab_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/spinner_ab_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/tab_selected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/tab_selected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/tab_selected_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/tab_unselected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/tab_unselected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xhdpi/tab_unselected_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/ab_bottom_solid_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/ab_solid_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/ab_stacked_solid_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/ab_texture_tile_shadow.png delete mode 100755 src/main/res/drawable-xxhdpi/ab_transparent_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/btn_cab_done_default_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/btn_cab_done_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/btn_cab_done_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/cab_background_bottom_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/cab_background_top_shadow.9.png delete mode 100644 src/main/res/drawable-xxhdpi/ic_drawer.png delete mode 100755 src/main/res/drawable-xxhdpi/list_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/list_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/menu_dropdown_panel_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/progress_bg_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/progress_primary_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/progress_secondary_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/spinner_ab_default_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/spinner_ab_disabled_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/spinner_ab_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/spinner_ab_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/tab_selected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/tab_selected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/tab_selected_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/tab_unselected_focused_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/tab_unselected_pressed_shadow.9.png delete mode 100755 src/main/res/drawable-xxhdpi/tab_unselected_shadow.9.png delete mode 100755 src/main/res/drawable/ab_background_textured_shadow.xml delete mode 100755 src/main/res/drawable/btn_cab_done_shadow.xml delete mode 100755 src/main/res/drawable/progress_horizontal_shadow.xml delete mode 100755 src/main/res/drawable/selectable_background_shadow.xml delete mode 100755 src/main/res/drawable/spinner_background_ab_shadow.xml delete mode 100755 src/main/res/drawable/tab_indicator_ab_shadow.xml delete mode 100644 src/main/res/layout/main.xml delete mode 100644 src/main/res/values/ids.xml diff --git a/src/main/res/drawable-hdpi/ab_bottom_solid_shadow.9.png b/src/main/res/drawable-hdpi/ab_bottom_solid_shadow.9.png deleted file mode 100755 index 758468cf0fa672d58914fb18cf87ea72e43f485c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SIy_w*Ln7SY-Z12AP!Mnl+{tJA z-JZery5p3VS@{Mx9|iNz{%YB~?Dd{pVz6?U{&GAj~xxD7ddYClI_HqNzBu7 S%=ZJ`#Ng@b=d#Wzp$PymH&WUF diff --git a/src/main/res/drawable-hdpi/ab_solid_shadow.9.png b/src/main/res/drawable-hdpi/ab_solid_shadow.9.png deleted file mode 100755 index da77e95cb0805e14d09274fad7aa687d4307555c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^SdOcknLn7SY&T!;9puod2Tc7h@ zZPmM`_)VFu^L8gFPWiZ}<*dc>8yml$l}NXCyXPF0ef@yR`McN4wq6T4TJ>IJvPt8N z7VSd<%`?0l&OVkn62g=vcU)naP{3ykHp8h6vyK~ftYo=j)AzUUM$hfmU00S@$^?IW yrXJ?ySt>7`yymyW(YRCJ1iEWht?#ibWBTYbiFq}{**!pqF?hQAxvXqmV y{Op_>6m<9aF^Si9ZX2g>vOS_S|CRRQ{<*y>lb8>&amdKI;Vst0PN*1LI3~& diff --git a/src/main/res/drawable-hdpi/ab_transparent_shadow.9.png b/src/main/res/drawable-hdpi/ab_transparent_shadow.9.png deleted file mode 100755 index c58997f1150474658581df5059939bbfd1ba167e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 205 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^Srg*wIhD5l(y>XDU!9c*}Vh&?i zg53S*l;>BiqR1t;tVJRgBq>8(i<{xS_kfSoh0} z$vSGQl+>C;j|c>_Ua^sN_7M&ET*6}*>Tve5;gJwVQ~%=-iQm&_ylr<&tvq?zP;_(g z#>|`N=9Ly-tIWASN$1-~-@J{p-oMg(ZCA*kS!m3Bd=c{pp!*m+UHx3vIVCg!0NbTb ANdN!< diff --git a/src/main/res/drawable-hdpi/btn_cab_done_default_shadow.9.png b/src/main/res/drawable-hdpi/btn_cab_done_default_shadow.9.png deleted file mode 100755 index c8d351eda0378104385537b71d9aed3ebe9e150a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Qo!3HFq_#{<IIIzBM4-~a#r|5XV|$^1jkJ!(uFIHY^Ul^(H9+j3A-n&B(EJ@d@H6T*NdFnGH9 KxvXG#2+I9$RD4!`E%=q1vhri!ijIpe2_|tKp3^QY;q|-85cvBlv+k{4 QJ)l7hp00i_>zopr0LY0WqyPW_ diff --git a/src/main/res/drawable-hdpi/btn_cab_done_pressed_shadow.9.png b/src/main/res/drawable-hdpi/btn_cab_done_pressed_shadow.9.png deleted file mode 100755 index 8d332ef228c697950ab12467dcced05b6d0ea43b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Qu!3HFS4tGogQZAk@jv*Ss$tevD{~gY7BsFwi zUhaS1#MIQ6-Lr>FKv3>~qoUdABS)4@pE&WOn#K_h?jANH!OR>k1JP#(f)!2XHci%K YxWD8CvubY5Dxi4`p00i_>zopr06eiKkpKVy diff --git a/src/main/res/drawable-hdpi/cab_background_bottom_shadow.9.png b/src/main/res/drawable-hdpi/cab_background_bottom_shadow.9.png deleted file mode 100755 index f7adb4365f70d3ff632529f00914b21d7bd52792..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206 zcmeAS@N?(olHy`uVBq!ia0vp^Y9P$P1|(P5zFY^Srh2+KhD5l(y|GcSK|#Rf;$psP z1HP|TY-GU_ yTa$PG`LL@0+u7i{tKwkk`&MaUuj|&tc*OI(C}QSZ&a(mNKn71&KbLh*2~7YJU`_h~ diff --git a/src/main/res/drawable-hdpi/cab_background_top_shadow.9.png b/src/main/res/drawable-hdpi/cab_background_top_shadow.9.png deleted file mode 100755 index 732428503d16052df45cfef6679a502b4956588b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 206 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 diff --git a/src/main/res/drawable-hdpi/list_pressed_shadow.9.png b/src/main/res/drawable-hdpi/list_pressed_shadow.9.png deleted file mode 100755 index 74e43594f2d2802d4e28d7e1092f6be4f09b1f75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^+#t-s1|(OmDOUqh7M?DSArj%qDF;~oPi&Exxb)zh z%gg<(6E3zWrDSF8n!l~N-J~(fs7;wLn3CPZ!4!kIuJO4Y>{&@Hhvq{NlFv|INDNQ&?t6z4B$!f5v;Ln>B;0 zU-ImdKI;Vst0HI7c0ssI2 diff --git a/src/main/res/drawable-hdpi/menu_arrow.png b/src/main/res/drawable-hdpi/menu_arrow.png deleted file mode 100644 index c28d98f3bb435334b7852718214161d780896fce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1578 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 diff --git a/src/main/res/drawable-hdpi/spinner_ab_default_shadow.9.png b/src/main/res/drawable-hdpi/spinner_ab_default_shadow.9.png deleted file mode 100755 index 4fd4aeba02fd50da20150a79bb6055a621fa9134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 376 zcmV-;0f+vHP)C3<0003$Nkl*oX-X$i=vTvx^sDAnb(Aa~NYBBqX%9MvO6hmC_HB$HD-FU;ghk zuK~0gKFHT)G;*)-W$7>A5dx+!ElB2Xl3~l&gmMvv08B^Uypl2H08C#cAQ?!8ca=iV zK+l-nGkKmnQ4}@r;rxqL*T7|2t}(`5UDxLz2=3YjC4)3gv$t*AqvxaV`xh;k7Ghae zj1YQI%s~t08$y#Kfj*i W(hwfd;(_!40000C3<0003kNklF_L-*X%UYwPkR(Z>zVE}PY3^B;byhGVWEh64>$>l{u5VT_ zQwYI$2%*jjW)7jtVg<7Vv4UYijAPayMlo9uV;CNY5ezRxJ4OVe6(b7KhLM42!N@{( z$EZMd#S}$>f*`oi?n|4V=r(RwOj(u@*#ew>-$ybKdJo39dyt{Lg{Z2^C+%PP)Pg|z z-}M{P)C3<00061NklMZ0L3`Iw*f^$mh^p+A>#&b_`bTMZO$Uo*=nwh1YZ2rIs8by)!s^pUXn zMe^Z!f30m{Ht*U8+yx~RlyF&3V7HOP0VC?Qz0CCxQ*E8`DJ@A50(}6mS$jbwz@$K_ z487WJ_SD8)sJ4mloevEXeAZl0QVI}@OiHPy7;`*^fj%KVDXC_Qsy>ZGTlO4{B!+m- zTn>lHXwMv}VTv(R=8V-dYH9zjCiBA-W8z_QczBLK^x_F@cUIgpv!+elGtulBK_GyD zq&iNNT*&Skd!V}TIVV`Y${!^Qoi+a_QXmsmMU+DoCGeK+Q{IKx<C3<0004$Nkl3GZTjt&51YsE77>04HX_^Du6?3nY9Uz2$VT+rl`SyK3CzvRT z?sQ%E;4AlkKj1`d+y1z&`$bM3$MK`cMEW3{kmER?1d}Am6J@g8n%TDfp)f=7cF7wT)(^ zgb;T-sH$pT6vff9tdmp>hU9r3Kr(^nd9TtiXOIUdy!Y@(@*)M(hhT&h%n(EhW(*=6 zGX)Wfxdai0p@9g&&_cLl=0Lb&=0dn(mO!{*mO@s?us~MDutHYD)OCHxvg{tp0CM-8 zTgi3pSGiH9X&OK>N9gph6oQX~dghI}gec4M8Wtgqen+rUsl#v7tE8rBCd?R?G-!?$ zUXV|rwuVtluY;rYzbL(_<@!y%$k@~?o{1?Z^ySwdA(7P{ocvLC00000NkvXXu0mjf DGIG{R diff --git a/src/main/res/drawable-hdpi/tab_selected_focused_shadow.9.png b/src/main/res/drawable-hdpi/tab_selected_focused_shadow.9.png deleted file mode 100755 index 4d49b21e6a7ec4880a72b8249333cd78d9c72de6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1i!3HFsuehcLq>MaW9780+lT#WR{s&087#cOP z^lY;+ZseTzd7_o`EQRKe*OnI;pRe*ZZrH*v>G*|#kzwvDQ|39`1&@Kc89ZJ6T-G@y GGywp%z8}^A diff --git a/src/main/res/drawable-hdpi/tab_selected_pressed_shadow.9.png b/src/main/res/drawable-hdpi/tab_selected_pressed_shadow.9.png deleted file mode 100755 index 545e1b765dc068891c97c5b482d911abe0bfd8cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1i!3HFsuehcLq>MaW9780+lT#WR{s&087#cOP z+}mG&pF>zgL}ZP+?}URDuY-5YOy9dy(&1Knk3v-g1H+j|rp(JXmTm^>X7F_Nb6Mw< G&;$U+)gbi% diff --git a/src/main/res/drawable-hdpi/tab_selected_shadow.9.png b/src/main/res/drawable-hdpi/tab_selected_shadow.9.png deleted file mode 100755 index 2d7826260281b596afabcdc3fe3c15b4996e2a80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1i!3HFsuehcLq;x!89780+lT#WR{s&087#caT zI+*bMQTLs2u;O*_j+yCumr5Q;;}v!M!obKNJxzys<}cUVKz$6Ju6{1-oD!M<%sd>D diff --git a/src/main/res/drawable-hdpi/tab_unselected_focused_shadow.9.png b/src/main/res/drawable-hdpi/tab_unselected_focused_shadow.9.png deleted file mode 100755 index 57c5f18211438b7d1192301227723a940477c1de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1c!3HD^Kbl$tDQ!;|#}JO_+ yJ=<)I8#(8Fo@nJfOMy9Hx8bfbA(o4CSs2dzkY(O;G5-fp8-u5-pUXO@geCxPvK#FH diff --git a/src/main/res/drawable-hdpi/tab_unselected_pressed_shadow.9.png b/src/main/res/drawable-hdpi/tab_unselected_pressed_shadow.9.png deleted file mode 100755 index 4f18a95adf8415f5d584c98c626dab063d03f67e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 100 zcmeAS@N?(olHy`uVBq!ia0vp^tU%1c!3HD^Kbl$tDQ!;|#}JO_+ y_x9J{=MWYV5m}?|JArY`U| B9LxX! diff --git a/src/main/res/drawable-mdpi/ab_bottom_solid_shadow.9.png b/src/main/res/drawable-mdpi/ab_bottom_solid_shadow.9.png deleted file mode 100755 index 370f5fe254e98fc98f65f7d2c0a9c602be8d98f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%$(}BbAs*hzDGL05*t3#VT(u)M zPMap?p?vnh*6iyF>lV#+UAAnQ$=8c7FE3ZLliJ#GCB#^&WJ#Mu%-@U)y=-?gk`%0Y z6IkxnC%p9CnOWf@adtxr`}>RwfpR4d!Wp-?m`u$WSFTTDj^%lD5ojHQr>mdKI;Vst E0QWgIssI20 diff --git a/src/main/res/drawable-mdpi/ab_solid_shadow.9.png b/src/main/res/drawable-mdpi/ab_solid_shadow.9.png deleted file mode 100755 index cd8df3d2f7c55abb6f3b3eda00229e1e5b06d9c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%xt=bLAs*hzDGL05*t3#VT(u)M zHa9bSD4#vh$jq*=&dAhs=}On-{`2LwcI?TJ;kEj7h<8P{$qTn;J~^hvory10+WsH- z)sb^uXmO#5p@6Vg#MKM-FM4`I|)CNJEY`Q(@ucP742Y5RZR zS4Ylup~ZzJh62J~5mztRzhGi!&b(z2xxdbKNuiT@cSG65EA9)9sWE7;PGYY3{rnEl OVg^rFKbLh*2~7Z$wmRPc diff --git a/src/main/res/drawable-mdpi/ab_texture_tile_shadow.png b/src/main/res/drawable-mdpi/ab_texture_tile_shadow.png deleted file mode 100755 index 47838474fb405048981741d807b31ba3a12cfffc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_`5A|IT2?*XI?JY5_^IHHq%yuE+d|NB$PR&pRC zE9=+&3l}CZ#tP{$2KDN3PIs8@GSOk$kqHf+Obp(?B>hrcrA2^x89ZJ6T-G@yGywq6 C5g(!e diff --git a/src/main/res/drawable-mdpi/ab_transparent_shadow.9.png b/src/main/res/drawable-mdpi/ab_transparent_shadow.9.png deleted file mode 100755 index d101b0748bc17b2d7b9aed0703c8125a62d68843..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%*`6+rAs*hzDGL05*t3#VT(u)U z{{R2K((|Irswg+NWBw{TyF$1pT=_4*wd2kOX$x@5L^w(A0eB{Rzv*o>JNzWh*O{xvb+C(v33 MPgg&ebxsLQ0D%5EQvd(} diff --git a/src/main/res/drawable-mdpi/btn_cab_done_default_shadow.9.png b/src/main/res/drawable-mdpi/btn_cab_done_default_shadow.9.png deleted file mode 100755 index 70f1520f186ddee4adf122cfabfcb4a9f00f6ee0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQih%`jv*Ss$tevD{~gY7BsFlV ze5mi>Zm|9K|9^e5o7*wtg8dg<7{sPH+Z;(a$v8)fp>U5eGt-0n?}3^bJYD@<);T3K F0RYn%Aua#_ diff --git a/src/main/res/drawable-mdpi/btn_cab_done_focused_shadow.9.png b/src/main/res/drawable-mdpi/btn_cab_done_focused_shadow.9.png deleted file mode 100755 index be7948427d1225b2198389920d3bd4fa842f5b76..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^EI_Ql!3HEv&)kdyQkI@Bjv*Ss$tevD{~gY7BsFj@ z&h@W7U+J08=E+mo_}^jwkGWr`R2@5UqJr(6_$&^d$pX!)>;+j24F4TwGQVY#KLIp^ N!PC{xWt~$(69D=`BlrLS diff --git a/src/main/res/drawable-mdpi/btn_cab_done_pressed_shadow.9.png b/src/main/res/drawable-mdpi/btn_cab_done_pressed_shadow.9.png deleted file mode 100755 index 4acbbf62acc61538001b7771b80cfe6604fd3220..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol-0V16m&us-#zMd|QAsWHSDGd$(9nNs1HftI@ z|MK#(v9GW1<%uf)`n?i(C;dOLVODBV(j{(gZ8x`LvlnbQq-iL%YsSl0XJ#5-ZfKm* iI`P2*PZ8BtCI-9KHs%Xw?>__@%;4$j=d#Wzp$Pyh#xa8c diff --git a/src/main/res/drawable-mdpi/cab_background_bottom_shadow.9.png b/src/main/res/drawable-mdpi/cab_background_bottom_shadow.9.png deleted file mode 100755 index 1c49ba0baa8ee4df777917c8693b24ab706cdc26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%DV{ElAs*hzDF^ufF)x+mT%qVC zmDBO@+HwWvOty1X-p(=Be{_;AY+jss!7#>(rT0Z(w}8tDnm{r-UW| D#~?K- diff --git a/src/main/res/drawable-mdpi/cab_background_top_shadow.9.png b/src/main/res/drawable-mdpi/cab_background_top_shadow.9.png deleted file mode 100755 index d19d5b3f92f51527e8c3938e9e721da2d8dbb46f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155 zcmeAS@N?(olHy`uVBq!ia0vp^QXtI11|(N{`J4k%NuDl_As*hzDF^ufF)x+mT%qVC zmDDj$_JqT&M(_3o>twffTyc=&wF+|PSyyNB!mT;a#Bjn~wzm2Uf7!!orm*wd3A=SG zY&tA1R&p$Q{-rI2Mc1OGE?G#{i80!`US7a#>cqIZ!k5|P@tPW-Z492SelF{r5}E+7 Cnlf(y diff --git a/src/main/res/drawable-mdpi/ic_drawer.png b/src/main/res/drawable-mdpi/ic_drawer.png deleted file mode 100644 index c912125793233a6cb0d41595716907fe28bb48a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2853 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 DW(-0? diff --git a/src/main/res/drawable-mdpi/list_focused_shadow.9.png b/src/main/res/drawable-mdpi/list_focused_shadow.9.png deleted file mode 100755 index 4d3bcbfe070ffd89497fe64b0c044638efaa9178..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 120 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFq_MR?|Arj%qDGsdv7sj~FFqo0J z>Fr4$lh%ZHlKL}E7K!{}pJl+k=BfPSFoUyS?n~cfY2wl-XFg#ys3;G>XB~)z4*}Q$iB};0`Ba diff --git a/src/main/res/drawable-mdpi/list_pressed_shadow.9.png b/src/main/res/drawable-mdpi/list_pressed_shadow.9.png deleted file mode 100755 index a58996d4d93034d907c9a9483fa6cae4eca59658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqrk*a2Arj%qDGsdv7sj~FFql#J z>q{oPNo&Hol`CJ?EfV>|KI=ipd6p(FjdJD_RWrU{n0ttW;efUb^M`W+AwUBdJYD@< J);T3K0RVvQBfS6s diff --git a/src/main/res/drawable-mdpi/md__category_background.9.png b/src/main/res/drawable-mdpi/md__category_background.9.png deleted file mode 100644 index af0bc168d5874115709681fbedafb07826a02351..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^96+qZ!3HFgEN0vWQY^(zo*^7SP{WbZ0pxQQctjR6 zFmQK*Fr)d&(`$i(?w&4=Ar`%FCmV7xDDW@~e{}!%Klk~9W+&H!TiIp3`YtSG+Hzpd z#y621Pt&Gs{iIU!vCNrEbIFEaRnCmSjNkVX9JU?iXTQVf_Cz%GW$8;tppguou6{1- HoD!M$N{`01*y{8%w29 zLGZvPKCcc83^;Ni0U(#lSzfQVB&9R~G^A3g zMorUNVzF4=aTomODw;l@FAv}wfFv_-O-xLD-`?J~>H+|OnR$12_l$^+gb-htdF|}% zY-eO-2$hudV2cPw(S&vwS$9$)adAFrk2zz)5y$rHk&PaJf5^^ znp*&p$z<~L^z?MW5#apT`}_OH0QQJz1Hi`o{QTEMB2jV#xUJOxvlA~WsUr2$*x1;f zX_|Ijz&Yfa)YaA1op?OHTDOJDRsbl$V6d5pqC$usB2rdXR*Xm_^3KuYda!1&^00090Nklw5XY0IO<^wvW3*cz-tA=w$@l*h3FJjSz@FMt=qL=fW%cfi{^swC6ic?#sw@U! zNjb}RKi$dFWjIK?iZt;TmmbDy5G@!x;A@pTfN(R{7DU_Up37m9L%7Kx{=G@|xr|JG z4?_t83K@rf`+KNARk?l3!(eN8sDI!CVU5)`7Z{PNhgc8LHj3)*h0!$QM+Snn^#Yh& zp!kee-JS@7%4pjQ!v_L=YBWHE?trpySC1K=XPNCK&7y<-)lOghBv_uell-qnCiVBoG`P*km<=7(0*n67#}bWdy{P0|Bo{ z_6P-WDxvW?S0iKe5)juS_lvxu6$o7;{(Fx&tP$?>dH8D3K4LtZ&AtzZxuzd>uM$O3 z43^8~N4Gxk9-?;c@Ey8%A5rclrqk)|Xr$e*@7ioOgVkzvZZ=fjoh7Wp!Amz*c2jja znM@iNOr_uT>SGM(pkuAq>rc}D;n_^pPM|)I;6oSA8#sWehX4|C7P-VswK)$Hxn6=0~+xr9ZvEVv5KI)5FuGE=-j@+@$6nio$F1I}!Boxy!P zkE|0i)*LQ2tshL@VwQQPt>G5dK8$HQCTFs39bj~922#E&S$?=lg5V z8l3b`moIE`TMJSFHvaz^Yhd@CQmX3x$~W5i58O^sB3L8B8UO$Q07*qoM6N<$f=l~# A<^TWy diff --git a/src/main/res/drawable-mdpi/progress_bg_shadow.9.png b/src/main/res/drawable-mdpi/progress_bg_shadow.9.png deleted file mode 100755 index 9372a60f7b177f7df8d3eaf6c726cb42e46dcae6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol;0U|59*B=E^uAVNAArj%qDGd$(17-<&88=8M zIPPHZQHFVdQ&MBb@09AV@0{{R3 diff --git a/src/main/res/drawable-mdpi/progress_primary_shadow.9.png b/src/main/res/drawable-mdpi/progress_primary_shadow.9.png deleted file mode 100755 index 18a10d9d6586d539dfb0709a219629c7d7d01a93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 501 zcmVuP+9Vs~2EG<61tZI44 z2q4yfCr~}_l#3rj9*>tOBw^UX=(T}OXDDvHV47$QyrC?>V&0_A#dA6iRT!V`LN=NK zN4ImPNC+3y0`=Pl4fZuf4Gm_68*Y9N+_#V75kH>kl#|4JKj`-xCA--Y;k2I}tN4#8#~QD6f~ zGeRb!R3(JSrS?b`oJ}E%7H8L^ue)g6w)>|4uQ$3VK_qhlw3nV;_hiee4!AMd`;^g&g98Y_9naom8+=(t$!2^00000NkvXXu0mjfFUH{p diff --git a/src/main/res/drawable-mdpi/progress_secondary_shadow.9.png b/src/main/res/drawable-mdpi/progress_secondary_shadow.9.png deleted file mode 100755 index 6196d8b86e841bb288d8fa175a78bdd597d280dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol;0U|59*B=E^uAVNAArj%qDGd$(17-<&88=8M zIPPHZQH=N&ULj9fVlx}K#auOE{{7}Kf YV38%ye5${;7HA-Yr>mdKI;Vst0CrR-nE(I) diff --git a/src/main/res/drawable-mdpi/spinner_ab_default_shadow.9.png b/src/main/res/drawable-mdpi/spinner_ab_default_shadow.9.png deleted file mode 100755 index 9aeafee201a6f9567b34f5c45a9656136477d73c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 314 zcmV-A0mc4_P)R#fsQ0%e&73+@%z9IHT??i$f6qAbfeT-db3 zNsN;;5#@RAg<%*AAudUhv~N3OEu9Uh^O1rA6u4sU{c;ELdilP<`@GWjEK?5v_ zqXE{$Q2<-w-T+A43*aKY8{jIw8z7}j7-MJsFmNyv^3*l=EX&N>#`dTv%krc*kJE28 zO;e@C%^b4FP6P3uML=i40l^Mj@5Y?`by(ollD`4aE+8+)o5KsjGg^-T0000MH@&}H@S>%8Gr--jzjf;X-J9nN zy|n>;2=%HnARw`(64~R)_IY8!=#qj7hzBcnQb*s2X%Retur=)Ooc#cZu`d2zfcH88 zAve^BL-oe`H-No#bfsp+0G#F)L@P~LkfQR_<08jCy0ovf~X;$uP@+2OeMrMdqYmxm=Cbtd6c!+Bv zxP~o@Q|!tsX!t}cb#^gZ#|E0;$nASYlmz<$`2IVQ?TYFq!xW42p}3KA?-6Pos;Y4`JfWk6|JF)GMJ0A<*)3Fu_Ra_i@*2 zImoK{V&!epGT!-i0q}i)#~9lZLbT2^B@Y5C0oKqN&=o#NkmtD;1i?Ynx$3*!yG&t+?&COi08C4`w9^B@z1K#A?Z1H(tt*qH0$taC xy#%V1sK!waJDFs*&Tf|GciQ&7A&+Q3Ab*P`85-Du7EAyD002ovPDHLkV1g~tjS&C< diff --git a/src/main/res/drawable-mdpi/tab_selected_focused_shadow.9.png b/src/main/res/drawable-mdpi/tab_selected_focused_shadow.9.png deleted file mode 100755 index a6523c2e4fbc99fb1cad477eb8a8c26bc4f25dbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^EI`b~!3HEJ|NhShr1U*q978ywlT#WR{s+vOD0sy1 z)~7QpDh21bP0l+XkK Dr@bIY diff --git a/src/main/res/drawable-mdpi/tab_selected_pressed_shadow.9.png b/src/main/res/drawable-mdpi/tab_selected_pressed_shadow.9.png deleted file mode 100755 index a52c51d259bf6db50bd226dc7757da0298159a9e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 104 zcmeAS@N?(olHy`uVBq!ia0vp^EI`b~!3HEJ|NhShr1U*q978ywlT#WR{s+vOD0rmu z|G!#g4~Kw&4RWg)nm=A!o}in)cd4XbP0l+XkK Dw~8SG diff --git a/src/main/res/drawable-mdpi/tab_selected_shadow.9.png b/src/main/res/drawable-mdpi/tab_selected_shadow.9.png deleted file mode 100755 index 2660743ae83643adb79ecd1cfcf0e87e416fe150..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 97 zcmeAS@N?(olHy`uVBq!ia0vp^EI`b~!3HEJ|NhShq%=HT978ywlT#WR{s+vOD0qtT wVglzHCZ1!_^P9HL`8q9)L3?Q@!=}RwvQy-kXQ-;&1?pk&boFyt=akR{0G0S0CjbBd diff --git a/src/main/res/drawable-mdpi/tab_unselected_focused_shadow.9.png b/src/main/res/drawable-mdpi/tab_unselected_focused_shadow.9.png deleted file mode 100755 index 0fa12dbfe02483120b9d31d608027bb6c94223f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 98 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c0!3HFsSlX8YDNRoo#}JO_VDb9>W4@H=j_USDE>S6G7^>bP0l+XkKHXRvP diff --git a/src/main/res/drawable-mdpi/tab_unselected_shadow.9.png b/src/main/res/drawable-mdpi/tab_unselected_shadow.9.png deleted file mode 100755 index 1cf300262442e82dee0b0f22dc05e5e5238cd114..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 107 zcmeAS@N?(olHy`uVBq!ia0vp^EI`c0!3HFsSlX8YDI-r8#}JO_;PwjFUZ7BW;e^D&!jasLR^&EV_1b&MC4u+vyMt#+%PRjqmnrs9bgw;?z4rNn-18ET7d>$nE3A;tT${T$ zYVY^#tu-fT>7$g$_3brgdU0X6vqc^zd^yMWh?*y diff --git a/src/main/res/drawable-xhdpi/ab_solid_shadow.9.png b/src/main/res/drawable-xhdpi/ab_solid_shadow.9.png deleted file mode 100755 index 17f1607545cb7e7880659f93f4d8f5e374f977f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 259 zcmV+e0sQ`nP)Xq@#E1#3T#FGIohgVB6Ii(xBQiQua62P?{AV|@np3-- zk$rAHq?DGvi&ATS?xMsPm)=Ngjg8Ft9DSVf8X4~|eYD2u=DutF?Af@*od! zsF8<=nA^~ZMj!%SEeLE}tC1KT6x0X=Hm=o3j1CHF1Ogk^Y9vMn1vLVJjcYX$ql1DP zfxyPK8i~`Dl`CKNFI=b?!8BWG1JeW*J=X%(9U==g4lLtvX56K;hHHYTVbh+@)7=W~%nT0u Wl;wHi@=pRyWAJqKb6Mw<&;$SoSS5h~ diff --git a/src/main/res/drawable-xhdpi/ab_transparent_shadow.9.png b/src/main/res/drawable-xhdpi/ab_transparent_shadow.9.png deleted file mode 100755 index 671fa845232e75712472afa702b42fd853cd3fe9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^Mj*_=1|;R|J2nETE1oWnAsNnZXC34{WFWw@lW9eR zkw$ZsX0uU716z-x&?C#BlGQ3w`^~q1>-k(f*C_kUtXFG(@yRF8vG(4T9)5N8)S&N- z|DN&l3oY?oW#XivYAoe>Ni9}NampmgUX{$rdc6W(Cwtr`ZSkD$#<4WTP1*C-5^v>} zAfv?-RdO#a6?D>^dC_B%*~?2D3#XjPQ1P5ylGzgAm1Z(&iSI6iamS4={nKhxh@ELU zZQ@h|vyVRy_QbqDf4+Xx?XNpxr!9AvOHt;lcY9V>R=f4tzt_Ah!S>8n|G6gs{m0gTe~DWM4fZzE}1 diff --git a/src/main/res/drawable-xhdpi/btn_cab_done_default_shadow.9.png b/src/main/res/drawable-xhdpi/btn_cab_done_default_shadow.9.png deleted file mode 100755 index 3521ae38d306f33fe604477a94a7809eb2a1b274..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#v+DMwEi#}EtulzI8$Zx622WQ%mvv4FO#mKCC&B;# diff --git a/src/main/res/drawable-xhdpi/btn_cab_done_focused_shadow.9.png b/src/main/res/drawable-xhdpi/btn_cab_done_focused_shadow.9.png deleted file mode 100755 index 2ae6ea3f15bc57f1ac5d91eedf177402c7c94c5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqR!3HEvyN#v+DHl%{#}Etu<#YyJy+#*m*uFnvhri!ianQo3rwy$ZhGQzs_=pmM;sF) ZgXc0qp_2~M6+rVCJYD@<);T3K0RXK?C_n%J diff --git a/src/main/res/drawable-xhdpi/btn_cab_done_pressed_shadow.9.png b/src/main/res/drawable-xhdpi/btn_cab_done_pressed_shadow.9.png deleted file mode 100755 index 772bde13d87cb795afd61db126739605d7e126f2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 129 zcmeAS@N?(olHy`uVBq!ia0vp^tUzqW!3HGx8-t$#DGyH<#}Etu3??8uv6sWPH7qmE?UH#l$T&jLi@bvty diff --git a/src/main/res/drawable-xhdpi/cab_background_bottom_shadow.9.png b/src/main/res/drawable-xhdpi/cab_background_bottom_shadow.9.png deleted file mode 100755 index 19da0c6b1b95f2b0a13a13338fa2402b62523691..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 266 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 diff --git a/src/main/res/drawable-xhdpi/list_pressed_shadow.9.png b/src/main/res/drawable-xhdpi/list_pressed_shadow.9.png deleted file mode 100755 index 4f6f689b8785b1c3400a513b0ace3985a58f7f8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 zcmeAS@N?(olHy`uVBq!ia0vp^d?3uh1|;P@bT0xaOHUWa5RKsElmmSK7IPXe(q`tK zV^@2Nv7IrZ)z{beJHKJ?|Hir!mE--+9*;db+yg`wsb@J|JjKDVm%)try6*Etpdk#N Lu6{1-oD!MFFb?{!3Y}R7t9wIuTwN5mHj{%4? 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 Dd1F;_ diff --git a/src/main/res/drawable-xhdpi/progress_bg_shadow.9.png b/src/main/res/drawable-xhdpi/progress_bg_shadow.9.png deleted file mode 100755 index 8b4853aa62233ce662e22f0f0587aa816de1c2a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 134 zcmeAS@N?(olHy`uVBq!ia0vp^Ahr?*8<0#p>+uXo`FgrIhFJI~r!+MD50G**T=Y@W zfl0wtLMVglKmP`&lJexo&38R`Bu;Yu|NmdVRli3UA z(GULBGvn=@UD)-?T6vL28uj*LW`6bW>Z-CSsW0EOZ9|>@mFo(iKwo*#j&lAQe9OMH z+lp^ltV{V^P<$7!D+2D9a1eDvbS&@|!CSaL7envSVM3GfYt&F>dzXU1#@ z-c_i95de{;h4_5)B=qw)BP#a$G){*s{c@zJ>N8o~cRmrB9^*bEoAR9Ns(t5&*)8Xa z+)Va!_iK9J93LeP2DtToTwptZEo2M$@%`-pb}-UZOf(5#0N>Xvfcf4h7P!$!v(1RA zp<=6u28P+Gj7+7%^FxdU11smW9y+ax(z!j8rtk8@+b@JqH|DxcF z%7hOK__^xyO3wq;3U>{v;p6AJ@N>!oygt1vU1g^D4*}lz=((%JTfOKy3%=j@`P`XV z@bzWNmr#6gQN`zd9APXvoXZa5asv`M)N)`I3WvAt4Hd`lqCjFnIMm$N zl2Cd+SFT{hJ*^$QTH?9HZwZGI<~TtdR~4cp!XrAI*z@oh!XP`uRpPKV3Wr$xKaNs% z`uOMf8-YveUN?@%i3cf2dxPlRL!v?AkvQ(Hge6xlIB0B1722x^le{#E5%ECHOeGiOZ)4qx<&nhg7WwZvt%Xk~1Tu8y8jGf=cG&nk9BEDX3(=EHuX@ zLcc=IqG1TigaAHpzM`QW*z!7oqC_1?7GieLZl uaJ^l=lvTU^FSwm`m5_-pWdpbO68Z||*$*MQAB80V0000+uXo`FgrIhFJI~r!+MD50G**T=Y@W zfl0wtLMVglKmP`&lJexo&38R`Bu;YmZnOP*RNU?Po+ajuhYKS#Rg^+|p12qm95fC& hCHJLCWU&k@!=0Np%!Hc66v zkDb}Mb;ts*s_H(9q6BE)0sixXeL3J|S#IMveqOKFk8Rt&rfIqt4?dUN{ofbYeFpP1f`r6C*qAJbDw%LPAUS~mCv({jPDn3f5SFf9)pX<8Qe z4AXMJXPTA)PB3jBoM_rE_zkA*f!}D_4mg8p^WaRT&4M$UHV4jZ+6?#trk4kYBZRQ) zy4~0#PMr(#NaSkRa*ae?*BQM237(-xWF63V9ze(&98VnByL_na2jBNMtiZM6IRgSt&#Hn)Bbs|ocqpnL@-2HP&?EBRC9F$Z zoN&R>m;8#Scu08YcTL1a94R1M1qtPCOvJrWB2OgZNGNY(BJPb6c_Mz|RaI@_Wu9CB zukgCARi5X&uIs+bvYZ~o^9gU7MrT>JAIEXm_x&e?pV){0Ngt+ZIw++Kh#%R9U!;vO zAMjFI>l6F%YiVn(c3Xpe_+0w3pIL|Bl4c)%Pnvc3BWbqb&!ky~W2D)IW2ISzFOg;w zzEqk;I7K>oI8{1o_$$)U!e5n+67EAfc(^a=py58HgN6H+4idhGbdd12ZQYOBclfoU zkT-CajQzmyS5Xx1@4bU|d%|s#VHmbcYOu3#U&TW72=ns?*sf1O3&%#RI49vN;@&)U zvf{}-VDrzP>O%-39{R&6;v$X}z<#T+d+_}X8SIoI-&O0}00000NkvXXu0mjfzqs1! diff --git a/src/main/res/drawable-xhdpi/spinner_ab_focused_shadow.9.png b/src/main/res/drawable-xhdpi/spinner_ab_focused_shadow.9.png deleted file mode 100755 index 1c8d33d0bdb717b34f214bf481d31d47a07c0b6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 725 zcmV;`0xJE9P)uU01rj)=m4XlmV!H@ITByS#Ko_0`y5tdvQbo8;B1E?q4M`C}he4u9 z8gK}pxt!g2!2)BC*ZXr<8oQyGS%3TOvC&)|Qg$!CvyAMvrMD^sSoq2VXN~%#VVVQs z3$3}7-beO+Wn<_9puaTn_R}Zjy>D;nDg^hc^%-V<$4ZZAGP&DqcWZ_KWa^N2HjaP!Ex+Rh%D4m1I^)i`Gu~>T!_T3Mii?ViN-7z! zyr}zfT8c_+nKPc4O3Mos#W+s%kI1kwx;fV=0ysudC5!?qr1`*Lz7swZ>EN)8NgBOU zq$)TFf58OvR6Kao^faKSFpRp=iav`6k4zJ(*BHkJQ8^V4-f9}Q!=bBq@VlmO2U3EK zw=*ps{2|k#!8@523*ODNNN^j|;=pZ9ivsV(v>5PSO^X1JV>);6xTbRj@5gj*;QgA; z1w0AUnS&=~I#ci@O=kw4wCPO1F*z7wLsP*SF*>A}yv7x{=o(kXmGKh>irb+o6;&##R7BMPavt^NM2ce8Oc`gU5;+h_ z<8d6f48zE_+zuY(z+sEcTr3v7cDwx{4ftlWu>krOj1N4|dzJz`Gd-P72LRuPtw5{O z={%7KFHA>KbO*3z2237&*K}c-H26N#`1;w+;h~*YytQSm&G!ewxPa{<+e2VymD~Iw(WomIQp7% zYDjJ;3wxdl9BYbIJLwZbGXBpgc?wSEz@(fJRcS-PMGPArwO8=_Ba2~Ieq6J<@JrW{|vV)NvoW0US82CZB-W|elkDxe7rp00i_ I>zopr05T>Z@&Et; diff --git a/src/main/res/drawable-xhdpi/tab_selected_pressed_shadow.9.png b/src/main/res/drawable-xhdpi/tab_selected_pressed_shadow.9.png deleted file mode 100755 index f6d8ee5c77beb604bef6b9f6f517d903830e1425..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 111 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol;0U|59*B=E^W}YsNArj%qDGd$(1Ekyxjha~Q z@2|h#p`)mw5#gW8$@X}yf1r;2Yu&R9o03DAzopr02K!ycK`qY diff --git a/src/main/res/drawable-xhdpi/tab_selected_shadow.9.png b/src/main/res/drawable-xhdpi/tab_selected_shadow.9.png deleted file mode 100755 index aec4e87a251a5170aaf3f224b1c2fe40bc987f46..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^Y(Ol;0U|59*B=E^2A(dCArj%qDGd$(1Ekyxjht8= zO^kl{r*g7AUh5yIWB*$BEW@^v5GJvA9~2IX1v0eHw_;BE&gcZx%i!ti=d#Wzp$PyR CBpmAi diff --git a/src/main/res/drawable-xhdpi/tab_unselected_focused_shadow.9.png b/src/main/res/drawable-xhdpi/tab_unselected_focused_shadow.9.png deleted file mode 100755 index 3c87dd9c016e0fb1d0a838026bb074e1fb7a9762..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ#0V1dK=^Fzn9Zwg>5RT~Nl!k`?0a9*;Molce x+iZ*-r&&B#E^Rv{#N%Myv+<^*FK3P%3xkW58guZJRh&S544$rjF6*2UngA~r7^(mO diff --git a/src/main/res/drawable-xhdpi/tab_unselected_pressed_shadow.9.png b/src/main/res/drawable-xhdpi/tab_unselected_pressed_shadow.9.png deleted file mode 100755 index a5a2c25efd72107bfbf82cf58e663faf6a43d8c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ#0V1dK=^Fzn9Zwg>5RT~Nl!k`?0a9*;MoldD y_t)R=&{5RTi11J4WLqH1d*jW5Wh`d=OboBB)R@~&|1t&YWAJqKb6Mw<&;$TX-5M?c diff --git a/src/main/res/drawable-xhdpi/tab_unselected_shadow.9.png b/src/main/res/drawable-xhdpi/tab_unselected_shadow.9.png deleted file mode 100755 index d211e8a81f2a7febafa16aa5052107b9df0d23ae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 zcmeAS@N?(olHy`uVBq!ia0vp^Y(UJ#0V1dK=^FznYfl%)5RT~Nl!k`?0a9*;Moz4b zCPqK}Q#nl@EA}x)XKneKX}jr-W&TUH4J{w9E!Q|_`&##GLp;-LcE-~o;>>j{_qGF# OVeoYIb6Mw<&;$T@pCZoy diff --git a/src/main/res/drawable-xxhdpi/ab_bottom_solid_shadow.9.png b/src/main/res/drawable-xxhdpi/ab_bottom_solid_shadow.9.png deleted file mode 100755 index d767dd9271599bbc46ed3758c82d2e6658a238b8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 357 zcmeAS@N?(olHy`uVBq!ia0vp^ULefD1|(%J94cgBVASz+aSW-5dwa)_uPK0m)p4hQ z?00(xS@EDN5naE9g?(gRho1Z~A>u^I&$GwBo=x;kmworR_jzSqc|yAEb^pEZx8;fl zJXB^Bo$!uRBOp*AP0W;Qt4{aodyKbstvkP3ZpGuw#;)aZ5GhtIt|Mm_Ik+~?h!k0& zAz<9iB+8nU7Pw%M!x&SMzVdBTgoW z{k%>)pL+Z;VrSKw7rnrt)?Hy=*Zr!+0oCvOQjTX_=2hIKBsBTJK@ni^F?hQAxvX<69M0&_ zU9q2&?Y8{QNA~|o{}wB-RDu(ux;Jz=iMm_`j)e5*;Oq7 lJN!!IinZUbS-VNkSKOr}G}Ct<3ozgqJYD@<);T3K0RWpzfX)B_ diff --git a/src/main/res/drawable-xxhdpi/ab_stacked_solid_shadow.9.png b/src/main/res/drawable-xxhdpi/ab_stacked_solid_shadow.9.png deleted file mode 100755 index 47555f2f743b5e66ddcd705c65d6df02d8270f56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 350 zcmeAS@N?(olHy`uVBq!ia0vp^ULefD1|(%J94cgBU{v*VaSW-5dwa)_uPK0m)zLyx zbor7;EnQOH1uGQ_*IfT#Y~ys?;?C#qH!QDJTrIpWKJR(u`-Jehufwj#PD^DF&Es6r z@Wsoav5U!YvqnImLYf$>7T1w8iyT}VXGDsu&=4^0W)fvhN()@D$l;6*SBOZ*Ojmj< zzT&y!__y3?Kc@dbv#*=!>*IgTUHlvn$Ce6Z%~*C){3PFnYo&i{Ch}bQxW(b9J3qwX jR@_^^-m5yE@mP5J9wnhUo=bIr;l|+U>gTe~DWM4flQ@G& diff --git a/src/main/res/drawable-xxhdpi/ab_texture_tile_shadow.png b/src/main/res/drawable-xxhdpi/ab_texture_tile_shadow.png deleted file mode 100755 index 5f5299cab79068a4b7a023c9f729101af3dfdee0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 255 zcmVw1{p0B_+C3v;J5P2u}KMAI~qs&O2RUxFpj^a9W$a#DtCh!Ow*002ovPDHLk FV1jlhW<~%2 diff --git a/src/main/res/drawable-xxhdpi/ab_transparent_shadow.9.png b/src/main/res/drawable-xxhdpi/ab_transparent_shadow.9.png deleted file mode 100755 index 0e9ba38dfeefd172f0cf59b0eb1f04d10ca1997c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 352 zcmeAS@N?(olHy`uVBq!ia0vp^ULefD1|(%J94cgBU{v>XaSW-5dwb`g;K2X}*NaQ| zQZ=0So(gEQN@~fSBt2WA@2hH|jd9LDi<;-jQ9IUtTyfj>%^~-_5Bb+yH)a(rn01+f zD@3GYrfXvtli_BKfIx*bF;*?EBWD&lxHis+6j`AmVBF0l%9@lGxL}dP86CPS{^nrI z-&6SI#I75AGy-mKX4;x-BEA6ZwkvWg9@gyDmz^pW|9t!A+fTpzie$+8+sr1qp988O kZpHWeGk$E@f94o_je8RFzN)U%z>s6`boFyt=akR{0F=XqTmS$7 diff --git a/src/main/res/drawable-xxhdpi/btn_cab_done_default_shadow.9.png b/src/main/res/drawable-xxhdpi/btn_cab_done_default_shadow.9.png deleted file mode 100755 index 0c0079c7df77b8e03a798b0afdb59c285fea6eb6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^Y(N~q0V1uWSr!4QU{4pv5DWk0l!k`?4re%0n>9uF zCLQ@7$oV9Jsr_!ogdR3d9hMbyB@Re_{{R1fmI1efq-1`R(47Xa1;@Wm#PTCB>P mwj#i~zUR#p4lR~|tXzhKpbTbn)kY_v@eH1>elF{r5}E+6wkwVR diff --git a/src/main/res/drawable-xxhdpi/btn_cab_done_focused_shadow.9.png b/src/main/res/drawable-xxhdpi/btn_cab_done_focused_shadow.9.png deleted file mode 100755 index ddf7531b3a24c25e09ec956926ef73f580c520e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^Y(N~q0V1uWSr!2)FHaZ85DWk0l!k`?4re%0n>7uN zXWS0HUmSO7_C%F`{a!t6oI18WYHYKf_y0d&^P*jspKryHjFSdYYE7$qFWyRckj0#_ ewKpi6nc>dPJ|T;TDKmklGI+ZBxvX7ud ze|dS?*w@$h@99$S3j3^P6GJW%!~a~q zxmF`!^K1SrwUTN%h}}`_Pxal?;`X_pZFy&ZM%46k&=nt#z(9^G@(YiB=ubKSa+Ls>gTe~DWM4fDm;@B diff --git a/src/main/res/drawable-xxhdpi/cab_background_top_shadow.9.png b/src/main/res/drawable-xxhdpi/cab_background_top_shadow.9.png deleted file mode 100755 index 3480efff84b5023882590f7547edd09942cc4b56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 360 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 G5&s2lBtxbE diff --git a/src/main/res/drawable-xxhdpi/list_focused_shadow.9.png b/src/main/res/drawable-xxhdpi/list_focused_shadow.9.png deleted file mode 100755 index cc17ef5b42bb7e67385b426bd8099aaec6c1d0bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;AmZytjh=qT0$^rg=k0+!ZS<0)E zxasXlA0{?o)!Jj;YPnY&7Bz7#SDMxOus%WO{GqJ3_Q%#n9G&^EI$5}Vr@;Eg|1%^4 zE-78MXLD-{WKMkO86q)BSaWgZ%s+43H?ML3>%mwh6dvfm>c1r8D&ah4`B(Q9fVMJt My85}Sb4q9e0LUUb?*IS* diff --git a/src/main/res/drawable-xxhdpi/list_pressed_shadow.9.png b/src/main/res/drawable-xxhdpi/list_pressed_shadow.9.png deleted file mode 100755 index 3af5169d33c69a40be4958363b6f97740712d128..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;AfTxRNh=qT0$^rg=k0+!ZS<0(Z z`0Gn1I}@9*YHn86uKFtui<-EWE6r+sSf8L{9rVnsBX0(`JFkkpNv2ra;>wwyJS3SC kIlic@TQo1^zcCZT6T<-J-;c!`fo3y!y85}Sb4q9e08UgZ{r~^~ diff --git a/src/main/res/drawable-xxhdpi/menu_dropdown_panel_shadow.9.png b/src/main/res/drawable-xxhdpi/menu_dropdown_panel_shadow.9.png deleted file mode 100755 index c2ff4a09c8f0892254b730bd8992ab09f16e79be..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3948 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 D6$>r} diff --git a/src/main/res/drawable-xxhdpi/progress_bg_shadow.9.png b/src/main/res/drawable-xxhdpi/progress_bg_shadow.9.png deleted file mode 100755 index 7c221af9e7124874c6b6f9f31cee7ae9b30d990a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156 zcmeAS@N?(olHy`uVBq!ia0vp^d_Zi(!3HFAKD=TFQpuh!jv*f2$tevD{{v=4bWIdo z#pyDc>0f`=5!sjr2Ncl>$23?ExBznRhbXd%$$v1n!V!#+d#3aKXy5U z#@pOr9^&L-G8R2chT?hLt7tG9TO0jKm~$`^_D7|XWGEUq%7w5oywyb50su%M(o{-Y z!Z8^Mhx--80E|`^{(91Gcqo;!R%vIg)jCR&N+y#s%12e6o$CE)-yA*?x<8Nr1VZSN zHkWkhoJfN4O$j`GI<7Jw64fk$2BRHRH~ zEd-Cq;qyGvB6CV+Re6y=|Mt_<)qpfGkT|UexaeU>a3B~81S8)95KR8nCWJsEeZ7%M zlzo~22!LR~%LoG%U@I_$fv`q!NCHq zmjn0=piMxHli$Al*otx+-QyR z3mwjxKOg7U-?jK&_>30I=DYoOOy|{iGkf!W+Fmw3hslqhJ=p#6YCzCX*W6%zQ)KMy zM&_VQSN_$Z%pBCL2Y4<2bgW@sACwnI4|YGkE+FmRS%lJ44b0o~N@;+v1tn1YECK*X zy|Z%2EGp!>fP~VouiF|vOeNjn+jd`_;WPlL7s{z(1|aVkkR?ybg{PBO%1tUHc=S%6 zGV3m?Fn{{^?enB*TR__vRT2Gl^!4tY^%m9kJcQk7lQYytToa6GL3*8!-51V^?|%K} z&JRSZj;3WVtYug+$1_!&wzIP(d4-C{#<`MIyR;Q+Jaxxx6)ROt-El5uteCn(;wyN~ z5@xNwmhqWtlg&a>7-p_y8dSa3#Y#hgRN6Sot&Xr^GTBO^?CDqcUakxzEaiFXes;bg zdD>1euuP{C9aDD#ffcK+V85whuzo=hSf%!@VL*eB%0r#g)G!KCb?a*zOygl2Sixlh z85FXRx%SGHLFVv&d7>iT6?**YlTWGs{eiJ>}peFOEQx6?o!;{XVpSz--? zg`IF>qPNcT^fWE6R_)@IgV4c4yp2c29v%<7S{O!nJPak?U&T~@xBMC$ydg# z7$jg$R9-#ga0PWQ0+B+Mr7Me#O5_(Gq(zavuI`RLH&5=vgkI|4Cxur>xE7Jh_^mH(4%KbMD|F04f-ANWX*zE%(XlZ6 zI5g_6c_2;Sl)7xZ!`224+lM$WO^hv7Y4Uh%cA^W7?Zcy=4ooy_G_ToH?UL7J-E=;$ zrRf~DBzYeer-qH^Wv$6+xImK`8_n2cJ~^3K-!jC``@huY&bC#@QmtM9V1WkKOf%I9&y2vd5dGnS4xl|UtPZ)p% zs0JVdkmb=cD5Omx!#|m4REB>c4hre9h72JygiNPQhBc%s4_Wo^i@kHZ*e UKdj+M#sB~S07*qoM6N<$g7K>pasU7T diff --git a/src/main/res/drawable-xxhdpi/progress_secondary_shadow.9.png b/src/main/res/drawable-xxhdpi/progress_secondary_shadow.9.png deleted file mode 100755 index 1a7fb5894700701c6119792de9f2e7a36ed1e66b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmeAS@N?(olHy`uVBq!ia0vp^d_Zi(!3HFAKD=TFQYoG;jv*f2$tevD{{v=4bWIdo z#pyDc>0f`=5!sjr2NcE?Br0004}Nklwe7eqEW2#GIX$b) z-+|VYfMlY808$Pa6T*ZrA)<|l$PgJKLu5n(L}ooQ>4h5Q`f$1>2teLL14tGiKmaLs zDiiW)LiTLi-qzkHgd^K!00Cri28ax$TCwfYA#?~GQkw!wl~SctYt!<6gGjW(`N?z$ z9YTkQLQZ6e43Qx+A^{>pWJCkQE<@(VK=5Fmh*GsA>1Axwzq**uXUGDL>Rhy;jCpUAlV!<|2^ WwBQ??e^N&P0000E?Br0004~Nklj&33nm0J*%MI29JCv*Ap9Ha0t=a`$|df9e77M5MN-JG6P z=I=mjNLjy<_AV2^q zcPbO|X+rjF+uqjxP6$V~%K!q%;tUWOO0{C!r9fnf#C+E6^09tmKf$iT4R_7>49Muq!)%ske(RkKzd`C0yzT1 z49HO!CP0qFP!Do6hH8*AFw}yag`pDUObm4(XJe=W(SV@_L<@!r5KR~=K+;7RKm2{A zYUcw2NCpT9AmvOkAxy|h>+%aT84w_VlrzJGFddU$cO}pOrOZO{llFf Xw_ZsqNG1&A00000NkvXXu0mjfpQ6BT diff --git a/src/main/res/drawable-xxhdpi/spinner_ab_focused_shadow.9.png b/src/main/res/drawable-xxhdpi/spinner_ab_focused_shadow.9.png deleted file mode 100755 index 125bbda7de652de65e84724c3853b85317e070d6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 805 zcmV+=1KRwFP)E?Br0008)Nkl!>*wvbsal)>|}QLpJOE3}@|Ka8CkxBh9tk$=>=XYF` z35d&#_P{(<+MJOadUKJn(LV=m{lsNT0&=;(cUKeNY3`8n_iRYL{?u7|m4IC7?LJnD zF31nNxd@r*>&Nc$vjpU7Z*QFxx0^eh2YY5U*z7LZ8tOp$yU#O2Hmc{rsgw^+!GfdG<9R)7E`zkW@UA#A(Mi*a2hvZ8w5bs2#C%Ldza z0Wvx=0FtT`009V5L6=EtNbYZ$7`qHWQe6fh02%x9A2lTFJ_JJsLk2_UXk_3%q}=lm z6jc<}{D;iQ5M&54Zv=5DvBzKDvD}u5kZ$hmqC{)^>z-142H~K0cGeK zYxAa!5_15y`85FmA8cn?xHhSwlX zV0a7C6o!`|O=5Tl(lmxwAhW>m24q$kUVzLJLp;c=F+_vR14Asxyf8$9%o9T#$h7OXyG0VFs07>Zp1R(iU3>kt9nJPmtTjnSqrVmXe6F>k` zIBi#P4Uv8;UMar98Fw*Bwf*bF$RyR6#@u?OrZK-~r!ntTO21GxV%4|Pn7_nQ2=;=W zSPH>iP)E?Br00087NklbDcX{%<1N?-nskZ zJMbmky!&*{xlS(UTBX$vKjAcMwadwK*31obyIs4}=^S{Tw^ylDwk^x5$TL)NBk_Iz zhmH^1wqJX_-m~kvUU>C?kilTETP~N6>E(#~X!)-+old{$_0ViK-`Hpa5EdEjcKd`P z!j}IQ#E+07#_RX{_bgHZknwnYM1MRK|555(k%Hl=R;xV*Ae1g{wOZX#XZYerI+;w~ zDQ&s|$Z$A3*R_CVrDKJ*(P-QTAfwUfBI}7dzpq}e-vA`?9|lM)+yMfR^a_XwNr(`i zW|>Q!XOFD+MiFw&W*LC|i2-CjWe_1z6GR9iWa+dUqzs;AVnr1o09l+mVNpedAVLr! znZCUvWfH!JpoXA^poXA^WD-CP!LtlkpkUfX${=NsGF$>k8KewXz+jd^${=NsGF$>k z8G}=X780J)BDy=Ch|zYIVHmW`@~qWrT^SD&VlW8fL82JOgTyh623dq*EJzZDksxUp z#(^xuFbX6KhA|*nF^mA=!O$Lr7ei~1RWP&#SrtP|kaaM$16dbCD-aPF+JK0{&;mpx zhVmeyF_Z?$14CJmyfBmm$rD34ki0RJ0@(zHG9a76Py%F=7}A4m8bfN3A~2){DGEbM zkRmap11TCqDi9ekqydoyLkbX?Fr)xsgWx%6*^@<$8FOn!={U|8&v>+5W5$CJeJ?;_ zasUBHdNLtG5Ftw=1l=-YvkX80l9DxO4mn>`kunQYh91h$q&nK98g0x=rI|M7Xmn3o zAVeG8V=IK%RtT)HV6%+KW*K3n4YyOFeA=g7M7DI@4S;p|ryr(1Y5Rwl#O+i#e^k+S a!<}D^H{dx)7DpHW0000I@ytX`IZ{@Yp#;^Kyb6|aNW+_QPDdzRtT(G^V>3m8_#xX8ib)G5#1M16NfT^F;F#@jwF@JYD@< J);T3K0RS0iA!+~s diff --git a/src/main/res/drawable-xxhdpi/tab_unselected_focused_shadow.9.png b/src/main/res/drawable-xxhdpi/tab_unselected_focused_shadow.9.png deleted file mode 100755 index cf9c97a2edc31c40e4a2d20e9f1b6cf51f09dc8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102 zcmeAS@N?(olHy`uVBq!ia0vp^96-#+!3HFS!eXZZDP2z&#}J9|FVdQ&MBb@0J|m| AIsgCw diff --git a/src/main/res/drawable-xxhdpi/tab_unselected_shadow.9.png b/src/main/res/drawable-xxhdpi/tab_unselected_shadow.9.png deleted file mode 100755 index 7b5c16da0eb84eab9fe3f422b447c4324e2c9f0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^96-#+!3HFS!eXZZDN|1u#}J9| - - - \ No newline at end of file diff --git a/src/main/res/drawable/btn_cab_done_shadow.xml b/src/main/res/drawable/btn_cab_done_shadow.xml deleted file mode 100755 index 4dd67cf6..00000000 --- a/src/main/res/drawable/btn_cab_done_shadow.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - diff --git a/src/main/res/drawable/progress_horizontal_shadow.xml b/src/main/res/drawable/progress_horizontal_shadow.xml deleted file mode 100755 index 0e2ecfa1..00000000 --- a/src/main/res/drawable/progress_horizontal_shadow.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - - - - - - - - - - - diff --git a/src/main/res/drawable/selectable_background_shadow.xml b/src/main/res/drawable/selectable_background_shadow.xml deleted file mode 100755 index 6feb6539..00000000 --- a/src/main/res/drawable/selectable_background_shadow.xml +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/main/res/drawable/spinner_background_ab_shadow.xml b/src/main/res/drawable/spinner_background_ab_shadow.xml deleted file mode 100755 index 5ddd9ec0..00000000 --- a/src/main/res/drawable/spinner_background_ab_shadow.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - diff --git a/src/main/res/drawable/tab_indicator_ab_shadow.xml b/src/main/res/drawable/tab_indicator_ab_shadow.xml deleted file mode 100755 index e58ed862..00000000 --- a/src/main/res/drawable/tab_indicator_ab_shadow.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/res/layout/main.xml b/src/main/res/layout/main.xml deleted file mode 100644 index a4e6a136..00000000 --- a/src/main/res/layout/main.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - diff --git a/src/main/res/values/colors.xml b/src/main/res/values/colors.xml index 95094338..311f4003 100644 --- a/src/main/res/values/colors.xml +++ b/src/main/res/values/colors.xml @@ -2,16 +2,6 @@ - #ff5e5e5e - #17170443 - #FFFFFF - #000000 - #646464 - #c8c8c8 - #323232 - #00000000 - #FF555555 - #388E3C #90A4AE #607D8B diff --git a/src/main/res/values/ids.xml b/src/main/res/values/ids.xml deleted file mode 100644 index 925ac058..00000000 --- a/src/main/res/values/ids.xml +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala index 2b170f54..6869bfa1 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksSettings.scala @@ -15,7 +15,6 @@ class ShadowsocksSettings extends PreferenceFragment { if (ShadowsocksApplication.isRoot) activity.handler.post(() => { activity.deattachService() activity.attachService() - true }) else false) findPreference("recovery").setOnPreferenceClickListener((preference: Preference) => { ShadowsocksApplication.track(Shadowsocks.TAG, "reset") From f679772d60da1341f2f62675c0bfe75baca39200 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 08:37:23 +0800 Subject: [PATCH 06/10] Don't show circular progress for FAB when resetting --- src/main/scala/com/github/shadowsocks/Shadowsocks.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index c2e19700..2142c5f6 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -710,7 +710,7 @@ class Shadowsocks fab.setBackgroundTintList(greyTint) fab.setImageResource(R.drawable.ic_cloud_queue) fab.setEnabled(false) - fabProgressCircle.show() + if (state == State.CONNECTED) fabProgressCircle.show() // ignore for stopped setPreferenceEnabled(enabled = false) } state = s From cdb9ebe56eade078822b2254787deb4931e0b605 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 09:00:08 +0800 Subject: [PATCH 07/10] Fix menu in AppManager --- .../com/github/shadowsocks/AppManager.scala | 31 +++++++++---------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala index 5c20fd95..aca7aca4 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -42,16 +42,17 @@ package com.github.shadowsocks import java.io.{ByteArrayInputStream, ByteArrayOutputStream, InputStream} import android.app.ProgressDialog -import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} import android.content.pm.PackageManager +import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} import android.graphics.{Bitmap, PixelFormat} import android.os.{Bundle, Handler} import android.preference.PreferenceManager import android.support.v7.app.AppCompatActivity import android.support.v7.widget.Toolbar +import android.support.v7.widget.Toolbar.OnMenuItemClickListener import android.view.View.OnClickListener import android.view.ViewGroup.LayoutParams -import android.view.{Menu, MenuItem, View, ViewGroup, WindowManager} +import android.view.{MenuItem, View, ViewGroup, WindowManager} import android.widget.AbsListView.OnScrollListener import android.widget.CompoundButton.OnCheckedChangeListener import android.widget._ @@ -99,7 +100,8 @@ object AppManager { } } -class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnClickListener { +class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnClickListener + with OnMenuItemClickListener { val MSG_LOAD_START = 1 val MSG_LOAD_FINISH = 2 @@ -115,8 +117,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC var appsLoaded: Boolean = false def loadApps(context: Context): Array[ProxiedApp] = { - val prefs = PreferenceManager.getDefaultSharedPreferences(context) - val proxiedAppString = prefs.getString(Key.proxied, "") + val proxiedAppString = ShadowsocksApplication.settings.getString(Key.proxied, "") val proxiedApps = proxiedAppString.split('|').sortWith(_ < _) import scala.collection.JavaConversions._ @@ -218,7 +219,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC } } - protected override def onOptionsItemSelected(item: MenuItem): Boolean = { + def onMenuItemClick(item: MenuItem): Boolean = { val clipboard = getSystemService(Context.CLIPBOARD_SERVICE).asInstanceOf[ClipboardManager] val prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext) item.getItemId match { @@ -256,12 +257,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC Toast.makeText(this, R.string.action_import_err, Toast.LENGTH_SHORT).show() return false } - super.onOptionsItemSelected(item) - } - - protected override def onCreateOptionsMenu(menu: Menu): Boolean = { - getMenuInflater.inflate(R.menu.app_manager_menu, menu) - super.onCreateOptionsMenu(menu) + false } protected override def onCreate(savedInstanceState: Bundle) { @@ -277,6 +273,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC val intent = getParentActivityIntent if (intent == null) finish else navigateUpTo(intent) }) + toolbar.inflateMenu(R.menu.app_manager_menu) + toolbar.setOnMenuItemClickListener(this) + this.overlay = View.inflate(this, R.layout.overlay, null).asInstanceOf[TextView] getWindowManager.addView(overlay, new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, @@ -291,10 +290,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC ImageLoader.getInstance().init(config) val bypassSwitch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch] - val prefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext) bypassSwitch.setOnCheckedChangeListener((button: CompoundButton, checked: Boolean) => - prefs.edit().putBoolean(Key.isBypassApps, checked).apply()) - bypassSwitch.setChecked(prefs.getBoolean(Key.isBypassApps, false)) + ShadowsocksApplication.settings.edit().putBoolean(Key.isBypassApps, checked).apply()) + bypassSwitch.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isBypassApps, false)) appListView = findViewById(R.id.applistview).asInstanceOf[ListView] } @@ -310,14 +308,13 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC def saveAppSettings(context: Context) { if (apps == null) return - val prefs = PreferenceManager.getDefaultSharedPreferences(this) val proxiedApps = new StringBuilder apps.foreach(app => if (app.proxied) { proxiedApps ++= app.uid.toString proxiedApps += '|' }) - val edit: SharedPreferences.Editor = prefs.edit + val edit: SharedPreferences.Editor = ShadowsocksApplication.settings.edit edit.putString(Key.proxied, proxiedApps.toString()) edit.apply } From e6cf38e6ff3e2765e9da35f53481c149f5ebbade Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 09:12:05 +0800 Subject: [PATCH 08/10] Bugfix --- src/main/scala/com/github/shadowsocks/Shadowsocks.scala | 1 - .../com/github/shadowsocks/ShadowsocksApplication.scala | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index 2142c5f6..a6a061ce 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -457,7 +457,6 @@ class Shadowsocks case None => // removed val profiles = ShadowsocksApplication.profileManager.getAllProfiles.getOrElse(List[Profile]()) ShadowsocksApplication.profileId(if (profiles.isEmpty) -1 else profiles.head.id) - ShadowsocksApplication.currentProfile getOrElse currentProfile } updatePreferenceScreen() diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala index d507b88f..f63114e0 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksApplication.scala @@ -77,7 +77,10 @@ object ShadowsocksApplication { .build()) def profileId = settings.getInt(Key.profileId, -1) - def profileId(i: Int) = settings.edit.putInt(Key.profileId, i).apply + def profileId(i: Int) = { + settings.edit.putInt(Key.profileId, i).apply + profileManager.load(i) + } def proxy = settings.getString(Key.proxy, "") def currentProfile = profileManager.getProfile(profileId) } From d70480a85087d01cb039ba0049e808d2b7264829 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 09:32:00 +0800 Subject: [PATCH 09/10] Remove ProgressDialog in AppManager --- src/main/res/layout/layout_apps.xml | 17 +++-- .../com/github/shadowsocks/AppManager.scala | 67 +++++++------------ .../com/github/shadowsocks/utils/Utils.scala | 11 +++ 3 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/main/res/layout/layout_apps.xml b/src/main/res/layout/layout_apps.xml index f84d4bbd..0d75f23d 100644 --- a/src/main/res/layout/layout_apps.xml +++ b/src/main/res/layout/layout_apps.xml @@ -32,8 +32,17 @@ android:layout_marginEnd="6dp" android:layout_marginRight="6dp"/> - + + + + \ 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 aca7aca4..ebdc091e 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -41,7 +41,6 @@ package com.github.shadowsocks import java.io.{ByteArrayInputStream, ByteArrayOutputStream, InputStream} -import android.app.ProgressDialog import android.content.pm.PackageManager import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} import android.graphics.{Bitmap, PixelFormat} @@ -112,7 +111,6 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC var apps: Array[ProxiedApp] = null var appListView: ListView = null var overlay: TextView = null - var progressDialog: ProgressDialog = null var adapter: ListAdapter = null var appsLoaded: Boolean = false @@ -295,14 +293,37 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC bypassSwitch.setChecked(ShadowsocksApplication.settings.getBoolean(Key.isBypassApps, false)) appListView = findViewById(R.id.applistview).asInstanceOf[ListView] + appListView.setOnScrollListener(new AbsListView.OnScrollListener { + var visible = false + def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, + totalItemCount: Int) { + if (visible) { + val name: String = apps(firstVisibleItem).name + if (name != null && name.length > 1) { + overlay.setText(apps(firstVisibleItem).name.substring(0, 1)) + } else { + overlay.setText("*") + } + overlay.setVisibility(View.VISIBLE) + } + } + def onScrollStateChanged(view: AbsListView, scrollState: Int) { + visible = true + if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) { + overlay.setVisibility(View.INVISIBLE) + } + } + }) } protected override def onResume() { super.onResume() Future { - handler.post(loadStartRunnable) if (!appsLoaded) loadApps() - handler.post(loadFinishRunnable) + handler.post(() => { + appListView.setAdapter(adapter) + Utils.crossFade(AppManager.this, findViewById(R.id.loading), appListView) + }) } } @@ -319,44 +340,6 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC edit.apply } - val loadStartRunnable = new Runnable { - override def run() { - progressDialog = ProgressDialog - .show(AppManager.this, "", getString(R.string.loading), true, true) - } - } - - val loadFinishRunnable = new Runnable { - override def run() = { - appListView.setAdapter(adapter) - appListView.setOnScrollListener(new AbsListView.OnScrollListener { - def onScroll(view: AbsListView, firstVisibleItem: Int, visibleItemCount: Int, - totalItemCount: Int) { - if (visible) { - val name: String = apps(firstVisibleItem).name - if (name != null && name.length > 1) { - overlay.setText(apps(firstVisibleItem).name.substring(0, 1)) - } else { - overlay.setText("*") - } - overlay.setVisibility(View.VISIBLE) - } - } - def onScrollStateChanged(view: AbsListView, scrollState: Int) { - visible = true - if (scrollState == OnScrollListener.SCROLL_STATE_IDLE) { - overlay.setVisibility(View.INVISIBLE) - } - } - var visible = false - }) - if (progressDialog != null) { - progressDialog.dismiss() - progressDialog = null - } - } - } - var handler: Handler = null class AppIconDownloader(context: Context, connectTimeout: Int, readTimeout: Int) diff --git a/src/main/scala/com/github/shadowsocks/utils/Utils.scala b/src/main/scala/com/github/shadowsocks/utils/Utils.scala index e80012a4..f2d5c981 100644 --- a/src/main/scala/com/github/shadowsocks/utils/Utils.scala +++ b/src/main/scala/com/github/shadowsocks/utils/Utils.scala @@ -42,6 +42,7 @@ import java.io._ import java.net._ import java.security.MessageDigest +import android.animation.{AnimatorListenerAdapter, Animator} import android.app.ActivityManager import android.content.pm.{ApplicationInfo, PackageManager} import android.content.{Context, Intent} @@ -142,6 +143,16 @@ object Utils { toast } + def crossFade(context: Context, from: View, to: View) { + def shortAnimTime = context.getResources.getInteger(android.R.integer.config_shortAnimTime) + to.setAlpha(0) + to.setVisibility(View.VISIBLE) + to.animate().alpha(1).setDuration(shortAnimTime) + from.animate().alpha(0).setDuration(shortAnimTime).setListener(new AnimatorListenerAdapter { + override def onAnimationEnd(animation: Animator) = from.setVisibility(View.GONE) + }) + } + // Blocked > 3 seconds def toggleAirplaneMode(context: Context) { if (Build.VERSION.SDK_INT >= 17) { From d71c8dce2e0cdc37fb68b295d246bc9862522c71 Mon Sep 17 00:00:00 2001 From: Mygod Date: Mon, 9 Nov 2015 09:47:38 +0800 Subject: [PATCH 10/10] This commit seems to be able to speed up AppManager on second launch noticeably. P.S. Android 6.0, 200+ apps installed. --- build.sbt | 1 - .../com/github/shadowsocks/AppManager.scala | 52 +++---------------- .../com/github/shadowsocks/Shadowsocks.scala | 26 +--------- 3 files changed, 9 insertions(+), 70 deletions(-) diff --git a/build.sbt b/build.sbt index 5327bbdc..d2c8a1a9 100644 --- a/build.sbt +++ b/build.sbt @@ -35,7 +35,6 @@ libraryDependencies ++= Seq( "com.google.android.gms" % "play-services-analytics" % "8.1.0", "com.android.support" % "design" % "23.1.0", "com.github.jorgecastilloprz" % "fabprogresscircle" % "1.01", - "com.nostra13.universalimageloader" % "universal-image-loader" % "1.9.4", "com.j256.ormlite" % "ormlite-core" % "4.48", "com.j256.ormlite" % "ormlite-android" % "4.48" ) diff --git a/src/main/scala/com/github/shadowsocks/AppManager.scala b/src/main/scala/com/github/shadowsocks/AppManager.scala index ebdc091e..4ad4bfe6 100644 --- a/src/main/scala/com/github/shadowsocks/AppManager.scala +++ b/src/main/scala/com/github/shadowsocks/AppManager.scala @@ -39,11 +39,10 @@ package com.github.shadowsocks -import java.io.{ByteArrayInputStream, ByteArrayOutputStream, InputStream} - import android.content.pm.PackageManager import android.content.{ClipData, ClipboardManager, Context, SharedPreferences} -import android.graphics.{Bitmap, PixelFormat} +import android.graphics.PixelFormat +import android.graphics.drawable.Drawable import android.os.{Bundle, Handler} import android.preference.PreferenceManager import android.support.v7.app.AppCompatActivity @@ -55,16 +54,13 @@ import android.view.{MenuItem, View, ViewGroup, WindowManager} import android.widget.AbsListView.OnScrollListener import android.widget.CompoundButton.OnCheckedChangeListener import android.widget._ -import com.github.shadowsocks.utils.{Key, Scheme, Utils} -import com.nostra13.universalimageloader.core.display.FadeInBitmapDisplayer -import com.nostra13.universalimageloader.core.download.BaseImageDownloader -import com.nostra13.universalimageloader.core.{DisplayImageOptions, ImageLoader, ImageLoaderConfiguration} +import com.github.shadowsocks.utils.{Key, Utils} import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future import scala.language.implicitConversions -case class ProxiedApp(uid: Int, name: String, packageName: String, var proxied: Boolean) +case class ProxiedApp(uid: Int, name: String, packageName: String, icon: Drawable, var proxied: Boolean) class ObjectArrayTools[T <: AnyRef](a: Array[T]) { def binarySearch(key: T) = { @@ -94,7 +90,7 @@ object AppManager { val name = packageManager.getApplicationLabel(a).toString val packageName = a.packageName val proxied = proxiedApps.binarySearch(userName) >= 0 - new ProxiedApp(uid, name, packageName, proxied) + new ProxiedApp(uid, name, packageName, null, proxied) }.toArray } } @@ -132,7 +128,7 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC val name = packageManager.getApplicationLabel(a).toString val packageName = a.packageName val proxied = (proxiedApps binarySearch userName) >= 0 - new ProxiedApp(uid, name, packageName, proxied) + new ProxiedApp(uid, name, packageName, a.loadIcon(packageManager), proxied) }.toArray } @@ -167,19 +163,9 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC } val app: ProxiedApp = apps(position) - val options = - new DisplayImageOptions.Builder() - .showStubImage(STUB) - .showImageForEmptyUri(STUB) - .showImageOnFail(STUB) - .resetViewBeforeLoading() - .cacheInMemory() - .cacheOnDisc() - .displayer(new FadeInBitmapDisplayer(300)) - .build() - ImageLoader.getInstance().displayImage(Scheme.APP + app.packageName, entry.icon, options) entry.text.setText(app.name) + entry.icon.setImageDrawable(app.icon) val switch = entry.switch switch.setTag(app) switch.setChecked(app.proxied) @@ -281,12 +267,6 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC 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) - val bypassSwitch = findViewById(R.id.bypassSwitch).asInstanceOf[Switch] bypassSwitch.setOnCheckedChangeListener((button: CompoundButton, checked: Boolean) => ShadowsocksApplication.settings.edit().putBoolean(Key.isBypassApps, checked).apply()) @@ -342,22 +322,4 @@ class AppManager extends AppCompatActivity with OnCheckedChangeListener with OnC var handler: Handler = null - 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 packageName = imageUri.substring(Scheme.APP.length) - val drawable = Utils.getAppIcon(getBaseContext, packageName) - val bitmap = Utils.drawableToBitmap(drawable) - - val os = new ByteArrayOutputStream() - bitmap.compress(Bitmap.CompressFormat.PNG, 100, os) - new ByteArrayInputStream(os.toByteArray) - } - } - } diff --git a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala index a6a061ce..6c290b9d 100644 --- a/src/main/scala/com/github/shadowsocks/Shadowsocks.scala +++ b/src/main/scala/com/github/shadowsocks/Shadowsocks.scala @@ -38,7 +38,7 @@ */ package com.github.shadowsocks -import java.io.{ByteArrayInputStream, ByteArrayOutputStream, FileOutputStream, IOException, InputStream, OutputStream} +import java.io.{FileOutputStream, IOException, InputStream, OutputStream} import java.util import java.util.Locale @@ -46,7 +46,7 @@ import android.app.backup.BackupManager import android.app.{Activity, AlertDialog, ProgressDialog} import android.content._ import android.content.res.AssetManager -import android.graphics.{Bitmap, Color, Typeface} +import android.graphics.Typeface import android.net.{Uri, VpnService} import android.os._ import android.preference.{Preference, SwitchPreference} @@ -64,33 +64,11 @@ import com.github.shadowsocks.database._ import com.github.shadowsocks.preferences.{DropDownPreference, PasswordEditTextPreference, SummaryEditTextPreference} import com.github.shadowsocks.utils._ import com.google.android.gms.ads.{AdRequest, AdSize, AdView} -import com.nostra13.universalimageloader.core.download.BaseImageDownloader import scala.collection.mutable.ArrayBuffer import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.Future -class ProfileIconDownloader(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 text = imageUri.substring(Scheme.PROFILE.length) - val size = Utils.dpToPx(context, 16) - val idx = text.getBytes.last % 6 - val color = Seq(Color.MAGENTA, Color.GREEN, Color.YELLOW, Color.BLUE, Color.DKGRAY, Color.CYAN)( - idx) - val bitmap = Utils.getBitmap(text, size, size, color) - - val os = new ByteArrayOutputStream() - bitmap.compress(Bitmap.CompressFormat.PNG, 100, os) - new ByteArrayInputStream(os.toByteArray) - } -} - object Typefaces { def get(c: Context, assetPath: String): Typeface = { cache synchronized {