Skip to content

Commit b6e4c43

Browse files
author
Kholoud Mohamed
committed
Add cross profile apps whitelisting support
Bug: https://b.corp.google.com/issues/160294472 Test: manual testing Change-Id: I8ba199c020ba1499afabc9bd55c14c45dfae73ff
1 parent e7979f6 commit b6e4c43

File tree

5 files changed

+209
-0
lines changed

5 files changed

+209
-0
lines changed
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/*
2+
* Copyright (C) 2020 The Android Open Source Project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.afwsamples.testdpc;
17+
18+
import android.annotation.TargetApi;
19+
import android.app.Fragment;
20+
import android.app.admin.DevicePolicyManager;
21+
import android.content.ComponentName;
22+
import android.os.Build.VERSION_CODES;
23+
import android.os.Bundle;
24+
import android.view.LayoutInflater;
25+
import android.view.View;
26+
import android.view.ViewGroup;
27+
import android.widget.Button;
28+
import android.widget.EditText;
29+
import android.widget.TextView;
30+
import java.util.Collections;
31+
import java.util.Set;
32+
33+
/**
34+
* This fragment provides the ability to whitelist cross profile packages
35+
*
36+
* <p>APIs exercised:
37+
* <ul>
38+
* <li> {@link DevicePolicyManager#setCrossProfilePackages(ComponentName, Set)} </li>
39+
* <li> {@link DevicePolicyManager#getCrossProfilePackages(ComponentName)} </li>
40+
* </ul>
41+
*/
42+
@TargetApi(VERSION_CODES.R)
43+
public class CrossProfileAppsWhitelistFragment extends Fragment {
44+
private static final String DELIMITER = "\n";
45+
46+
private View mInflatedView;
47+
private EditText mAppNameEditText;
48+
private Button mResetButton;
49+
private Button mAddButton;
50+
private Button mRemoveButton;
51+
private TextView mAppsList;
52+
53+
private DevicePolicyManager mDevicePolicyManager;
54+
private ComponentName mAdminComponent;
55+
56+
@Override
57+
public View onCreateView(LayoutInflater inflater, ViewGroup container,
58+
Bundle savedInstanceState) {
59+
mDevicePolicyManager = getActivity().getSystemService(DevicePolicyManager.class);
60+
mAdminComponent = DeviceAdminReceiver.getComponentName(getActivity());
61+
mInflatedView = inflater.inflate(
62+
R.layout.cross_profile_apps_whitelist, container, false);
63+
64+
mAppNameEditText = mInflatedView.findViewById(R.id.cross_profile_app_whitelist_input);
65+
mResetButton = mInflatedView.findViewById(R.id.cross_profile_app_whitelist_reset_button);
66+
mAddButton = mInflatedView.findViewById(R.id.cross_profile_app_whitelist_add_button);
67+
mRemoveButton = mInflatedView.findViewById(R.id.cross_profile_app_whitelist_remove_button);
68+
mAppsList = mInflatedView.findViewById(R.id.cross_profile_app_list);
69+
70+
setOnClickListeners();
71+
updateCrossProfileAppsList();
72+
73+
return mInflatedView;
74+
}
75+
76+
private void setOnClickListeners() {
77+
mResetButton.setOnClickListener(view -> resetApps());
78+
mAddButton.setOnClickListener(
79+
view -> addApp(mAppNameEditText.getText().toString().toLowerCase().trim()));
80+
mRemoveButton.setOnClickListener(
81+
view -> removeApp(mAppNameEditText.getText().toString().toLowerCase().trim()));
82+
}
83+
84+
private void resetApps() {
85+
mDevicePolicyManager.setCrossProfilePackages(mAdminComponent, Collections.emptySet());
86+
updateCrossProfileAppsList();
87+
}
88+
89+
private void addApp(String app) {
90+
Set<String> currentApps = mDevicePolicyManager.getCrossProfilePackages(mAdminComponent);
91+
currentApps.add(app);
92+
mDevicePolicyManager.setCrossProfilePackages(mAdminComponent, currentApps);
93+
updateCrossProfileAppsList();
94+
}
95+
96+
private void removeApp(String app) {
97+
Set<String> currentApps = mDevicePolicyManager.getCrossProfilePackages(mAdminComponent);
98+
currentApps.remove(app);
99+
mDevicePolicyManager.setCrossProfilePackages(mAdminComponent, currentApps);
100+
updateCrossProfileAppsList();
101+
}
102+
103+
private void updateCrossProfileAppsList(){
104+
Set<String> currentApps = mDevicePolicyManager.getCrossProfilePackages(mAdminComponent);
105+
if (currentApps.isEmpty()) {
106+
mAppsList.setText(R.string.cross_profile_apps_no_whitelisted_apps);
107+
} else {
108+
mAppsList.setText(String.join(DELIMITER, currentApps));
109+
}
110+
}
111+
}

