Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ded9d3d37 | ||
|
|
88274fb732 | ||
|
|
36e6cfbe59 | ||
|
|
f05761ac4d | ||
|
|
a33efea2b5 | ||
|
|
b2e6639901 | ||
|
|
db74988190 | ||
|
|
9a43c78e7b | ||
|
|
e915a4221d | ||
|
|
a40f87f492 | ||
|
|
56f4a36a18 | ||
|
|
6db818cc46 | ||
|
|
c86b68c0e6 | ||
|
|
56728a3f40 | ||
|
|
cc070223b4 | ||
|
|
0335d67dba | ||
|
|
0d0c2d59de | ||
|
|
16ee0edea8 | ||
|
|
e03c34aa19 | ||
|
|
db011afcc0 | ||
|
|
ebe4d6fd0c | ||
|
|
cb9356e5e0 | ||
|
|
c55fd2dd65 | ||
|
|
3c3406d3c7 | ||
|
|
e603700587 | ||
|
|
040a6a2815 | ||
|
|
0b9b0a91c8 |
+2
-3
@@ -3,9 +3,8 @@
|
||||
Cannot connect to server:
|
||||
|
||||
1. Stop battery saver if it's active;
|
||||
2. If an upgrade breaks anything, do a manual reset first by pressing Reset at the end of the list;
|
||||
3. Check your config;
|
||||
4. Wipe app data.
|
||||
2. Check your config;
|
||||
3. Wipe app data.
|
||||
|
||||
Crash: [Submit an issue](https://github.com/shadowsocks/shadowsocks-android/issues/new) with logcat attached, or submit a crash report to Google Play. Then, try wiping app data.
|
||||
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
### Решение проблем
|
||||
|
||||
Не получается подключиться к серверу:
|
||||
|
||||
1. Выключите режим энергосбережения, если он активен;
|
||||
2. Проверьте настройки;
|
||||
3. Сотрите данные приложения.
|
||||
|
||||
Не работает: [Добавьте отчет](https://github.com/shadowsocks/shadowsocks-android/issues/new) прикрепив лог (logcat), или отправьте отзыв в Google Play. Затем попробуйте стереть данные приложения.
|
||||
|
||||
### Как добавить виджет и/или переключать профиль на основании состояния сети?
|
||||
|
||||
Использйте интеграцию с [Tasker](http://tasker.dinglisch.net/).
|
||||
|
||||
### Как добавить QR код из локальной галереи?
|
||||
|
||||
Отсканируйте его при помощи стороннего сканера, например [QuickMark Barcode Scanner](https://play.google.com/store/apps/details?id=tw.com.quickmark) и нажмите на `ss` ссылку.
|
||||
|
||||
|
||||
### Почему режим NAT более не поддерживается?
|
||||
|
||||
1. Требуются ROOT права;
|
||||
2. Нет поддержки IPv6;
|
||||
3. Нет поддержки UDP relay.
|
||||
|
||||
### Как убрать восклицательный знак когда используется режим VPN?
|
||||
|
||||
Восклицательный знак на значке Wi-Fi/Сотовой связи появляется, потому что система не может подключиться к portal-серверу (по-умолчанию к `clients3.google.com`) без VPN подключения. Чтобы убрать его, следуйте инструкциям в [этом топике](https://www.noisyfox.cn/45.html). (на упрощенном китайском)
|
||||
|
||||
### Почему мой ROM не поддерживается?
|
||||
|
||||
1. Некоторые ROM используют неправильную реализацию службы VPN, особенно IPv6;
|
||||
2. Некоторые ROM используют агрессивную (или так называемую неправильную) фоновую службу с ошибочной политикой остановки;
|
||||
3. Если вы используете фреймворк Xposed и/или приложения для энергосбережения, вероятно наше приложение не будет нормально работать с ними.
|
||||
|
||||
* Иправления для MIUI: [#772](https://github.com/shadowsocks/shadowsocks-android/issues/772)
|
||||
* Иправления для Huawei: [#1091 (comment)](https://github.com/shadowsocks/shadowsocks-android/issues/1091#issuecomment-276949836)
|
||||
* Вызванные из-за Xposed: [#1414](https://github.com/shadowsocks/shadowsocks-android/issues/1414)
|
||||
* Samsung и/или Brevent: [#1410](https://github.com/shadowsocks/shadowsocks-android/issues/1410)
|
||||
* Не устанавливайте это приложение на SD карту, из-за проблем с разрешениями: [#1124 (comment)](https://github.com/shadowsocks/shadowsocks-android/issues/1124#issuecomment-307556453)
|
||||
|
||||
### Как приостановить службу Shadowsocks?
|
||||
|
||||
* Для Android 7.0+: Используйте переключатель в быстрых настройках;
|
||||
* Используйте интеграцию с Tasker;
|
||||
* Добавьте профиль c выбранными приложениями, которые будут работать через Shadowsocks прокси, выключив обходной режим.
|
||||
|
||||
### Почему Shadowsocks потребляет так много энергии на Android 5.0+?
|
||||
|
||||
Так как Shadowsocks работает со всем траффиком устройства, заряд батареи используемый другими приложениями также считается за тот, что использует Shadowsocks. Таким образом использование батареи Shadowsocks'ом равен сумме всей активности устройства в сети. Shadowsocks сам по себе в общем-то является приложением связанного процесса ввода/вывода на современных Android устройствах, которое, ожидаемо, не потребляет значительного количества энергии.
|
||||
|
||||
Так что если вы заметите значительное увеличение потребляемой энергии после того, как вы использовали Shadowsocks, это скорее всего вызванно другими приложениями. Например, сервисы Google Play могут потреблять больше энергии после того, как подключатся к Google, и т.д.
|
||||
|
||||
Больше информации: https://kb.adguard.com/en/android/solving-problems/battery
|
||||
|
||||
### Оно прекрасно работает при Wi-Fi но не может подключиться через сотовую связь?
|
||||
|
||||
Разрешите этому app to consume background data in app settings.
|
||||
|
||||
### Почему требуется разрешение камере на устройствах младше Android 6.0?
|
||||
|
||||
Чтобы сканировать QR код через встроенный QR сканер.
|
||||
|
||||
Кстати, обновите уже свою версию Android.
|
||||
|
||||
### Как использовать режим Transproxy (прозрачный прокси)?
|
||||
|
||||
1. Установите [AFWall+](https://github.com/ukanth/afwall);
|
||||
2. Настройте пользовательский скрипт:
|
||||
```sh
|
||||
IP6TABLES=/system/bin/ip6tables
|
||||
IPTABLES=/system/bin/iptables
|
||||
ULIMIT=/system/bin/ulimit
|
||||
SHADOWSOCKS_UID=`dumpsys package com.github.shadowsocks | grep userId | cut -d= -f2 - | cut -d' ' -f1 -`
|
||||
PORT_DNS=5450
|
||||
PORT_TRANSPROXY=8200
|
||||
$ULIMIT -n 4096
|
||||
$IP6TABLES -F
|
||||
$IP6TABLES -A INPUT -j DROP
|
||||
$IP6TABLES -A OUTPUT -j DROP
|
||||
$IPTABLES -t nat -F OUTPUT
|
||||
$IPTABLES -t nat -A OUTPUT -o lo -j RETURN
|
||||
$IPTABLES -t nat -A OUTPUT -d 127.0.0.1 -j RETURN
|
||||
$IPTABLES -t nat -A OUTPUT -m owner --uid-owner $SHADOWSOCKS_UID -j RETURN
|
||||
$IPTABLES -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to-destination 127.0.0.1:$PORT_DNS
|
||||
$IPTABLES -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to-destination 127.0.0.1:$PORT_DNS
|
||||
$IPTABLES -t nat -A OUTPUT -p tcp -j DNAT --to-destination 127.0.0.1:$PORT_TRANSPROXY
|
||||
$IPTABLES -t nat -A OUTPUT -p udp -j DNAT --to-destination 127.0.0.1:$PORT_TRANSPROXY
|
||||
```
|
||||
3. Настройте пользовательский скрипт отключения:
|
||||
```sh
|
||||
IP6TABLES=/system/bin/ip6tables
|
||||
IPTABLES=/system/bin/iptables
|
||||
$IPTABLES -t nat -F OUTPUT
|
||||
$IP6TABLES -F
|
||||
```
|
||||
4. Убедитесь, что траффик для Shadowsocks разрешен;
|
||||
5. Запустите службу прозрачного прокси (transproxy) в Shadowsocks и включите брандмауэр.
|
||||
+1
-1
@@ -24,7 +24,7 @@ install:
|
||||
- popd
|
||||
- touch $HOME/.android/repositories.cfg
|
||||
- yes | sdkmanager
|
||||
"build-tools;27.0.2"
|
||||
"build-tools;27.0.3"
|
||||
ndk-bundle
|
||||
"platforms;android-27"
|
||||
>/dev/null
|
||||
|
||||
+2
-2
@@ -5,10 +5,10 @@ buildscript {
|
||||
kotlinVersion = '1.2.10'
|
||||
minSdkVersion = 19
|
||||
sdkVersion = 27
|
||||
buildToolsVersion = '27.0.2'
|
||||
buildToolsVersion = '27.0.3'
|
||||
supportLibraryVersion = '27.0.2'
|
||||
takisoftFixVersion = '27.0.2.0'
|
||||
playServicesVersion = '11.6.2'
|
||||
playServicesVersion = '11.8.0'
|
||||
junitVersion = '4.12'
|
||||
androidTestVersion = '1.0.1'
|
||||
androidEspressoVersion = '3.0.1'
|
||||
|
||||
Submodule core/src/main/jni/shadowsocks-libev updated: 0c3cf8beb3...cba94db423
+30
-25
@@ -56,33 +56,38 @@ export GOROOT=$DIR/go
|
||||
export GOPATH=$DIR
|
||||
export PATH=$GOROOT/bin:$GOPATH/bin:$PATH
|
||||
|
||||
echo "Get dependences for overture"
|
||||
go get -u github.com/tools/godep
|
||||
if [ ! -f "$TARGET/armeabi-v7a/liboverture.so" ] || [ ! -f "$TARGET/arm64-v8a/liboverture.so" ] ||
|
||||
[ ! -f "$TARGET/x86/liboverture.so" ]; then
|
||||
|
||||
pushd $GOPATH/src/github.com/shadowsocks/overture/main
|
||||
godep restore
|
||||
echo "Get dependences for overture"
|
||||
go get -u github.com/tools/godep
|
||||
|
||||
pushd $GOPATH/src/github.com/shadowsocks/overture/main
|
||||
godep restore
|
||||
|
||||
echo "Cross compile overture for arm"
|
||||
if [ ! -f "$TARGET/armeabi-v7a/liboverture.so" ]; then
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_ARM_CC GOOS=android GOARCH=arm GOARM=7 go build -ldflags="-s -w"
|
||||
try $ANDROID_ARM_STRIP main
|
||||
try mv main $TARGET/armeabi-v7a/liboverture.so
|
||||
fi
|
||||
|
||||
echo "Cross compile overture for arm64"
|
||||
if [ ! -f "$TARGET/arm64-v8a/liboverture.so" ]; then
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_ARM64_CC GOOS=android GOARCH=arm64 go build -ldflags="-s -w"
|
||||
try $ANDROID_ARM64_STRIP main
|
||||
try mv main $TARGET/arm64-v8a/liboverture.so
|
||||
fi
|
||||
|
||||
echo "Cross compile overture for x86"
|
||||
if [ ! -f "$TARGET/x86/liboverture.so" ]; then
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_X86_CC GOOS=android GOARCH=386 go build -ldflags="-s -w"
|
||||
try $ANDROID_X86_STRIP main
|
||||
try mv main $TARGET/x86/liboverture.so
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
echo "Cross compile overture for arm"
|
||||
if [ ! -f "$TARGET/armeabi-v7a/liboverture.so" ]; then
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_ARM_CC GOOS=android GOARCH=arm GOARM=7 go build -ldflags="-s -w"
|
||||
try $ANDROID_ARM_STRIP main
|
||||
try mv main $TARGET/armeabi-v7a/liboverture.so
|
||||
fi
|
||||
|
||||
echo "Cross compile overture for arm64"
|
||||
if [ ! -f "$TARGET/arm64-v8a/liboverture.so" ]; then
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_ARM64_CC GOOS=android GOARCH=arm64 go build -ldflags="-s -w"
|
||||
try $ANDROID_ARM64_STRIP main
|
||||
try mv main $TARGET/arm64-v8a/liboverture.so
|
||||
fi
|
||||
|
||||
echo "Cross compile overture for x86"
|
||||
if [ ! -f "$TARGET/x86/liboverture.so" ]; then
|
||||
try env CGO_ENABLED=1 CC=$ANDROID_X86_CC GOOS=android GOARCH=386 go build -ldflags="-s -w"
|
||||
try $ANDROID_X86_STRIP main
|
||||
try mv main $TARGET/x86/liboverture.so
|
||||
fi
|
||||
|
||||
popd
|
||||
|
||||
echo "Successfully build overture"
|
||||
|
||||
Submodule core/src/overture/src/github.com/shadowsocks/overture updated: 0743242de1...fae912215d
+3
-3
@@ -20,12 +20,12 @@ android {
|
||||
applicationId "com.github.shadowsocks"
|
||||
minSdkVersion rootProject.minSdkVersion
|
||||
targetSdkVersion rootProject.sdkVersion
|
||||
versionCode 202
|
||||
versionName "4.4.2"
|
||||
versionCode 204
|
||||
versionName "4.4.4"
|
||||
testApplicationId "com.github.shadowsocks.test"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
vectorDrawables.useSupportLibrary true
|
||||
resConfigs "fa", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
|
||||
resConfigs "fa", "fr", "ja", "ko", "ru", "zh-rCN", "zh-rTW"
|
||||
}
|
||||
buildTypes {
|
||||
debug {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<application
|
||||
android:name=".App"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
android:backupAgent=".ConfigBackupHelper"
|
||||
android:fullBackupContent="@xml/backup_descriptor"
|
||||
android:fullBackupOnly="true"
|
||||
|
||||
+3763
-3763
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,6 @@
|
||||
[proxy_all]
|
||||
|
||||
[bypass_list]
|
||||
0.0.0.0/8
|
||||
10.0.0.0/8
|
||||
100.64.0.0/10
|
||||
|
||||
+3763
-3763
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
package android.support.design.widget
|
||||
|
||||
import android.view.animation.Interpolator
|
||||
|
||||
object SnackbarAnimation {
|
||||
val FAST_OUT_SLOW_IN_INTERPOLATOR: Interpolator get() = AnimationUtils.FAST_OUT_SLOW_IN_INTERPOLATOR
|
||||
const val ANIMATION_DURATION = BaseTransientBottomBar.ANIMATION_DURATION.toLong()
|
||||
}
|
||||
@@ -61,7 +61,8 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
|
||||
private const val SELECTED_HOSTNAMES = "com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_HOSTNAMES"
|
||||
private const val SELECTED_URLS = "com.github.shadowsocks.acl.CustomRulesFragment.SELECTED_URLS"
|
||||
|
||||
private val PATTERN_DOMAIN = """(?<=^\(\^\|\\\.\)).*(?=\$$)""".toRegex()
|
||||
// unescaped: (?<=^(\(\^\|\\\.\)|\^\(\.\*\\\.\)\?)).*(?=\$$)
|
||||
private val PATTERN_DOMAIN = "(?<=^(\\(\\^\\|\\\\\\.\\)|\\^\\(\\.\\*\\\\\\.\\)\\?)).*(?=\\\$\$)".toRegex()
|
||||
}
|
||||
|
||||
private enum class Template {
|
||||
@@ -355,7 +356,7 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
|
||||
undoManager = UndoSnackbarManager(activity!!.findViewById(R.id.snackbar), adapter::undo)
|
||||
ItemTouchHelper(object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.START or ItemTouchHelper.END) {
|
||||
override fun getSwipeDirs(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int =
|
||||
if (isEnabled) super.getSwipeDirs(recyclerView, viewHolder) else 0
|
||||
if (isEnabled && selectedItems.isEmpty()) super.getSwipeDirs(recyclerView, viewHolder) else 0
|
||||
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) =
|
||||
adapter.remove(viewHolder.adapterPosition)
|
||||
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
|
||||
@@ -438,4 +439,9 @@ class CustomRulesFragment : ToolbarFragment(), Toolbar.OnMenuItemClickListener {
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun onDetach() {
|
||||
undoManager.flush()
|
||||
super.onDetach()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,13 @@ import com.github.shadowsocks.utils.Action
|
||||
import com.github.shadowsocks.utils.broadcastReceiver
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Android < 8 VPN: always invisible because of VPN notification/icon
|
||||
* Android 4.x other: always visible
|
||||
* Android 5-7 other: only invisible in (possibly unsecure) lockscreen
|
||||
* Android 8+: always visible due to system limitations
|
||||
* (user can choose to hide the notification in secure lockscreen or anywhere)
|
||||
*/
|
||||
class ServiceNotification(private val service: BaseService.Interface, profileName: String,
|
||||
channel: String, private val visible: Boolean = false) {
|
||||
private val keyGuard = (service as Context).getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
|
||||
package com.github.shadowsocks.bg
|
||||
|
||||
import android.app.KeyguardManager
|
||||
import android.content.Context
|
||||
import android.graphics.drawable.Icon
|
||||
import android.os.Build
|
||||
import android.service.quicksettings.Tile
|
||||
import android.support.annotation.RequiresApi
|
||||
import com.github.shadowsocks.App.Companion.app
|
||||
@@ -31,34 +32,35 @@ import com.github.shadowsocks.aidl.IShadowsocksService
|
||||
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
|
||||
import android.service.quicksettings.TileService as BaseTileService
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
@RequiresApi(24)
|
||||
class TileService : BaseTileService(), ShadowsocksConnection.Interface {
|
||||
private val iconIdle by lazy { Icon.createWithResource(this, R.drawable.ic_service_idle).setTint(0x79ffffff) }
|
||||
private val iconBusy by lazy { Icon.createWithResource(this, R.drawable.ic_service_busy) }
|
||||
private val iconConnected by lazy { Icon.createWithResource(this, R.drawable.ic_service_active) }
|
||||
private val keyguard by lazy { getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager }
|
||||
|
||||
override val serviceCallback: IShadowsocksServiceCallback.Stub by lazy {
|
||||
@RequiresApi(Build.VERSION_CODES.N)
|
||||
@RequiresApi(24)
|
||||
object : IShadowsocksServiceCallback.Stub() {
|
||||
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
|
||||
val tile = qsTile ?: return
|
||||
var label: String? = null
|
||||
when (state) {
|
||||
BaseService.STOPPED -> {
|
||||
tile.icon = iconIdle
|
||||
tile.label = getString(R.string.app_name)
|
||||
tile.state = Tile.STATE_INACTIVE
|
||||
}
|
||||
BaseService.CONNECTED -> {
|
||||
tile.icon = iconConnected
|
||||
tile.label = profileName ?: getString(R.string.app_name)
|
||||
if (!keyguard.isDeviceLocked) label = profileName
|
||||
tile.state = Tile.STATE_ACTIVE
|
||||
}
|
||||
else -> {
|
||||
tile.icon = iconBusy
|
||||
tile.label = getString(R.string.app_name)
|
||||
tile.state = Tile.STATE_UNAVAILABLE
|
||||
}
|
||||
}
|
||||
tile.label = label ?: getString(R.string.app_name)
|
||||
tile.updateTile()
|
||||
}
|
||||
override fun trafficUpdated(profileId: Int, txRate: Long, rxRate: Long, txTotal: Long, rxTotal: Long) { }
|
||||
|
||||
+2
@@ -103,6 +103,8 @@ class BottomSheetPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
|
||||
val activity = activity
|
||||
val dialog = BottomSheetDialog(activity!!, theme)
|
||||
val recycler = RecyclerView(activity)
|
||||
val padding = resources.getDimensionPixelOffset(R.dimen.bottom_sheet_padding)
|
||||
recycler.setPadding(0, padding, 0, padding)
|
||||
recycler.setHasFixedSize(true)
|
||||
recycler.layoutManager = LinearLayoutManager(activity)
|
||||
recycler.adapter = IconListAdapter(dialog)
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.support.annotation.AttrRes
|
||||
import android.support.v4.app.Fragment
|
||||
import android.support.v4.app.FragmentManager
|
||||
import android.support.v7.util.SortedList
|
||||
import android.view.accessibility.AccessibilityManager
|
||||
import android.util.TypedValue
|
||||
import com.github.shadowsocks.App.Companion.app
|
||||
import com.github.shadowsocks.JniHelper
|
||||
@@ -21,6 +22,11 @@ private val fieldChildFragmentManager by lazy {
|
||||
field
|
||||
}
|
||||
|
||||
fun isAccessibilityEnabled(context: Context): Boolean {
|
||||
val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
|
||||
return am.isEnabled()
|
||||
}
|
||||
|
||||
fun String.isNumericAddress() = JniHelper.parseNumericAddress(this) != null
|
||||
fun String.parseNumericAddress(): InetAddress? {
|
||||
val addr = JniHelper.parseNumericAddress(this)
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.widget
|
||||
|
||||
import android.content.Context
|
||||
import android.support.design.widget.CoordinatorLayout
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.github.shadowsocks.R
|
||||
|
||||
class BottomMarginBehavior : CoordinatorLayout.Behavior<View> {
|
||||
constructor() : super()
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean =
|
||||
dependency.id == R.id.stat // sorry I'm too lazy to write an attribute
|
||||
|
||||
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
|
||||
(child.layoutParams as CoordinatorLayout.LayoutParams).bottomMargin = (parent.height - dependency.y).toInt()
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Copyright (C) 2017 by Max Lv <max.c.lv@gmail.com> *
|
||||
* Copyright (C) 2017 by Mygod Studio <contact-shadowsocks-android@mygod.be> *
|
||||
* *
|
||||
* This program is free software: you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation, either version 3 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
* This program is distributed in the hope that it will be useful, *
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||
* GNU General Public License for more details. *
|
||||
* *
|
||||
* You should have received a copy of the GNU General Public License *
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||
* *
|
||||
*******************************************************************************/
|
||||
|
||||
package com.github.shadowsocks.widget
|
||||
|
||||
import android.animation.Animator
|
||||
import android.animation.AnimatorListenerAdapter
|
||||
import android.animation.ValueAnimator
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.support.design.widget.CoordinatorLayout
|
||||
import android.support.design.widget.SnackbarAnimation
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v4.view.ViewCompat
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
|
||||
import com.github.shadowsocks.utils.isAccessibilityEnabled
|
||||
|
||||
/**
|
||||
* Full credits go to: https://stackoverflow.com/a/35904421/2245107
|
||||
*/
|
||||
class MoveUpwardBehavior : CoordinatorLayout.Behavior<View> {
|
||||
constructor() : super()
|
||||
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
|
||||
|
||||
override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean =
|
||||
dependency is Snackbar.SnackbarLayout
|
||||
|
||||
override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean {
|
||||
val params = child.layoutParams
|
||||
params.height = parent.height - dependency.height
|
||||
child.layoutParams = params
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Based on BaseTransientBottomBar.animateViewOut (support lib 27.0.2).
|
||||
*/
|
||||
override fun onDependentViewRemoved(parent: CoordinatorLayout, child: View, dependency: View) {
|
||||
if (!isAccessibilityEnabled(parent.getContext())) {
|
||||
val animator = ValueAnimator()
|
||||
val start = child.height
|
||||
animator.setIntValues(start, parent.height)
|
||||
animator.interpolator = SnackbarAnimation.FAST_OUT_SLOW_IN_INTERPOLATOR
|
||||
animator.duration = SnackbarAnimation.ANIMATION_DURATION
|
||||
animator.addUpdateListener(object : ValueAnimator.AnimatorUpdateListener {
|
||||
override fun onAnimationUpdate(animator: ValueAnimator) {
|
||||
val currentValue = animator.animatedValue as Int
|
||||
val params = child.layoutParams
|
||||
params.height = currentValue
|
||||
child.layoutParams = params
|
||||
}
|
||||
})
|
||||
animator.start()
|
||||
} else {
|
||||
val params = child.layoutParams
|
||||
params.height = parent.height
|
||||
child.layoutParams = params
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,6 +108,7 @@ class ServiceButton @JvmOverloads constructor(context: Context, attrs: Attribute
|
||||
animationQueue.peekFirst()?.stop()
|
||||
animationQueue.clear()
|
||||
setImageDrawable(icon)
|
||||
icon.start() // force ensureAnimatorSet to be called so that stop() will work
|
||||
icon.stop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,82 +1,157 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent" android:layout_height="match_parent"
|
||||
tools:ignore="UnknownIdInLayout" android:clipChildren="false">
|
||||
<FrameLayout android:id="@+id/fragment_holder"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/stat"/>
|
||||
<LinearLayout android:id="@+id/stat"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:elevation="4dp"
|
||||
android:paddingStart="16dip"
|
||||
android:paddingEnd="16dip"
|
||||
android:paddingTop="16dip"
|
||||
android:paddingBottom="16dip"
|
||||
android:focusable="true"
|
||||
android:background="@drawable/background_stat"
|
||||
android:orientation="vertical"
|
||||
android:nextFocusRight="@+id/fab"
|
||||
android:layout_above="@+id/snackbar">
|
||||
<TextView android:id="@+id/status"
|
||||
android:textSize="16sp"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:ellipsize="marquee"
|
||||
android:paddingEnd="72dip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
tools:ignore="RtlSymmetry"/>
|
||||
<com.github.shadowsocks.widget.BoundedGridLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:bounded_width="288dp"
|
||||
app:columnCount="4">
|
||||
<TextView app:layout_column="0" style="@style/TextAppearance.AppCompat.Body2"
|
||||
android:ellipsize="marquee" android:text="@string/sent"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="end"/>
|
||||
<TextView app:layout_column="1" android:id="@+id/tx" android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary" android:ellipsize="marquee"
|
||||
android:layout_width="0dp" android:layout_height="wrap_content"
|
||||
app:layout_columnWeight="1" android:layout_gravity="fill_horizontal"/>
|
||||
<TextView app:layout_column="2" android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:ellipsize="marquee" android:text="▲"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"/>
|
||||
<TextView app:layout_column="3" android:id="@+id/txRate" android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary" android:ellipsize="marquee"
|
||||
android:layout_width="0dp" android:layout_height="wrap_content" app:layout_columnWeight="1"
|
||||
android:layout_gravity="fill_horizontal" android:gravity="end"/>
|
||||
<TextView app:layout_row="1" app:layout_column="0" style="@style/TextAppearance.AppCompat.Body2"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:gravity="end"
|
||||
android:ellipsize="marquee" android:text="@string/received"/>
|
||||
<TextView app:layout_row="1" app:layout_column="1" android:id="@+id/rx" android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary" android:ellipsize="marquee"
|
||||
android:layout_width="0dp" android:layout_height="wrap_content" app:layout_columnWeight="1"
|
||||
android:layout_gravity="fill_horizontal" />
|
||||
<TextView app:layout_row="1" app:layout_column="2" android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary" android:ellipsize="marquee"
|
||||
android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="▼"/>
|
||||
<TextView app:layout_row="1" app:layout_column="3" android:id="@+id/rxRate" android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary" android:ellipsize="marquee"
|
||||
android:layout_width="0dp" android:layout_height="wrap_content" app:layout_columnWeight="1"
|
||||
android:layout_gravity="fill_horizontal" android:gravity="end"/>
|
||||
</com.github.shadowsocks.widget.BoundedGridLayout>
|
||||
</LinearLayout>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/snackbar"
|
||||
android:background="@color/material_primary_700"
|
||||
android:clipChildren="false"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.github.shadowsocks.widget.MoveUpwardBehavior">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/fragment_holder"
|
||||
android:background="?android:attr/windowBackground"
|
||||
android:layout_above="@+id/stat"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/stat"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/background_stat"
|
||||
android:elevation="4dp"
|
||||
android:focusable="true"
|
||||
android:nextFocusRight="@+id/fab"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="16dip"
|
||||
android:paddingEnd="16dip"
|
||||
android:paddingStart="16dip"
|
||||
android:paddingTop="16dip"
|
||||
android:layout_alignParentBottom="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/status"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:paddingEnd="72dip"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="16sp"
|
||||
tools:ignore="RtlSymmetry"/>
|
||||
|
||||
<com.github.shadowsocks.widget.BoundedGridLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:bounded_width="288dp"
|
||||
app:columnCount="4">
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.AppCompat.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="end"
|
||||
android:text="@string/sent"
|
||||
app:layout_column="0"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tx"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:ellipsize="marquee"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_column="1"
|
||||
app:layout_columnWeight="1"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:text="▲"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_column="2"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/txRate"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="end"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_column="3"
|
||||
app:layout_columnWeight="1"/>
|
||||
|
||||
<TextView
|
||||
style="@style/TextAppearance.AppCompat.Body2"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="end"
|
||||
android:text="@string/received"
|
||||
app:layout_column="0"
|
||||
app:layout_row="1"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rx"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:ellipsize="marquee"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_column="1"
|
||||
app:layout_columnWeight="1"
|
||||
app:layout_row="1"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="marquee"
|
||||
android:text="▼"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_column="2"
|
||||
app:layout_row="1"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/rxRate"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="fill_horizontal"
|
||||
android:ellipsize="marquee"
|
||||
android:gravity="end"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="14sp"
|
||||
app:layout_column="3"
|
||||
app:layout_columnWeight="1"
|
||||
app:layout_row="1"/>
|
||||
</com.github.shadowsocks.widget.BoundedGridLayout>
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<!-- workaround for 0 elevation in disabled state -->
|
||||
<FrameLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignTop="@+id/stat"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginTop="@dimen/fab_margin_top"
|
||||
android:elevation="6dp">
|
||||
android:elevation="6dp"
|
||||
app:layout_anchor="@id/stat"
|
||||
app:layout_anchorGravity="top|end">
|
||||
<com.github.shadowsocks.widget.ServiceButton
|
||||
android:id="@+id/fab"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -86,9 +161,4 @@
|
||||
app:pressedTranslationZ="6dp"
|
||||
app:srcCompat="@drawable/ic_service_idle"/>
|
||||
</FrameLayout>
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:id="@+id/snackbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true" />
|
||||
</RelativeLayout>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
@@ -138,6 +138,7 @@
|
||||
|
||||
<string name="acl_rule_templates_generic">"URL/子网/域名 PCRE 正则表达式"</string>
|
||||
<string name="acl_rule_templates_domain">"域名及其子域名"</string>
|
||||
<string name="acl_rule_online_config">配置文件地址</string>
|
||||
|
||||
<!-- plugin -->
|
||||
<string name="plugin">"插件"</string>
|
||||
|
||||
@@ -133,6 +133,7 @@
|
||||
|
||||
<string name="acl_rule_templates_generic">"URL/子網路/主機名稱 PCRE 模式"</string>
|
||||
<string name="acl_rule_templates_domain">"網域及其所有子網域"</string>
|
||||
<string name="acl_rule_online_config">配置文件地址</string>
|
||||
|
||||
<!-- plugin -->
|
||||
<string name="plugin">"外掛程式"</string>
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
<string-array name="acl_rule_templates" translatable="false">
|
||||
<item>@string/acl_rule_templates_generic</item>
|
||||
<item>@string/acl_rule_templates_domain</item>
|
||||
<item>URL</item>
|
||||
<item>@string/acl_rule_online_config</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="service_modes">
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
<dimen name="profile_item_max_width">480dp</dimen>
|
||||
<dimen name="qr_code_size">250dp</dimen>
|
||||
<dimen name="profile_padding">8dp</dimen>
|
||||
<dimen name="bottom_sheet_padding">8dp</dimen>
|
||||
<dimen name="fab_margin_top">-44dp</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<string name="port_transproxy">Transproxy port</string>
|
||||
|
||||
<string name="remote_dns">Remote DNS</string>
|
||||
<string name="traffic" translatable="false">%s↑\t%s↓</string>
|
||||
<string name="traffic">%s↑\t%s↓</string>
|
||||
<string name="stat_summary">Sent: \t\t\t\t\t%3$s\t↑\t%1$s\nReceived: \t%4$s\t↓\t%2$s</string>
|
||||
<string name="speed">%s/s</string>
|
||||
<plurals name="bytes">
|
||||
@@ -139,6 +139,7 @@
|
||||
<string name="action_add_rule">Add rule(s)…</string>
|
||||
<string name="acl_rule_templates_generic">Subnet or Hostname PCRE pattern</string>
|
||||
<string name="acl_rule_templates_domain">Domain name and all its subdomain names</string>
|
||||
<string name="acl_rule_online_config">URL to online config</string>
|
||||
<string name="edit_rule">Edit rule</string>
|
||||
|
||||
<!-- plugin -->
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
apply from: 'gradle-mvn-push.gradle'
|
||||
|
||||
android {
|
||||
buildToolsVersion rootProject.buildToolsVersion
|
||||
compileSdkVersion rootProject.sdkVersion
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2013 Chris Banes
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
@SuppressWarnings(["GroovyUnusedDeclaration", "GrMethodMayBeStatic"])
|
||||
def isReleaseBuild() {
|
||||
return !android.defaultConfig.versionName.contains("SNAPSHOT")
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyUnusedDeclaration")
|
||||
def getReleaseRepositoryUrl() {
|
||||
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL
|
||||
: "https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyUnusedDeclaration")
|
||||
def getSnapshotRepositoryUrl() {
|
||||
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL
|
||||
: "https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyUnusedDeclaration")
|
||||
def getRepositoryUsername() {
|
||||
return hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : ""
|
||||
}
|
||||
|
||||
@SuppressWarnings("GroovyUnusedDeclaration")
|
||||
def getRepositoryPassword() {
|
||||
return hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : ""
|
||||
}
|
||||
|
||||
afterEvaluate { project ->
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
pom.groupId = 'com.github.shadowsocks'
|
||||
pom.artifactId = 'plugin'
|
||||
pom.version = android.defaultConfig.versionName
|
||||
|
||||
repository(url: getReleaseRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||
}
|
||||
snapshotRepository(url: getSnapshotRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
|
||||
}
|
||||
|
||||
pom.project {
|
||||
name 'Shadowsocks Plugin'
|
||||
packaging 'aar'
|
||||
description 'Shadowsocks Plugin'
|
||||
url 'https://github.com/shadowsocks/shadowsocks-android'
|
||||
|
||||
scm {
|
||||
url 'https://github.com/shadowsocks/shadowsocks-android.git'
|
||||
connection 'scm:git:git://github.com/shadowsocks/shadowsocks-android.git'
|
||||
developerConnection 'scm:git:git@github.com:shadowsocks/shadowsocks-android.git'
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name 'GPLv3'
|
||||
url 'https://www.gnu.org/licenses/gpl-3.0.html'
|
||||
distribution 'repo'
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id 'madeye'
|
||||
name 'Max Lv'
|
||||
url 'https://github.com/madeye'
|
||||
}
|
||||
developer {
|
||||
id 'Mygod'
|
||||
name 'Mygod Studio'
|
||||
url 'https://github.com/Mygod'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
android.libraryVariants.all { variant ->
|
||||
def javadocTask = task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
|
||||
description "Generates Javadoc for $variant.name."
|
||||
source = variant.javaCompiler.source
|
||||
ext.androidJar = project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||
classpath = files(variant.javaCompiler.classpath.files) + files(ext.androidJar)
|
||||
exclude '**/BuildConfig.java'
|
||||
exclude '**/R.java'
|
||||
}
|
||||
|
||||
javadocTask.dependsOn variant.javaCompiler
|
||||
|
||||
def jarJavadocTask = task("jar${variant.name.capitalize()}Javadoc", type: Jar) {
|
||||
description "Generate Javadoc Jar for $variant.name"
|
||||
classifier = 'javadoc'
|
||||
from javadocTask.destinationDir
|
||||
}
|
||||
|
||||
jarJavadocTask.dependsOn javadocTask
|
||||
artifacts.add('archives', jarJavadocTask)
|
||||
|
||||
def jarSourceTask = task("jar${variant.name.capitalize()}Sources", type: Jar) {
|
||||
description "Generates Java Sources for $variant.name."
|
||||
classifier = 'sources'
|
||||
from variant.javaCompiler.source
|
||||
}
|
||||
|
||||
jarSourceTask.dependsOn variant.javaCompiler
|
||||
artifacts.add('archives', jarSourceTask)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user