diff options
39 files changed, 921 insertions, 569 deletions
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml index 2d7af379a..ff9c2ed0a 100644 --- a/PermissionController/AndroidManifest.xml +++ b/PermissionController/AndroidManifest.xml @@ -103,9 +103,6 @@ <service android:name="com.android.permissioncontroller.hibernation.HibernationJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> - <service android:name="com.android.permissioncontroller.permission.service.AutoRevokeReGrantService" - android:permission="android.permission.BIND_JOB_SERVICE" /> - <service android:name="com.android.permissioncontroller.permission.service.DecisionCleanupJobService" android:permission="android.permission.BIND_JOB_SERVICE" /> @@ -177,13 +174,13 @@ </intent-filter> </activity> - <activity android:name="com.android.permissioncontroller.permission.ui.SafetyHubQSActivity" + <activity android:name="com.android.permissioncontroller.permission.ui.SafetyCenterQSActivity" android:excludeFromRecents="true" android:exported="true" - android:theme="@style/SafetyHub" + android:theme="@style/SafetyCenter" android:permission="android.permission.REVOKE_RUNTIME_PERMISSIONS"> <intent-filter android:priority="1"> - <action android:name="android.intent.action.VIEW_SAFETY_HUB" /> + <action android:name="android.intent.action.VIEW_SAFETY_CENTER_QS" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> @@ -341,7 +338,7 @@ </intent-filter> </service> - <service android:name="com.android.permissioncontroller.permission.service.SafetyHubQsTileService" + <service android:name="com.android.permissioncontroller.permission.service.SafetyCenterQSTileService" android:exported="true" android:label="@string/safety_privacy_qs_tile_title" android:icon ="@drawable/safety_shield" diff --git a/PermissionController/res/drawable/safety_hub_button_background.xml b/PermissionController/res/drawable/safety_center_button_background.xml index 5723588f5..5723588f5 100644 --- a/PermissionController/res/drawable/safety_hub_button_background.xml +++ b/PermissionController/res/drawable/safety_center_button_background.xml diff --git a/PermissionController/res/drawable/safety_hub_button_background_dark.xml b/PermissionController/res/drawable/safety_center_button_background_dark.xml index 90884857c..90884857c 100644 --- a/PermissionController/res/drawable/safety_hub_button_background_dark.xml +++ b/PermissionController/res/drawable/safety_center_button_background_dark.xml diff --git a/PermissionController/res/layout-v31/safety_hub_toggle_button.xml b/PermissionController/res/layout-v31/safety_center_toggle_button.xml index d1413c25a..b0b4933e0 100644 --- a/PermissionController/res/layout-v31/safety_hub_toggle_button.xml +++ b/PermissionController/res/layout-v31/safety_center_toggle_button.xml @@ -22,25 +22,25 @@ android:layout_weight="0.33" android:layout_height="wrap_content" android:orientation="vertical" - style="@style/SafetyHubSensorToggleButton" - android:id="@+id/safety_hub_toggle_button"> + style="@style/SafetyCenterSensorToggleButton" + android:id="@+id/safety_center_toggle_button"> <ImageView android:id="@+id/toggle_sensor_icon" android:layout_width="wrap_content" - style="@style/SafetyHubToggleText" + style="@style/SafetyCenterToggleText" android:layout_height="wrap_content"/> <TextView android:id="@+id/toggle_sensor_name" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/SafetyHubToggleText" + style="@style/SafetyCenterToggleText" android:textColor="?android:textColorPrimaryInverse"/> <TextView android:id="@+id/toggle_sensor_status" android:layout_width="wrap_content" android:layout_height="wrap_content" - style="@style/SafetyHubToggleText" + style="@style/SafetyCenterToggleText" android:text="@string/available" - android:textColor="@color/safety_hub_secondary"/> + android:textColor="@color/safety_center_secondary"/> </LinearLayout> diff --git a/PermissionController/res/layout/app_permission.xml b/PermissionController/res/layout/app_permission.xml index 48de3864d..697150b6f 100644 --- a/PermissionController/res/layout/app_permission.xml +++ b/PermissionController/res/layout/app_permission.xml @@ -119,7 +119,9 @@ <TextView android:id="@+id/permission_details" - style="@style/AppPermissionDetails" /> + style="@style/AppPermissionDetails" + android:gravity="start" + android:textAlignment="viewStart"/> <LinearLayout android:id="@+id/two_target_divider" diff --git a/PermissionController/res/layout/safety_hub_qs.xml b/PermissionController/res/layout/safety_center_qs.xml index b4b2c3f7e..6b1b169d6 100644 --- a/PermissionController/res/layout/safety_hub_qs.xml +++ b/PermissionController/res/layout/safety_center_qs.xml @@ -20,9 +20,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" - style="@style/SafetyHub" + style="@style/SafetyCenter" android:background="?android:colorBackground" - android:id="@+id/safety_hub_root"> + android:id="@+id/safety_center_root"> @@ -72,13 +72,13 @@ android:layout_marginBottom="10dp" android:layout_marginTop="10dp"> <include android:id="@+id/camera_toggle" - layout="@layout/safety_hub_toggle_button" /> + layout="@layout/safety_center_toggle_button" /> <include android:id="@+id/mic_toggle" - layout="@layout/safety_hub_toggle_button" /> + layout="@layout/safety_center_toggle_button" /> <include android:id="@+id/location_toggle" - layout="@layout/safety_hub_toggle_button" /> + layout="@layout/safety_center_toggle_button" /> </LinearLayout> <Button @@ -88,7 +88,7 @@ android:layout_width="300dp" android:layout_gravity="center_horizontal" android:background="@drawable/oval_outline_button" - style="@style/SafetyHubLinkText" + style="@style/SafetyCenterLinkText" android:textColor="#ffffffff" android:text="@string/security_settings"/> diff --git a/PermissionController/res/values-v31/styles.xml b/PermissionController/res/values-v31/styles.xml index 693be8387..45ad28a87 100644 --- a/PermissionController/res/values-v31/styles.xml +++ b/PermissionController/res/values-v31/styles.xml @@ -116,9 +116,9 @@ <item name="android:textAppearance">?android:attr/textAppearanceListItem</item> </style> - <!-- START SAFETY HUB QUICK SETTINGS PAGE --> + <!-- START SAFETY Center QUICK SETTINGS PAGE --> - <style name="SafetyHubLinkText"> + <style name="SafetyCenterLinkText"> <item name="android:layout_marginTop">5dp</item> <item name="android:layout_marginBottom">5dp</item> <item name="android:layout_marginStart">5dp</item> @@ -131,7 +131,7 @@ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> </style> - <style name="SafetyHubToggleText" parent="Theme.AppCompat"> + <style name="SafetyCenterToggleText" parent="Theme.AppCompat"> <item name="android:layout_marginTop">2dp</item> <item name="android:layout_marginStart">5dp</item> <item name="android:layout_marginEnd">5dp</item> @@ -139,8 +139,8 @@ <item name="android:textAppearance">?android:attr/textAppearanceSmall</item> </style> - <style name="SafetyHubSensorToggleButton" parent="SafetyHubLinkText"> - <item name="android:background">@drawable/safety_hub_button_background</item> + <style name="SafetyCenterSensorToggleButton" parent="SafetyCenterLinkText"> + <item name="android:background">@drawable/safety_center_button_background</item> </style> <style name="TextAppearance.SafetyStatusTitle" diff --git a/PermissionController/res/values/colors.xml b/PermissionController/res/values/colors.xml index 1bdf6f25c..083a32194 100644 --- a/PermissionController/res/values/colors.xml +++ b/PermissionController/res/values/colors.xml @@ -22,7 +22,7 @@ <color name="incident_reason_bullet_color">#de000000</color> <color name="divider_color_primary">#24000000</color> <color name="divider_color_secondary">#85FFFFFF</color> - <color name="safety_hub_secondary">#FF777777</color> + <color name="safety_center_secondary">#FF777777</color> <!-- Auto related colors --> <color name="car_tint">#fff8f9fa</color> diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml index 7893f755c..9f4ed7eff 100644 --- a/PermissionController/res/values/strings.xml +++ b/PermissionController/res/values/strings.xml @@ -828,6 +828,9 @@ other {While driving, you gave <xliff:g id="app" example="Waze">%1$s</xliff:g> & # other apps access} }</string> + <!-- The text of a button for an action in a notification that opens the Settings app [CHAR LIMIT=60] --> + <string name="go_to_settings">Go to Settings</string> + <!-- The subtitle for the auto revoke settings card [CHAR LIMIT=none] --> <string name="auto_revoke_setting_subtitle">Some apps haven\u2019t been used in a few months</string> @@ -1484,9 +1487,9 @@ Allow <xliff:g id="app_name" example="Gmail">%4$s</xliff:g> to upload a bug repo <string name="safety_center_issue_card_dismiss_button">Dismiss</string> <!-- Label for the button that takes the user to the settings page for Android Security [CHAR LIMIT=60] --> <string name="security_settings">Security Settings</string> - <!-- Label for the permission usage section of safety hub QS page[CHAR LIMIT=30] --> + <!-- Label for the permission usage section of safety center QS page[CHAR LIMIT=30] --> <string name="sensor_permissions_qs">Sensor Permissions</string> - <!-- Label for the privacy controls section of safety hub QS page [CHAR LIMIT=30] --> + <!-- Label for the privacy controls section of safety center QS page [CHAR LIMIT=30] --> <string name="privacy_controls_qs">Privacy Controls</string> <!-- Label when permissions were removed via safety center QS page [CHAR LIMIT=30] --> <string name="permissions_removed_qs">Permission removed</string> diff --git a/PermissionController/res/values/themes.xml b/PermissionController/res/values/themes.xml index edbfcc2b4..fe74cf39b 100644 --- a/PermissionController/res/values/themes.xml +++ b/PermissionController/res/values/themes.xml @@ -134,7 +134,7 @@ <item name="android:filterTouchesWhenObscured">true</item> </style> - <style name="SafetyHub" parent="@android:style/Theme.DeviceDefault.NoActionBar"> + <style name="SafetyCenter" parent="@android:style/Theme.DeviceDefault.NoActionBar"> <item name="android:filterTouchesWhenObscured">true</item> </style> diff --git a/PermissionController/res/xml/roles.xml b/PermissionController/res/xml/roles.xml index 04a786e4e..37ac359a7 100644 --- a/PermissionController/res/xml/roles.xml +++ b/PermissionController/res/xml/roles.xml @@ -1102,8 +1102,8 @@ ~ including during provisioning. --> <role - name="android.app.role.DEVICE_MANAGER" - defaultHolders="config_deviceManager" + name="android.app.role.DEVICE_POLICY_MANAGEMENT" + defaultHolders="config_devicePolicyManagement" exclusive="true" minSdkVersion="33" static="true" diff --git a/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt b/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt index 5bfe4dc86..f4ff49081 100644 --- a/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt +++ b/PermissionController/src/com/android/permissioncontroller/auto/DrivingDecisionReminderService.kt @@ -264,6 +264,9 @@ class DrivingDecisionReminderService : Service() { .setColor(getColor(android.R.color.system_notification_accent_color)) .setAutoCancel(true) .setContentIntent(pendingIntent) + // Auto doesn't show icons for actions + .addAction(Notification.Action.Builder(/* icon= */ null, + getString(R.string.go_to_settings), pendingIntent).build()) Utils.getSettingsLabelForNotifications(applicationContext.packageManager)?.let { label -> val extras = Bundle() extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, label.toString()) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/SafetyHubQsTileService.kt b/PermissionController/src/com/android/permissioncontroller/permission/service/SafetyCenterQSTileService.kt index 70531b9e0..5ee5d6f90 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/service/SafetyHubQsTileService.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/service/SafetyCenterQSTileService.kt @@ -27,9 +27,9 @@ import android.service.quicksettings.TileService import com.android.permissioncontroller.R /** - * The service backing a Quick Settings Tile which will take users to the Safety Hub QS Fragment. + * The service backing a Quick Settings Tile which will take users to the Safety Center QS Fragment. */ -class SafetyHubQsTileService : TileService() { +class SafetyCenterQSTileService : TileService() { private var disabled = false override fun onBind(intent: Intent?): IBinder? { @@ -59,7 +59,7 @@ class SafetyHubQsTileService : TileService() { } override fun onClick() { - val intent = Intent(Intent.ACTION_VIEW_SAFETY_HUB) + val intent = Intent(Intent.ACTION_VIEW_SAFETY_CENTER_QS) intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK startActivityAndCollapse(intent) } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyHubQSActivity.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyCenterQSActivity.java index 8286e21ed..c52be4bc8 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyHubQSActivity.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/SafetyCenterQSActivity.java @@ -26,15 +26,15 @@ import androidx.fragment.app.FragmentActivity; import com.android.modules.utils.build.SdkLevel; import com.android.permissioncontroller.Constants; -import com.android.permissioncontroller.permission.ui.handheld.SafetyHubQSFragment; +import com.android.permissioncontroller.permission.ui.handheld.SafetyCenterQSFragment; import java.util.ArrayList; import java.util.Random; /** - * Activity for the Safety Hub Quick Settings Activity + * Activity for the Safety Center Quick Settings Activity */ -public class SafetyHubQSActivity extends FragmentActivity { +public class SafetyCenterQSActivity extends FragmentActivity { @Override @SuppressWarnings("NewApi") @@ -53,6 +53,6 @@ public class SafetyHubQSActivity extends FragmentActivity { ArrayList<PermissionGroupUsage> permissionUsages = getIntent().getParcelableArrayListExtra( PermissionManager.EXTRA_PERMISSION_USAGES); getSupportFragmentManager().beginTransaction().replace(android.R.id.content, - SafetyHubQSFragment.newInstance(sessionId, permissionUsages)).commit(); + SafetyCenterQSFragment.newInstance(sessionId, permissionUsages)).commit(); } } diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SafetyHubQSFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SafetyCenterQSFragment.java index e5a977a51..c74cece93 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SafetyHubQSFragment.java +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/SafetyCenterQSFragment.java @@ -51,8 +51,8 @@ import androidx.transition.AutoTransition; import androidx.transition.TransitionManager; import com.android.permissioncontroller.R; -import com.android.permissioncontroller.permission.ui.model.SafetyHubViewModel; -import com.android.permissioncontroller.permission.ui.model.SafetyHubViewModelFactory; +import com.android.permissioncontroller.permission.ui.model.SafetyCenterViewModel; +import com.android.permissioncontroller.permission.ui.model.SafetyCenterViewModelFactory; import com.android.permissioncontroller.permission.utils.KotlinUtils; import com.android.permissioncontroller.permission.utils.Utils; @@ -63,17 +63,17 @@ import java.util.List; import java.util.Map; /** - * The Quick Settings fragment for the safety hub. Displays information to the user about the + * The Quick Settings fragment for the safety center. Displays information to the user about the * current safety and privacy status of their device, including showing mic/camera usage, and having * mic/camera/location toggles. */ @RequiresApi(Build.VERSION_CODES.TIRAMISU) -public class SafetyHubQSFragment extends Fragment { +public class SafetyCenterQSFragment extends Fragment { private static final ArrayMap<String, Integer> sToggleButtons = new ArrayMap<>(); private long mSessionId; private List<PermissionGroupUsage> mPermGroupUsages; - private SafetyHubViewModel mViewModel; + private SafetyCenterViewModel mViewModel; static { sToggleButtons.put(CAMERA, R.id.camera_toggle); @@ -87,12 +87,12 @@ public class SafetyHubQSFragment extends Fragment { * @param sessionId The current session Id * @return A bundle with the required arguments */ - public static SafetyHubQSFragment newInstance(long sessionId, + public static SafetyCenterQSFragment newInstance(long sessionId, ArrayList<PermissionGroupUsage> usages) { Bundle args = new Bundle(); args.putLong(EXTRA_SESSION_ID, sessionId); args.putParcelableArrayList(PermissionManager.EXTRA_PERMISSION_USAGES, usages); - SafetyHubQSFragment frag = new SafetyHubQSFragment(); + SafetyCenterQSFragment frag = new SafetyCenterQSFragment(); frag.setArguments(args); return frag; } @@ -112,11 +112,11 @@ public class SafetyHubQSFragment extends Fragment { mPermGroupUsages = new ArrayList<>(); } - getActivity().setTheme(R.style.SafetyHub); + getActivity().setTheme(R.style.SafetyCenter); - SafetyHubViewModelFactory factory = new SafetyHubViewModelFactory( + SafetyCenterViewModelFactory factory = new SafetyCenterViewModelFactory( getActivity().getApplication(), mSessionId, mPermGroupUsages); - mViewModel = new ViewModelProvider(this, factory).get(SafetyHubViewModel.class); + mViewModel = new ViewModelProvider(this, factory).get(SafetyCenterViewModel.class); mViewModel.getSensorPrivacyLiveData() .observe(this, (v) -> setSensorToggleState(v, getView())); //LightAppPermGroupLiveDatas are kept track of in the view model, @@ -127,7 +127,7 @@ public class SafetyHubQSFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - ViewGroup root = (ViewGroup) inflater.inflate(R.layout.safety_hub_qs, container, false); + ViewGroup root = (ViewGroup) inflater.inflate(R.layout.safety_center_qs, container, false); root.findViewById(R.id.security_settings_button).setOnClickListener( (v) -> mViewModel.navigateToSecuritySettings(this)); setSensorToggleState(new ArrayMap<>(), root); @@ -422,12 +422,12 @@ public class SafetyHubQSFragment extends Fragment { Drawable icon; if (sensorEnabled) { blockedStatus.setText(R.string.available); - toggle.setBackgroundResource(R.drawable.safety_hub_button_background); + toggle.setBackgroundResource(R.drawable.safety_center_button_background); icon = KotlinUtils.INSTANCE.getPermGroupIcon(getContext(), groupName, Color.BLACK); groupLabel.setTextColor(Color.BLACK); } else { blockedStatus.setText(R.string.blocked); - toggle.setBackgroundResource(R.drawable.safety_hub_button_background_dark); + toggle.setBackgroundResource(R.drawable.safety_center_button_background_dark); icon = getContext().getDrawable(getBlockedIconResId(groupName)); icon.setTint(Color.LTGRAY); groupLabel.setTextColor(Color.LTGRAY); diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt index 576da07e4..eff0fc5b9 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionGroupsViewModel.kt @@ -30,6 +30,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.navigation.fragment.findNavController +import com.android.modules.utils.build.SdkLevel import com.android.permissioncontroller.PermissionControllerApplication import com.android.permissioncontroller.PermissionControllerStatsLog import com.android.permissioncontroller.PermissionControllerStatsLog.APP_PERMISSION_GROUPS_FRAGMENT_AUTO_REVOKE_ACTION @@ -241,7 +242,10 @@ class AppPermissionGroupsViewModel( MODE_IGNORED } aom.setUidMode(OPSTR_AUTO_REVOKE_PERMISSIONS_IF_UNUSED, uid, mode) - if (isHibernationEnabled() && !enabled) { + if (isHibernationEnabled() && + SdkLevel.isAtLeastSv2() && + !enabled) { + // Only unhibernate on S_V2+ to have consistent toggle behavior w/ Settings val ahm = app.getSystemService(AppHibernationManager::class.java)!! ahm.setHibernatingForUser(packageName, false) ahm.setHibernatingGlobally(packageName, false) diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/SafetyHubViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/SafetyCenterViewModel.kt index 731bab400..f4500e262 100644 --- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/SafetyHubViewModel.kt +++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/SafetyCenterViewModel.kt @@ -46,7 +46,7 @@ import com.android.permissioncontroller.permission.utils.LocationUtils import kotlin.collections.set @RequiresApi(Build.VERSION_CODES.TIRAMISU) -class SafetyHubViewModel( +class SafetyCenterViewModel( private val app: Application, private val sessionId: Long, private val permGroupUsages: List<PermissionGroupUsage> @@ -174,19 +174,19 @@ class SafetyHubViewModel( } /** - * Factory for a SafetyHubFragment + * Factory for a SafetyCenterViewModel * * @param app The current application * @param sessionId A session ID used in logs to identify this particular session */ @RequiresApi(Build.VERSION_CODES.S) -class SafetyHubViewModelFactory( +class SafetyCenterViewModelFactory( private val app: Application, private val sessionId: Long, private val permGroupUsages: List<PermissionGroupUsage> ) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { @Suppress("UNCHECKED_CAST") - return SafetyHubViewModel(app, sessionId, permGroupUsages) as T + return SafetyCenterViewModel(app, sessionId, permGroupUsages) as T } } diff --git a/SafetyCenter/Config/safety_center_config.xsd b/SafetyCenter/Config/safety_center_config.xsd index 16d5ddfa0..77909d341 100644 --- a/SafetyCenter/Config/safety_center_config.xsd +++ b/SafetyCenter/Config/safety_center_config.xsd @@ -70,8 +70,8 @@ <xsd:attribute name="maxSeverityLevel" type="xsd:int" default="2147483647"/> <xsd:attribute name="searchTerms" type="xsd:string"/> <xsd:attribute name="broadcastReceiverClassName" type="xsd:string"/> - <xsd:attribute name="allowLogging" type="xsd:boolean" default="true"/> - <xsd:attribute name="allowRefreshOnPageOpen" type="xsd:boolean" default="false"/> + <xsd:attribute name="loggingAllowed" type="xsd:boolean" default="true"/> + <xsd:attribute name="refreshOnPageOpenAllowed" type="xsd:boolean" default="false"/> </xsd:complexType> <xsd:complexType name="issue-only-safety-source"> @@ -81,8 +81,8 @@ <xsd:attribute name="profile" type="profile" use="required"/> <xsd:attribute name="maxSeverityLevel" type="xsd:int" default="2147483647"/> <xsd:attribute name="broadcastReceiverClassName" type="xsd:string"/> - <xsd:attribute name="disallowLogging" type="xsd:boolean" default="false"/> - <xsd:attribute name="allowRefreshOnPageOpen" type="xsd:boolean" default="false"/> + <xsd:attribute name="loggingAllowed" type="xsd:boolean" default="true"/> + <xsd:attribute name="refreshOnPageOpenAllowed" type="xsd:boolean" default="false"/> </xsd:complexType> <xsd:complexType name="static-safety-source"> diff --git a/framework-s/api/system-current.txt b/framework-s/api/system-current.txt index 8c3550b11..7f301c1a4 100644 --- a/framework-s/api/system-current.txt +++ b/framework-s/api/system-current.txt @@ -35,7 +35,7 @@ package android.app.role { method @RequiresPermission(android.Manifest.permission.BYPASS_ROLE_QUALIFICATION) public void setBypassingRoleQualification(boolean); method @Deprecated @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>); field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1 - field public static final String ROLE_DEVICE_MANAGER = "android.app.role.DEVICE_MANAGER"; + field public static final String ROLE_DEVICE_POLICY_MANAGEMENT = "android.app.role.DEVICE_POLICY_MANAGEMENT"; field public static final String ROLE_SYSTEM_ACTIVITY_RECOGNIZER = "android.app.role.SYSTEM_ACTIVITY_RECOGNIZER"; field public static final String ROLE_SYSTEM_SUPERVISION = "android.app.role.SYSTEM_SUPERVISION"; field public static final String ROLE_SYSTEM_WELLBEING = "android.app.role.SYSTEM_WELLBEING"; @@ -200,22 +200,23 @@ package android.safetycenter { } public final class SafetyCenterManager { - method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void addAdditionalSafetySource(@NonNull String, @NonNull String, @NonNull String); method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void addOnSafetyCenterDataChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener); - method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void clearAdditionalSafetySources(); - method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void clearSafetyCenterData(); + method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void clearAllSafetySourceData(); + method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void clearSafetyCenterConfigOverride(); method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void dismissSafetyIssue(@NonNull String); method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void executeAction(@NonNull String, @NonNull String); - method @Nullable @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public android.safetycenter.SafetySourceData getLastSafetyCenterUpdate(@NonNull String); method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public android.safetycenter.SafetyCenterData getSafetyCenterData(); + method @Nullable @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public android.safetycenter.SafetySourceData getSafetySourceData(@NonNull String); method @RequiresPermission(anyOf={android.Manifest.permission.READ_SAFETY_CENTER_STATUS, android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE}) public boolean isSafetyCenterEnabled(); method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void refreshSafetySources(int); method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void removeOnSafetyCenterDataChangedListener(@NonNull android.safetycenter.SafetyCenterManager.OnSafetyCenterDataChangedListener); method @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public void reportSafetySourceError(@NonNull String, @NonNull android.safetycenter.SafetySourceError); - method @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public void sendSafetyCenterUpdate(@NonNull android.safetycenter.SafetySourceData); + method @RequiresPermission(android.Manifest.permission.MANAGE_SAFETY_CENTER) public void setSafetyCenterConfigOverride(@NonNull android.safetycenter.config.SafetyCenterConfig); + method @RequiresPermission(android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE) public void setSafetySourceData(@NonNull String, @Nullable android.safetycenter.SafetySourceData, @NonNull android.safetycenter.SafetyEvent); field public static final String ACTION_REFRESH_SAFETY_SOURCES = "android.safetycenter.action.REFRESH_SAFETY_SOURCES"; field public static final int EXTRA_REFRESH_REQUEST_TYPE_FETCH_FRESH_DATA = 0; // 0x0 field public static final int EXTRA_REFRESH_REQUEST_TYPE_GET_DATA = 1; // 0x1 + field public static final String EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID = "android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID"; field public static final String EXTRA_REFRESH_SAFETY_SOURCES_REQUEST_TYPE = "android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE"; field public static final String EXTRA_REFRESH_SAFETY_SOURCE_IDS = "android.safetycenter.extra.REFRESH_SAFETY_SOURCE_IDS"; field public static final int REFRESH_REASON_PAGE_OPEN = 100; // 0x64 @@ -273,9 +274,32 @@ package android.safetycenter { method @NonNull public android.safetycenter.SafetyCenterStatus.Builder setTitle(@NonNull CharSequence); } + public final class SafetyEvent implements android.os.Parcelable { + method public int describeContents(); + method @Nullable public String getRefreshBroadcastId(); + method public int getSafetyEventType(); + method @Nullable public String getSafetySourceIssueActionId(); + method @Nullable public String getSafetySourceIssueId(); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetyEvent> CREATOR; + field public static final int SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED = 500; // 0x1f4 + field public static final int SAFETY_EVENT_TYPE_DEVICE_REBOOTED = 500; // 0x1f4 + field public static final int SAFETY_EVENT_TYPE_REFRESH_REQUESTED = 200; // 0xc8 + field public static final int SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED = 400; // 0x190 + field public static final int SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED = 300; // 0x12c + field public static final int SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED = 100; // 0x64 + } + + public static final class SafetyEvent.Builder { + ctor public SafetyEvent.Builder(int); + method @NonNull public android.safetycenter.SafetyEvent build(); + method @NonNull public android.safetycenter.SafetyEvent.Builder setRefreshBroadcastId(@Nullable String); + method @NonNull public android.safetycenter.SafetyEvent.Builder setSafetySourceIssueActionId(@Nullable String); + method @NonNull public android.safetycenter.SafetyEvent.Builder setSafetySourceIssueId(@Nullable String); + } + public final class SafetySourceData implements android.os.Parcelable { method public int describeContents(); - method @NonNull public String getId(); method @NonNull public java.util.List<android.safetycenter.SafetySourceIssue> getIssues(); method @Nullable public android.safetycenter.SafetySourceStatus getStatus(); method public void writeToParcel(@NonNull android.os.Parcel, int); @@ -283,7 +307,7 @@ package android.safetycenter { } public static final class SafetySourceData.Builder { - ctor public SafetySourceData.Builder(@NonNull String); + ctor public SafetySourceData.Builder(); method @NonNull public android.safetycenter.SafetySourceData.Builder addIssue(@NonNull android.safetycenter.SafetySourceIssue); method @NonNull public android.safetycenter.SafetySourceData build(); method @NonNull public android.safetycenter.SafetySourceData.Builder clearIssues(); @@ -291,21 +315,11 @@ package android.safetycenter { } public final class SafetySourceError implements android.os.Parcelable { + ctor public SafetySourceError(@NonNull android.safetycenter.SafetyEvent); method public int describeContents(); - method @Nullable public String getActionId(); - method @Nullable public String getIssueId(); - method public int getType(); + method @NonNull public android.safetycenter.SafetyEvent getSafetyEvent(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.SafetySourceError> CREATOR; - field public static final int SOURCE_ERROR_TYPE_ACTION_ERROR = 10; // 0xa - field public static final int SOURCE_ERROR_TYPE_UNKNOWN = 0; // 0x0 - } - - public static final class SafetySourceError.Builder { - ctor public SafetySourceError.Builder(int); - method @NonNull public android.safetycenter.SafetySourceError build(); - method @NonNull public android.safetycenter.SafetySourceError.Builder setActionId(@Nullable String); - method @NonNull public android.safetycenter.SafetySourceError.Builder setIssueId(@Nullable String); } public final class SafetySourceIssue implements android.os.Parcelable { @@ -395,17 +409,14 @@ package android.safetycenter { package android.safetycenter.config { - public final class Parser { - method @NonNull public static android.safetycenter.config.SafetyCenterConfig parseXmlResource(@NonNull android.content.res.XmlResourceParser) throws android.safetycenter.config.Parser.ParseException; - } - - public static final class Parser.ParseException extends java.lang.Exception { - ctor public Parser.ParseException(@NonNull String); - ctor public Parser.ParseException(@NonNull String, @NonNull Throwable); + public final class ParseException extends java.lang.Exception { + ctor public ParseException(@NonNull String); + ctor public ParseException(@NonNull String, @NonNull Throwable); } public final class SafetyCenterConfig implements android.os.Parcelable { method public int describeContents(); + method @NonNull public static android.safetycenter.config.SafetyCenterConfig fromXml(@NonNull android.content.res.XmlResourceParser) throws android.safetycenter.config.ParseException; method @NonNull public java.util.List<android.safetycenter.config.SafetySourcesGroup> getSafetySourcesGroups(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.config.SafetyCenterConfig> CREATOR; @@ -422,17 +433,17 @@ package android.safetycenter.config { method @Nullable public String getBroadcastReceiverClassName(); method @NonNull public String getId(); method public int getInitialDisplayState(); - method @NonNull public String getIntentAction(); + method @Nullable public String getIntentAction(); method public int getMaxSeverityLevel(); method @NonNull public String getPackageName(); method public int getProfile(); - method @IdRes public int getSearchTermsResId(); - method @IdRes public int getSummaryResId(); - method @IdRes public int getTitleForWorkResId(); - method @IdRes public int getTitleResId(); + method @StringRes public int getSearchTermsResId(); + method @StringRes public int getSummaryResId(); + method @StringRes public int getTitleForWorkResId(); + method @StringRes public int getTitleResId(); method public int getType(); - method public boolean isAllowLogging(); - method public boolean isAllowRefreshOnPageOpen(); + method public boolean isLoggingAllowed(); + method public boolean isRefreshOnPageOpenAllowed(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.config.SafetySource> CREATOR; field public static final int INITIAL_DISPLAY_STATE_DISABLED = 1; // 0x1 @@ -449,19 +460,19 @@ package android.safetycenter.config { public static final class SafetySource.Builder { ctor public SafetySource.Builder(int); method @NonNull public android.safetycenter.config.SafetySource build(); - method @NonNull public android.safetycenter.config.SafetySource.Builder setAllowLogging(boolean); - method @NonNull public android.safetycenter.config.SafetySource.Builder setAllowRefreshOnPageOpen(boolean); method @NonNull public android.safetycenter.config.SafetySource.Builder setBroadcastReceiverClassName(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setId(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setInitialDisplayState(int); method @NonNull public android.safetycenter.config.SafetySource.Builder setIntentAction(@Nullable String); + method @NonNull public android.safetycenter.config.SafetySource.Builder setLoggingAllowed(boolean); method @NonNull public android.safetycenter.config.SafetySource.Builder setMaxSeverityLevel(int); method @NonNull public android.safetycenter.config.SafetySource.Builder setPackageName(@Nullable String); method @NonNull public android.safetycenter.config.SafetySource.Builder setProfile(int); - method @NonNull public android.safetycenter.config.SafetySource.Builder setSearchTermsResId(@IdRes int); - method @NonNull public android.safetycenter.config.SafetySource.Builder setSummaryResId(@IdRes int); - method @NonNull public android.safetycenter.config.SafetySource.Builder setTitleForWorkResId(@IdRes int); - method @NonNull public android.safetycenter.config.SafetySource.Builder setTitleResId(@IdRes int); + method @NonNull public android.safetycenter.config.SafetySource.Builder setRefreshOnPageOpenAllowed(boolean); + method @NonNull public android.safetycenter.config.SafetySource.Builder setSearchTermsResId(@StringRes int); + method @NonNull public android.safetycenter.config.SafetySource.Builder setSummaryResId(@StringRes int); + method @NonNull public android.safetycenter.config.SafetySource.Builder setTitleForWorkResId(@StringRes int); + method @NonNull public android.safetycenter.config.SafetySource.Builder setTitleResId(@StringRes int); } public final class SafetySourcesGroup implements android.os.Parcelable { @@ -469,8 +480,8 @@ package android.safetycenter.config { method @NonNull public String getId(); method @NonNull public java.util.List<android.safetycenter.config.SafetySource> getSafetySources(); method public int getStatelessIconType(); - method @IdRes public int getSummaryResId(); - method @IdRes public int getTitleResId(); + method @StringRes public int getSummaryResId(); + method @StringRes public int getTitleResId(); method public int getType(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator<android.safetycenter.config.SafetySourcesGroup> CREATOR; @@ -487,8 +498,8 @@ package android.safetycenter.config { method @NonNull public android.safetycenter.config.SafetySourcesGroup build(); method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setId(@Nullable String); method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setStatelessIconType(int); - method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setSummaryResId(@IdRes int); - method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setTitleResId(@IdRes int); + method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setSummaryResId(@StringRes int); + method @NonNull public android.safetycenter.config.SafetySourcesGroup.Builder setTitleResId(@StringRes int); } } diff --git a/framework-s/java/android/app/role/RoleManager.java b/framework-s/java/android/app/role/RoleManager.java index 9f234c214..bd8831070 100644 --- a/framework-s/java/android/app/role/RoleManager.java +++ b/framework-s/java/android/app/role/RoleManager.java @@ -154,12 +154,13 @@ public final class RoleManager { "android.app.role.SYSTEM_ACTIVITY_RECOGNIZER"; /** - * The name of the device manager role. + * The name of the device policy management role. * * @hide */ @SystemApi - public static final String ROLE_DEVICE_MANAGER = "android.app.role.DEVICE_MANAGER"; + public static final String ROLE_DEVICE_POLICY_MANAGEMENT = + "android.app.role.DEVICE_POLICY_MANAGEMENT"; /** * @hide diff --git a/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl b/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl index 7ab6cf20c..6c67c483b 100644 --- a/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl +++ b/framework-s/java/android/safetycenter/ISafetyCenterManager.aidl @@ -19,8 +19,10 @@ package android.safetycenter; import android.safetycenter.IOnSafetyCenterDataChangedListener; import android.safetycenter.SafetyCenterData; import android.safetycenter.SafetyCenterError; +import android.safetycenter.SafetyEvent; import android.safetycenter.SafetySourceData; import android.safetycenter.SafetySourceError; +import android.safetycenter.config.SafetyCenterConfig; /** * AIDL service for the safety center. @@ -38,28 +40,23 @@ interface ISafetyCenterManager { */ boolean isSafetyCenterEnabled(); - /** - * Called by a safety source to send a SafetySourceData update to the safety center. + /** + * Sets the latest SafetySourceData for the given safetySourceId and user to be displayed in + * SafetyCenter UI. */ - void sendSafetyCenterUpdate( + void setSafetySourceData( + String sourceId, in SafetySourceData safetySourceData, + in SafetyEvent safetyEvent, String packageName, int userId); - /** - * Returns the last SafetySourceData update received by the safety center for the given safety - * source id. - */ - SafetySourceData getLastSafetyCenterUpdate( + /** Returns the latest SafetySourceData set for the given safetySourceId and user. */ + SafetySourceData getSafetySourceData( String safetySourceId, String packageName, int userId); - /** - * Requests safety sources to send a SafetySourceData update to Safety Center. - */ - void refreshSafetySources(int refreshReason, int userId); - /** * Notifies the SafetyCenter of an error related to a given safety source. * @@ -71,24 +68,8 @@ interface ISafetyCenterManager { String packageName, int userId); - /** - * Add a safety source dynamically to be used in addition to the sources in the Safety Center - * xml configuration. - * - * <p>Note: This API serves to facilitate CTS testing and should not be used for other purposes. - */ - void addAdditionalSafetySource( - String sourceId, - String packageName, - String broadcastReceiverName); - - /** - * Clears additional safety sources added dynamically to be used in addition to the sources in - * the Safety Center xml configuration. - * - * <p>Note: This API serves to facilitate CTS testing and should not be used for other purposes. - */ - void clearAdditionalSafetySources(); + /** Requests safety sources to send their latest SafetySourceData to Safety Center. */ + void refreshSafetySources(int refreshReason, int userId); /** * Returns the current SafetyCenterData, assembled from the SafetySourceData from all sources. @@ -103,17 +84,40 @@ interface ISafetyCenterManager { IOnSafetyCenterDataChangedListener listener, int userId); + /** + * Dismisses the issue corresponding to the given issue ID. + */ + void dismissSafetyIssue(String issueId, int userId); + /** Executes the specified action on the specified issue. */ void executeAction(String safetyCenterIssueId, String safetyCenterActionId, int userId); /** - * Dismisses the issue corresponding to the given issue ID. + * Clears all SafetySourceData set by safety sources using setSafetySourceData. + * + * <p>Note: This API serves to facilitate CTS testing and should not be used for other purposes. */ - void dismissSafetyIssue(String issueId, int userId); + void clearAllSafetySourceData(); + + /** + * Sets an override of the SafetyCenterConfig set through XML. + * + * When set, the override SafetyCenterConfig will be used instead of the + * SafetyCenterConfig parsed from the XML file to read configured safety sources. + * + * <p>Note: This API serves to facilitate CTS testing and should not be used to configure safety + * sources dynamically for production. Once used for testing, the override should be cleared. + * + * See clearSafetyCenterConfigOverride. + */ + void setSafetyCenterConfigOverride(in SafetyCenterConfig safetyCenterConfig); /** - * Clears all SafetySourceData updates sent to the safety center using sendSafetyCenterUpdate, - * for all packages and users. + * Clears the override of the SafetyCenterConfig set through XML. + * + * <p>Note: This API serves to facilitate CTS testing and should not be used for other purposes. + * + * See setSafetyCenterConfigOverride(SafetyCenterConfig). */ - void clearSafetyCenterData(); + void clearSafetyCenterConfigOverride(); }
\ No newline at end of file diff --git a/framework-s/java/android/safetycenter/SafetyCenterEntry.java b/framework-s/java/android/safetycenter/SafetyCenterEntry.java index 48f42cb53..0d92679e6 100644 --- a/framework-s/java/android/safetycenter/SafetyCenterEntry.java +++ b/framework-s/java/android/safetycenter/SafetyCenterEntry.java @@ -70,13 +70,18 @@ public final class SafetyCenterEntry implements Parcelable { public @interface EntrySeverityLevel { } - /** Indicates the severity level of this entry is not currently known. */ + /** + * Indicates the severity level of this entry is not currently known. This may be because of an + * error or because some information is missing. + */ public static final int ENTRY_SEVERITY_LEVEL_UNKNOWN = 3000; /** - * Indicates this entry does not currently have a severity level, but may change in the future. - * This may be because there is some information missing, or that the Safety Center currently - * has no opinion on the state of this entry. + * Indicates this entry does not have a severity level. + * + * <p>This is used when the Safety Center has no opinion on the severity of this entry (e.g. + * a security setting isn't configured but it's not considered a risk, or for privacy-related + * entries). */ public static final int ENTRY_SEVERITY_LEVEL_NONE = 3100; @@ -325,14 +330,14 @@ public final class SafetyCenterEntry implements Parcelable { mIconAction = safetyCenterEntry.mIconAction; } - /** Sets the ID for this entry. */ + /** Sets the ID for this entry. Required. */ @NonNull public Builder setId(@NonNull String id) { mId = requireNonNull(id); return this; } - /** Sets the title for this entry. */ + /** Sets the title for this entry. Required. */ @NonNull public Builder setTitle(@NonNull CharSequence title) { mTitle = requireNonNull(title); @@ -346,28 +351,34 @@ public final class SafetyCenterEntry implements Parcelable { return this; } - /** Sets the {@link EntrySeverityLevel} for this entry. */ + /** + * Sets the {@link EntrySeverityLevel} for this entry. Defaults to {@link + * #ENTRY_SEVERITY_LEVEL_UNKNOWN}. + */ @NonNull public Builder setSeverityLevel(@EntrySeverityLevel int severityLevel) { mSeverityLevel = severityLevel; return this; } - /** Sets the {@link SeverityNoneIconType} for this entry. */ + /** + * Sets the {@link SeverityNoneIconType} for this entry. Defaults to {@link + * #SEVERITY_NONE_ICON_TYPE_NO_ICON}. + */ @NonNull public Builder setSeverityNoneIconType(@SeverityNoneIconType int severityNoneIconType) { mSeverityNoneIconType = severityNoneIconType; return this; } - /** Sets whether or not this entry is enabled. Defaults to {@code true} if not set. */ + /** Sets whether or not this entry is enabled. Defaults to {@code true}. */ @NonNull public Builder setEnabled(boolean enabled) { mEnabled = enabled; return this; } - /** Sets the {@link PendingIntent} to execute when this entry is selected. */ + /** Sets the {@link PendingIntent} to execute when this entry is selected. Required. */ @NonNull public Builder setPendingIntent(@NonNull PendingIntent pendingIntent) { mPendingIntent = requireNonNull(pendingIntent); diff --git a/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java b/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java index 32ed46f5a..ac371c789 100644 --- a/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java +++ b/framework-s/java/android/safetycenter/SafetyCenterEntryGroup.java @@ -211,35 +211,41 @@ public final class SafetyCenterEntryGroup implements Parcelable { mEntries = new ArrayList<>(safetyCenterEntryGroup.mEntries); } - /** Sets the ID for this entry group. */ + /** Sets the ID for this entry group. Required. */ @NonNull public Builder setId(@NonNull String id) { mId = requireNonNull(id); return this; } - /** Sets the title for this entry group. */ + /** Sets the title for this entry group. Required. */ @NonNull public Builder setTitle(@NonNull CharSequence title) { mTitle = requireNonNull(title); return this; } - /** Sets the summary text for this entry group. */ + /** Sets the optional summary text for this entry group. */ @NonNull public Builder setSummary(@Nullable CharSequence summary) { mSummary = summary; return this; } - /** Sets the {@link SafetyCenterEntry.EntrySeverityLevel} of this entry group. */ + /** + * Sets the {@link SafetyCenterEntry.EntrySeverityLevel} of this entry group. Defaults to + * {@link SafetyCenterEntry#ENTRY_SEVERITY_LEVEL_UNKNOWN}. + */ @NonNull public Builder setSeverityLevel(@SafetyCenterEntry.EntrySeverityLevel int severityLevel) { mSeverityLevel = severityLevel; return this; } - /** Sets the {@link SafetyCenterEntry.SeverityNoneIconType} of this entry group. */ + /** + * Sets the {@link SafetyCenterEntry.SeverityNoneIconType} of this entry group. Defaults to + * {@link SafetyCenterEntry#SEVERITY_NONE_ICON_TYPE_NO_ICON}. + */ @NonNull public Builder setSeverityNoneIconType( @SafetyCenterEntry.SeverityNoneIconType int severityNoneIconType) { @@ -247,7 +253,10 @@ public final class SafetyCenterEntryGroup implements Parcelable { return this; } - /** Sets the list of {@link SafetyCenterEntry} contained by this entry group. */ + /** + * Sets the list of {@link SafetyCenterEntry} contained by this entry group. Defaults to + * an empty list. + */ @NonNull public Builder setEntries(@NonNull List<SafetyCenterEntry> entries) { mEntries = requireNonNull(entries); diff --git a/framework-s/java/android/safetycenter/SafetyCenterIssue.java b/framework-s/java/android/safetycenter/SafetyCenterIssue.java index 847d62ba7..9f5b83c55 100644 --- a/framework-s/java/android/safetycenter/SafetyCenterIssue.java +++ b/framework-s/java/android/safetycenter/SafetyCenterIssue.java @@ -250,8 +250,8 @@ public final class SafetyCenterIssue implements Parcelable { private CharSequence mSummary; @IssueSeverityLevel private int mSeverityLevel = ISSUE_SEVERITY_LEVEL_OK; - private boolean mDismissible; - private boolean mShouldConfirmDismissal; + private boolean mDismissible = true; + private boolean mShouldConfirmDismissal = true; private List<Action> mActions = new ArrayList<>(); /** @@ -274,14 +274,14 @@ public final class SafetyCenterIssue implements Parcelable { mActions = new ArrayList<>(issue.mActions); } - /** Sets the ID for this issue. */ + /** Sets the ID for this issue. Required. */ @NonNull public Builder setId(@NonNull String id) { mId = requireNonNull(id); return this; } - /** Sets the title for this issue. */ + /** Sets the title for this issue. Required. */ @NonNull public Builder setTitle(@NonNull CharSequence title) { mTitle = requireNonNull(title); @@ -295,35 +295,44 @@ public final class SafetyCenterIssue implements Parcelable { return this; } - /** Sets the summary for this issue. */ + /** Sets the summary for this issue. Required. */ @NonNull public Builder setSummary(@NonNull CharSequence summary) { mSummary = requireNonNull(summary); return this; } - /** Sets {@link IssueSeverityLevel} for this issue. */ + /** + * Sets {@link IssueSeverityLevel} for this issue. Defaults to {@link + * #ISSUE_SEVERITY_LEVEL_OK}. + */ @NonNull public Builder setSeverityLevel(@IssueSeverityLevel int severityLevel) { mSeverityLevel = severityLevel; return this; } - /** Sets whether or not this issue can be dismissed. */ + /** Sets whether or not this issue can be dismissed. Defaults to {@code true}. */ @NonNull public Builder setDismissible(boolean dismissible) { mDismissible = dismissible; return this; } - /** Sets whether or not this issue should have its dismissal confirmed. */ + /** + * Sets whether or not this issue should have its dismissal confirmed. Defaults to {@code + * true}. + */ @NonNull public Builder setShouldConfirmDismissal(boolean confirmDismissal) { mShouldConfirmDismissal = confirmDismissal; return this; } - /** Sets the list of potential actions to be taken to resolve this issue. */ + /** + * Sets the list of potential actions to be taken to resolve this issue. Defaults to an + * empty list. + */ @NonNull public Builder setActions(@NonNull List<Action> actions) { mActions = requireNonNull(actions); @@ -502,14 +511,17 @@ public final class SafetyCenterIssue implements Parcelable { mId = id; } - /** Sets the label of this {@link Action}. */ + /** Sets the label of this {@link Action}. Required. */ @NonNull public Builder setLabel(@NonNull CharSequence label) { mLabel = requireNonNull(label); return this; } - /** Sets the {@link PendingIntent} to be sent when this {@link Action} is taken. */ + /** + * Sets the {@link PendingIntent} to be sent when this {@link Action} is taken. + * Required. + */ @NonNull public Builder setPendingIntent(@NonNull PendingIntent pendingIntent) { mPendingIntent = requireNonNull(pendingIntent); @@ -539,7 +551,7 @@ public final class SafetyCenterIssue implements Parcelable { } /** - * Sets or clears the success message to be displayed when this {@link Action} + * Sets or clears the optional success message to be displayed when this {@link Action} * completes. */ @NonNull diff --git a/framework-s/java/android/safetycenter/SafetyCenterManager.java b/framework-s/java/android/safetycenter/SafetyCenterManager.java index 8ba453f38..3795d485e 100644 --- a/framework-s/java/android/safetycenter/SafetyCenterManager.java +++ b/framework-s/java/android/safetycenter/SafetyCenterManager.java @@ -34,6 +34,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.os.RemoteException; +import android.safetycenter.config.SafetyCenterConfig; import android.util.ArrayMap; import androidx.annotation.RequiresApi; @@ -70,7 +71,7 @@ public final class SafetyCenterManager { * * <p>On receiving this broadcast, safety sources should determine their safety state according * to the parameters specified in the intent extras (see below) and send Safety Center data - * about their safety state using {@link #sendSafetyCenterUpdate(SafetySourceData)}. + * about their safety state using {@link #setSafetySourceData}. * * <p class="note">This is a protected intent that can only be sent by the system. * @@ -115,6 +116,14 @@ public final class SafetyCenterManager { "android.safetycenter.extra.REFRESH_SAFETY_SOURCES_REQUEST_TYPE"; /** + * Used as an {@code String} extra field in {@link #ACTION_REFRESH_SAFETY_SOURCES} intents to + * specify a string identifier for the broadcast. + * + */ + public static final String EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID = + "android.safetycenter.extra.REFRESH_SAFETY_SOURCES_BROADCAST_ID"; + + /** * All possible types of data refresh requests in broadcasts with intent action * {@link #ACTION_REFRESH_SAFETY_SOURCES}. * @@ -210,20 +219,47 @@ public final class SafetyCenterManager { } /** - * Sends a {@link SafetySourceData} update to the safety center. + * Returns whether the SafetyCenter page is enabled. + */ + @RequiresPermission(anyOf = { + READ_SAFETY_CENTER_STATUS, + SEND_SAFETY_CENTER_UPDATE + }) + public boolean isSafetyCenterEnabled() { + try { + return mService.isSafetyCenterEnabled(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Set the latest {@link SafetySourceData} for a safety source, to be displayed in + * SafetyCenter UI. * - * <p>Each {@link SafetySourceData#getId()} uniquely identifies the {@link SafetySourceData} for - * the current package and user. + * <p>Each {@code safetySourceId} uniquely identifies the {@link SafetySourceData} for the + * calling user. * - * <p>This call will override any existing {@link SafetySourceData} already present for the - * given {@link SafetySourceData#getId()} for the current package and user. + * <p>This call will rewrite any existing {@link SafetySourceData} already set for the given + * {@code safetySourceId} for the calling user. + * + * @param safetySourceId the unique identifier for a safety source in the calling user + * @param safetySourceData the latest safety data for the safety source in the calling user. If + * a safety source does not have any data to set, it can set its + * {@link SafetySourceData} to {@code null}, in which case Safety Center + * will fall back to any placeholder data specified in the safety source + * xml configuration. + * @param safetyEvent the event that triggered the safety source to set safety data */ @RequiresPermission(SEND_SAFETY_CENTER_UPDATE) - public void sendSafetyCenterUpdate(@NonNull SafetySourceData safetySourceData) { - requireNonNull(safetySourceData, "safetySourceData cannot be null"); + public void setSafetySourceData(@NonNull String safetySourceId, + @Nullable SafetySourceData safetySourceData, + @NonNull SafetyEvent safetyEvent) { try { - mService.sendSafetyCenterUpdate( + mService.setSafetySourceData( + safetySourceId, safetySourceData, + safetyEvent, mContext.getPackageName(), mContext.getUser().getIdentifier()); } catch (RemoteException e) { @@ -232,19 +268,18 @@ public final class SafetyCenterManager { } /** - * Returns the last {@link SafetySourceData} update received through {@link - * #sendSafetyCenterUpdate(SafetySourceData)} for the given - * {@code safetySourceId}, package and user. + * Returns the latest {@link SafetySourceData} set through {@link #setSafetySourceData} + * for the given {@code safetySourceId} and calling user. * - * <p>Returns {@code null} if there never was any update for the given {@code safetySourceId}, - * package and user. + * <p>Returns {@code null} if there never was any data sent for the given {@code safetySourceId} + * and user. */ @RequiresPermission(SEND_SAFETY_CENTER_UPDATE) @Nullable - public SafetySourceData getLastSafetyCenterUpdate(@NonNull String safetySourceId) { + public SafetySourceData getSafetySourceData(@NonNull String safetySourceId) { requireNonNull(safetySourceId, "safetySourceId cannot be null"); try { - return mService.getLastSafetyCenterUpdate( + return mService.getSafetySourceData( safetySourceId, mContext.getPackageName(), mContext.getUser().getIdentifier()); @@ -277,22 +312,7 @@ public final class SafetyCenterManager { } /** - * Returns whether the SafetyCenter page is enabled. - */ - @RequiresPermission(anyOf = { - READ_SAFETY_CENTER_STATUS, - SEND_SAFETY_CENTER_UPDATE - }) - public boolean isSafetyCenterEnabled() { - try { - return mService.isSafetyCenterEnabled(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** - * Requests safety sources to send a {@link SafetySourceData} update to Safety Center. + * Requests safety sources to send their latest {@link SafetySourceData} to Safety Center. * * <p>This API sends a broadcast to all safety sources with action * {@link #ACTION_REFRESH_SAFETY_SOURCES}. @@ -391,19 +411,6 @@ public final class SafetyCenterManager { } /** - * Clears all {@link SafetySourceData} updates sent to the safety center using {@link - * #sendSafetyCenterUpdate(SafetySourceData)}, for all packages and users. - */ - @RequiresPermission(MANAGE_SAFETY_CENTER) - public void clearSafetyCenterData() { - try { - mService.clearSafetyCenterData(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - - /** * Executes the specified action on the specified issue. * * @param safetyCenterIssueId the target issue ID returned by {@link SafetyCenterIssue#getId()} @@ -425,35 +432,50 @@ public final class SafetyCenterManager { } /** - * Add a safety source dynamically to be used in addition to the sources in the Safety Center - * xml configuration. + * Clears all {@link SafetySourceData} set by safety sources using {@link #setSafetySourceData}. * * <p>Note: This API serves to facilitate CTS testing and should not be used for other purposes. */ - // TODO(b/217944317): Modify the parameters to be a SafetySource or SafetyCenterConfig once - // these classes are Parcelable and part of the API surface. @RequiresPermission(MANAGE_SAFETY_CENTER) - public void addAdditionalSafetySource(@NonNull String sourceId, @NonNull String packageName, - @NonNull String broadcastReceiverName) { + public void clearAllSafetySourceData() { + try { + mService.clearAllSafetySourceData(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Sets an override of the {@link SafetyCenterConfig} set through XML. + * + * When set, the override {@link SafetyCenterConfig} will be used instead of the + * {@link SafetyCenterConfig} parsed from the XML file to read configured safety sources. + * + * <p>Note: This API serves to facilitate CTS testing and should not be used to configure safety + * sources dynamically for production. Once used for testing, the override should be cleared. + * + * @see #clearSafetyCenterConfigOverride() + */ + @RequiresPermission(MANAGE_SAFETY_CENTER) + public void setSafetyCenterConfigOverride(@NonNull SafetyCenterConfig safetyCenterConfig) { try { - mService.addAdditionalSafetySource(sourceId, packageName, broadcastReceiverName); + mService.setSafetyCenterConfigOverride(safetyCenterConfig); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** - * Clears additional safety sources added dynamically to be used in addition to the sources in - * the Safety Center xml configuration. + * Clears the override of the {@link SafetyCenterConfig} set through XML. * * <p>Note: This API serves to facilitate CTS testing and should not be used for other purposes. + * + * @see #setSafetyCenterConfigOverride(SafetyCenterConfig) */ - // TODO(b/217944317): Modify the parameters to be a SafetySource or SafetyCenterConfig once - // these classes are Parcelable and part of the API surface. @RequiresPermission(MANAGE_SAFETY_CENTER) - public void clearAdditionalSafetySources() { + public void clearSafetyCenterConfigOverride() { try { - mService.clearAdditionalSafetySources(); + mService.clearSafetyCenterConfigOverride(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/framework-s/java/android/safetycenter/SafetyCenterStatus.java b/framework-s/java/android/safetycenter/SafetyCenterStatus.java index 24e775ca1..341bdabed 100644 --- a/framework-s/java/android/safetycenter/SafetyCenterStatus.java +++ b/framework-s/java/android/safetycenter/SafetyCenterStatus.java @@ -240,28 +240,33 @@ public final class SafetyCenterStatus implements Parcelable { mRefreshStatus = safetyCenterStatus.mRefreshStatus; } - /** Sets the title for this status. */ + /** Sets the title for this status. Required. */ @NonNull public Builder setTitle(@NonNull CharSequence title) { mTitle = requireNonNull(title); return this; } - /** Sets the summary text for this status. */ + /** Sets the summary text for this status. Required. */ @NonNull public Builder setSummary(@NonNull CharSequence summary) { mSummary = requireNonNull(summary); return this; } - /** Sets the {@link OverallSeverityLevel} of this status. */ + /** + * Sets the {@link OverallSeverityLevel} of this status. Defaults to {@link + * #OVERALL_SEVERITY_LEVEL_UNKNOWN}. + */ @NonNull public Builder setSeverityLevel(@OverallSeverityLevel int severityLevel) { mSeverityLevel = severityLevel; return this; } - /** Sets the {@link RefreshStatus} of this status. */ + /** + * Sets the {@link RefreshStatus} of this status. Defaults to {@link #REFRESH_STATUS_NONE}. + */ @NonNull public Builder setRefreshStatus(@RefreshStatus int refreshStatus) { mRefreshStatus = refreshStatus; diff --git a/framework-s/java/android/safetycenter/SafetyEvent.aidl b/framework-s/java/android/safetycenter/SafetyEvent.aidl new file mode 100644 index 000000000..d54115a48 --- /dev/null +++ b/framework-s/java/android/safetycenter/SafetyEvent.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter; + +/** + * Parcelable AIDL SafetyEvent. + * + * @hide + */ +parcelable SafetyEvent;
\ No newline at end of file diff --git a/framework-s/java/android/safetycenter/SafetyEvent.java b/framework-s/java/android/safetycenter/SafetyEvent.java new file mode 100644 index 000000000..135c002e6 --- /dev/null +++ b/framework-s/java/android/safetycenter/SafetyEvent.java @@ -0,0 +1,297 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter; + +import static android.os.Build.VERSION_CODES.TIRAMISU; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.SystemApi; +import android.os.Parcel; +import android.os.Parcelable; + +import androidx.annotation.RequiresApi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * A safety event that may trigger a safety source to set its {@link SafetySourceData}. + * + * @hide + */ +@SystemApi +@RequiresApi(TIRAMISU) +public final class SafetyEvent implements Parcelable { + /** + * Types of safety events that may trigger a set of a safety source's {@link SafetySourceData}. + * + * @hide + */ + @IntDef(prefix = {"SAFETY_EVENT_TYPE_"}, value = { + SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED, + SAFETY_EVENT_TYPE_REFRESH_REQUESTED, + SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED, + SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED, + SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED, + SAFETY_EVENT_TYPE_DEVICE_REBOOTED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface SafetyEventType { + } + /** + * Indicates that there has been a change of state for safety source, which may be independent + * of Safety Center interactions. + */ + public static final int SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED = 100; + + /** + * Indicates that the safety source performed a data refresh in response to a request from + * Safety Center. + */ + public static final int SAFETY_EVENT_TYPE_REFRESH_REQUESTED = 200; + + /** + * Indicates that the safety source successfully completed a resolving + * {@link SafetySourceIssue.Action}. + */ + public static final int SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED = 300; + + /** + * Indicates that the safety source failed to complete a resolving + * {@link SafetySourceIssue.Action}. + */ + public static final int SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED = 400; + + /** + * Indicates that the device's locale changed. + */ + public static final int SAFETY_EVENT_TYPE_DEVICE_LOCALE_CHANGED = 500; + + /** + * Indicates that the device was rebooted. + */ + public static final int SAFETY_EVENT_TYPE_DEVICE_REBOOTED = 500; + + @NonNull + public static final Creator<SafetyEvent> CREATOR = + new Creator<SafetyEvent>() { + @Override + public SafetyEvent createFromParcel(Parcel in) { + return new SafetyEvent(in.readInt(), in.readString(), + in.readString(), in.readString()); + } + + @Override + public SafetyEvent[] newArray(int size) { + return new SafetyEvent[size]; + } + }; + + @SafetyEventType + private final int mSafetyEventType; + @Nullable + private final String mRefreshBroadcastId; + @Nullable + private final String mSafetySourceIssueId; + @Nullable + private final String mSafetySourceIssueActionId; + + private SafetyEvent(@SafetyEventType int safetyEvent, + @Nullable String refreshBroadcastId, + @Nullable String safetySourceIssueId, + @Nullable String safetySourceIssueActionId) { + mSafetyEventType = safetyEvent; + mRefreshBroadcastId = refreshBroadcastId; + mSafetySourceIssueId = safetySourceIssueId; + mSafetySourceIssueActionId = safetySourceIssueActionId; + } + + /** Returns the type of the safety event. */ + @SafetyEventType + public int getSafetyEventType() { + return mSafetyEventType; + } + + /** + * Returns an optional broadcast id provided by Safety Center when requesting a refresh, through + * {@link SafetyCenterManager#EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID}. + * + * <p>This will only be relevant for events of type + * {@link #SAFETY_EVENT_TYPE_REFRESH_REQUESTED}. + * + * @see #getSafetyEventType() + */ + @Nullable + public String getRefreshBroadcastId() { + return mRefreshBroadcastId; + } + + /** + * Returns the id of the {@link SafetySourceIssue} this event is associated with (if any). + * + * <p>This will only be relevant for events of type + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}. + * + * @see #getSafetyEventType() + * @see SafetySourceIssue#getId() + */ + @Nullable + public String getSafetySourceIssueId() { + return mSafetySourceIssueId; + } + + /** + * Returns the id of the {@link SafetySourceIssue.Action} this event is associated with (if + * any). + * + * <p>This will only be relevant for events of type + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}. + * + * @see #getSafetyEventType() + * @see SafetySourceIssue.Action#getId() + */ + @Nullable + public String getSafetySourceIssueActionId() { + return mSafetySourceIssueActionId; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mSafetyEventType); + dest.writeString(mRefreshBroadcastId); + dest.writeString(mSafetySourceIssueId); + dest.writeString(mSafetySourceIssueActionId); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof SafetyEvent)) return false; + SafetyEvent that = (SafetyEvent) o; + return mSafetyEventType == that.mSafetyEventType + && Objects.equals(mRefreshBroadcastId, that.mRefreshBroadcastId) + && Objects.equals(mSafetySourceIssueId, that.mSafetySourceIssueId) + && Objects.equals(mSafetySourceIssueActionId, that.mSafetySourceIssueActionId); + } + + @Override + public int hashCode() { + return Objects.hash(mSafetyEventType, mRefreshBroadcastId, mSafetySourceIssueId, + mSafetySourceIssueActionId); + } + + @Override + public String toString() { + return "SafetySourceDataRewriteReason{" + + "mSafetyEventType=" + + mSafetyEventType + + ", mRefreshBroadcastId='" + + mRefreshBroadcastId + + '\'' + + ", mSafetySourceIssueId='" + + mSafetySourceIssueId + + '\'' + + ", mSafetySourceIssueActionId='" + + mSafetySourceIssueActionId + + '\'' + + '}'; + } + + /** Builder class for {@link SafetyEvent}. */ + public static final class Builder { + @SafetyEventType + private final int mSafetyEventType; + @Nullable + private String mRefreshBroadcastId; + @Nullable + private String mSafetySourceIssueId; + @Nullable + private String mSafetySourceIssueActionId; + + /** Creates a {@link Builder} for {@link SafetyEvent}. */ + public Builder(@SafetyEventType int safetyEventType) { + mSafetyEventType = safetyEventType; + } + + /** + * Sets an optional broadcast id provided by Safety Center when requesting a refresh, + * through {@link SafetyCenterManager#EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID}. + * + * <p>This will only be relevant for events of type + * {@link #SAFETY_EVENT_TYPE_REFRESH_REQUESTED}. + * + * @see #getSafetyEventType() + */ + @NonNull + public Builder setRefreshBroadcastId(@Nullable String refreshBroadcastId) { + mRefreshBroadcastId = refreshBroadcastId; + return this; + } + + /** + * Sets the id of the {@link SafetySourceIssue} this event is associated with (if any). + * + * <p>This will only be relevant for events of type + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}. + * + * @see #getSafetyEventType() + * @see SafetySourceIssue#getId() + */ + @NonNull + public Builder setSafetySourceIssueId(@Nullable String safetySourceIssueId) { + mSafetySourceIssueId = safetySourceIssueId; + return this; + } + + /** + * Sets the id of the {@link SafetySourceIssue.Action} this event is associated with (if + * any). + * + * <p>This will only be relevant for events of type + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_SUCCEEDED} or + * {@link #SAFETY_EVENT_TYPE_RESOLVING_ACTION_FAILED}. + * + * @see #getSafetyEventType() + * @see SafetySourceIssue.Action#getId() + */ + @NonNull + public Builder setSafetySourceIssueActionId(@Nullable String safetySourceIssueActionId) { + mSafetySourceIssueActionId = safetySourceIssueActionId; + return this; + } + + /** + * Creates the {@link SafetyEvent} represented by this {@link Builder}. + */ + @NonNull + public SafetyEvent build() { + return new SafetyEvent(mSafetyEventType, mRefreshBroadcastId, mSafetySourceIssueId, + mSafetySourceIssueActionId); + } + } +} diff --git a/framework-s/java/android/safetycenter/SafetySourceData.java b/framework-s/java/android/safetycenter/SafetySourceData.java index cee62af06..6e4fe11c5 100644 --- a/framework-s/java/android/safetycenter/SafetySourceData.java +++ b/framework-s/java/android/safetycenter/SafetySourceData.java @@ -48,13 +48,12 @@ public final class SafetySourceData implements Parcelable { new Parcelable.Creator<SafetySourceData>() { @Override public SafetySourceData createFromParcel(Parcel in) { - String id = requireNonNull(in.readString()); SafetySourceStatus status = in.readParcelable(SafetySourceStatus.class.getClassLoader(), SafetySourceStatus.class); List<SafetySourceIssue> issues = new ArrayList<>(); in.readParcelableList(issues, SafetySourceIssue.class.getClassLoader()); - return new SafetySourceData(id, status, issues); + return new SafetySourceData(status, issues); } @Override @@ -63,31 +62,17 @@ public final class SafetySourceData implements Parcelable { } }; - @NonNull - private final String mId; @Nullable private final SafetySourceStatus mStatus; @NonNull private final List<SafetySourceIssue> mIssues; - private SafetySourceData(@NonNull String id, @Nullable SafetySourceStatus status, + private SafetySourceData(@Nullable SafetySourceStatus status, @NonNull List<SafetySourceIssue> issues) { - this.mId = id; this.mStatus = status; this.mIssues = new ArrayList<>(issues); } - /** - * Returns the id of the associated safety source. - * - * <p>The id uniquely identifies a safety source within the scope of the application that is - * creating the source. - */ - @NonNull - public String getId() { - return mId; - } - /** Returns the data for the safety source status to be shown in UI. */ @Nullable public SafetySourceStatus getStatus() { @@ -107,7 +92,6 @@ public final class SafetySourceData implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeString(mId); dest.writeParcelable(mStatus, flags); dest.writeParcelableList(mIssues, flags); } @@ -117,21 +101,18 @@ public final class SafetySourceData implements Parcelable { if (this == o) return true; if (!(o instanceof SafetySourceData)) return false; SafetySourceData that = (SafetySourceData) o; - return mId.equals(that.mId) && Objects.equals(mStatus, that.mStatus) + return Objects.equals(mStatus, that.mStatus) && mIssues.equals(that.mIssues); } @Override public int hashCode() { - return Objects.hash(mId, mStatus, mIssues); + return Objects.hash(mStatus, mIssues); } @Override public String toString() { return "SafetySourceData{" - + "mId='" - + mId - + '\'' + ", mStatus=" + mStatus + ", mIssues=" @@ -142,22 +123,10 @@ public final class SafetySourceData implements Parcelable { /** Builder class for {@link SafetySourceData}. */ public static final class Builder { @NonNull - private final String mId; - @NonNull private final List<SafetySourceIssue> mIssues = new ArrayList<>(); @Nullable private SafetySourceStatus mStatus; - /** - * Creates a {@link Builder} for a {@link SafetySourceData}. - * - * @param id uniquely identifies the associated safety source, scoped within the application - * that is creating the associated safety source. - */ - public Builder(@NonNull String id) { - this.mId = requireNonNull(id); - } - /** Sets data for the safety source status to be shown in UI. */ @NonNull public Builder setStatus(@Nullable SafetySourceStatus status) { @@ -186,7 +155,7 @@ public final class SafetySourceData implements Parcelable { public SafetySourceData build() { // TODO(b/207329841): Validate data matches validation in S, for eg that the status // and severity levels of the settings and issues are compatible. - return new SafetySourceData(mId, mStatus, mIssues); + return new SafetySourceData(mStatus, mIssues); } } } diff --git a/framework-s/java/android/safetycenter/SafetySourceError.java b/framework-s/java/android/safetycenter/SafetySourceError.java index 4b07495c3..afc33eaff 100644 --- a/framework-s/java/android/safetycenter/SafetySourceError.java +++ b/framework-s/java/android/safetycenter/SafetySourceError.java @@ -18,17 +18,13 @@ package android.safetycenter; import static android.os.Build.VERSION_CODES.TIRAMISU; -import android.annotation.IntDef; import android.annotation.NonNull; -import android.annotation.Nullable; import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import androidx.annotation.RequiresApi; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; import java.util.Objects; /** @@ -39,87 +35,38 @@ import java.util.Objects; @SystemApi @RequiresApi(TIRAMISU) public final class SafetySourceError implements Parcelable { + @NonNull + private final SafetyEvent mSafetyEvent; - /** - * All possible types for a {@link SafetySourceError}. - * - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = "SOURCE_ERROR_TYPE_", value = { - SOURCE_ERROR_TYPE_UNKNOWN, - SOURCE_ERROR_TYPE_ACTION_ERROR, - }) - public @interface SourceErrorType {} - - /** Indicates this error is of an unknown type. */ - public static final int SOURCE_ERROR_TYPE_UNKNOWN = 0; - - /** Indicates this error reports a problem while executing an action on an issue. */ - public static final int SOURCE_ERROR_TYPE_ACTION_ERROR = 10; - - @SourceErrorType - private final int mType; - @Nullable - private final String mIssueId; - @Nullable - private final String mActionId; - - private SafetySourceError( - @SourceErrorType int type, @Nullable String issueId, @Nullable String actionId) { - mType = type; - mIssueId = issueId; - mActionId = actionId; + public SafetySourceError(@NonNull SafetyEvent safetyEvent) { + mSafetyEvent = safetyEvent; } - /** Returns the {@link SourceErrorType} of this error. */ - @SourceErrorType - public int getType() { - return mType; + /** Returns the safety event associated with this error. */ + @NonNull + public SafetyEvent getSafetyEvent() { + return mSafetyEvent; } - /** - * Returns the id of the {@link SafetySourceIssue} this error is associated with (if any). - * - * @see SafetySourceIssue#getId() - */ - @Nullable - public String getIssueId() { - return mIssueId; - } - - /** - * Returns the id of the {@link SafetySourceIssue.Action} this error is associated with (if - * any). - * - * @see SafetySourceIssue.Action#getId() - */ - @Nullable - public String getActionId() { - return mActionId; - } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; SafetySourceError that = (SafetySourceError) o; - return mType == that.mType - && Objects.equals(mIssueId, that.mIssueId) - && Objects.equals(mActionId, that.mActionId); + return mSafetyEvent.equals(that.mSafetyEvent); } @Override public int hashCode() { - return Objects.hash(mType, mIssueId, mActionId); + return Objects.hash(mSafetyEvent); } @Override public String toString() { return "SafetySourceError{" - + "mType=" + mType - + ", mIssueId='" + mIssueId + '\'' - + ", mActionId='" + mActionId + '\'' + + "mSafetyEvent=" + + mSafetyEvent + '}'; } @@ -130,19 +77,15 @@ public final class SafetySourceError implements Parcelable { @Override public void writeToParcel(@NonNull Parcel dest, int flags) { - dest.writeInt(mType); - dest.writeString(mIssueId); - dest.writeString(mActionId); + dest.writeParcelable(mSafetyEvent, flags); } @NonNull public static final Creator<SafetySourceError> CREATOR = new Creator<SafetySourceError>() { @Override public SafetySourceError createFromParcel(Parcel in) { - return new SafetySourceError( - in.readInt(), - in.readString(), - in.readString()); + return new SafetySourceError(in.readParcelable(SafetyEvent.class.getClassLoader(), + SafetyEvent.class)); } @Override @@ -150,52 +93,4 @@ public final class SafetySourceError implements Parcelable { return new SafetySourceError[0]; } }; - - /** Builder class for a {@link SafetySourceError}. */ - public static final class Builder { - @SourceErrorType - private final int mType; - @Nullable - private String mIssueId; - @Nullable - private String mActionId; - - /** Creates a {@link Builder} for a {@link SafetySourceError}. */ - public Builder(@SourceErrorType int type) { - mType = type; - } - - /** - * Sets the id of the {@link SafetySourceIssue} this error is associated with (if any). - * - * <p>Typically this would only be used for issues containing actions marked {@link - * SafetySourceIssue.Action#isResolving()}, since Safety Center is waiting for a response - * and will return an error if none is given in a certain amount of time. - */ - @NonNull - public Builder setIssueId(@Nullable String issueId) { - mIssueId = issueId; - return this; - } - - /** - * Sets the id of the {@link SafetySourceIssue.Action} this error is associated with (if - * any). - * - * <p>Typically this would only be used for actions marked {@link - * SafetySourceIssue.Action#isResolving()}, since Safety Center is waiting for a response - * and will return an error if none is given in a certain amount of time. - */ - @NonNull - public Builder setActionId(@Nullable String actionId) { - mActionId = actionId; - return this; - } - - /** Creates the {@link SafetySourceError} defined by this {@link Builder}. */ - @NonNull - public SafetySourceError build() { - return new SafetySourceError(mType, mIssueId, mActionId); - } - } } diff --git a/framework-s/java/android/safetycenter/config/ParseException.java b/framework-s/java/android/safetycenter/config/ParseException.java new file mode 100644 index 000000000..3b01e0bb7 --- /dev/null +++ b/framework-s/java/android/safetycenter/config/ParseException.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter.config; + +import static android.os.Build.VERSION_CODES.TIRAMISU; + +import android.annotation.NonNull; +import android.annotation.SystemApi; + +import androidx.annotation.RequiresApi; + +/** + * Exception thrown when there is an error parsing the Safety Center configuration + * + * @hide + */ +@SystemApi +@RequiresApi(TIRAMISU) +public final class ParseException extends Exception { + public ParseException(@NonNull String message) { + super(message); + } + + public ParseException(@NonNull String message, @NonNull Throwable ex) { + super(message, ex); + } +} diff --git a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.aidl b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.aidl new file mode 100644 index 000000000..ef2493894 --- /dev/null +++ b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.safetycenter.config; + +/** + * Parcelable AIDL SafetyCenterConfig. + * + * @hide + */ +parcelable SafetyCenterConfig;
\ No newline at end of file diff --git a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java index 235fa99f8..9f74be082 100644 --- a/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java +++ b/framework-s/java/android/safetycenter/config/SafetyCenterConfig.java @@ -22,6 +22,7 @@ import static java.util.Objects.requireNonNull; import android.annotation.NonNull; import android.annotation.SystemApi; +import android.content.res.XmlResourceParser; import android.os.Parcel; import android.os.Parcelable; @@ -152,4 +153,18 @@ public final class SafetyCenterConfig implements Parcelable { } } + /** + * Parses and validates the given XML resource into a {@link SafetyCenterConfig} object. + * + * <p>It throws a {@link ParseException} if the given XML resource does not comply with the + * safety_center_config.xsd schema. + * + * @param parser the XML resource parsing interface + */ + @NonNull + public static SafetyCenterConfig fromXml(@NonNull XmlResourceParser parser) + throws ParseException { + return SafetyCenterConfigParser.parseXmlResource(parser); + } + } diff --git a/framework-s/java/android/safetycenter/config/Parser.java b/framework-s/java/android/safetycenter/config/SafetyCenterConfigParser.java index 0f6c219b2..75ca73758 100644 --- a/framework-s/java/android/safetycenter/config/Parser.java +++ b/framework-s/java/android/safetycenter/config/SafetyCenterConfigParser.java @@ -27,9 +27,8 @@ import static org.xmlpull.v1.XmlPullParser.TEXT; import static java.util.Locale.ROOT; import static java.util.Objects.requireNonNull; -import android.annotation.IdRes; import android.annotation.NonNull; -import android.annotation.SystemApi; +import android.annotation.StringRes; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.safetycenter.config.SafetySource.InitialDisplayState; @@ -43,15 +42,9 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; -/** - * Utility class to parse and validate a Safety Center Config - * - * @hide - */ -@SystemApi @RequiresApi(TIRAMISU) -public final class Parser { - private Parser() { +final class SafetyCenterConfigParser { + private SafetyCenterConfigParser() { } private static final String TAG_SAFETY_CENTER_CONFIG = "safety-center-config"; @@ -78,9 +71,9 @@ public final class Parser { private static final String ATTR_SAFETY_SOURCE_SEARCH_TERMS = "searchTerms"; private static final String ATTR_SAFETY_SOURCE_BROADCAST_RECEIVER_CLASS_NAME = "broadcastReceiverClassName"; - private static final String ATTR_SAFETY_SOURCE_ALLOW_LOGGING = "allowLogging"; - private static final String ATTR_SAFETY_SOURCE_ALLOW_REFRESH_ON_PAGE_OPEN = - "allowRefreshOnPageOpen"; + private static final String ATTR_SAFETY_SOURCE_LOGGING_ALLOWED = "loggingAllowed"; + private static final String ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED = + "refreshOnPageOpenAllowed"; private static final String ENUM_STATELESS_ICON_TYPE_NONE = "none"; private static final String ENUM_STATELESS_ICON_TYPE_PRIVACY = "privacy"; @@ -92,27 +85,8 @@ public final class Parser { private static final String ENUM_INITIAL_DISPLAY_STATE_DISABLED = "disabled"; private static final String ENUM_INITIAL_DISPLAY_STATE_HIDDEN = "hidden"; - /** Thrown when there is an error parsing the Safety Center Config */ - public static final class ParseException extends Exception { - public ParseException(@NonNull String message) { - super(message); - } - - public ParseException(@NonNull String message, @NonNull Throwable ex) { - super(message, ex); - } - } - - /** - * Parses and validates the given XML resource into a {@link SafetyCenterConfig} object. - * - * <p>It throws a {@link ParseException} if the given XML resource does not comply with the - * safety_center_config.xsd schema. - * - * @param parser the XML resource parsing interface - */ @NonNull - public static SafetyCenterConfig parseXmlResource(@NonNull XmlResourceParser parser) + static SafetyCenterConfig parseXmlResource(@NonNull XmlResourceParser parser) throws ParseException { requireNonNull(parser); try { @@ -171,10 +145,10 @@ public final class Parser { builder.setId(parser.getAttributeValue(i)); break; case ATTR_SAFETY_SOURCES_GROUP_TITLE: - builder.setTitleResId(parseReference(parser, i, name)); + builder.setTitleResId(parseStringReference(parser, i, name)); break; case ATTR_SAFETY_SOURCES_GROUP_SUMMARY: - builder.setSummaryResId(parseReference(parser, i, name)); + builder.setSummaryResId(parseStringReference(parser, i, name)); break; case ATTR_SAFETY_SOURCES_GROUP_STATELESS_ICON_TYPE: builder.setStatelessIconType( @@ -228,13 +202,13 @@ public final class Parser { builder.setPackageName(parser.getAttributeValue(i)); break; case ATTR_SAFETY_SOURCE_TITLE: - builder.setTitleResId(parseReference(parser, i, name)); + builder.setTitleResId(parseStringReference(parser, i, name)); break; case ATTR_SAFETY_SOURCE_TITLE_FOR_WORK: - builder.setTitleForWorkResId(parseReference(parser, i, name)); + builder.setTitleForWorkResId(parseStringReference(parser, i, name)); break; case ATTR_SAFETY_SOURCE_SUMMARY: - builder.setSummaryResId(parseReference(parser, i, name)); + builder.setSummaryResId(parseStringReference(parser, i, name)); break; case ATTR_SAFETY_SOURCE_INTENT_ACTION: builder.setIntentAction(parser.getAttributeValue(i)); @@ -253,17 +227,17 @@ public final class Parser { parser.getAttributeName(i))); break; case ATTR_SAFETY_SOURCE_SEARCH_TERMS: - builder.setSearchTermsResId(parseReference(parser, i, name)); + builder.setSearchTermsResId(parseStringReference(parser, i, name)); break; case ATTR_SAFETY_SOURCE_BROADCAST_RECEIVER_CLASS_NAME: builder.setBroadcastReceiverClassName(parser.getAttributeValue(i)); break; - case ATTR_SAFETY_SOURCE_ALLOW_LOGGING: - builder.setAllowLogging(parseBoolean(parser.getAttributeValue(i), name, + case ATTR_SAFETY_SOURCE_LOGGING_ALLOWED: + builder.setLoggingAllowed(parseBoolean(parser.getAttributeValue(i), name, parser.getAttributeName(i))); break; - case ATTR_SAFETY_SOURCE_ALLOW_REFRESH_ON_PAGE_OPEN: - builder.setAllowRefreshOnPageOpen( + case ATTR_SAFETY_SOURCE_REFRESH_ON_PAGE_OPEN_ALLOWED: + builder.setRefreshOnPageOpenAllowed( parseBoolean(parser.getAttributeValue(i), name, parser.getAttributeName(i))); break; @@ -352,8 +326,8 @@ public final class Parser { return false; } - @IdRes - private static int parseReference(@NonNull XmlResourceParser parser, int index, + @StringRes + private static int parseStringReference(@NonNull XmlResourceParser parser, int index, @NonNull String parent) throws ParseException { int id = parser.getAttributeResourceValue(index, Resources.ID_NULL); if (id == Resources.ID_NULL) { diff --git a/framework-s/java/android/safetycenter/config/SafetySource.java b/framework-s/java/android/safetycenter/config/SafetySource.java index dce0fac43..2ec6cfdba 100644 --- a/framework-s/java/android/safetycenter/config/SafetySource.java +++ b/framework-s/java/android/safetycenter/config/SafetySource.java @@ -18,10 +18,10 @@ package android.safetycenter.config; import static android.os.Build.VERSION_CODES.TIRAMISU; -import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringRes; import android.annotation.SystemApi; import android.content.res.Resources; import android.os.Parcel; @@ -122,11 +122,11 @@ public final class SafetySource implements Parcelable { private final String mId; @Nullable private final String mPackageName; - @IdRes + @StringRes private final int mTitleResId; - @IdRes + @StringRes private final int mTitleForWorkResId; - @IdRes + @StringRes private final int mSummaryResId; @Nullable private final String mIntentAction; @@ -135,29 +135,29 @@ public final class SafetySource implements Parcelable { @InitialDisplayState private final int mInitialDisplayState; private final int mMaxSeverityLevel; - @IdRes + @StringRes private final int mSearchTermsResId; @Nullable private final String mBroadcastReceiverClassName; - private final boolean mAllowLogging; - private final boolean mAllowRefreshOnPageOpen; + private final boolean mLoggingAllowed; + private final boolean mRefreshOnPageOpenAllowed; /** Returns the id of this safety source. */ private SafetySource( @SafetySourceType int type, @NonNull String id, @Nullable String packageName, - @IdRes int titleResId, - @IdRes int titleForWorkResId, - @IdRes int summaryResId, + @StringRes int titleResId, + @StringRes int titleForWorkResId, + @StringRes int summaryResId, @Nullable String intentAction, @Profile int profile, @InitialDisplayState int initialDisplayState, int maxSeverityLevel, - @IdRes int searchTermsResId, + @StringRes int searchTermsResId, @Nullable String broadcastReceiverClassName, - boolean allowLogging, - boolean allowRefreshOnPageOpen) { + boolean loggingAllowed, + boolean refreshOnPageOpenAllowed) { mType = type; mId = id; mPackageName = packageName; @@ -170,8 +170,8 @@ public final class SafetySource implements Parcelable { mMaxSeverityLevel = maxSeverityLevel; mSearchTermsResId = searchTermsResId; mBroadcastReceiverClassName = broadcastReceiverClassName; - mAllowLogging = allowLogging; - mAllowRefreshOnPageOpen = allowRefreshOnPageOpen; + mLoggingAllowed = loggingAllowed; + mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed; } /** Returns the type of this safety source. */ @@ -197,7 +197,7 @@ public final class SafetySource implements Parcelable { } /** Returns the resource id of the title of this safety source. */ - @IdRes + @StringRes public int getTitleResId() { if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) { throw new UnsupportedOperationException( @@ -207,7 +207,7 @@ public final class SafetySource implements Parcelable { } /** Returns the resource id of the title for work of this safety source. */ - @IdRes + @StringRes public int getTitleForWorkResId() { if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) { throw new UnsupportedOperationException( @@ -221,7 +221,7 @@ public final class SafetySource implements Parcelable { } /** Returns the resource id of the summary of this safety source. */ - @IdRes + @StringRes public int getSummaryResId() { if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) { throw new UnsupportedOperationException( @@ -231,7 +231,7 @@ public final class SafetySource implements Parcelable { } /** Returns the intent action of this safety source. */ - @NonNull + @Nullable public String getIntentAction() { if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) { throw new UnsupportedOperationException( @@ -273,7 +273,7 @@ public final class SafetySource implements Parcelable { * Returns the resource id of the search terms of this safety source if set; otherwise * {@link Resources#ID_NULL}. */ - @IdRes + @StringRes public int getSearchTermsResId() { if (mType == SAFETY_SOURCE_TYPE_ISSUE_ONLY) { throw new UnsupportedOperationException( @@ -292,22 +292,22 @@ public final class SafetySource implements Parcelable { return mBroadcastReceiverClassName; } - /** Returns the allow logging property of this safety source. */ - public boolean isAllowLogging() { + /** Returns the logging allowed property of this safety source. */ + public boolean isLoggingAllowed() { if (mType == SAFETY_SOURCE_TYPE_STATIC) { throw new UnsupportedOperationException( - "isAllowLogging unsupported for static safety source"); + "isLoggingAllowed unsupported for static safety source"); } - return mAllowLogging; + return mLoggingAllowed; } - /** Returns the allow refresh on page open property of this safety source. */ - public boolean isAllowRefreshOnPageOpen() { + /** Returns the refresh on page open allowed property of this safety source. */ + public boolean isRefreshOnPageOpenAllowed() { if (mType == SAFETY_SOURCE_TYPE_STATIC) { throw new UnsupportedOperationException( - "isAllowRefreshOnPageOpen unsupported for static safety source"); + "isRefreshOnPageOpenAllowed unsupported for static safety source"); } - return mAllowRefreshOnPageOpen; + return mRefreshOnPageOpenAllowed; } @Override @@ -327,16 +327,16 @@ public final class SafetySource implements Parcelable { && mMaxSeverityLevel == that.mMaxSeverityLevel && mSearchTermsResId == that.mSearchTermsResId && Objects.equals(mBroadcastReceiverClassName, that.mBroadcastReceiverClassName) - && mAllowLogging == that.mAllowLogging - && mAllowRefreshOnPageOpen == that.mAllowRefreshOnPageOpen; + && mLoggingAllowed == that.mLoggingAllowed + && mRefreshOnPageOpenAllowed == that.mRefreshOnPageOpenAllowed; } @Override public int hashCode() { return Objects.hash(mType, mId, mPackageName, mTitleResId, mTitleForWorkResId, mSummaryResId, mIntentAction, mProfile, mInitialDisplayState, mMaxSeverityLevel, - mSearchTermsResId, mBroadcastReceiverClassName, mAllowLogging, - mAllowRefreshOnPageOpen); + mSearchTermsResId, mBroadcastReceiverClassName, mLoggingAllowed, + mRefreshOnPageOpenAllowed); } @Override @@ -354,8 +354,8 @@ public final class SafetySource implements Parcelable { + ", mMaxSeverityLevel=" + mMaxSeverityLevel + ", mSearchTermsResId=" + mSearchTermsResId + ", mBroadcastReceiverClassName='" + mBroadcastReceiverClassName + '\'' - + ", mAllowLogging=" + mAllowLogging - + ", mAllowRefreshOnPageOpen=" + mAllowRefreshOnPageOpen + + ", mLoggingAllowed=" + mLoggingAllowed + + ", mRefreshOnPageOpenAllowed=" + mRefreshOnPageOpenAllowed + '}'; } @@ -378,8 +378,8 @@ public final class SafetySource implements Parcelable { dest.writeInt(mMaxSeverityLevel); dest.writeInt(mSearchTermsResId); dest.writeString(mBroadcastReceiverClassName); - dest.writeBoolean(mAllowLogging); - dest.writeBoolean(mAllowRefreshOnPageOpen); + dest.writeBoolean(mLoggingAllowed); + dest.writeBoolean(mRefreshOnPageOpenAllowed); } @NonNull @@ -399,12 +399,12 @@ public final class SafetySource implements Parcelable { int maxSeverityLevel = in.readInt(); int searchTermsResId = in.readInt(); String broadcastReceiverClassName = in.readString(); - boolean allowLogging = in.readBoolean(); - boolean allowRefreshOnPageOpen = in.readBoolean(); + boolean loggingAllowed = in.readBoolean(); + boolean refreshOnPageOpenAllowed = in.readBoolean(); return new SafetySource(type, id, packageName, titleResId, titleForWorkResId, summaryResId, intentAction, profile, initialDisplayState, maxSeverityLevel, searchTermsResId, broadcastReceiverClassName, - allowLogging, allowRefreshOnPageOpen); + loggingAllowed, refreshOnPageOpenAllowed); } @Override @@ -422,13 +422,13 @@ public final class SafetySource implements Parcelable { @Nullable private String mPackageName; @Nullable - @IdRes + @StringRes private Integer mTitleResId; @Nullable - @IdRes + @StringRes private Integer mTitleForWorkResId; @Nullable - @IdRes + @StringRes private Integer mSummaryResId; @Nullable private String mIntentAction; @@ -441,14 +441,14 @@ public final class SafetySource implements Parcelable { @Nullable private Integer mMaxSeverityLevel; @Nullable - @IdRes + @StringRes private Integer mSearchTermsResId; @Nullable private String mBroadcastReceiverClassName; @Nullable - private Boolean mAllowLogging; + private Boolean mLoggingAllowed; @Nullable - private Boolean mAllowRefreshOnPageOpen; + private Boolean mRefreshOnPageOpenAllowed; /** Creates a {@link Builder} for a {@link SafetySource}. */ public Builder(@SafetySourceType int type) { @@ -471,21 +471,21 @@ public final class SafetySource implements Parcelable { /** Sets the resource id of the title of this safety source. */ @NonNull - public Builder setTitleResId(@IdRes int titleResId) { + public Builder setTitleResId(@StringRes int titleResId) { mTitleResId = titleResId; return this; } /** Sets the resource id of the title for work of this safety source. */ @NonNull - public Builder setTitleForWorkResId(@IdRes int titleForWorkResId) { + public Builder setTitleForWorkResId(@StringRes int titleForWorkResId) { mTitleForWorkResId = titleForWorkResId; return this; } /** Sets the resource id of the summary of this safety source. */ @NonNull - public Builder setSummaryResId(@IdRes int summaryResId) { + public Builder setSummaryResId(@StringRes int summaryResId) { mSummaryResId = summaryResId; return this; } @@ -520,7 +520,7 @@ public final class SafetySource implements Parcelable { /** Sets the resource id of the search terms of this safety source. */ @NonNull - public Builder setSearchTermsResId(@IdRes int searchTermsResId) { + public Builder setSearchTermsResId(@StringRes int searchTermsResId) { mSearchTermsResId = searchTermsResId; return this; } @@ -532,17 +532,17 @@ public final class SafetySource implements Parcelable { return this; } - /** Sets the allow logging property of this safety source. */ + /** Sets the logging allowed property of this safety source. */ @NonNull - public Builder setAllowLogging(boolean allowLogging) { - mAllowLogging = allowLogging; + public Builder setLoggingAllowed(boolean loggingAllowed) { + mLoggingAllowed = loggingAllowed; return this; } - /** Sets the allow refresh on page open property of this safety source. */ + /** Sets the refresh on page open allowed property of this safety source. */ @NonNull - public Builder setAllowRefreshOnPageOpen(boolean allowRefreshOnPageOpen) { - mAllowRefreshOnPageOpen = allowRefreshOnPageOpen; + public Builder setRefreshOnPageOpenAllowed(boolean refreshOnPageOpenAllowed) { + mRefreshOnPageOpenAllowed = refreshOnPageOpenAllowed; return this; } @@ -583,14 +583,14 @@ public final class SafetySource implements Parcelable { false, isIssueOnly); BuilderUtils.validateAttribute(mBroadcastReceiverClassName, "broadcastReceiverClassName", false, isStatic); - boolean allowLogging = BuilderUtils.validateBoolean(mAllowLogging, "allowLogging", + boolean loggingAllowed = BuilderUtils.validateBoolean(mLoggingAllowed, "loggingAllowed", false, isStatic, true); - boolean allowRefreshOnPageOpen = BuilderUtils.validateBoolean(mAllowRefreshOnPageOpen, - "allowRefreshOnPageOpen", false, isStatic, false); + boolean refreshOnPageOpenAllowed = BuilderUtils.validateBoolean( + mRefreshOnPageOpenAllowed, "refreshOnPageOpenAllowed", false, isStatic, false); return new SafetySource(mType, mId, mPackageName, titleResId, titleForWorkResId, summaryResId, mIntentAction, profile, initialDisplayState, maxSeverityLevel, - searchTermsResId, mBroadcastReceiverClassName, allowLogging, - allowRefreshOnPageOpen); + searchTermsResId, mBroadcastReceiverClassName, loggingAllowed, + refreshOnPageOpenAllowed); } } diff --git a/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java b/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java index 0e4f11d7c..84ce67748 100644 --- a/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java +++ b/framework-s/java/android/safetycenter/config/SafetySourcesGroup.java @@ -20,10 +20,10 @@ import static android.os.Build.VERSION_CODES.TIRAMISU; import static java.util.Objects.requireNonNull; -import android.annotation.IdRes; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.StringRes; import android.annotation.SystemApi; import android.content.res.Resources; import android.os.Parcel; @@ -105,17 +105,21 @@ public final class SafetySourcesGroup implements Parcelable { @NonNull private final String mId; - @IdRes + @StringRes private final int mTitleResId; - @IdRes + @StringRes private final int mSummaryResId; @StatelessIconType private final int mStatelessIconType; @NonNull private final List<SafetySource> mSafetySources; - private SafetySourcesGroup(@NonNull String id, @IdRes int titleResId, @IdRes int summaryResId, - @StatelessIconType int statelessIconType, @NonNull List<SafetySource> safetySources) { + private SafetySourcesGroup( + @NonNull String id, + @StringRes int titleResId, + @StringRes int summaryResId, + @StatelessIconType int statelessIconType, + @NonNull List<SafetySource> safetySources) { mId = id; mTitleResId = titleResId; mSummaryResId = summaryResId; @@ -142,13 +146,13 @@ public final class SafetySourcesGroup implements Parcelable { } /** Returns the resource id of the title of this safety sources group. */ - @IdRes + @StringRes public int getTitleResId() { return mTitleResId; } /** Returns the resource id of the summary of this safety sources group. */ - @IdRes + @StringRes public int getSummaryResId() { return mSummaryResId; } @@ -233,10 +237,10 @@ public final class SafetySourcesGroup implements Parcelable { @Nullable private String mId; @Nullable - @IdRes + @StringRes private Integer mTitleResId; @Nullable - @IdRes + @StringRes private Integer mSummaryResId; @Nullable @StatelessIconType @@ -257,14 +261,14 @@ public final class SafetySourcesGroup implements Parcelable { /** Sets the resource id of the title of this safety sources group. */ @NonNull - public Builder setTitleResId(@IdRes int titleResId) { + public Builder setTitleResId(@StringRes int titleResId) { mTitleResId = titleResId; return this; } /** Sets the resource id of the summary of this safety sources group. */ @NonNull - public Builder setSummaryResId(@IdRes int summaryResId) { + public Builder setSummaryResId(@StringRes int summaryResId) { mSummaryResId = summaryResId; return this; } diff --git a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java index df695a0d6..61315a125 100644 --- a/service/java/com/android/safetycenter/SafetyCenterConfigReader.java +++ b/service/java/com/android/safetycenter/SafetyCenterConfigReader.java @@ -24,7 +24,7 @@ import android.annotation.StringRes; import android.content.Context; import android.content.res.Resources; import android.content.res.XmlResourceParser; -import android.safetycenter.config.Parser; +import android.safetycenter.config.ParseException; import android.safetycenter.config.SafetyCenterConfig; import android.util.Log; @@ -107,10 +107,10 @@ final class SafetyCenterConfigReader { } try { - SafetyCenterConfig safetyCenterConfig = Parser.parseXmlResource(parser); + SafetyCenterConfig safetyCenterConfig = SafetyCenterConfig.fromXml(parser); Log.i(TAG, "SafetyCenterConfig read successfully"); return safetyCenterConfig; - } catch (Parser.ParseException e) { + } catch (ParseException e) { Log.e(TAG, "Cannot read SafetyCenterConfig", e); return null; } diff --git a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java index f54cc2b4e..e119ce6bd 100644 --- a/service/java/com/android/safetycenter/SafetyCenterDataTracker.java +++ b/service/java/com/android/safetycenter/SafetyCenterDataTracker.java @@ -53,7 +53,7 @@ import java.util.Map; import java.util.Objects; /** - * A class that keeps track of all the {@link SafetySourceData} updates received by safety center, + * A class that keeps track of all the {@link SafetySourceData} set by safety sources, * and aggregates them into a {@link SafetyCenterData} object to be used by permission controller. * * <p>This class isn't thread safe. Thread safety must be handled by the caller. @@ -82,23 +82,24 @@ final class SafetyCenterDataTracker { } /** - * Adds a {@link SafetySourceData} update for the given {@code packageName} and {@code userId}, - * and returns the updated {@link SafetyCenterData} of the {@code userId}. + * Sets the latest {@link SafetySourceData} for the given {@code safetySourceId} and + * {@code userId}, and returns the updated {@link SafetyCenterData} of the {@code userId}. * * <p>Returns {@code null} if there was no update to the underlying {@link SafetyCenterData}, or * if the {@link SafetyCenterConfig} is not available. */ @Nullable - SafetyCenterData addSafetySourceData( + SafetyCenterData setSafetySourceData( + @NonNull String safetySourceId, @NonNull SafetySourceData safetySourceData, @NonNull String packageName, @UserIdInt int userId) { - if (!configContains(safetySourceData.getId(), packageName)) { + if (!configContains(safetySourceId, packageName)) { // TODO(b/218801292): Should this be hard error for the caller? return null; } - Key key = Key.of(safetySourceData.getId(), packageName, userId); + Key key = Key.of(safetySourceId, packageName, userId); SafetySourceData existingSafetySourceData = mSafetySourceDataForKey.get(key); if (safetySourceData.equals(existingSafetySourceData)) { return null; @@ -109,10 +110,10 @@ final class SafetyCenterDataTracker { } /** - * Returns the latest {@link SafetySourceData} update for the given {@code safetySourceId}, - * {@code packageName} and {@code userId}. + * Returns the latest {@link SafetySourceData} for the given {@code safetySourceId} and + * {@code userId}. * - * <p>Returns {@code null} if there was no update. + * <p>Returns {@code null} if there was no data set. */ @Nullable SafetySourceData getSafetySourceData( @@ -127,14 +128,14 @@ final class SafetyCenterDataTracker { return mSafetySourceDataForKey.get(Key.of(safetySourceId, packageName, userId)); } - /** Clears all the {@link SafetySourceData} updates received so far, for all users. */ + /** Clears all the {@link SafetySourceData} set received so far, for all users. */ void clear() { mSafetySourceDataForKey.clear(); } /** * Returns the current {@link SafetyCenterData} for the given {@code userId}, aggregated from - * all the {@link SafetySourceData} updates received so far. + * all the {@link SafetySourceData} set so far. * * <p>Returns an arbitrary default value if no data has been received for the user so far, or if * the {@link SafetyCenterConfig} is not available. @@ -616,7 +617,7 @@ final class SafetyCenterDataTracker { } /** - * A key for {@link SafetySourceData} updates; based on the {@code safetySourceId}, {@code + * A key for {@link SafetySourceData}; based on the {@code safetySourceId}, {@code * packageName} and {@code userId}. */ // TODO(b/219697341): Look into using AutoValue for this data class. diff --git a/service/java/com/android/safetycenter/SafetyCenterService.java b/service/java/com/android/safetycenter/SafetyCenterService.java index 1a06b8fb0..98edc8a62 100644 --- a/service/java/com/android/safetycenter/SafetyCenterService.java +++ b/service/java/com/android/safetycenter/SafetyCenterService.java @@ -21,6 +21,7 @@ import static android.Manifest.permission.READ_SAFETY_CENTER_STATUS; import static android.Manifest.permission.SEND_SAFETY_CENTER_UPDATE; import static android.os.Build.VERSION_CODES.TIRAMISU; import static android.safetycenter.SafetyCenterManager.RefreshReason; +import static android.safetycenter.config.SafetySource.SAFETY_SOURCE_TYPE_STATIC; import static java.util.Objects.requireNonNull; @@ -38,8 +39,12 @@ import android.provider.DeviceConfig; import android.safetycenter.IOnSafetyCenterDataChangedListener; import android.safetycenter.ISafetyCenterManager; import android.safetycenter.SafetyCenterData; +import android.safetycenter.SafetyEvent; import android.safetycenter.SafetySourceData; import android.safetycenter.SafetySourceError; +import android.safetycenter.config.SafetyCenterConfig; +import android.safetycenter.config.SafetySource; +import android.safetycenter.config.SafetySourcesGroup; import androidx.annotation.Keep; import androidx.annotation.RequiresApi; @@ -99,24 +104,50 @@ public final class SafetyCenterService extends SystemService { /** Service implementation of {@link ISafetyCenterManager.Stub}. */ private final class Stub extends ISafetyCenterManager.Stub { @Override - public void sendSafetyCenterUpdate( - @NonNull SafetySourceData safetySourceData, + public boolean isSafetyCenterEnabled() { + enforceAnyCallingOrSelfPermissions("isSafetyCenterEnabled", + READ_SAFETY_CENTER_STATUS, + SEND_SAFETY_CENTER_UPDATE); + // TODO(b/214568975): Decide if we should disable safety center if there is a problem + // reading the config. + + // We don't require the caller to have READ_DEVICE_CONFIG permission. + final long callingId = Binder.clearCallingIdentity(); + try { + return DeviceConfig.getBoolean( + DeviceConfig.NAMESPACE_PRIVACY, + PROPERTY_SAFETY_CENTER_ENABLED, + /* defaultValue = */ false) + && getSafetyCenterConfigValue(); + } finally { + Binder.restoreCallingIdentity(callingId); + } + } + + @Override + public void setSafetySourceData( + @NonNull String safetySourceId, + @Nullable SafetySourceData safetySourceData, + @NonNull SafetyEvent safetyEvent, @NonNull String packageName, @UserIdInt int userId) { mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); // TODO(b/217235899): Finalize cross-user behavior. PermissionUtils.enforceCrossUserPermission( - userId, false, "sendSafetyCenterUpdate", getContext()); + userId, false, "setSafetySourceData", getContext()); // TODO(b/205706756): Security: check certs? getContext().enforceCallingOrSelfPermission(SEND_SAFETY_CENTER_UPDATE, - "sendSafetyCenterUpdate"); + "setSafetySourceData"); // TODO(b/218812582): Validate the SafetySourceData. SafetyCenterData safetyCenterData; RemoteCallbackList<IOnSafetyCenterDataChangedListener> listeners; synchronized (mApiLock) { - safetyCenterData = mSafetyCenterDataTracker.addSafetySourceData(safetySourceData, - packageName, userId); + safetyCenterData = mSafetyCenterDataTracker.setSafetySourceData( + safetySourceId, + safetySourceData, + packageName, + userId); listeners = mSafetyCenterListeners.getListeners(userId); } // This doesn't need to be done while holding the lock, as RemoteCallbackList already @@ -125,7 +156,7 @@ public final class SafetyCenterService extends SystemService { // doing this while holding the lock could also potentially lead to deadlocks. if (listeners != null && safetyCenterData != null) { // TODO(b/218811189): This should be called on all listeners associated with the - // userId, i.e. if #sendSafetyCenterUpdate is called with a work profile userId, + // userId, i.e. if #setSafetySourceData is called with a work profile userId, // we should also let the personal profile listeners know about the update. SafetyCenterListeners.deliverUpdate(listeners, safetyCenterData); } @@ -133,17 +164,17 @@ public final class SafetyCenterService extends SystemService { @Override @Nullable - public SafetySourceData getLastSafetyCenterUpdate( + public SafetySourceData getSafetySourceData( @NonNull String safetySourceId, @NonNull String packageName, @UserIdInt int userId) { mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); // TODO(b/217235899): Finalize cross-user behavior. PermissionUtils.enforceCrossUserPermission( - userId, false, "getLastSafetyCenterUpdate", getContext()); + userId, false, "getSafetySourceData", getContext()); // TODO(b/205706756): Security: check certs? getContext().enforceCallingOrSelfPermission( - SEND_SAFETY_CENTER_UPDATE, "getLastSafetyCenterUpdate"); + SEND_SAFETY_CENTER_UPDATE, "getSafetySourceData"); synchronized (mApiLock) { return mSafetyCenterDataTracker.getSafetySourceData(safetySourceId, packageName, @@ -167,27 +198,6 @@ public final class SafetyCenterService extends SystemService { } @Override - public boolean isSafetyCenterEnabled() { - enforceAnyCallingOrSelfPermissions("isSafetyCenterEnabled", - READ_SAFETY_CENTER_STATUS, - SEND_SAFETY_CENTER_UPDATE); - // TODO(b/214568975): Decide if we should disable safety center if there is a problem - // reading the config. - - // We don't require the caller to have READ_DEVICE_CONFIG permission. - final long callingId = Binder.clearCallingIdentity(); - try { - return DeviceConfig.getBoolean( - DeviceConfig.NAMESPACE_PRIVACY, - PROPERTY_SAFETY_CENTER_ENABLED, - /* defaultValue = */ false) - && getSafetyCenterConfigValue(); - } finally { - Binder.restoreCallingIdentity(callingId); - } - } - - @Override public void refreshSafetySources( @RefreshReason int refreshReason, @UserIdInt int userId) { @@ -271,16 +281,6 @@ public final class SafetyCenterService extends SystemService { } @Override - public void clearSafetyCenterData() { - getContext().enforceCallingOrSelfPermission( - MANAGE_SAFETY_CENTER, "clearSafetyCenterData"); - - synchronized (mApiLock) { - mSafetyCenterDataTracker.clear(); - } - } - - @Override public void executeAction( @NonNull String safetyCenterIssueId, @NonNull String safetyCenterActionId, @@ -294,23 +294,47 @@ public final class SafetyCenterService extends SystemService { } @Override - public void addAdditionalSafetySource( - @NonNull String sourceId, - @NonNull String packageName, - @NonNull String broadcastReceiverName) { + public void clearAllSafetySourceData() { + getContext().enforceCallingOrSelfPermission( + MANAGE_SAFETY_CENTER, "clearAllSafetySourceData"); + + synchronized (mApiLock) { + mSafetyCenterDataTracker.clear(); + } + } + + @Override + public void setSafetyCenterConfigOverride( + @NonNull SafetyCenterConfig safetyCenterConfig) { getContext().enforceCallingOrSelfPermission(MANAGE_SAFETY_CENTER, - "addAdditionalSafetySource"); + "setSafetyCenterConfigOverride"); synchronized (mRefreshLock) { - mSafetyCenterRefreshManager.addAdditionalSafetySourceBroadcastReceiverComponent( - new ComponentName(packageName, broadcastReceiverName)); + // TODO(b/217944317): Implement properly by overriding config in + // SafetyCenterConfigReader instead. This placeholder impl serves to allow this + // API to be merged in tm-dev, and final impl will be in tm-mainline-prod. + for (int i = 0; i < safetyCenterConfig.getSafetySourcesGroups().size(); i++) { + SafetySourcesGroup group = safetyCenterConfig.getSafetySourcesGroups().get(i); + for (int j = 0; j < group.getSafetySources().size(); j++) { + SafetySource safetySource = group.getSafetySources().get(j); + if (safetySource.getType() != SAFETY_SOURCE_TYPE_STATIC + && safetySource.getBroadcastReceiverClassName() != null) { + mSafetyCenterRefreshManager + .addAdditionalSafetySourceBroadcastReceiverComponent( + new ComponentName( + safetySource.getPackageName(), + safetySource.getBroadcastReceiverClassName() + )); + } + } + } } } @Override - public void clearAdditionalSafetySources() { + public void clearSafetyCenterConfigOverride() { getContext().enforceCallingOrSelfPermission( - MANAGE_SAFETY_CENTER, "clearAdditionalSafetySources"); + MANAGE_SAFETY_CENTER, "clearSafetyCenterConfigOverride"); synchronized (mRefreshLock) { mSafetyCenterRefreshManager |