Skip to content

Commit 57eb205

Browse files
author
Kenny Guy
committed
Add support for notification listeners whitelist
Let user type package names as the package may not be installed in the work profile Bug: 36657192 Test: Manual Change-Id: I5eae16654e5d52f222f8ba6d3439a31e423e4547
1 parent 10618a3 commit 57eb205

File tree

3 files changed

+142
-0
lines changed

3 files changed

+142
-0
lines changed

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

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import android.content.pm.ApplicationInfo;
3535
import android.content.pm.PackageManager;
3636
import android.content.pm.ResolveInfo;
37+
import android.content.pm.ServiceInfo;
3738
import android.net.ProxyInfo;
3839
import android.net.Uri;
3940
import android.os.AsyncTask;
@@ -46,6 +47,7 @@
4647
import android.provider.Settings;
4748
import android.security.KeyChain;
4849
import android.security.KeyChainAliasCallback;
50+
import android.service.notification.NotificationListenerService;
4951
import android.support.annotation.StringRes;
5052
import android.support.v14.preference.SwitchPreference;
5153
import android.support.v4.content.FileProvider;
@@ -80,6 +82,8 @@
8082
import com.afwsamples.testdpc.common.CertificateUtil;
8183
import com.afwsamples.testdpc.common.MediaDisplayFragment;
8284
import com.afwsamples.testdpc.common.Util;
85+
import com.afwsamples.testdpc.common.CertificateUtil;
86+
import com.afwsamples.testdpc.common.ReflectionUtil;
8387
import com.afwsamples.testdpc.common.preference.DpcPreference;
8488
import com.afwsamples.testdpc.common.preference.DpcPreferenceBase;
8589
import com.afwsamples.testdpc.common.preference.DpcPreferenceHelper;
@@ -111,6 +115,9 @@
111115
import java.io.FileNotFoundException;
112116
import java.io.IOException;
113117
import java.io.InputStream;
118+
import java.lang.reflect.InvocationTargetException;
119+
import java.lang.reflect.Method;
120+
import java.security.KeyStore;
114121
import java.security.KeyStoreException;
115122
import java.security.NoSuchAlgorithmException;
116123
import java.security.PrivateKey;
@@ -274,6 +281,8 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
274281
private static final String SET_DISABLE_ACCOUNT_MANAGEMENT_KEY
275282
= "set_disable_account_management";
276283
private static final String SET_INPUT_METHODS_KEY = "set_input_methods";
284+
private static final String SET_NOTIFICATION_LISTENERS_KEY = "set_notification_listeners";
285+
private static final String SET_NOTIFICATION_LISTENERS_TEXT_KEY = "set_notification_listeners_text";
277286
private static final String SET_LONG_SUPPORT_MESSAGE_KEY = "set_long_support_message";
278287
private static final String SET_PERMISSION_POLICY_KEY = "set_permission_policy";
279288
private static final String SET_SHORT_SUPPORT_MESSAGE_KEY = "set_short_support_message";
@@ -333,6 +342,7 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
333342

334343
private GetAccessibilityServicesTask mGetAccessibilityServicesTask = null;
335344
private GetInputMethodsTask mGetInputMethodsTask = null;
345+
private GetNotificationListenersTask mGetNotificationListenersTask = null;
336346
private ShowCaCertificateListTask mShowCaCertificateListTask = null;
337347