app/src/main/java/com/afwsamples/testdpc/policy/PolicyManagementFragment.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
import com.afwsamples.testdpc.AddAccountActivity;
9595
import com.afwsamples.testdpc.BuildConfig;
9696
import com.afwsamples.testdpc.CrossProfileAppsFragment;
97+
import com.afwsamples.testdpc.CrossProfileAppsWhitelistFragment;
9798
import com.afwsamples.testdpc.DeviceAdminReceiver;
9899
import com.afwsamples.testdpc.R;
99100
import com.afwsamples.testdpc.SetupManagementActivity;
@@ -385,6 +386,7 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
385386
private static final String SET_PROFILE_PARENT_NEW_PASSWORD = "set_profile_parent_new_password";
386387
private static final String BIND_DEVICE_ADMIN_POLICIES = "bind_device_admin_policies";
387388
private static final String CROSS_PROFILE_APPS = "cross_profile_apps";
389+
private static final String CROSS_PROFILE_APPS_WHITELIST = "cross_profile_apps_whitelist";
388390
private static final String SET_SCREEN_BRIGHTNESS_KEY = "set_screen_brightness";
389391
private static final String AUTO_BRIGHTNESS_KEY = "auto_brightness";
390392
private static final String CROSS_PROFILE_CALENDAR_KEY = "cross_profile_calendar";
@@ -710,6 +712,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
710712
findPreference(SET_NEW_PASSWORD).setOnPreferenceClickListener(this);
711713
findPreference(SET_PROFILE_PARENT_NEW_PASSWORD).setOnPreferenceClickListener(this);
712714
findPreference(CROSS_PROFILE_APPS).setOnPreferenceClickListener(this);
715+
findPreference(CROSS_PROFILE_APPS_WHITELIST).setOnPreferenceClickListener(this);
713716

