Skip to content

Commit 69f6f8f

Browse files
committed
Add Storage Redirect support
Signed-off-by: Fung Gwo <fython@163.com>
1 parent 42023b7 commit 69f6f8f

8 files changed

Lines changed: 116 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
SAF Enhancer Lite
22
----
33

4-
Help applications that haven't supported Storage Access Framework (likes WeChat)
4+
Help applications that haven't supported Storage Access Framework (like WeChat)
55
to pick media from Android Documents UI
66

77
## What can it do?

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,5 @@ dependencies {
3333
implementation "androidx.recyclerview:recyclerview:1.0.0"
3434
implementation 'io.reactivex.rxjava2:rxjava:2.2.7'
3535
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
36+
implementation 'moe.shizuku.redirectstorage:api:1.0.0-alpha1'
3637
}

app/src/main/AndroidManifest.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@
22
xmlns:tools="http://schemas.android.com/tools"
33
package="app.gwo.safenhancer.lite">
44

5+
<uses-sdk tools:overrideLibrary="moe.shizuku.redirectstorage"/>
6+
57
<!-- We do not use this permission actually. But it is required for Android M+ security limitations. -->
68
<uses-permission android:name="android.permission.CAMERA"/>
79

810
<!-- Use to save choose result in the ProxyCameraActivity -->
911
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
1012
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
1113

14+
<uses-permission android:name="moe.shizuku.redirectstorage.permission.GET_CONFIGURATION"/>
15+
1216
<application
1317
android:name=".ProxyApplication"
1418
android:allowBackup="true"

app/src/main/java/app/gwo/safenhancer/lite/ProxyCameraActivity.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@
99
import android.net.Uri;
1010
import android.os.Build;
1111
import android.os.Bundle;
12+
import android.os.Environment;
1213
import android.provider.MediaStore;
1314
import android.util.Log;
1415
import android.view.ContextThemeWrapper;
1516
import android.view.LayoutInflater;
1617
import android.view.View;
1718

19+
import java.util.Objects;
20+
1821
import androidx.annotation.NonNull;
1922
import androidx.annotation.Nullable;
2023
import app.gwo.safenhancer.lite.util.DumpUtils;
2124
import app.gwo.safenhancer.lite.util.Settings;
25+
import moe.shizuku.redirectstorage.RedirectPackageInfo;
26+
import moe.shizuku.redirectstorage.StorageRedirectManager;
2227

2328
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
2429
import static app.gwo.safenhancer.lite.BuildConfig.DEBUG;
@@ -86,6 +91,48 @@ private void getExtrasFromCaptureIntent(@NonNull Intent intent) {
8691

8792
if (intent.hasExtra(MediaStore.EXTRA_OUTPUT)) {
8893
mExpectedOutput = intent.getParcelableExtra(MediaStore.EXTRA_OUTPUT);
94+
String referrerPackage = getReferrerPackage();
95+
if (mExpectedOutput != null
96+
&& "file".equals(mExpectedOutput.getScheme())
97+
&& referrerPackage != null
98+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
99+
&& StorageRedirectManager.installed(getPackageManager())
100+
&& checkSelfPermission(StorageRedirectManager.PERMISSION) == PERMISSION_GRANTED
101+
) {
102+
StorageRedirectManager srm = StorageRedirectManager.create();
103+
if (srm != null) {
104+
try {
105+
RedirectPackageInfo rpi = srm.getRedirectPackageInfo(
106+
referrerPackage, 0, 0);
107+
if (rpi != null && rpi.enabled && rpi.redirectTarget != null) {
108+
Log.d(TAG, "Package " + referrerPackage + " is enabled redirect.");
109+
String originalPath = mExpectedOutput.toString();
110+
String externalRoot = Environment.getExternalStorageDirectory()
111+
.getAbsolutePath();
112+
String redirectTarget = rpi.redirectTarget;
113+
if (rpi.redirectTarget.contains("%s")) {
114+
redirectTarget = String.format(redirectTarget, referrerPackage);
115+
}
116+
String newExternalRoot = externalRoot;
117+
if (!redirectTarget.isEmpty()) {
118+
newExternalRoot = newExternalRoot + "/" + redirectTarget;
119+
}
120+
mExpectedOutput = Uri.parse(
121+
originalPath.replace(externalRoot, newExternalRoot)
122+
);
123+
Log.d(TAG, "Original path: " + originalPath + ", external root: " +
124+
externalRoot + ", redirect target: " + rpi.redirectTarget +
125+
", after: " + mExpectedOutput);
126+
}
127+
} catch (Exception e) {
128+
e.printStackTrace();
129+
if (DEBUG) {
130+
throw e;
131+
}
132+
}
133+
}
134+
}
135+
89136
Log.d(TAG, "Expected output path: " + mExpectedOutput);
90137
}
91138
}

app/src/main/java/app/gwo/safenhancer/lite/SettingsActivity.java

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,17 @@
99
import android.os.Bundle;
1010
import android.preference.Preference;
1111
import android.preference.PreferenceFragment;
12+
import android.preference.SwitchPreference;
13+
import android.util.Log;
1214
import android.widget.Toast;
1315

