Skip to content

Commit 565fd7f

Browse files
TreeHugger RobotAndroid (Google) Code Review
authored andcommitted
Merge "Add AppStatesService to TestDPC." into ub-testdpc-qt
2 parents 8755bed + 4993f91 commit 565fd7f

File tree

6 files changed

+125
-0
lines changed

6 files changed

+125
-0
lines changed

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ private void stripTestOnlyForBuild(flavor, buildType) {
125125
}
126126

127127
dependencies {
128+
implementation 'androidx.enterprise:enterprise-feedback:1.0.0-alpha01'
128129
implementation 'com.android.support:multidex:1.0.1'
129130
implementation 'com.android.support:preference-v14:28.0.0-SNAPSHOT'
130131
implementation 'com.android.support:recyclerview-v7:28.0.0-SNAPSHOT'

app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,12 @@
197197
</intent-filter>
198198
</service>
199199

200+
<service android:name=".feedback.AppStatesService">
201+
<intent-filter>
202+
<action android:name="androidx.enterprise.feedback.action.APP_STATES" />
203+
</intent-filter>
204+
</service>
205+
200206
</application>
201207

202208
</manifest>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
package com.afwsamples.testdpc.feedback;
2+
3+
import android.app.NotificationChannel;
4+
import android.app.NotificationManager;
5+
import android.os.Build;
6+
import android.support.v4.app.NotificationCompat;
7+
import android.support.v4.app.NotificationManagerCompat;
8+
import android.support.v7.preference.PreferenceManager;
9+
import android.util.Log;
10+
import androidx.enterprise.feedback.KeyedAppState;
11+
import androidx.enterprise.feedback.KeyedAppStatesService;
12+
import androidx.enterprise.feedback.ReceivedKeyedAppState;
13+
import com.afwsamples.testdpc.R;
14+
import java.util.Collection;
15+
import java.util.HashMap;
16+
import java.util.Map;
17+
18+
/**
19+
* Receive {@link KeyedAppState} instances and show them as a notification.
20+
*
21+
* <p>Also logs received keyed app states using the tag "KeyedAppStates".
22+
*/
23+
public class AppStatesService extends KeyedAppStatesService {
24+
25+
private static final String CHANNEL_ID = "KeyedAppStates";
26+
private static final String CHANNEL_NAME = "Keyed App States";
27+
28+
private int nextNotificationId = 0;
29+
private Map<String, Integer> idMapping = new HashMap<>();
30+
31+
@Override
32+
public void onReceive(Collection<ReceivedKeyedAppState> states, boolean requestSync) {
33+
boolean shouldNotify =
34+
PreferenceManager.getDefaultSharedPreferences(this)
35+
.getBoolean(getString(R.string.app_feedback_notifications), false);
36+
37+
if (!shouldNotify) {
38+
return;
39+
}
40+
41+
createNotificationChannel();
42+
43+
for (ReceivedKeyedAppState state : states) {
44+
showNotification(state, requestSync);
45+
}
46+
}
47+
48+
private void showNotification(ReceivedKeyedAppState state, boolean requestSync) {
49+
Log.i("KeyedAppStates",
50+
state.timestamp() + " " +
51+
state.packageName() + ":" +
52+
state.key() + "=" +
53+
state.data() + " (" +
54+
state.message() + ")" + (requestSync ? " - SYNC REQUESTED" : ""));
55+
56+
NotificationCompat.Builder notificationBuilder =
57+
new NotificationCompat.Builder(this, CHANNEL_ID)
58+
.setSmallIcon(R.drawable.arrow_down)
59+
.setContentTitle(state.packageName() + ":" + state.key())
60+
.setContentText(state.timestamp() + " " +
61+
state.data() +
62+
" (" + state.message() +")" +
63+
(requestSync ? "\nSYNC REQUESTED" : ""));
64+
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
65+
notificationManager.notify(getIdForState(state), notificationBuilder.build());
66+
}
67+
68+
private void createNotificationChannel() {
69+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
70+
NotificationChannel channel =
71+
new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
72+
NotificationManager notificationManager = getSystemService(NotificationManager.class);
73+
notificationManager.createNotificationChannel(channel);
74+
}
75+
}
76+
77+
private int getIdForState(ReceivedKeyedAppState state) {
78+
String key = state.packageName() + ":" + state.key();
79+
80+
if (!idMapping.containsKey(key)) {
81+
idMapping.put(key, nextNotificationId++);
82+
}
83+
return idMapping.get(key);
84+
}
85+
}

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import android.content.Context;
4242
import android.content.DialogInterface;
4343
import android.content.Intent;
44+
import android.content.SharedPreferences;
4445
import android.content.pm.ApplicationInfo;
4546
import android.content.pm.PackageManager;
4647
import android.content.pm.ResolveInfo;
@@ -66,6 +67,7 @@
6667
import android.support.v7.preference.EditTextPreference;
6768
import android.support.v7.preference.ListPreference;
6869
import android.support.v7.preference.Preference;
70+
import android.support.v7.preference.PreferenceManager;
6971
import android.telephony.TelephonyManager;
7072
import android.text.InputType;
7173
import android.text.TextUtils;
@@ -270,6 +272,7 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
270272
private static final String DISABLE_SCREEN_CAPTURE_KEY = "disable_screen_capture";
271273
private static final String DISABLE_STATUS_BAR = "disable_status_bar";
272274
private static final String ENABLE_BACKUP_SERVICE = "enable_backup_service";
275+
private static final String APP_FEEDBACK_NOTIFICATIONS = "app_feedback_notifications";
273276
private static final String ENABLE_SECURITY_LOGGING = "enable_security_logging";
274277
private static final String ENABLE_NETWORK_LOGGING = "enable_network_logging";
275278
private static final String ENABLE_SYSTEM_APPS_BY_INTENT_KEY = "enable_system_apps_by_intent";
@@ -458,6 +461,8 @@ public class PolicyManagementFragment extends BaseSearchablePolicyPreferenceFrag
458461