338348
private Uri mImageUri;
@@ -416,6 +426,8 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
416426
mEnableNetworkLoggingPreference.setOnPreferenceChangeListener(this);
417427
findPreference(SET_ACCESSIBILITY_SERVICES_KEY).setOnPreferenceClickListener(this);
418428
findPreference(SET_INPUT_METHODS_KEY).setOnPreferenceClickListener(this);
429+
findPreference(SET_NOTIFICATION_LISTENERS_KEY).setOnPreferenceClickListener(this);
430+
findPreference(SET_NOTIFICATION_LISTENERS_TEXT_KEY).setOnPreferenceClickListener(this);
419431
findPreference(SET_DISABLE_ACCOUNT_MANAGEMENT_KEY).setOnPreferenceClickListener(this);
420432
findPreference(GET_DISABLE_ACCOUNT_MANAGEMENT_KEY).setOnPreferenceClickListener(this);
421433
findPreference(ADD_ACCOUNT_KEY).setOnPreferenceClickListener(this);
@@ -600,6 +612,18 @@ public void onPositiveButtonClicked(String[] lockTaskArray) {
600612
mGetInputMethodsTask = new GetInputMethodsTask();
601613
mGetInputMethodsTask.execute();
602614
return true;
615+
case SET_NOTIFICATION_LISTENERS_KEY:
616+
// Avoid starting the same task twice.
617+
if (mGetNotificationListenersTask != null
618+
&& !mGetNotificationListenersTask.isCancelled()) {
619+
mGetNotificationListenersTask.cancel(true);
620+
}
621+
mGetNotificationListenersTask = new GetNotificationListenersTask();
622+
mGetNotificationListenersTask.execute();
623+
return true;
624+
case SET_NOTIFICATION_LISTENERS_TEXT_KEY:
625+
setNotificationWhitelistEditBox();
626+
return true;
603627
case SET_DISABLE_ACCOUNT_MANAGEMENT_KEY:
604628
showSetDisableAccountManagementPrompt();
605629
return true;
@@ -2288,6 +2312,101 @@ protected void setPermittedComponentsList(List<String> permittedInputMethods) {
22882312
}
22892313
}
22902314

2315+
private void setNotificationWhitelistEditBox() {
2316+
if (getActivity() == null || getActivity().isFinishing()) {
2317+
return;
2318+
}
2319+
View view = getActivity().getLayoutInflater().inflate(R.layout.simple_edittext, null);
2320+
final EditText input = (EditText) view.findViewById(R.id.input);
2321+
input.setHint(getString(R.string.set_notification_listener_text_hint));
2322+
List<String> enabledComponents = getPermittedNotificationListeners();
2323+
if (enabledComponents == null) {
2324+
input.setText("null");
2325+
} else {
2326+
input.setText(TextUtils.join(", ", enabledComponents));
2327+
}
2328+
2329+
new AlertDialog.Builder(getActivity())
2330+
.setTitle(getString(R.string.set_notification_listener_text_hint))
2331+
.setView(view)
2332+
.setPositiveButton(android.R.string.ok,
2333+
(DialogInterface dialog, int which) -> {
2334+
String packageNames = input.getText().toString();
2335+
if (packageNames.trim().equals("null")) {
2336+
setPermittedNotificationListeners(null);
2337+
} else {
2338+
List<String> items = Arrays.asList(
2339+
packageNames.trim().split("\\s*,\\s*"));
2340+
setPermittedNotificationListeners(items);
2341+
}
2342+
dialog.dismiss();
2343+
})
2344+
.setNegativeButton(android.R.string.cancel,
2345+
(DialogInterface dialog, int which) -> dialog.dismiss())
2346+
.show();
2347+
}
2348+
2349+
/**
2350+
* Gets all the NotificationListenerServices and displays them in a prompt.
2351+
*/
2352+
private class GetNotificationListenersTask extends GetAvailableComponentsTask<ResolveInfo> {
2353+
public GetNotificationListenersTask() {
2354+
super(getActivity(), R.string.set_notification_listeners);
2355+
}
2356+
2357+
@Override
2358+
protected List<ResolveInfo> doInBackground(Void... voids) {
2359+
return mPackageManager.queryIntentServices(
2360+
new Intent(NotificationListenerService.SERVICE_INTERFACE),
2361+
PackageManager.GET_META_DATA | PackageManager.MATCH_UNINSTALLED_PACKAGES);
2362+
}
2363+
2364+
@Override
2365+
protected List<ResolveInfo> getResolveInfoListFromAvailableComponents(
2366+
List<ResolveInfo> notificationListenerServices) {
2367+
return notificationListenerServices;
2368+
}
2369+
2370+
@Override
2371+
protected List<String> getPermittedComponentsList() {
2372+
return getPermittedNotificationListeners();
2373+
}
2374+
2375+
@Override
2376+
protected void setPermittedComponentsList(List<String> permittedNotificationListeners) {
2377+
setPermittedNotificationListeners(permittedNotificationListeners);
2378+
}
2379+
}
2380+
2381+
private void setPermittedNotificationListeners(List<String> permittedNotificationListeners) {
2382+
// STOPSHIP: Call actual method once in the SDK
2383+
boolean result;
2384+
try {
2385+
result = (boolean) ReflectionUtil.invoke(mDevicePolicyManager,
2386+
"setPermittedCrossProfileNotificationListeners",
2387+
new Class<?>[] {ComponentName.class, List.class},
2388+
mAdminComponentName, permittedNotificationListeners);
2389+
} catch (ReflectionUtil.ReflectionIsTemporaryException e) {
2390+
Log.e(TAG, "Setting permitted notification listeners failed", e);
2391+
result = false;
2392+
}
2393+
int successMsgId = (permittedNotificationListeners == null)
2394+
? R.string.all_notification_listeners_enabled
2395+
: R.string.set_notification_listeners_successful;
2396+
showToast(result ? successMsgId : R.string.set_notification_listeners_fail);
2397+
}
2398+
2399+
private List<String> getPermittedNotificationListeners() {
2400+
// STOPSHIP: Call actual method once in the SDK
2401+
try {
2402+
return (List<String>) ReflectionUtil.invoke(mDevicePolicyManager,
2403+
"getPermittedCrossProfileNotificationListeners", mAdminComponentName);
2404+
} catch (ReflectionUtil.ReflectionIsTemporaryException e) {
2405+
Log.e(TAG, "Setting permitted notification listeners failed", e);
2406+
}
2407+
return null;
2408+
}
2409+
22912410
/**
22922411
* Gets all CA certificates and displays them in a prompt.
22932412
*/

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,16 @@
475475
<string name="set_input_methods_fail">Cannot disallow input methods enabled by the primary user</string>
476476
<string name="all_input_methods_enabled">All input methods are enabled.</string>
477477

