Shelter: implement cross-profile interaction
This commit is contained in:
parent
dd20dd7768
commit
83ea35cfd0
|
@ -25,7 +25,7 @@
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
|
|
@ -4,7 +4,7 @@ android {
|
||||||
compileSdkVersion 28
|
compileSdkVersion 28
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
applicationId "net.typeblog.shelter"
|
applicationId "net.typeblog.shelter"
|
||||||
minSdkVersion 24
|
minSdkVersion 26
|
||||||
targetSdkVersion 28
|
targetSdkVersion 28
|
||||||
versionCode 1
|
versionCode 1
|
||||||
versionName "1.0"
|
versionName "1.0"
|
||||||
|
@ -16,10 +16,14 @@ android {
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
|
implementation 'com.android.support:appcompat-v7:28.0.0-rc01'
|
||||||
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
|
|
|
@ -2,6 +2,10 @@
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="net.typeblog.shelter">
|
package="net.typeblog.shelter">
|
||||||
|
|
||||||
|
<uses-feature android:name="android.software.device_admin" android:required="true"/>
|
||||||
|
<uses-feature android:name="android.software.managed_users" android:required="true"/>
|
||||||
|
<!--<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>-->
|
||||||
|
|
||||||
<application
|
<application
|
||||||
android:name=".ShelterApplication"
|
android:name=".ShelterApplication"
|
||||||
android:allowBackup="false"
|
android:allowBackup="false"
|
||||||
|
@ -17,6 +21,13 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity android:name=".ui.DummyActivity"
|
||||||
|
android:theme="@android:style/Theme.Translucent.NoTitleBar">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="net.typeblog.shelter.action.START_SERVICE"/>
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
<receiver android:name=".receivers.ShelterDeviceAdminReceiver"
|
<receiver android:name=".receivers.ShelterDeviceAdminReceiver"
|
||||||
android:label="@string/device_admin_label"
|
android:label="@string/device_admin_label"
|
||||||
android:description="@string/device_admin_desc"
|
android:description="@string/device_admin_desc"
|
||||||
|
@ -27,6 +38,9 @@
|
||||||
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
|
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
<service android:name=".services.ShelterService"
|
||||||
|
android:exported="true"
|
||||||
|
android:permission="android.permission.BIND_DEVICE_ADMIN"/>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -0,0 +1,9 @@
|
||||||
|
// IShelterService.aidl
|
||||||
|
package net.typeblog.shelter.services;
|
||||||
|
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
|
||||||
|
interface IShelterService {
|
||||||
|
void stopShelterService(boolean kill);
|
||||||
|
List<ResolveInfo> getApps();
|
||||||
|
}
|
|
@ -1,13 +1,34 @@
|
||||||
package net.typeblog.shelter;
|
package net.typeblog.shelter;
|
||||||
|
|
||||||
import android.app.Application;
|
import android.app.Application;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
|
||||||
|
import net.typeblog.shelter.services.ShelterService;
|
||||||
import net.typeblog.shelter.util.LocalStorageManager;
|
import net.typeblog.shelter.util.LocalStorageManager;
|
||||||
|
|
||||||
public class ShelterApplication extends Application {
|
public class ShelterApplication extends Application {
|
||||||
|
private ServiceConnection mShelterServiceConnection = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate() {
|
public void onCreate() {
|
||||||
super.onCreate();
|
super.onCreate();
|
||||||
LocalStorageManager.initialize(this);
|
LocalStorageManager.initialize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void bindShelterService(ServiceConnection conn) {
|
||||||
|
unbindShelterService();
|
||||||
|
Intent intent = new Intent(getApplicationContext(), ShelterService.class);
|
||||||
|
bindService(intent, conn, Context.BIND_AUTO_CREATE);
|
||||||
|
mShelterServiceConnection = conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unbindShelterService() {
|
||||||
|
if (mShelterServiceConnection != null) {
|
||||||
|
unbindService(mShelterServiceConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
mShelterServiceConnection = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.IntentFilter;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
|
||||||
import net.typeblog.shelter.ui.MainActivity;
|
import net.typeblog.shelter.ui.MainActivity;
|
||||||
|
@ -26,14 +27,21 @@ public class ShelterDeviceAdminReceiver extends DeviceAdminReceiver {
|
||||||
@Override
|
@Override
|
||||||
public void onProfileProvisioningComplete(Context context, Intent intent) {
|
public void onProfileProvisioningComplete(Context context, Intent intent) {
|
||||||
super.onProfileProvisioningComplete(context, intent);
|
super.onProfileProvisioningComplete(context, intent);
|
||||||
|
DevicePolicyManager manager = context.getSystemService(DevicePolicyManager.class);
|
||||||
|
ComponentName adminComponent = new ComponentName(context.getApplicationContext(), ShelterDeviceAdminReceiver.class);
|
||||||
|
|
||||||
// Enable the profile
|
// Enable the profile
|
||||||
DevicePolicyManager manager = context.getSystemService(DevicePolicyManager.class);
|
manager.setProfileEnabled(adminComponent);
|
||||||
manager.setProfileEnabled(new ComponentName(context.getApplicationContext(), ShelterDeviceAdminReceiver.class));
|
|
||||||
|
|
||||||
// Hide this app in the work profile
|
// Hide this app in the work profile
|
||||||
context.getPackageManager().setComponentEnabledSetting(
|
context.getPackageManager().setComponentEnabledSetting(
|
||||||
new ComponentName(context.getApplicationContext(), MainActivity.class),
|
new ComponentName(context.getApplicationContext(), MainActivity.class),
|
||||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
|
PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);
|
||||||
|
|
||||||
|
// Allow cross-profile intents for START_SERVICE
|
||||||
|
manager.addCrossProfileIntentFilter(
|
||||||
|
adminComponent,
|
||||||
|
new IntentFilter("net.typeblog.shelter.action.START_SERVICE"),
|
||||||
|
DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
package net.typeblog.shelter.services;
|
||||||
|
|
||||||
|
import android.app.Service;
|
||||||
|
import android.app.admin.DevicePolicyManager;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.typeblog.shelter.ShelterApplication;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class ShelterService extends Service {
|
||||||
|
private DevicePolicyManager mPolicyManager = null;
|
||||||
|
private boolean mIsWorkProfile = false;
|
||||||
|
private IShelterService.Stub mBinder = new IShelterService.Stub() {
|
||||||
|
@Override
|
||||||
|
public void stopShelterService(boolean kill) {
|
||||||
|
// dirty: just wait for some time and kill this service itself
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
((ShelterApplication) getApplication()).unbindShelterService();
|
||||||
|
|
||||||
|
if (kill) {
|
||||||
|
// Just kill the entire process if this signal is received
|
||||||
|
System.exit(0);
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<ResolveInfo> getApps() {
|
||||||
|
Intent mainIntent = new Intent(Intent.ACTION_MAIN);
|
||||||
|
mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||||
|
return getPackageManager().queryIntentActivities(mainIntent, 0);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onCreate() {
|
||||||
|
mPolicyManager = getSystemService(DevicePolicyManager.class);
|
||||||
|
mIsWorkProfile = mPolicyManager.isProfileOwnerApp(getPackageName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public IBinder onBind(Intent intent) {
|
||||||
|
return mBinder;
|
||||||
|
}
|
||||||
|
}
|
35
app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java
Normal file
35
app/src/main/java/net/typeblog/shelter/ui/DummyActivity.java
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package net.typeblog.shelter.ui;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.support.annotation.Nullable;
|
||||||
|
|
||||||
|
import net.typeblog.shelter.ShelterApplication;
|
||||||
|
|
||||||
|
public class DummyActivity extends Activity {
|
||||||
|
@Override
|
||||||
|
protected void onCreate(@Nullable Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
((ShelterApplication) getApplication()).bindShelterService(new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
Intent data = new Intent();
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.putBinder("service", service);
|
||||||
|
data.putExtra("extra", bundle);
|
||||||
|
setResult(RESULT_OK, data);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
// dummy
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,21 +3,32 @@ package net.typeblog.shelter.ui;
|
||||||
import android.app.admin.DevicePolicyManager;
|
import android.app.admin.DevicePolicyManager;
|
||||||
import android.content.ComponentName;
|
import android.content.ComponentName;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.content.ServiceConnection;
|
||||||
|
import android.os.IBinder;
|
||||||
|
import android.os.RemoteException;
|
||||||
import android.support.annotation.Nullable;
|
import android.support.annotation.Nullable;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import net.typeblog.shelter.R;
|
import net.typeblog.shelter.R;
|
||||||
|
import net.typeblog.shelter.ShelterApplication;
|
||||||
import net.typeblog.shelter.receivers.ShelterDeviceAdminReceiver;
|
import net.typeblog.shelter.receivers.ShelterDeviceAdminReceiver;
|
||||||
|
import net.typeblog.shelter.services.IShelterService;
|
||||||
import net.typeblog.shelter.util.LocalStorageManager;
|
import net.typeblog.shelter.util.LocalStorageManager;
|
||||||
|
import net.typeblog.shelter.util.Utility;
|
||||||
|
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private static final int REQUEST_PROVISION_PROFILE = 1;
|
private static final int REQUEST_PROVISION_PROFILE = 1;
|
||||||
|
private static final int REQUEST_START_SERVICE_IN_WORK_PROFILE = 2;
|
||||||
|
|
||||||
private LocalStorageManager mStorage = null;
|
private LocalStorageManager mStorage = null;
|
||||||
private DevicePolicyManager mPolicyManager = null;
|
private DevicePolicyManager mPolicyManager = null;
|
||||||
|
|
||||||
|
// Two services running in main / work profile
|
||||||
|
private IShelterService mServiceMain = null;
|
||||||
|
private IShelterService mServiceWork = null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -28,6 +39,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (mPolicyManager.isProfileOwnerApp(getPackageName())) {
|
if (mPolicyManager.isProfileOwnerApp(getPackageName())) {
|
||||||
// We are now in our own profile
|
// We are now in our own profile
|
||||||
// We should never start the main activity here.
|
// We should never start the main activity here.
|
||||||
|
android.util.Log.d("MainActivity", "started in user profile. stopping.");
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
if (!mStorage.getBoolean(LocalStorageManager.PREF_IS_DEVICE_ADMIN)) {
|
if (!mStorage.getBoolean(LocalStorageManager.PREF_IS_DEVICE_ADMIN)) {
|
||||||
|
@ -39,14 +51,13 @@ public class MainActivity extends AppCompatActivity {
|
||||||
setupProfile();
|
setupProfile();
|
||||||
} else {
|
} else {
|
||||||
// Initialize the app
|
// Initialize the app
|
||||||
// we should bind to a service running in the work profile
|
initializeApp();
|
||||||
// in order to get the application lists etc.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setupProfile() {
|
private void setupProfile() {
|
||||||
// Check if provisioning is allowed
|
// Check if provisioning is allowed
|
||||||
if (!mPolicyManager.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)) {
|
if (!mPolicyManager.isProvisioningAllowed(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE)) {
|
||||||
Toast.makeText(this,
|
Toast.makeText(this,
|
||||||
|
@ -55,27 +66,85 @@ public class MainActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start provisioning
|
// Start provisioning
|
||||||
|
ComponentName admin = new ComponentName(getApplicationContext(), ShelterDeviceAdminReceiver.class);
|
||||||
Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
|
Intent intent = new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE);
|
||||||
|
|
||||||
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION, true);
|
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_SKIP_ENCRYPTION, true);
|
||||||
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME,
|
intent.putExtra(DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME, admin);
|
||||||
new ComponentName(getApplicationContext(), ShelterDeviceAdminReceiver.class));
|
|
||||||
startActivityForResult(intent, REQUEST_PROVISION_PROFILE);
|
startActivityForResult(intent, REQUEST_PROVISION_PROFILE);
|
||||||
|
}
|
||||||
|
|
||||||
// We should continue the setup process later when provision completed
|
private void initializeApp() {
|
||||||
return false;
|
// Bind to the service provided by this app in main user
|
||||||
|
((ShelterApplication) getApplication()).bindShelterService(new ServiceConnection() {
|
||||||
|
@Override
|
||||||
|
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||||
|
mServiceMain = IShelterService.Stub.asInterface(service);
|
||||||
|
bindWorkService();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onServiceDisconnected(ComponentName name) {
|
||||||
|
// dummy
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bindWorkService() {
|
||||||
|
// Bind to the ShelterService in work profile
|
||||||
|
Intent intent = new Intent("net.typeblog.shelter.action.START_SERVICE");
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
|
||||||
|
Utility.transferIntentToProfile(this, intent);
|
||||||
|
startActivityForResult(intent, REQUEST_START_SERVICE_IN_WORK_PROFILE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void buildView() {
|
||||||
|
// Finally we can build the view
|
||||||
|
// TODO: Actually implement this method
|
||||||
|
try {
|
||||||
|
android.util.Log.d("MainActivity", "Main profile app count: " + mServiceMain.getApps().size());
|
||||||
|
android.util.Log.d("MainActivity", "Work profile app count: " + mServiceWork.getApps().size());
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
|
||||||
|
try {
|
||||||
|
// For the work instance, we just kill it entirely
|
||||||
|
// We don't need it to be awake to do anything useful
|
||||||
|
mServiceWork.stopShelterService(true);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// We are stopping anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
mServiceMain.stopShelterService(false);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
// We are stopping anyway
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
if (resultCode == REQUEST_PROVISION_PROFILE) {
|
if (requestCode == REQUEST_PROVISION_PROFILE && resultCode == RESULT_OK) {
|
||||||
// Provisioning finished.
|
// Provisioning finished.
|
||||||
// Set the HAS_SETUP flag
|
// Set the HAS_SETUP flag
|
||||||
mStorage.setBoolean(LocalStorageManager.PREF_HAS_SETUP, true);
|
mStorage.setBoolean(LocalStorageManager.PREF_HAS_SETUP, true);
|
||||||
|
|
||||||
// Initialize the app just as if the activity was started.
|
// Initialize the app just as if the activity was started.
|
||||||
|
// TODO: Should not initialize here. It is possible that the process is not finished yet.
|
||||||
|
//initializeApp();
|
||||||
|
} else if (requestCode == REQUEST_START_SERVICE_IN_WORK_PROFILE && resultCode == RESULT_OK) {
|
||||||
|
// TODO: Set the service in work profile as foreground to keep it alive
|
||||||
|
Bundle extra = data.getBundleExtra("extra");
|
||||||
|
IBinder binder = extra.getBinder("service");
|
||||||
|
mServiceWork = IShelterService.Stub.asInterface(binder);
|
||||||
|
buildView();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
22
app/src/main/java/net/typeblog/shelter/util/Utility.java
Normal file
22
app/src/main/java/net/typeblog/shelter/util/Utility.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
package net.typeblog.shelter.util;
|
||||||
|
|
||||||
|
import android.content.ComponentName;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
|
import android.content.pm.ResolveInfo;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class Utility {
|
||||||
|
// Affiliate an Intent to another profile (i.e. the Work profile that we manage)
|
||||||
|
public static void transferIntentToProfile(Context context, Intent intent) {
|
||||||
|
PackageManager pm = context.getPackageManager();
|
||||||
|
List<ResolveInfo> info = pm.queryIntentActivities(intent, 0);
|
||||||
|
ResolveInfo i = info.stream()
|
||||||
|
.filter((r) -> !r.activityInfo.packageName.equals(context.getPackageName()))
|
||||||
|
.collect(Collectors.toList()).get(0);
|
||||||
|
intent.setComponent(new ComponentName(i.activityInfo.packageName, i.activityInfo.name));
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue