Commit 4a6dc804 authored by Mygod's avatar Mygod

Improve direct boot support for plugins

parent 85c23a12
...@@ -30,6 +30,7 @@ abstract class Plugin { ...@@ -30,6 +30,7 @@ abstract class Plugin {
open val defaultConfig: String? get() = null open val defaultConfig: String? get() = null
open val packageName: String get() = "" open val packageName: String get() = ""
open val trusted: Boolean get() = true open val trusted: Boolean get() = true
open val directBootAware: Boolean get() = true
override fun equals(other: Any?): Boolean { override fun equals(other: Any?): Boolean {
if (this === other) return true if (this === other) return true
......
...@@ -139,8 +139,11 @@ object PluginManager { ...@@ -139,8 +139,11 @@ object PluginManager {
} }
private fun initNative(configuration: PluginConfiguration): Pair<String, PluginOptions>? { private fun initNative(configuration: PluginConfiguration): Pair<String, PluginOptions>? {
val providers = app.packageManager.queryIntentContentProviders(Intent(PluginContract.ACTION_NATIVE_PLUGIN, val providers = app.packageManager.queryIntentContentProviders(
buildUri(configuration.selected)), PackageManager.GET_META_DATA) Intent(PluginContract.ACTION_NATIVE_PLUGIN, buildUri(configuration.selected)),
PackageManager.GET_META_DATA or
PackageManager.MATCH_DIRECT_BOOT_UNAWARE or PackageManager.MATCH_DIRECT_BOOT_AWARE
)
if (providers.isEmpty()) return null if (providers.isEmpty()) return null
val provider = providers.single().providerInfo val provider = providers.single().providerInfo
val options = configuration.getOptions { provider.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) } val options = configuration.getOptions { provider.loadString(PluginContract.METADATA_KEY_DEFAULT_CONFIG) }
......
...@@ -23,6 +23,7 @@ package com.github.shadowsocks.plugin ...@@ -23,6 +23,7 @@ package com.github.shadowsocks.plugin
import android.content.pm.ComponentInfo import android.content.pm.ComponentInfo
import android.content.pm.ResolveInfo import android.content.pm.ResolveInfo
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Build
import com.github.shadowsocks.Core import com.github.shadowsocks.Core
import com.github.shadowsocks.Core.app import com.github.shadowsocks.Core.app
import com.github.shadowsocks.plugin.PluginManager.loadString import com.github.shadowsocks.plugin.PluginManager.loadString
...@@ -52,4 +53,5 @@ abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin() ...@@ -52,4 +53,5 @@ abstract class ResolvedPlugin(protected val resolveInfo: ResolveInfo) : Plugin()
override val trusted by lazy { override val trusted by lazy {
Core.getPackageInfo(packageName).signaturesCompat.any(PluginManager.trustedSignatures::contains) Core.getPackageInfo(packageName).signaturesCompat.any(PluginManager.trustedSignatures::contains)
} }
override val directBootAware get() = Build.VERSION.SDK_INT < 24 || componentInfo.directBootAware
} }
...@@ -160,4 +160,5 @@ ...@@ -160,4 +160,5 @@
<string name="plugin_unknown">Unknown plugin %s</string> <string name="plugin_unknown">Unknown plugin %s</string>
<string name="plugin_untrusted">Warning: This plugin does not seem to come from a known trusted source.</string> <string name="plugin_untrusted">Warning: This plugin does not seem to come from a known trusted source.</string>
<string name="profile_plugin">Plugin: %s</string> <string name="profile_plugin">Plugin: %s</string>
<string name="plugin_auto_connect_unlock_only">This plugin might not work with Auto Connect</string>
</resources> </resources>
...@@ -33,7 +33,9 @@ import android.view.View ...@@ -33,7 +33,9 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.ImageView import android.widget.ImageView
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.widget.TooltipCompat
import androidx.core.os.bundleOf import androidx.core.os.bundleOf
import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.preference.PreferenceDialogFragmentCompat import androidx.preference.PreferenceDialogFragmentCompat
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
...@@ -54,6 +56,9 @@ class PluginPreferenceDialogFragment : PreferenceDialogFragmentCompat() { ...@@ -54,6 +56,9 @@ class PluginPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
private val text1 = view.findViewById<TextView>(android.R.id.text1) private val text1 = view.findViewById<TextView>(android.R.id.text1)
private val text2 = view.findViewById<TextView>(android.R.id.text2) private val text2 = view.findViewById<TextView>(android.R.id.text2)
private val icon = view.findViewById<ImageView>(android.R.id.icon) private val icon = view.findViewById<ImageView>(android.R.id.icon)
private val unlock = view.findViewById<View>(R.id.unlock).apply {
TooltipCompat.setTooltipText(this, getText(R.string.plugin_auto_connect_unlock_only))
}
init { init {
view.setOnClickListener(this) view.setOnClickListener(this)
...@@ -70,6 +75,7 @@ class PluginPreferenceDialogFragment : PreferenceDialogFragmentCompat() { ...@@ -70,6 +75,7 @@ class PluginPreferenceDialogFragment : PreferenceDialogFragmentCompat() {
text2.setTypeface(null, typeface) text2.setTypeface(null, typeface)
text2.isVisible = plugin.id.isNotEmpty() && label != plugin.id text2.isVisible = plugin.id.isNotEmpty() && label != plugin.id
icon.setImageDrawable(plugin.icon) icon.setImageDrawable(plugin.icon)
unlock.isGone = plugin.directBootAware || !DataStore.persistAcrossReboot
} }
override fun onClick(v: View?) { override fun onClick(v: View?) {
......
<vector android:autoMirrored="true" android:height="24dp"
android:tint="?attr/colorControlNormal"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6h1.9c0,-1.71 1.39,-3.1 3.1,-3.1 1.71,0 3.1,1.39 3.1,3.1v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM18,20L6,20L6,10h12v10z"/>
</vector>
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground" android:background="?android:attr/selectableItemBackground"
...@@ -30,4 +31,14 @@ ...@@ -30,4 +31,14 @@
android:maxLines="2" android:maxLines="2"
android:ellipsize="end"/> android:ellipsize="end"/>
</LinearLayout> </LinearLayout>
<ImageView
android:id="@+id/unlock"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:paddingStart="12dp"
android:src="@drawable/ic_action_lock_open"
android:tint="@color/material_amber_a700"
android:importantForAccessibility="no"
tools:ignore="RtlSymmetry" />
</LinearLayout> </LinearLayout>
...@@ -2,4 +2,5 @@ ...@@ -2,4 +2,5 @@
<resources> <resources>
<color name="background_selected">@color/material_primary_100</color> <color name="background_selected">@color/material_primary_100</color>
<color name="background_stat">@color/material_primary_300</color> <color name="background_stat">@color/material_primary_300</color>
<color name="material_amber_a700">#ffab00</color>
</resources> </resources>
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* Optional new metadata `com.github.shadowsocks.plugin.id.aliases` for plugin ID aliases; * Optional new metadata `com.github.shadowsocks.plugin.id.aliases` for plugin ID aliases;
(see doc for `PluginContract.METADATA_KEY_ID_ALIASES` and main documentation "Plugin ID Aliasing" for more information) (see doc for `PluginContract.METADATA_KEY_ID_ALIASES` and main documentation "Plugin ID Aliasing" for more information)
* Please use `android:path` instead of `android:pathPrefix`, sample code in documentations have been updated to reflect this recommendation. * Please use `android:path` instead of `android:pathPrefix`, sample code in documentations have been updated to reflect this recommendation.
* Added missing documentation regarding direct boot support.
Please add `android:directBootAware="true"` with proper support for your `provider` if possible.
* You can now use `android:resources` on `meta-data` tags. (main/host app update required, however, you should never use dynamic resources) * You can now use `android:resources` on `meta-data` tags. (main/host app update required, however, you should never use dynamic resources)
* Fix occasional crash in `AlertDialogFragment`. * Fix occasional crash in `AlertDialogFragment`.
* Translation updates. * Translation updates.
......
...@@ -84,6 +84,7 @@ Then add it to your manifest: ...@@ -84,6 +84,7 @@ Then add it to your manifest:
... ...
<provider android:name=".BinaryProvider" <provider android:name=".BinaryProvider"
android:exported="true" android:exported="true"
android:directBootAware="true"
android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER"> android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER">
<intent-filter> <intent-filter>
<action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/> <action android:name="com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN"/>
......
...@@ -125,7 +125,8 @@ In native mode, plugins are provided as native executables and `shadowsocks-libe ...@@ -125,7 +125,8 @@ In native mode, plugins are provided as native executables and `shadowsocks-libe
Every native mode plugin MUST have a content provider to provide the native executables (since they Every native mode plugin MUST have a content provider to provide the native executables (since they
can exceed 1M which is the limit of Intent size) that: can exceed 1M which is the limit of Intent size) that:
* MUST have `android:label` and `android:icon`; (may be configured by its parent `application`) * MUST have `android:label` and `android:icon`; (may be inherited from parent `application`)
* SHOULD have `android:directBootAware="true"` with proper support if possible;
* MUST have an intent filter with action `com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN`; * MUST have an intent filter with action `com.github.shadowsocks.plugin.ACTION_NATIVE_PLUGIN`;
(used for discovering plugins) (used for discovering plugins)
* MUST have meta-data `com.github.shadowsocks.plugin.id` with string value `$PLUGIN_ID` or a string resource; * MUST have meta-data `com.github.shadowsocks.plugin.id` with string value `$PLUGIN_ID` or a string resource;
...@@ -154,6 +155,7 @@ This corresponds to `com.github.shadowsocks.plugin.NativePluginProvider` in the ...@@ -154,6 +155,7 @@ This corresponds to `com.github.shadowsocks.plugin.NativePluginProvider` in the
... ...
<provider android:name=".BinaryProvider" <provider android:name=".BinaryProvider"
android:exported="true" android:exported="true"
android:directBootAware="true"
android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER" android:authorities="$FULLY_QUALIFIED_NAME_OF_YOUR_CONTENTPROVIDER"
tools:ignore="ExportedContentProvider"> tools:ignore="ExportedContentProvider">
<intent-filter> <intent-filter>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment