diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 1e82231..d992a57 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -54,6 +54,7 @@
+
@@ -89,7 +90,8 @@
android:authorities="net.typeblog.shelter.documents"
android:grantUriPermissions="true"
android:permission="android.permission.MANAGE_DOCUMENTS"
- android:exported="true">
+ android:exported="true"
+ android:enabled="false">
diff --git a/app/src/main/java/net/typeblog/shelter/ShelterApplication.java b/app/src/main/java/net/typeblog/shelter/ShelterApplication.java
index d2fb177..8458680 100644
--- a/app/src/main/java/net/typeblog/shelter/ShelterApplication.java
+++ b/app/src/main/java/net/typeblog/shelter/ShelterApplication.java
@@ -8,6 +8,7 @@ import android.content.ServiceConnection;
import net.typeblog.shelter.services.FileShuttleService;
import net.typeblog.shelter.services.ShelterService;
import net.typeblog.shelter.util.LocalStorageManager;
+import net.typeblog.shelter.util.SettingsManager;
public class ShelterApplication extends Application {
private ServiceConnection mShelterServiceConnection = null;
@@ -17,6 +18,7 @@ public class ShelterApplication extends Application {
public void onCreate() {
super.onCreate();
LocalStorageManager.initialize(this);
+ SettingsManager.initialize(this);
}
public void bindShelterService(ServiceConnection conn, boolean foreground) {
diff --git a/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java b/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java
index 664d76b..d23819c 100644
--- a/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java
+++ b/app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java
@@ -26,6 +26,7 @@ import net.typeblog.shelter.services.IFileShuttleService;
import net.typeblog.shelter.services.IFileShuttleServiceCallback;
import net.typeblog.shelter.util.FileProviderProxy;
import net.typeblog.shelter.util.LocalStorageManager;
+import net.typeblog.shelter.util.SettingsManager;
import net.typeblog.shelter.util.Utility;
import java.io.File;
@@ -51,6 +52,7 @@ public class DummyActivity extends Activity {
// This is a bad experience, so we use two to avoid this.
public static final String START_FILE_SHUTTLE = "net.typeblog.shelter.action.START_FILE_SHUTTLE";
public static final String START_FILE_SHUTTLE_2 = "net.typeblog.shelter.action.START_FILE_SHUTTLE_2";
+ public static final String SYNCHRONIZE_PREFERENCE = "net.typeblog.shelter.action.SYNCHRONIZE_PREFERENCE";
private static final int REQUEST_INSTALL_PACKAGE = 1;
private static final int REQUEST_PERMISSION_EXTERNAL_STORAGE= 2;
@@ -69,6 +71,7 @@ public class DummyActivity extends Activity {
// so that we can make sure those are updated with our app
Utility.enforceWorkProfilePolicies(this);
Utility.enforceUserRestrictions(this);
+ SettingsManager.getInstance().applyAll();
}
Intent intent = getIntent();
@@ -93,6 +96,8 @@ public class DummyActivity extends Activity {
actionFreezeAllInList();
} else if (START_FILE_SHUTTLE.equals(intent.getAction()) || START_FILE_SHUTTLE_2.equals(intent.getAction())) {
actionStartFileShuttle();
+ } else if (SYNCHRONIZE_PREFERENCE.equals(intent.getAction())) {
+ actionSynchronizePreference();
} else {
finish();
}
@@ -331,4 +336,15 @@ public class DummyActivity extends Activity {
}
});
}
+
+ private void actionSynchronizePreference() {
+ String name = getIntent().getStringExtra("name");
+ if (getIntent().hasExtra("boolean")) {
+ LocalStorageManager.getInstance()
+ .setBoolean(name, getIntent().getBooleanExtra("boolean", false));
+ }
+ // TODO: Cases for other types
+ SettingsManager.getInstance().applyAll();
+ finish();
+ }
}
diff --git a/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java b/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java
index 7e11601..0212abb 100644
--- a/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java
+++ b/app/src/main/java/net/typeblog/shelter/ui/MainActivity.java
@@ -31,6 +31,7 @@ import net.typeblog.shelter.services.IAppInstallCallback;
import net.typeblog.shelter.services.IShelterService;
import net.typeblog.shelter.services.KillerService;
import net.typeblog.shelter.util.LocalStorageManager;
+import net.typeblog.shelter.util.SettingsManager;
import net.typeblog.shelter.util.UriForwardProxy;
import net.typeblog.shelter.util.Utility;
@@ -120,6 +121,8 @@ public class MainActivity extends AppCompatActivity {
(dialog, which) -> finish())
.show();
} else {
+ // Initialize the settings
+ SettingsManager.getInstance().applyAll();
// Initialize the app (start by binding the services)
bindServices();
}
diff --git a/app/src/main/java/net/typeblog/shelter/ui/SettingsFragment.java b/app/src/main/java/net/typeblog/shelter/ui/SettingsFragment.java
index c0c606a..d2c6a23 100644
--- a/app/src/main/java/net/typeblog/shelter/ui/SettingsFragment.java
+++ b/app/src/main/java/net/typeblog/shelter/ui/SettingsFragment.java
@@ -4,15 +4,22 @@ import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
+import android.support.v7.preference.CheckBoxPreference;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceFragmentCompat;
import net.typeblog.shelter.R;
+import net.typeblog.shelter.util.SettingsManager;
-public class SettingsFragment extends PreferenceFragmentCompat {
+public class SettingsFragment extends PreferenceFragmentCompat implements Preference.OnPreferenceChangeListener {
private static final String SETTINGS_VERSION = "settings_version";
private static final String SETTINGS_SOURCE_CODE = "settings_source_code";
private static final String SETTINGS_BUG_REPORT = "settings_bug_report";
+ private static final String SETTINGS_CROSS_PROFILE_FILE_CHOOSER = "settings_cross_profile_file_chooser";
+
+ private SettingsManager mManager = SettingsManager.getInstance();
+
+ private CheckBoxPreference mPrefCrossProfileFileChooser = null;
@Override
public void onCreatePreferences(Bundle bundle, String s) {
@@ -32,6 +39,11 @@ public class SettingsFragment extends PreferenceFragmentCompat {
.setOnPreferenceClickListener(this::openSummaryUrl);
findPreference(SETTINGS_BUG_REPORT)
.setOnPreferenceClickListener(this::openSummaryUrl);
+
+ // === Interactions ===
+ mPrefCrossProfileFileChooser = (CheckBoxPreference) findPreference(SETTINGS_CROSS_PROFILE_FILE_CHOOSER);
+ mPrefCrossProfileFileChooser.setChecked(mManager.getCrossProfileFileChooserEnabled());
+ mPrefCrossProfileFileChooser.setOnPreferenceChangeListener(this);
}
private boolean openSummaryUrl(Preference pref) {
@@ -40,4 +52,14 @@ public class SettingsFragment extends PreferenceFragmentCompat {
startActivity(intent);
return true;
}
+
+ @Override
+ public boolean onPreferenceChange(Preference preference, Object newState) {
+ if (preference == mPrefCrossProfileFileChooser) {
+ mManager.setCrossProfileFileChooserEnabled((boolean) newState);
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/app/src/main/java/net/typeblog/shelter/util/LocalStorageManager.java b/app/src/main/java/net/typeblog/shelter/util/LocalStorageManager.java
index f2b7fc3..bc7ff0e 100644
--- a/app/src/main/java/net/typeblog/shelter/util/LocalStorageManager.java
+++ b/app/src/main/java/net/typeblog/shelter/util/LocalStorageManager.java
@@ -12,6 +12,7 @@ public class LocalStorageManager {
public static final String PREF_IS_SETTING_UP = "is_setting_up";
public static final String PREF_HAS_SETUP = "has_setup";
public static final String PREF_AUTO_FREEZE_LIST_WORK_PROFILE = "auto_freeze_list_work_profile";
+ public static final String PREF_CROSS_PROFILE_FILE_CHOOSER = "cross_profile_file_chooser";
private static final String LIST_DIVIDER = ",";
diff --git a/app/src/main/java/net/typeblog/shelter/util/SettingsManager.java b/app/src/main/java/net/typeblog/shelter/util/SettingsManager.java
new file mode 100644
index 0000000..ec10942
--- /dev/null
+++ b/app/src/main/java/net/typeblog/shelter/util/SettingsManager.java
@@ -0,0 +1,62 @@
+package net.typeblog.shelter.util;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+import net.typeblog.shelter.ui.DummyActivity;
+
+public class SettingsManager {
+ private static SettingsManager sInstance = null;
+
+ public static void initialize(Context context) {
+ sInstance = new SettingsManager(context);
+ }
+
+ public static SettingsManager getInstance() {
+ return sInstance;
+ }
+
+ private LocalStorageManager mStorage = LocalStorageManager.getInstance();
+ private Context mContext;
+
+ private SettingsManager(Context context) {
+ mContext = context;
+ }
+
+ private void syncSettingsToProfileBool(String name, boolean value) {
+ Intent intent = new Intent(DummyActivity.SYNCHRONIZE_PREFERENCE);
+ intent.putExtra("name", name);
+ intent.putExtra("boolean", value);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ Utility.transferIntentToProfile(mContext, intent);
+ mContext.startActivity(intent);
+ }
+
+ // Enforce all settings
+ public void applyAll() {
+ applyCrossProfileFileChooser();
+ }
+
+ // Read and apply the enabled state of the cross profile file chooser
+ public void applyCrossProfileFileChooser() {
+ boolean enabled = mStorage.getBoolean(LocalStorageManager.PREF_CROSS_PROFILE_FILE_CHOOSER);
+ mContext.getPackageManager().setComponentEnabledSetting(
+ new ComponentName(mContext, CrossProfileDocumentsProvider.class),
+ enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ PackageManager.DONT_KILL_APP);
+ }
+
+ // Set the enabled state of the cross profile file chooser
+ public void setCrossProfileFileChooserEnabled(boolean enabled) {
+ mStorage.setBoolean(LocalStorageManager.PREF_CROSS_PROFILE_FILE_CHOOSER, enabled);
+ applyCrossProfileFileChooser();
+ syncSettingsToProfileBool(LocalStorageManager.PREF_CROSS_PROFILE_FILE_CHOOSER, enabled);
+ }
+
+ // Get the enabled state of the cross profile file chooser
+ public boolean getCrossProfileFileChooserEnabled() {
+ return mStorage.getBoolean(LocalStorageManager.PREF_CROSS_PROFILE_FILE_CHOOSER);
+ }
+}
diff --git a/app/src/main/java/net/typeblog/shelter/util/Utility.java b/app/src/main/java/net/typeblog/shelter/util/Utility.java
index 925222c..1f8b956 100644
--- a/app/src/main/java/net/typeblog/shelter/util/Utility.java
+++ b/app/src/main/java/net/typeblog/shelter/util/Utility.java
@@ -116,6 +116,11 @@ public class Utility {
new IntentFilter(DummyActivity.START_FILE_SHUTTLE_2),
DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED);
+ manager.addCrossProfileIntentFilter(
+ adminComponent,
+ new IntentFilter(DummyActivity.SYNCHRONIZE_PREFERENCE),
+ DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
+
// Allow ACTION_SEND and ACTION_SEND_MULTIPLE to cross from managed to parent
// TODO: Make this configurable
IntentFilter actionSendFilter = new IntentFilter();
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 87a7228..8445bbd 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -36,6 +36,9 @@
Settings
+ Interaction
+ Cross-profile Documents UI
+ When enabled, an option will be shown in the system\'s Documents UI (named Files or Downloads on your launcher) and apps that support Documents UI to allow browsing / viewing / picking / copying files in Shelter from main profile and vice-versa.
About
Version
Source Code
diff --git a/app/src/main/res/xml/preferences_settings.xml b/app/src/main/res/xml/preferences_settings.xml
index d84a3fb..42bca5e 100644
--- a/app/src/main/res/xml/preferences_settings.xml
+++ b/app/src/main/res/xml/preferences_settings.xml
@@ -2,6 +2,16 @@
+
+
+
+
+
+