459462
private DpcSwitchPreference mAutoBrightnessPreference;
460463

464+
private DpcSwitchPreference mEnableAppFeedbackNotificationsPreference;
465+
461466
private GetAccessibilityServicesTask mGetAccessibilityServicesTask = null;
462467
private GetInputMethodsTask mGetInputMethodsTask = null;
463468
private GetNotificationListenersTask mGetNotificationListenersTask = null;
@@ -600,6 +605,9 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
600605
findPreference(REMOVE_ACCOUNT_KEY).setOnPreferenceClickListener(this);
601606
findPreference(BLOCK_UNINSTALLATION_BY_PKG_KEY).setOnPreferenceClickListener(this);
602607
findPreference(BLOCK_UNINSTALLATION_LIST_KEY).setOnPreferenceClickListener(this);
608+
findPreference(APP_FEEDBACK_NOTIFICATIONS).setOnPreferenceChangeListener(this);
609+
mEnableAppFeedbackNotificationsPreference =
610+
(DpcSwitchPreference) findPreference(APP_FEEDBACK_NOTIFICATIONS);
603611
findPreference(ENABLE_SYSTEM_APPS_KEY).setOnPreferenceClickListener(this);
604612
findPreference(ENABLE_SYSTEM_APPS_BY_PACKAGE_NAME_KEY).setOnPreferenceClickListener(this);
605613
findPreference(ENABLE_SYSTEM_APPS_BY_INTENT_KEY).setOnPreferenceClickListener(this);
@@ -687,6 +695,7 @@ public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
687695
constrainSpecialCasePreferences();
688696

689697
maybeDisableLockTaskPreferences();
698+
loadAppFeedbackNotifications();
690699
loadAppStatus();
691700
loadSecurityPatch();
692701
loadIsEphemeralUserUi();
@@ -1331,6 +1340,14 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
13311340
Integer.parseInt((String) newValue));
13321341
startActivity(intent);
13331342
return true;
1343+
case APP_FEEDBACK_NOTIFICATIONS:
1344+
SharedPreferences.Editor editor =
1345+
PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
1346+
editor.putBoolean(
1347+
getString(
1348+
R.string.app_feedback_notifications), newValue.equals(true));
1349+
editor.commit();
1350+
return true;
13341351
}
13351352
return false;
13361353
}
@@ -2085,6 +2102,13 @@ public void onClick(DialogInterface dialogInterface, int i) {
20852102
.show();
20862103
}
20872104

2105+
@TargetApi(Build.VERSION_CODES.M)
2106+
private void loadAppFeedbackNotifications() {
2107+
mEnableAppFeedbackNotificationsPreference.setChecked(
2108+
PreferenceManager.getDefaultSharedPreferences(getContext())
2109+
.getBoolean(getString(R.string.app_feedback_notifications), false));
2110+
}
2111+
20882112
private void loadAppStatus() {
20892113
final @StringRes int appStatusStringId;
20902114
if (mDevicePolicyManager.isProfileOwnerApp(mPackageName)) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -548,6 +548,10 @@
548548
<string name="plus">+</string>
549549
<string name="app_restrictions_managing_package">App restrictions manager</string>
550550

551+
<!-- Strings for app feedback -->
552+
<!-- [CHAR LIMIT=40] Settings label. A user can toggle this setting to turn on notifications for app feedback. -->
553+
<string name="app_feedback_notifications">App feedback notifications</string>
554+
551555
<!-- Strings for metered data restriction -->
552556
<string name="metered_data_restriction">Disable metered data</string>
553557
<string name="update_pkgs">Update</string>

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,11 @@
178178
android:title="@string/metered_data_restriction"
179179
testdpc:admin="deviceOwner|profileOwner"
180180
testdpc:minSdkVersion="P" />
181+
<com.afwsamples.testdpc.common.preference.DpcSwitchPreference
182+
android:key="app_feedback_notifications"
183+
android:title="@string/app_feedback_notifications"
184+
testdpc:admin="deviceOwner|profileOwner"
185+
testdpc:minSdkVersion="N" />
181186
</PreferenceCategory>
182187

183188
<PreferenceCategory android:title="@string/delegation_title">

0 commit comments

Comments
 (0)