714717
findPreference(SET_SCREEN_BRIGHTNESS_KEY).setOnPreferenceClickListener(this);
715718
mAutoBrightnessPreference = (DpcSwitchPreference) findPreference(AUTO_BRIGHTNESS_KEY);
@@ -1217,6 +1220,9 @@ public void onPositiveButtonClicked(String[] lockTaskArray) {
12171220
case CROSS_PROFILE_APPS:
12181221
showFragment(new CrossProfileAppsFragment());
12191222
return true;
1223+
case CROSS_PROFILE_APPS_WHITELIST:
1224+
showFragment(new CrossProfileAppsWhitelistFragment());
1225+
return true;
12201226
case SET_SCREEN_BRIGHTNESS_KEY:
12211227
showSetScreenBrightnessDialog();
12221228
return true;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<!--
3+
Copyright (C) 2020 Google Inc.
4+
5+
Licensed under the Apache License, Version 2.0 (the "License");
6+
you may not use this file except in compliance with the License.
7+
You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
-->
17+
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
18+
android:layout_width="match_parent"
19+
android:layout_height="match_parent"
20+
android:fadeScrollbars="false">
21+
<LinearLayout
22+
android:layout_width="match_parent"
23+
android:layout_height="match_parent"
24+
android:orientation="vertical"
25+
android:paddingRight="@dimen/activity_horizontal_margin"
26+
android:paddingLeft="@dimen/activity_horizontal_margin">
27+
28+
<TextView
29+
android:layout_width="match_parent"
30+
android:layout_height="wrap_content"
31+
android:text="@string/cross_profile_apps_enabled_title"
32+
android:textSize="20sp"
33+
android:paddingBottom="@dimen/content_padding_between_text"
34+
android:paddingTop="@dimen/content_padding_between_text"/>
35+
36+
<TextView
37+
android:id="@+id/cross_profile_app_list"
38+
android:layout_width="wrap_content"
39+
android:layout_height="wrap_content"
40+
android:textSize="16sp"
41+
android:paddingBottom="@dimen/content_padding_bottom"/>
42+
43+
<EditText
44+
android:id="@+id/cross_profile_app_whitelist_input"
45+
android:layout_width="wrap_content"
46+
android:layout_height="wrap_content"
47+
android:hint="@string/cross_profile_apps_example_text"
48+
android:singleLine="false" />
49+
50+
<LinearLayout
51+
android:layout_width="wrap_content"
52+
android:layout_height="wrap_content"
53+
android:gravity="center"
54+
android:orientation="horizontal"
55+
android:paddingBottom="@dimen/content_padding_between_text">
56+
57+
<Button
58+
android:id="@+id/cross_profile_app_whitelist_add_button"
59+
android:layout_width="wrap_content"
60+
android:layout_height="wrap_content"
61+
android:layout_marginTop="10dp"
62+
android:text="@string/cross_profile_apps_add_button_text" />
63+
64+
<Button
65+
android:id="@+id/cross_profile_app_whitelist_remove_button"
66+
android:layout_width="wrap_content"
67+
android:layout_height="wrap_content"
68+
android:layout_marginTop="10dp"
69+
android:text="@string/cross_profile_apps_remove_button_text" />
70+
</LinearLayout>
71+
72+
<Button
73+
android:id="@+id/cross_profile_app_whitelist_reset_button"
74+
android:layout_width="wrap_content"
75+
android:layout_height="wrap_content"
76+
android:text="@string/cross_profile_apps_reset_button_text" />
77+
</LinearLayout>
78+
</ScrollView>

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,14 @@
11061106
<string name="cross_profile_apps_available">TestDPC is installed in another profile, tap the icon to launch it in that profile.</string>
11071107
<string name="cross_profile_apps_not_available">TestDPC is not installed in another profile, try installing it and come back to here.</string>
11081108

1109+
<string name="cross_profile_apps_whitelist">Whitelisted cross profile apps</string>
1110+
<string name="cross_profile_apps_enabled_title">Enabled cross profile apps</string>
1111+
<string name="cross_profile_apps_no_whitelisted_apps">No apps whitelisted</string>
1112+
<string name="cross_profile_apps_example_text">example.package.name</string>
1113+
<string name="cross_profile_apps_add_button_text">Add app</string>
1114+
<string name="cross_profile_apps_remove_button_text">Remove app</string>
1115+
<string name="cross_profile_apps_reset_button_text">Reset cross profile apps</string>
1116+
11091117
<string name="install_update">Install update from file</string>
11101118
<string name="install_update_prompt">This will attempt to install the update file ota.zip in the TestDPC files directory, if the file exists (i.e. if you pushed it there with adb). Do you want to continue?</string>
11111119
<string name="install_update_prompt_yes">Yes</string>

app/src/main/res/xml/device_policy_header.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -786,5 +786,11 @@
786786
android:title="@string/cross_profile_apps_api"
787787
testdpc:admin="any"
788788
testdpc:minSdkVersion="P" />
789+
<com.afwsamples.testdpc.common.preference.DpcPreference
790+
android:key="cross_profile_apps_whitelist"
791+
android:title="@string/cross_profile_apps_whitelist"
792+
testdpc:admin="any"
793+
testdpc:user="managedProfile"
794+
testdpc:minSdkVersion="R" />
789795
</PreferenceCategory>
790796
</PreferenceScreen>

0 commit comments

Comments
 (0)