Compare commits

..

2 commits

5 changed files with 90 additions and 6 deletions

View file

@ -9,6 +9,34 @@ repositories {
} }
} }
def getVersionCode = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-list', '--first-parent', '--count', 'master'
standardOutput = stdout
}
return Integer.parseInt(stdout.toString().trim())
}
catch (ignored) {
return -1;
}
}
def getVersionName = { ->
try {
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'describe', '--tags', '--dirty'
standardOutput = stdout
}
return stdout.toString().trim()
}
catch (ignored) {
return null;
}
}
android { android {
compileSdk 34 compileSdk 34
buildToolsVersion = '34.0.0' buildToolsVersion = '34.0.0'
@ -16,8 +44,8 @@ android {
applicationId "net.typeblog.shelter" applicationId "net.typeblog.shelter"
minSdkVersion 24 minSdkVersion 24
targetSdkVersion 34 targetSdkVersion 34
versionCode 24 versionCode getVersionCode()
versionName "1.9-dev" versionName getVersionName()
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {

View file

@ -26,4 +26,6 @@ interface IShelterService {
List<String> getCrossProfileWidgetProviders(); List<String> getCrossProfileWidgetProviders();
boolean setCrossProfileWidgetProviderEnabled(String pkgName, boolean enabled); boolean setCrossProfileWidgetProviderEnabled(String pkgName, boolean enabled);
void setStartActivityProxy(in IStartActivityProxy proxy); void setStartActivityProxy(in IStartActivityProxy proxy);
List<String> getCrossProfilePackages();
void setCrossProfilePackages(in List<String> packages);
} }

View file

@ -25,6 +25,8 @@ import net.typeblog.shelter.util.FileProviderProxy;
import net.typeblog.shelter.util.UriForwardProxy; import net.typeblog.shelter.util.UriForwardProxy;
import net.typeblog.shelter.util.Utility; import net.typeblog.shelter.util.Utility;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -272,6 +274,24 @@ public class ShelterService extends Service {
public void setStartActivityProxy(IStartActivityProxy proxy) { public void setStartActivityProxy(IStartActivityProxy proxy) {
mStartActivityProxy = proxy; mStartActivityProxy = proxy;
} }
@Override
public List<String> getCrossProfilePackages() throws RemoteException {
if (!mIsProfileOwner)
throw new IllegalStateException("Cannot access cross-profile packages without being profile owner");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
throw new IllegalStateException("Cross-profile packages support is only available on Android 11 and later");
return new ArrayList<>(mPolicyManager.getCrossProfilePackages(mAdminComponent));
}
@Override
public void setCrossProfilePackages(List<String> packages) throws RemoteException {
if (!mIsProfileOwner)
throw new IllegalStateException("Cannot access cross-profile packages without being profile owner");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R)
throw new IllegalStateException("Cross-profile packages support is only available on Android 11 and later");
mPolicyManager.setCrossProfilePackages(mAdminComponent, new HashSet<>(packages));
}
}; };
@Override @Override

View file

@ -9,6 +9,7 @@ import android.content.IntentFilter;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon; import android.graphics.drawable.Icon;
import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.IBinder; import android.os.IBinder;
import android.os.RemoteException; import android.os.RemoteException;
@ -40,6 +41,7 @@ import net.typeblog.shelter.util.ApplicationInfoWrapper;
import net.typeblog.shelter.util.LocalStorageManager; import net.typeblog.shelter.util.LocalStorageManager;
import net.typeblog.shelter.util.Utility; import net.typeblog.shelter.util.Utility;
import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
@ -57,6 +59,7 @@ public class AppListFragment extends BaseFragment {
private static final int MENU_ITEM_CREATE_UNFREEZE_SHORTCUT = 10006; private static final int MENU_ITEM_CREATE_UNFREEZE_SHORTCUT = 10006;
private static final int MENU_ITEM_AUTO_FREEZE = 10007; private static final int MENU_ITEM_AUTO_FREEZE = 10007;
private static final int MENU_ITEM_ALLOW_CROSS_PROFILE_WIDGET = 10008; private static final int MENU_ITEM_ALLOW_CROSS_PROFILE_WIDGET = 10008;
private static final int MENU_ITEM_ALLOW_CROSS_PROFILE_INTERACTION = 10009;
private IShelterService mService = null; private IShelterService mService = null;
private boolean mIsRemote = false; private boolean mIsRemote = false;
@ -68,6 +71,9 @@ public class AppListFragment extends BaseFragment {
// Only useful if this fragment manages the work profile // Only useful if this fragment manages the work profile
private Set<String> mCrossProfileWidgetProviders = new HashSet<>(); private Set<String> mCrossProfileWidgetProviders = new HashSet<>();
// Packages allowed to interact across profiles
private Set<String> mCrossProfilePackages = new HashSet<>();
// Views // Views
private RecyclerView mList = null; private RecyclerView mList = null;
private AppListAdapter mAdapter = null; private AppListAdapter mAdapter = null;
@ -200,11 +206,13 @@ public class AppListFragment extends BaseFragment {
public void callback(List<ApplicationInfoWrapper> apps) { public void callback(List<ApplicationInfoWrapper> apps) {
if (mIsRemote) { if (mIsRemote) {
mCrossProfileWidgetProviders.clear(); mCrossProfileWidgetProviders.clear();
mCrossProfilePackages.clear();
// Update the cross-profile widget provider list // Update the cross-profile packages / widget providers list
try { try {
mCrossProfileWidgetProviders.addAll(mService.getCrossProfileWidgetProviders()); mCrossProfileWidgetProviders.addAll(mService.getCrossProfileWidgetProviders());
} catch (RemoteException e) { mCrossProfilePackages.addAll(mService.getCrossProfilePackages());
} catch (RemoteException ignored) {
} }
} }
@ -288,7 +296,7 @@ public class AppListFragment extends BaseFragment {
menu.add(Menu.NONE, MENU_ITEM_FREEZE, Menu.NONE, R.string.freeze_app); menu.add(Menu.NONE, MENU_ITEM_FREEZE, Menu.NONE, R.string.freeze_app);
menu.add(Menu.NONE, MENU_ITEM_LAUNCH, Menu.NONE, R.string.launch); menu.add(Menu.NONE, MENU_ITEM_LAUNCH, Menu.NONE, R.string.launch);
} }
// Cross-profile widget settings is also limited to work profile // Cross-profile widget / packages settings is also limited to work profile
MenuItem crossProfileWdiegt = MenuItem crossProfileWdiegt =
menu.add(Menu.NONE, MENU_ITEM_ALLOW_CROSS_PROFILE_WIDGET, Menu.NONE, menu.add(Menu.NONE, MENU_ITEM_ALLOW_CROSS_PROFILE_WIDGET, Menu.NONE,
R.string.allow_cross_profile_widgets); R.string.allow_cross_profile_widgets);
@ -296,6 +304,15 @@ public class AppListFragment extends BaseFragment {
crossProfileWdiegt.setChecked( crossProfileWdiegt.setChecked(
mCrossProfileWidgetProviders.contains(mSelectedApp.getPackageName())); mCrossProfileWidgetProviders.contains(mSelectedApp.getPackageName()));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
MenuItem crossProfileInteraction =
menu.add(Menu.NONE, MENU_ITEM_ALLOW_CROSS_PROFILE_INTERACTION, Menu.NONE,
R.string.allow_cross_profile_interaction);
crossProfileInteraction.setCheckable(true);
crossProfileInteraction.setChecked(
mCrossProfilePackages.contains(mSelectedApp.getPackageName()));
}
// TODO: If we implement God Mode (i.e. Shelter as device owner), we should // TODO: If we implement God Mode (i.e. Shelter as device owner), we should
// TODO: use two different lists to store auto freeze apps because we'll be // TODO: use two different lists to store auto freeze apps because we'll be
// TODO: able to freeze apps in main profile. // TODO: able to freeze apps in main profile.
@ -393,7 +410,7 @@ public class AppListFragment extends BaseFragment {
LocalStorageManager.PREF_AUTO_FREEZE_LIST_WORK_PROFILE, mSelectedApp.getPackageName()); LocalStorageManager.PREF_AUTO_FREEZE_LIST_WORK_PROFILE, mSelectedApp.getPackageName());
} }
return true; return true;
case MENU_ITEM_ALLOW_CROSS_PROFILE_WIDGET: case MENU_ITEM_ALLOW_CROSS_PROFILE_WIDGET: {
boolean newState = !item.isChecked(); boolean newState = !item.isChecked();
try { try {
if (mService.setCrossProfileWidgetProviderEnabled(mSelectedApp.getPackageName(), newState)) { if (mService.setCrossProfileWidgetProviderEnabled(mSelectedApp.getPackageName(), newState)) {
@ -411,6 +428,22 @@ public class AppListFragment extends BaseFragment {
} }
return true; return true;
} }
case MENU_ITEM_ALLOW_CROSS_PROFILE_INTERACTION: {
boolean newState = !item.isChecked();
if (newState) {
mCrossProfilePackages.add(mSelectedApp.getPackageName());
} else {
mCrossProfilePackages.remove(mSelectedApp.getPackageName());
}
try {
mService.setCrossProfilePackages(new ArrayList<>(mCrossProfilePackages));
item.setChecked(newState);
} catch (RemoteException ignored) {
}
return true;
}
}
return super.onContextItemSelected(item); return super.onContextItemSelected(item);
} }

View file

@ -51,6 +51,7 @@
<string name="unfreeze_and_launch">Unfreeze and Launch</string> <string name="unfreeze_and_launch">Unfreeze and Launch</string>
<string name="auto_freeze">Auto Freeze</string> <string name="auto_freeze">Auto Freeze</string>
<string name="allow_cross_profile_widgets">Allow Widgets in Main Profile</string> <string name="allow_cross_profile_widgets">Allow Widgets in Main Profile</string>
<string name="allow_cross_profile_interaction">Allow Cross-Profile Interaction</string>
<!-- Action Bar Options Menu --> <!-- Action Bar Options Menu -->
<string name="search">Search</string> <string name="search">Search</string>