478+
<!-- Notification listeners -->
479+
<string name="notification_listeners_title">Notification Listener Services</string>
480+
<string name="set_notification_listeners">Set notification listener services</string>
481+
<string name="set_notification_listeners_successful">The given list of notification listeners is enabled</string>
482+
<string name="set_notification_listeners_fail">Cannot add the notification listener list provided</string>
483+
<string name="all_notification_listeners_enabled">All notification listeners are enabled.</string>
484+
<string name="set_notification_listeners_text">Set notification listener services text</string>
485+
<string name="set_notification_listener_text_title">Notification listener packages</string>
486+
<string name="set_notification_listener_text_hint">Comma separated package list</string>
487+
478488
<string name="loading_resuls">Loading\u2026</string>
479489

480490
<!-- Account management -->

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,19 @@
203203
testdpc:minSdkVersion="L" />
204204
</PreferenceCategory>
205205

206+
<PreferenceCategory android:title="@string/notification_listeners_title">
207+
<com.afwsamples.testdpc.common.preference.DpcPreference
208+
android:key="set_notification_listeners"
209+
android:title="@string/set_notification_listeners"
210+
testdpc:user="managedProfile"
211+
testdpc:minSdkVersion="O" />
212+
<com.afwsamples.testdpc.common.preference.DpcPreference
213+
android:key="set_notification_listeners_text"
214+
android:title="@string/set_notification_listeners_text"
215+
testdpc:user="managedProfile"
216+
testdpc:minSdkVersion="O" />
217+
</PreferenceCategory>
218+
206219
<PreferenceCategory android:title="@string/lock_category">
207220
<com.afwsamples.testdpc.common.preference.DpcPreference
208221
android:key="password_compliant"

0 commit comments

Comments
 (0)