16+
import java.util.Arrays;
1417
import java.util.List;
1518

19+
import androidx.annotation.NonNull;
1620
import androidx.annotation.Nullable;
1721
import app.gwo.safenhancer.lite.util.Settings;
22+
import moe.shizuku.redirectstorage.StorageRedirectManager;
1823

1924
public final class SettingsActivity extends BaseActivity {
2025

@@ -48,13 +53,18 @@ public static final class SettingsFragment extends PreferenceFragment {
4853
private static final String KEY_HANDLED_APPS_CHOOSE = "handled_apps_choose";
4954
private static final String KEY_ABOUT_VERSION = "version";
5055
private static final String KEY_ABOUT_GITHUB = "github";
56+
private static final String KEY_SR_API_PERMISSION = "sr_api_permission";
57+
58+
private static final int REQUEST_CODE_SR_PERMISSION = 1;
5159

5260
private Preference mHandledAppsChoose;
61+
private SwitchPreference mSRPermission;
5362

5463
@Override
5564
public void onCreate(@Nullable Bundle savedInstanceState) {
5665
super.onCreate(savedInstanceState);
5766
addPreferencesFromResource(R.xml.settings_screen);
67+
PackageManager pm = getActivity().getPackageManager();
5868

5969
findPreference(KEY_PREFERRED_CAMERA_CLEAR).setOnPreferenceClickListener(p -> {
6070
Settings.getInstance().setPreferredCamera(null);
@@ -72,8 +82,31 @@ public void onCreate(@Nullable Bundle savedInstanceState) {
7282
});
7383
updateHandledAppsSummary();
7484

85+
mSRPermission = (SwitchPreference) findPreference(KEY_SR_API_PERMISSION);
86+
mSRPermission.setOnPreferenceChangeListener((pref, newValue) -> {
87+
boolean newBool = (boolean) newValue;
88+
if (newBool) {
89+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
90+
requestPermissions(new String[] {
91+
StorageRedirectManager.PERMISSION
92+
}, REQUEST_CODE_SR_PERMISSION);
93+
}
94+
} else {
95+
// TODO Jump to settings
96+
}
97+
return false;
98+
});
99+
mSRPermission.setEnabled(
100+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
101+
StorageRedirectManager.installed(pm)
102+
);
103+
mSRPermission.setChecked(
104+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
105+
getActivity().checkSelfPermission(StorageRedirectManager.PERMISSION)
106+
== PackageManager.PERMISSION_GRANTED
107+
);
108+
75109
Preference versionPref = findPreference(KEY_ABOUT_VERSION);
76-
PackageManager pm = getActivity().getPackageManager();
77110
String version = "Unknown";
78111
try {
79112
PackageInfo pi = pm.getPackageInfo(getActivity().getPackageName(), 0);
@@ -111,6 +144,17 @@ private void updateHandledAppsSummary(int count) {
111144
R.string.handled_apps_choose_apps_summary, count));
112145
}
113146

147+
@Override
148+
public void onRequestPermissionsResult(int requestCode,
149+
@NonNull String[] permissions,
150+
@NonNull int[] grantResults) {
151+
if (REQUEST_CODE_SR_PERMISSION == requestCode) {
152+
if (StorageRedirectManager.PERMISSION.equals(permissions[0]) &&
153+
grantResults[0] == PackageManager.PERMISSION_GRANTED) {
154+
mSRPermission.setChecked(true);
155+
}
156+
}
157+
}
114158
}
115159

116160
}

app/src/main/res/values/strings.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ If they use their own interface only, it will have no effect even if apps are ch
2424
<string name="action_done">Done</string>
2525
<string name="packages_selector_search_hint">Search title/package name…</string>
2626

27+
<string name="isolated_storage_support_title">Isolated storage support</string>
28+
<string name="isolated_storage_support_for_sr">Enable "Storage Redirect" support</string>
29+
<string name="isolated_storage_support_for_sr_summary"><![CDATA[
30+
If apps handled by SAFEnhancer is controlled by Storage Redirect and you cannot choose images
31+
normally, you need enable this feature.
32+
]]></string>
33+
2734
<string name="action_camera">Camera</string>
2835
<string name="action_documents">Documents</string>
2936

app/src/main/res/xml/settings_screen.xml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121

2222
</PreferenceCategory>
2323

24+
<PreferenceCategory android:title="@string/isolated_storage_support_title">
25+
26+
<SwitchPreference android:key="sr_api_permission"
27+
android:title="@string/isolated_storage_support_for_sr"
28+
android:summary="@string/isolated_storage_support_for_sr_summary"/>
29+
30+
</PreferenceCategory>
31+
2432
<PreferenceCategory android:title="@string/about_title">
2533

2634
<Preference android:key="version"

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ allprojects {
2525
repositories {
2626
google()
2727
jcenter()
28+
maven {
29+
url 'https://dl.bintray.com/rikkaw/StorageRedirect'
30+
}
2831
}
2932
}
3033

0 commit comments

Comments
 (0)