summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--PermissionController/AndroidManifest.xml7
-rw-r--r--PermissionController/res/values/strings.xml13
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java84
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java63
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt6
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java1
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/CardViewPreference.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java)5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelLegacy.kt)4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModelLegacy.kt)2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt28
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java2
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt (renamed from PermissionController/src/com/android/permissioncontroller/permission/ui/AdvancedConfirmDialogArgs.kt)17
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java4
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/utils/AdminRestrictedPermissionsUtils.java)3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/permission/utils/v31/SubattributionUtils.java (renamed from PermissionController/src/com/android/permissioncontroller/permission/utils/SubattributionUtils.java)9
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt3
-rw-r--r--PermissionController/src/com/android/permissioncontroller/privacysources/v34/HealthConnectPrivacySource.kt126
-rw-r--r--PermissionController/tests/inprocess/Android.bp6
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java258
-rw-r--r--PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt209
-rw-r--r--PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/HealthConnectPrivacySourceTest.kt200
-rw-r--r--SafetyCenter/Resources/res/raw-v34/safety_center_config.xml4
33 files changed, 616 insertions, 471 deletions
diff --git a/PermissionController/AndroidManifest.xml b/PermissionController/AndroidManifest.xml
index b85e5ebdc..325597e67 100644
--- a/PermissionController/AndroidManifest.xml
+++ b/PermissionController/AndroidManifest.xml
@@ -356,11 +356,6 @@
</intent-filter>
</activity>
- <activity android:name="com.android.permissioncontroller.permission.ui.OverlayWarningDialog"
- android:excludeFromRecents="true"
- android:exported="false"
- android:theme="@style/Theme.DeviceDefault.Dialog.NoActionBar.DayNight" />
-
<activity android:name="com.android.permissioncontroller.permission.ui.LocationProviderInterceptDialog"
android:excludeFromRecents="true"
android:exported="false"
@@ -599,6 +594,8 @@
</intent-filter>
</activity>
+ <!-- Unexported empty activity for in-process tests -->
+ <activity android:name="android.app.Activity" />
</application>
</manifest>
diff --git a/PermissionController/res/values/strings.xml b/PermissionController/res/values/strings.xml
index 8c9f86d70..8399147c3 100644
--- a/PermissionController/res/values/strings.xml
+++ b/PermissionController/res/values/strings.xml
@@ -330,19 +330,6 @@
<!-- Title of the permission dialog for accessibility purposes- spoken to the user. [CHAR LIMIT=none] -->
<string name="permission_request_title">Permission request</string>
- <!-- Title for the dialog that warns the user they need to turn off screen overlays
- before permissions can be changed. [CHAR LIMIT=NONE] -->
- <string name="screen_overlay_title">Screen overlay detected</string>
-
- <!-- Message for the dialog that warns the user they need to turn off screen overlays
- before permissions can be changed. The "Settings > Apps" conveys to the user to
- go to Settings and click on apps, this may need updates in RTL languages. [CHAR LIMIT=NONE] -->
- <string name="screen_overlay_message">To change this permission setting, you first have to turn off the screen overlay from Settings \u003e Apps</string>
-
- <!-- Button for the dialog that warns the user they need to turn off screen overlays
- before permissions can be changed. [CHAR LIMIT=NONE] -->
- <string name="screen_overlay_button">Open settings</string>
-
<!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=30] -->
<string name="wear_not_allowed_dlg_title">Android Wear</string>
<!-- Title of dialog telling users that Install/Uninstall action is not supported on Android Wear. [CHAR LIMIT=none] -->
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java b/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java
new file mode 100644
index 000000000..637eb5fc4
--- /dev/null
+++ b/PermissionController/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompat.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2023 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 com.android.permissioncontroller.permission.compat;
+
+import android.text.Layout;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.method.LinkMovementMethod;
+import android.text.method.Touch;
+import android.view.MotionEvent;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+
+/**
+ * Fixes the issue that links can be triggered for touches outside of line bounds for
+ * {@link LinkMovementMethod}.
+ * <p>
+ * This is based on the fix in ag/22301465.
+ */
+public class LinkMovementMethodCompat extends LinkMovementMethod {
+ @Override
+ public boolean onTouchEvent(@NonNull TextView widget, @NonNull Spannable buffer,
+ @NonNull MotionEvent event) {
+ int action = event.getAction();
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_DOWN) {
+ int x = (int) event.getX();
+ int y = (int) event.getY();
+
+ x -= widget.getTotalPaddingLeft();
+ y -= widget.getTotalPaddingTop();
+
+ x += widget.getScrollX();
+ y += widget.getScrollY();
+
+ Layout layout = widget.getLayout();
+ boolean isOutOfLineBounds;
+ if (y < 0 || y > layout.getHeight()) {
+ isOutOfLineBounds = true;
+ } else {
+ int line = layout.getLineForVertical(y);
+ isOutOfLineBounds = x < layout.getLineLeft(line) || x > layout.getLineRight(line);
+ }
+
+ if (isOutOfLineBounds) {
+ Selection.removeSelection(buffer);
+
+ // return LinkMovementMethod.super.onTouchEvent(widget, buffer, event);
+ return Touch.onTouchEvent(widget, buffer, event);
+ }
+ }
+
+ return super.onTouchEvent(widget, buffer, event);
+ }
+
+ /**
+ * @return a {@link LinkMovementMethodCompat} instance
+ */
+ @NonNull
+ public static LinkMovementMethodCompat getInstance() {
+ if (sInstance == null) {
+ sInstance = new LinkMovementMethodCompat();
+ }
+
+ return sInstance;
+ }
+
+ private static LinkMovementMethodCompat sInstance;
+}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java b/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java
index 53ba48ace..196bfc6af 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/model/legacy/PermissionApps.java
@@ -38,8 +38,8 @@ import androidx.annotation.Nullable;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
-import com.android.permissioncontroller.permission.utils.SubattributionUtils;
import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
index 3c1a9df39..82620058d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/service/PermissionControllerServiceImpl.java
@@ -59,12 +59,12 @@ import com.android.permissioncontroller.permission.model.Permission;
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo;
import com.android.permissioncontroller.permission.model.livedatatypes.AppPermGroupUiInfo.PermGrantState;
import com.android.permissioncontroller.permission.ui.AutoGrantPermissionsNotifier;
-import com.android.permissioncontroller.permission.utils.AdminRestrictedPermissionsUtils;
import com.android.permissioncontroller.permission.utils.ArrayUtils;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.PermissionMapping;
import com.android.permissioncontroller.permission.utils.UserSensitiveFlagsUtils;
import com.android.permissioncontroller.permission.utils.Utils;
+import com.android.permissioncontroller.permission.utils.v31.AdminRestrictedPermissionsUtils;
import com.android.role.controller.model.Role;
import com.android.role.controller.model.Roles;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java
deleted file mode 100644
index de1f68c98..000000000
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/OverlayWarningDialog.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2015 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 com.android.permissioncontroller.permission.ui;
-
-import android.app.Activity;
-import android.app.AlertDialog;
-import android.content.ActivityNotFoundException;
-import android.content.DialogInterface;
-import android.content.DialogInterface.OnClickListener;
-import android.content.DialogInterface.OnDismissListener;
-import android.content.Intent;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.util.Log;
-
-import com.android.permissioncontroller.R;
-
-public class OverlayWarningDialog extends Activity implements OnClickListener, OnDismissListener {
-
- private static final String TAG = "OverlayWarningDialog";
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- new AlertDialog.Builder(this)
- .setTitle(R.string.screen_overlay_title)
- .setMessage(R.string.screen_overlay_message)
- .setPositiveButton(R.string.screen_overlay_button, this)
- .setOnDismissListener(this)
- .show();
- }
-
- @Override
- public void onDismiss(DialogInterface dialog) {
- finish();
- }
-
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- try {
- startActivity(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "No manage overlay settings", e);
- }
- }
-
-}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
index ad6b993fa..2de936469 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/AutoAppPermissionFragment.java
@@ -55,11 +55,11 @@ import androidx.preference.TwoStatePreference;
import com.android.car.ui.AlertDialogBuilder;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.auto.AutoSettingsFrameFragment;
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ChangeRequest;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.PackageRemovalMonitor;
import com.android.settingslib.RestrictedLockUtils;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
index a7cb6c340..7ea400127 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionHistoryPreference.kt
@@ -24,7 +24,7 @@ import androidx.preference.Preference.OnPreferenceClickListener
import com.android.car.ui.preference.CarUiPreference
import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModel
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelLegacy
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
/** Preference that displays a permission usage for an app. */
@RequiresApi(Build.VERSION_CODES.S)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
index eee9e8b6e..a16bc1ce4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageDetailsFragment.kt
@@ -42,8 +42,8 @@ import com.android.permissioncontroller.permission.model.v31.PermissionUsages
import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.auto.AutoDividerPreference
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelFactoryLegacy
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageDetailsViewModelLegacy
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelFactoryLegacy
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageDetailsViewModelLegacy
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPermGroupLabel
import com.android.permissioncontroller.permission.utils.Utils
import java.time.Clock
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt
index a21e257c3..d4a2a073e 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/auto/dashboard/AutoPermissionUsageFragment.kt
@@ -40,9 +40,9 @@ import com.android.permissioncontroller.permission.model.v31.PermissionUsages
import com.android.permissioncontroller.permission.model.v31.PermissionUsages.PermissionsUsagesChangeCallback
import com.android.permissioncontroller.permission.ui.model.ManagePermissionsViewModel
import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageControlPreferenceUtils
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModelFactoryLegacy
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModelLegacy
-import com.android.permissioncontroller.permission.ui.model.v31.PermissionUsageViewModelLegacy.PermissionGroupWithUsageCount
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageViewModelFactoryLegacy
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageViewModelLegacy
+import com.android.permissioncontroller.permission.ui.legacy.PermissionUsageViewModelLegacy.PermissionGroupWithUsageCount
import com.android.permissioncontroller.permission.utils.Utils
@RequiresApi(Build.VERSION_CODES.S)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
index bacf50144..946484626 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/AppPermissionFragment.java
@@ -74,13 +74,13 @@ import androidx.lifecycle.ViewModelProvider;
import com.android.modules.utils.build.SdkLevel;
import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState;
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonState;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ChangeRequest;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
import com.android.settingslib.RestrictedLockUtils;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
index 90d7204cf..220507426 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/PermissionAppsFragment.java
@@ -53,6 +53,7 @@ import com.android.permissioncontroller.permission.model.v31.AppPermissionUsage;
import com.android.permissioncontroller.permission.model.v31.PermissionUsages;
import com.android.permissioncontroller.permission.ui.Category;
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity;
+import com.android.permissioncontroller.permission.ui.handheld.v31.CardViewPreference;
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModel;
import com.android.permissioncontroller.permission.ui.model.PermissionAppsViewModelFactory;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/CardViewPreference.java
index 6c76d906b..008813a83 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/CardViewPreference.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v31/CardViewPreference.java
@@ -14,13 +14,15 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.ui.handheld;
+package com.android.permissioncontroller.permission.ui.handheld.v31;
import android.content.Context;
import android.content.Intent;
+import android.os.Build;
import android.view.View;
import android.widget.Button;
+import androidx.annotation.RequiresApi;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
@@ -30,6 +32,7 @@ import com.android.permissioncontroller.R;
/**
* A Preference representing a banner message represented as a CardView
*/
+@RequiresApi(Build.VERSION_CODES.S)
public class CardViewPreference extends Preference {
private String mAction;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
index f3abc7619..88b5ebe87 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/AppDataSharingUpdatesFooterPreference.kt
@@ -18,7 +18,6 @@ package com.android.permissioncontroller.permission.ui.handheld.v34
import android.content.Context
import android.text.SpannableString
-import android.text.method.LinkMovementMethod
import android.text.style.ClickableSpan
import android.util.AttributeSet
import android.view.View
@@ -26,6 +25,7 @@ import android.widget.TextView
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.compat.LinkMovementMethodCompat
/** A preference for a footer with an icon and a link. */
class AppDataSharingUpdatesFooterPreference : Preference {
@@ -80,7 +80,7 @@ class AppDataSharingUpdatesFooterPreference : Preference {
footerLinkView?.let {
it.visibility = if (onFooterLinkClick == null) View.GONE else View.VISIBLE
it.text = footerLinkText
- it.movementMethod = LinkMovementMethod.getInstance()
+ it.movementMethod = LinkMovementMethodCompat.getInstance()
}
super.onBindViewHolder(holder)
}
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
index 7504ae7d4..3998ca141 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/handheld/v34/PermissionRationaleViewHandlerImpl.kt
@@ -21,7 +21,6 @@ import android.content.Context
import android.content.res.ColorStateList
import android.os.Build
import android.os.Bundle
-import android.text.method.LinkMovementMethod
import android.transition.ChangeBounds
import android.transition.TransitionManager
import android.view.Gravity
@@ -29,13 +28,13 @@ import android.view.LayoutInflater
import android.view.View
import android.view.View.OnClickListener
import android.view.ViewGroup
-import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.widget.Button
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
import com.android.permissioncontroller.R
+import com.android.permissioncontroller.permission.compat.LinkMovementMethodCompat
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleViewHandler
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleViewHandler.Result.Companion.CANCELLED
@@ -146,16 +145,16 @@ class PermissionRationaleViewHandlerImpl(
titleView = rootView.findViewById(R.id.permission_rationale_title)
dataSharingSourceMessageView = rootView.findViewById(R.id.data_sharing_source_message)
- dataSharingSourceMessageView!!.movementMethod = LinkMovementMethod.getInstance()
+ dataSharingSourceMessageView!!.movementMethod = LinkMovementMethodCompat.getInstance()
purposeTitleView = rootView.findViewById(R.id.purpose_title)
purposeMessageView = rootView.findViewById(R.id.purpose_message)
learnMoreMessageView = rootView.findViewById(R.id.learn_more_message)
- learnMoreMessageView!!.movementMethod = LinkMovementMethod.getInstance()
+ learnMoreMessageView!!.movementMethod = LinkMovementMethodCompat.getInstance()
settingsMessageView = rootView.findViewById(R.id.settings_message)
- settingsMessageView!!.movementMethod = LinkMovementMethod.getInstance()
+ settingsMessageView!!.movementMethod = LinkMovementMethodCompat.getInstance()
if (!shouldShowSettingsSection) {
val settingsSectionView: ViewGroup? = rootView.findViewById(R.id.settings_section)
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelLegacy.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
index 667667200..e219153f3 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModelLegacy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageDetailsViewModelLegacy.kt
@@ -15,7 +15,7 @@
*/
@file:Suppress("DEPRECATION")
-package com.android.permissioncontroller.permission.ui.model.v31
+package com.android.permissioncontroller.permission.ui.legacy
import android.Manifest
import android.app.AppOpsManager
@@ -44,7 +44,7 @@ import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageLabel
import com.android.permissioncontroller.permission.utils.PermissionMapping
import com.android.permissioncontroller.permission.utils.StringUtils
-import com.android.permissioncontroller.permission.utils.SubattributionUtils
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
import com.android.permissioncontroller.permission.utils.Utils
import java.time.Instant
import java.util.concurrent.TimeUnit
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModelLegacy.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt
index ff21a7216..d0e751f7d 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageViewModelLegacy.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/legacy/PermissionUsageViewModelLegacy.kt
@@ -15,7 +15,7 @@
*/
@file:Suppress("DEPRECATION")
-package com.android.permissioncontroller.permission.ui.model.v31
+package com.android.permissioncontroller.permission.ui.legacy
import android.Manifest
import android.app.LoaderManager
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
index ddae7c0ee..91b6de077 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/AppPermissionViewModel.kt
@@ -63,7 +63,7 @@ import com.android.permissioncontroller.permission.model.livedatatypes.LightAppP
import com.android.permissioncontroller.permission.model.livedatatypes.LightPermission
import com.android.permissioncontroller.permission.service.PermissionChangeStorageImpl
import com.android.permissioncontroller.permission.service.v33.PermissionDecisionStorageImpl
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW_ALWAYS
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType.ALLOW_FOREGROUND
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
index 7cd1ea325..3a689fd72 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/GrantPermissionsViewModel.kt
@@ -118,7 +118,7 @@ import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_INTERACTED
import com.android.permissioncontroller.permission.ui.ManagePermissionsActivity.EXTRA_RESULT_PERMISSION_RESULT
import com.android.permissioncontroller.permission.ui.v34.PermissionRationaleActivity
-import com.android.permissioncontroller.permission.utils.AdminRestrictedPermissionsUtils
+import com.android.permissioncontroller.permission.utils.v31.AdminRestrictedPermissionsUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils.getDefaultPrecision
import com.android.permissioncontroller.permission.utils.KotlinUtils.grantBackgroundRuntimePermissions
@@ -302,8 +302,9 @@ class GrantPermissionsViewModel(
appPermGroup.permissions[perm]?.isGrantedIncludingAppOp == true &&
appPermGroup.permissions[perm]?.isRevokeWhenRequested == false
}
- if (allAffectedGranted) {
- groupStates[key]!!.state = STATE_ALLOWED
+ if (allAffectedGranted || isCompatStorageGrant(appPermGroup)) {
+ groupStates[key] = GroupState(appPermGroup, state.isBackground,
+ state.affectedPermissions, STATE_ALLOWED)
}
}
} else {
@@ -804,6 +805,11 @@ class GrantPermissionsViewModel(
// then skip the request
return STATE_SKIPPED
}
+ // If the "false grant" for apps that don't support the permission has been applied,
+ // treat the permission as already granted
+ if (isCompatStorageGrant(group)) {
+ return STATE_ALLOWED
+ }
}
val isBackground = perm in group.backgroundPermNames
@@ -876,7 +882,7 @@ class GrantPermissionsViewModel(
* ACCESS_MEDIA_LOCATION granted
*/
private fun isPartialStorageGrant(group: LightAppPermGroup): Boolean {
- if (!KotlinUtils.isPhotoPickerPromptEnabled() || group.permGroupName != READ_MEDIA_VISUAL) {
+ if (group.permGroupName != READ_MEDIA_VISUAL || !KotlinUtils.isPhotoPickerPromptEnabled()) {
return false
}
@@ -886,6 +892,20 @@ class GrantPermissionsViewModel(
}
}
+ /**
+ * A compat storage grant is provided when the user selects "select photos" on an app that does
+ * not explicitly request the READ_MEDIA_VISUAL_USER_SELECTED permission. It grants RMVUS, and
+ * applies the "revoked compat" state to all other permissions in the group.
+ */
+ private fun isCompatStorageGrant(group: LightAppPermGroup): Boolean {
+ if (group.permGroupName != READ_MEDIA_VISUAL || !KotlinUtils.isPhotoPickerPromptEnabled()) {
+ return false
+ }
+ return group.permissions[READ_MEDIA_VISUAL_USER_SELECTED]
+ ?.isGrantedIncludingAppOp == true &&
+ group.permissions.values.any { it.isCompatRevoked }
+ }
+
private fun getStateFromPolicy(perm: String, group: LightAppPermGroup): Int {
val isBackground = perm in group.backgroundPermNames
var skipGroup = false
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
index 00df47d3e..7633859fb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v31/PermissionUsageDetailsViewModel.kt
@@ -55,7 +55,7 @@ import com.android.permissioncontroller.permission.ui.handheld.v31.shouldShowSub
import com.android.permissioncontroller.permission.utils.KotlinUtils
import com.android.permissioncontroller.permission.utils.KotlinUtils.getPackageLabel
import com.android.permissioncontroller.permission.utils.PermissionMapping
-import com.android.permissioncontroller.permission.utils.SubattributionUtils
+import com.android.permissioncontroller.permission.utils.v31.SubattributionUtils
import com.android.permissioncontroller.permission.utils.Utils
import java.time.Instant
import java.util.Objects
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
index caf073632..3d205a270 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/model/v34/PermissionRationaleViewModel.kt
@@ -126,7 +126,7 @@ class PermissionRationaleViewModel(
val purposes = PermissionMapping.getSafetyLabelSharingPurposesForGroup(
safetyLabelInfo.safetyLabel, permissionGroupName)
- if (isStale) {
+ if (value == null) {
logPermissionRationaleDialogViewed(purposes)
}
value =
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
index a5961dcec..e2df47009 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/television/AppPermissionFragment.java
@@ -66,13 +66,13 @@ import com.android.permissioncontroller.R;
import com.android.permissioncontroller.permission.data.FullStoragePermissionAppsLiveData.FullStoragePackageState;
import com.android.permissioncontroller.permission.model.AppPermissionGroup;
import com.android.permissioncontroller.permission.model.AppPermissions;
-import com.android.permissioncontroller.permission.ui.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.ui.GrantPermissionsViewHandler;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonState;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ButtonType;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel.ChangeRequest;
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModelFactory;
+import com.android.permissioncontroller.permission.ui.v33.AdvancedConfirmDialogArgs;
import com.android.permissioncontroller.permission.utils.KotlinUtils;
import com.android.permissioncontroller.permission.utils.Utils;
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/ui/AdvancedConfirmDialogArgs.kt b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
index 6b26c7e47..b841f3aeb 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/ui/AdvancedConfirmDialogArgs.kt
+++ b/PermissionController/src/com/android/permissioncontroller/permission/ui/v33/AdvancedConfirmDialogArgs.kt
@@ -1,28 +1,27 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
- * Licensed under the Apache License;
- * Version 2.0 (the "License");
+ * 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.
+ * 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 com.android.permissioncontroller.permission.ui
+package com.android.permissioncontroller.permission.ui.v33
+import android.os.Build
import androidx.annotation.DrawableRes
+import androidx.annotation.RequiresApi
import androidx.annotation.StringRes
import com.android.permissioncontroller.permission.ui.model.AppPermissionViewModel
+@RequiresApi(Build.VERSION_CODES.TIRAMISU)
data class AdvancedConfirmDialogArgs(
@DrawableRes val iconId: Int = 0,
@StringRes val titleId: Int = 0,
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
index 7ccdd6465..b0aaac9ea 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/Utils.java
@@ -660,10 +660,6 @@ public final class Utils {
return typedValue.resourceId;
}
- public static List<ApplicationInfo> getAllInstalledApplications(Context context) {
- return context.getPackageManager().getInstalledApplications(0);
- }
-
/**
* Is the group or background group user sensitive?
*
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/AdminRestrictedPermissionsUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
index 4944093ac..e9d68c9c6 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/AdminRestrictedPermissionsUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/AdminRestrictedPermissionsUtils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.utils;
+package com.android.permissioncontroller.permission.utils.v31;
import android.Manifest;
import android.app.admin.DevicePolicyManager;
@@ -24,6 +24,7 @@ import android.os.UserManager;
import android.util.ArraySet;
import com.android.modules.utils.build.SdkLevel;
+import com.android.permissioncontroller.permission.utils.Utils;
/**
* A class for dealing with permissions that the admin may not grant in certain configurations.
diff --git a/PermissionController/src/com/android/permissioncontroller/permission/utils/SubattributionUtils.java b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/SubattributionUtils.java
index 2785eca74..8919953b4 100644
--- a/PermissionController/src/com/android/permissioncontroller/permission/utils/SubattributionUtils.java
+++ b/PermissionController/src/com/android/permissioncontroller/permission/utils/v31/SubattributionUtils.java
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-package com.android.permissioncontroller.permission.utils;
+package com.android.permissioncontroller.permission.utils.v31;
-import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.Attribution;
@@ -25,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
+import androidx.annotation.ChecksSdkIntAtLeast;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
@@ -42,6 +42,7 @@ public class SubattributionUtils {
/**
* Returns true if the app supports subattribution.
*/
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
public static boolean isSubattributionSupported(Context context, ApplicationInfo appInfo) {
if (!SdkLevel.isAtLeastS()) {
return false;
@@ -50,6 +51,7 @@ public class SubattributionUtils {
}
/** Returns whether the provided package supports subattribution. */
+ @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.S)
public static boolean isSubattributionSupported(LightPackageInfo lightPackageInfo) {
return SdkLevel.isAtLeastS() && lightPackageInfo.getAreAttributionsUserVisible();
}
@@ -59,7 +61,6 @@ public class SubattributionUtils {
* {@code null} otherwise.
*/
@Nullable
- @SuppressLint("NewApi") // isSubattributionSupported checks api level
public static Map<Integer, String> getAttributionLabels(Context context, PackageInfo pkgInfo) {
if (!isSubattributionSupported(context, pkgInfo.applicationInfo)) {
return null;
@@ -72,7 +73,6 @@ public class SubattributionUtils {
* {@code null} otherwise.
*/
@Nullable
- @SuppressLint("NewApi") // isSubattributionSupported checks api level
public static Map<Integer, String> getAttributionLabels(Context context,
ApplicationInfo appInfo) {
if (!isSubattributionSupported(context, appInfo)) {
@@ -114,7 +114,6 @@ public class SubattributionUtils {
/** Returns the attribution label map for the package if the app supports subattribution. */
@Nullable
- @SuppressLint("NewApi") // isSubattributionSupported checks api level
public static Map<Integer, String> getAttributionLabels(Context context,
LightPackageInfo lightPackageInfo) {
if (!isSubattributionSupported(lightPackageInfo)) {
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt
index 874fe942e..885b8ea86 100644
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt
+++ b/PermissionController/src/com/android/permissioncontroller/privacysources/SafetyCenterReceiver.kt
@@ -39,8 +39,6 @@ import com.android.permissioncontroller.permission.utils.Utils
import com.android.permissioncontroller.privacysources.WorkPolicyInfo.Companion.WORK_POLICY_INFO_SOURCE_ID
import com.android.permissioncontroller.privacysources.v34.AppDataSharingUpdatesPrivacySource
import com.android.permissioncontroller.privacysources.v34.AppDataSharingUpdatesPrivacySource.Companion.APP_DATA_SHARING_UPDATES_SOURCE_ID
-import com.android.permissioncontroller.privacysources.v34.HealthConnectPrivacySource
-import com.android.permissioncontroller.privacysources.v34.HealthConnectPrivacySource.Companion.HEALTH_CONNECT_SOURCE_ID
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.Default
@@ -59,7 +57,6 @@ private fun createMapOfSourceIdsToSources(context: Context): Map<String, Privacy
if (SdkLevel.isAtLeastU()) {
sourceMap[APP_DATA_SHARING_UPDATES_SOURCE_ID] = AppDataSharingUpdatesPrivacySource()
- sourceMap[HEALTH_CONNECT_SOURCE_ID] = HealthConnectPrivacySource()
}
return sourceMap
diff --git a/PermissionController/src/com/android/permissioncontroller/privacysources/v34/HealthConnectPrivacySource.kt b/PermissionController/src/com/android/permissioncontroller/privacysources/v34/HealthConnectPrivacySource.kt
deleted file mode 100644
index f05b061c7..000000000
--- a/PermissionController/src/com/android/permissioncontroller/privacysources/v34/HealthConnectPrivacySource.kt
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2023 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 com.android.permissioncontroller.privacysources.v34
-
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
-import android.app.PendingIntent.FLAG_UPDATE_CURRENT
-import android.content.Context
-import android.content.Intent
-import android.os.Build
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_DEVICE_REBOOTED
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
-import android.safetycenter.SafetySourceStatus
-import androidx.annotation.RequiresApi
-import com.android.permissioncontroller.R
-import com.android.permissioncontroller.permission.utils.Utils
-import com.android.permissioncontroller.privacysources.PrivacySource
-import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent
-import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_DEVICE_REBOOTED
-import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_REFRESH_REQUESTED
-import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.UNKNOWN
-
-/**
- * Privacy source providing the Health Connect entry to Safety Center.
- *
- * The content of the Health Connect is static, however the entry should only be displayed if the
- * Health Connect Permission UI Enabled feature is enabled.
- */
-@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
-class HealthConnectPrivacySource : PrivacySource {
-
- override val shouldProcessProfileRequest: Boolean = false
-
- override fun safetyCenterEnabledChanged(context: Context, enabled: Boolean) {
- // Do nothing.
- }
-
- override fun rescanAndPushSafetyCenterData(
- context: Context,
- intent: Intent,
- refreshEvent: RefreshEvent
- ) {
- val safetyCenterManager: SafetyCenterManager =
- Utils.getSystemServiceSafe(context, SafetyCenterManager::class.java)
-
- val safetySourceData =
- if (Utils.isHealthPermissionUiEnabled()) {
- SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- context.getString(R.string.health_connect_title),
- context.getString(R.string.health_connect_summary),
- SEVERITY_LEVEL_UNSPECIFIED
- )
- .setPendingIntent(
- PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent(HEALTH_CONNECT_INTENT_ACTION),
- FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
- )
- )
- .build(),
- )
- .build()
- } else {
- null
- }
-
- safetyCenterManager.setSafetySourceData(
- HEALTH_CONNECT_SOURCE_ID,
- safetySourceData,
- createSafetyEventForHealthConnect(refreshEvent, intent)
- )
- }
-
- private fun createSafetyEventForHealthConnect(
- refreshEvent: RefreshEvent,
- intent: Intent
- ): SafetyEvent {
- return when (refreshEvent) {
- EVENT_REFRESH_REQUESTED -> {
- val refreshBroadcastId =
- intent.getStringExtra(
- SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
- )
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(refreshBroadcastId)
- .build()
- }
- EVENT_DEVICE_REBOOTED -> {
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_DEVICE_REBOOTED).build()
- }
- UNKNOWN -> {
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_SOURCE_STATE_CHANGED).build()
- }
- }
- }
-
- /** Companion object for [HealthConnectPrivacySource]. */
- companion object {
- /** Source id for safety center source for health connect. */
- const val HEALTH_CONNECT_SOURCE_ID = "AndroidHealthConnect"
- const val HEALTH_CONNECT_INTENT_ACTION =
- "android.health.connect.action.HEALTH_HOME_SETTINGS"
- }
-}
diff --git a/PermissionController/tests/inprocess/Android.bp b/PermissionController/tests/inprocess/Android.bp
index 0cc355daa..78c767f1d 100644
--- a/PermissionController/tests/inprocess/Android.bp
+++ b/PermissionController/tests/inprocess/Android.bp
@@ -33,7 +33,10 @@ android_test {
target_sdk_version: "30",
min_sdk_version: "30",
- srcs: ["src/**/*.kt"],
+ srcs: [
+ "src/**/*.kt",
+ "src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java",
+ ],
libs: [
"android.test.base",
@@ -46,6 +49,7 @@ android_test {
"androidx.test.ext.junit",
"androidx.test.uiautomator_uiautomator",
"compatibility-device-util-axt",
+ "kotlin-test",
"permission-test-util-lib",
],
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java
new file mode 100644
index 000000000..b4b18dbbe
--- /dev/null
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/compat/LinkMovementMethodCompatTest.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2023 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 com.android.permissioncontroller.permission.compat;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.SystemClock;
+import android.text.Selection;
+import android.text.Spannable;
+import android.text.Spanned;
+import android.text.method.MovementMethod;
+import android.text.style.ClickableSpan;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ * Test for {@link LinkMovementMethodCompat} without using Mockito, which is unavailable for
+ * in-process tests.
+ *
+ * @see android.text.method.cts.LinkMovementMethodTest
+ */
+public class LinkMovementMethodCompatTest {
+ private static final String CONTENT = "clickable\nunclickable\nclickable";
+
+ private Activity mActivity;
+ private LinkMovementMethodCompat mMethod;
+ private TextView mView;
+ private Spannable mSpannable;
+ private MockClickableSpan mClickable0;
+ private MockClickableSpan mClickable1;
+
+ @Rule
+ public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+ @Before
+ public void setup() throws Throwable {
+ mActivity = mActivityRule.getActivity();
+ mMethod = new LinkMovementMethodCompat();
+
+ // Set the content view with a text view which contains 3 lines,
+ mActivityRule.runOnUiThread(() -> mView = new TextViewNoIme(mActivity));
+ mView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 10);
+ mView.setText(CONTENT, TextView.BufferType.SPANNABLE);
+
+ mActivityRule.runOnUiThread(() -> mActivity.setContentView(mView));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ mSpannable = (Spannable) mView.getText();
+ // make first line clickable
+ mClickable0 = markClickable(0, CONTENT.indexOf('\n'));
+ // make last line clickable
+ mClickable1 = markClickable(CONTENT.lastIndexOf('\n'), CONTENT.length());
+ }
+
+ @Test
+ public void testConstructor() {
+ new LinkMovementMethodCompat();
+ }
+
+ @Test
+ public void testGetInstance() {
+ MovementMethod method0 = LinkMovementMethodCompat.getInstance();
+ assertTrue(method0 instanceof LinkMovementMethodCompat);
+
+ MovementMethod method1 = LinkMovementMethodCompat.getInstance();
+ assertNotNull(method1);
+ assertSame(method0, method1);
+ }
+
+ @UiThreadTest
+ @Test
+ public void testOnTouchEvent() {
+ assertSelection(mSpannable, -1);
+
+ // press on first line (Clickable)
+ assertTrue(pressOnLine(0));
+ assertSelectClickableLeftToRight(mSpannable, mClickable0);
+
+ // release on first line
+ mClickable0.clearClickCount();
+ assertTrue(releaseOnLine(0));
+ mClickable0.assertClickCount(1);
+
+ // press on second line (unclickable)
+ assertSelectClickableLeftToRight(mSpannable, mClickable0);
+ // just clear selection
+ pressOnLine(1);
+ assertSelection(mSpannable, -1);
+
+ // press on last line (Clickable)
+ assertTrue(pressOnLine(2));
+ assertSelectClickableLeftToRight(mSpannable, mClickable1);
+
+ // release on last line
+ mClickable1.clearClickCount();
+ assertTrue(releaseOnLine(2));
+ mClickable1.assertClickCount(1);
+
+ // release on second line (unclickable)
+ assertSelectClickableLeftToRight(mSpannable, mClickable1);
+ // just clear selection
+ releaseOnLine(1);
+ assertSelection(mSpannable, -1);
+ }
+
+ @UiThreadTest
+ @Test
+ public void testOnTouchEvent_outsideLineBounds() {
+ assertSelection(mSpannable, -1);
+
+ // press on first line (clickable)
+ assertTrue(pressOnLine(0));
+ assertSelectClickableLeftToRight(mSpannable, mClickable0);
+
+ // release above first line
+ mClickable0.clearClickCount();
+ float x = (mView.getLayout().getLineLeft(0) + mView.getLayout().getLineRight(0)) / 2f;
+ float y = -1f;
+ assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
+ mClickable0.assertClickCount(0);
+
+ // press on first line (clickable)
+ assertTrue(pressOnLine(0));
+ assertSelectClickableLeftToRight(mSpannable, mClickable0);
+
+ // release to left of first line
+ mClickable0.clearClickCount();
+ x = mView.getLayout().getLineLeft(0) - 1f;
+ y = (mView.getLayout().getLineTop(0) + mView.getLayout().getLineBottom(0)) / 2f;
+ assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
+ mClickable0.assertClickCount(0);
+
+ // press on first line (clickable)
+ assertTrue(pressOnLine(0));
+ assertSelectClickableLeftToRight(mSpannable, mClickable0);
+
+ // release to right of first line
+ mClickable0.clearClickCount();
+ x = mView.getLayout().getLineRight(0) + 1f;
+ y = (mView.getLayout().getLineTop(0) + mView.getLayout().getLineBottom(0)) / 2f;
+ assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
+ mClickable0.assertClickCount(0);
+
+ // press on last line (clickable)
+ assertTrue(pressOnLine(2));
+ assertSelectClickableLeftToRight(mSpannable, mClickable1);
+
+ // release below last line
+ mClickable1.clearClickCount();
+ x = (mView.getLayout().getLineLeft(0) + mView.getLayout().getLineRight(0)) / 2f;
+ y = mView.getLayout().getHeight() + 1f;
+ assertFalse(performMotionAtPoint(x, y, MotionEvent.ACTION_UP));
+ mClickable1.assertClickCount(0);
+ }
+
+ private MockClickableSpan markClickable(final int start, final int end) throws Throwable {
+ final MockClickableSpan clickableSpan = new MockClickableSpan();
+ mActivityRule.runOnUiThread(() -> mSpannable.setSpan(clickableSpan, start, end,
+ Spanned.SPAN_MARK_MARK));
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ return clickableSpan;
+ }
+ private boolean performMotionAtPoint(float x, float y, int action) {
+ long now = SystemClock.uptimeMillis();
+ return mMethod.onTouchEvent(mView, mSpannable,
+ MotionEvent.obtain(now, now, action, x, y, 0));
+ }
+
+ private boolean performMotionOnLine(int line, int action) {
+ float x = (mView.getLayout().getLineLeft(line) + mView.getLayout().getLineRight(line)) / 2f;
+ float y = (mView.getLayout().getLineTop(line) + mView.getLayout().getLineBottom(line)) / 2f;
+ return performMotionAtPoint(x, y, action);
+ }
+
+ private boolean pressOnLine(int line) {
+ return performMotionOnLine(line, MotionEvent.ACTION_DOWN);
+ }
+
+ private boolean releaseOnLine(int line) {
+ return performMotionOnLine(line, MotionEvent.ACTION_UP);
+ }
+
+ private void assertSelection(Spannable spannable, int start, int end) {
+ assertEquals(start, Selection.getSelectionStart(spannable));
+ assertEquals(end, Selection.getSelectionEnd(spannable));
+ }
+
+ private void assertSelection(Spannable spannable, int position) {
+ assertSelection(spannable, position, position);
+ }
+
+ private void assertSelectClickableLeftToRight(Spannable spannable,
+ ClickableSpan clickableSpan) {
+ assertSelection(spannable, spannable.getSpanStart(clickableSpan),
+ spannable.getSpanEnd(clickableSpan));
+ }
+
+ public static class TextViewNoIme extends TextView {
+ public TextViewNoIme(@NonNull Context context) {
+ super(context);
+ }
+
+ @Override
+ public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ return null;
+ }
+ }
+
+ public static class MockClickableSpan extends ClickableSpan {
+ private int mClickCount = 0;
+
+ @Override
+ public void onClick(@NonNull View widget) {
+ ++mClickCount;
+ }
+
+ public void assertClickCount(int expectedClickCount) {
+ assertEquals(expectedClickCount, mClickCount);
+ }
+
+ public void clearClickCount() {
+ mClickCount = 0;
+ }
+ }
+}
diff --git a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
index c53f94195..9cd6da588 100644
--- a/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
+++ b/PermissionController/tests/inprocess/src/com/android/permissioncontroller/permission/util/UtilsTest.kt
@@ -17,23 +17,199 @@
package com.android.permissioncontroller.permission.util
import android.Manifest.permission.READ_CONTACTS
+import android.Manifest.permission_group.ACTIVITY_RECOGNITION
+import android.Manifest.permission_group.CALENDAR
+import android.Manifest.permission_group.CALL_LOG
+import android.Manifest.permission_group.CAMERA
import android.Manifest.permission_group.CONTACTS
+import android.Manifest.permission_group.LOCATION
+import android.Manifest.permission_group.MICROPHONE
+import android.Manifest.permission_group.NEARBY_DEVICES
+import android.Manifest.permission_group.PHONE
+import android.Manifest.permission_group.READ_MEDIA_AURAL
+import android.Manifest.permission_group.READ_MEDIA_VISUAL
+import android.Manifest.permission_group.SENSORS
+import android.Manifest.permission_group.SMS
+import android.Manifest.permission_group.STORAGE
+import android.Manifest.permission_group.UNDEFINED
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.SharedPreferences
+import android.content.pm.PackageManager.NameNotFoundException
import android.content.res.Resources
import androidx.test.platform.app.InstrumentationRegistry
import com.android.permissioncontroller.Constants.EXTRA_SESSION_ID
import com.android.permissioncontroller.Constants.INVALID_SESSION_ID
+import com.android.permissioncontroller.R
import com.android.permissioncontroller.permission.utils.Utils
+import com.android.permissioncontroller.privacysources.WorkPolicyInfo
import com.google.common.truth.Truth.assertThat
import org.junit.Test
-
+import kotlin.test.assertFailsWith
class UtilsTest {
- private val context = InstrumentationRegistry.getInstrumentation().context as Context
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext as Context
+
+ @Test
+ fun getAbsoluteTimeString_zero_returnsNull() {
+ assertThat(Utils.getAbsoluteTimeString(context, 0)).isNull()
+ }
+
+ @Test
+ fun getAbsoluteTimeString_currentTime_returnsTimeFormatString() {
+ val time = Utils.getAbsoluteTimeString(context, System.currentTimeMillis())
+ assertThat(time).isNotNull()
+ if (time != null) {
+ if (time.contains(":")) {
+ val times = time.split(":")
+ assertThat(times.size).isEqualTo(2)
+ val isTime = times[1].contains("am", true) || times[1].contains("pm", true)
+ assertThat(isTime).isTrue()
+ } else {
+ assertThat(time.contains(".")).isTrue()
+ val times = time.split(".")
+ assertThat(times.size).isEqualTo(3)
+ }
+ }
+ }
+
+ @Test
+ fun getAbsoluteTimeString_previousDateTime_returnsDateFormatString() {
+ val lastAccessTime = 1680739840723L
+ val time = Utils.getAbsoluteTimeString(context, lastAccessTime)
+ assertThat(time).isEqualTo("Apr 5, 2023")
+ }
+
+ @Test
+ fun getBlockedIcon_invalidGroupName_returnsMinusOne() {
+ assertThat(Utils.getBlockedIcon(INVALID_GROUP_NAME)).isEqualTo(-1)
+ }
+
+ @Test
+ fun getBlockedIcon_validGroupName() {
+ assertThat(Utils.getBlockedIcon(CAMERA)).isEqualTo(R.drawable.ic_camera_blocked)
+ }
+
+ @Test
+ fun getBlockedTitle_invalidGroupName_returnsMinusOne() {
+ assertThat(Utils.getBlockedTitle(INVALID_GROUP_NAME)).isEqualTo(-1)
+ }
+ @Test
+ fun getBlockedTitle_validGroupName() {
+ assertThat(Utils.getBlockedTitle(CAMERA)).isEqualTo(R.string.blocked_camera_title)
+ }
+
+ @Test
+ fun getDeviceProtectedSharedPreferences() {
+ assertThat(Utils.getDeviceProtectedSharedPreferences(context))
+ .isInstanceOf(SharedPreferences::class.java)
+ }
+
+ @Test
+ fun getEnterpriseString() {
+ assertThat(Utils.getEnterpriseString(context, WorkPolicyInfo.WORK_POLICY_TITLE,
+ R.string.work_policy_title)).isInstanceOf(String::class.java)
+ }
+
+ @Test
+ fun getOneTimePermissionsTimeout_returnsNonNegativeTimeout() {
+ assertThat(Utils.getOneTimePermissionsTimeout()).isGreaterThan(0L)
+ }
+
+ @Test
+ fun getOneTimePermissionsKilledDelaySelfRevoked() {
+ assertThat(Utils.getOneTimePermissionsKilledDelay(true)).isEqualTo(0)
+ }
+
+ @Test
+ fun getOneTimePermissionsKilledDelayNonSelfRevoked() {
+ assertThat(Utils.getOneTimePermissionsKilledDelay(false)).isAtLeast(0L)
+ }
@Test
- fun assertGetOrGenerateSessionIdExpectedSessionId() {
+ fun getPackageInfoForComponentName_NonExistComponent_throwsNameNotFoundException() {
+ val testComponent = ComponentName("com.test.package", "TestClass")
+ assertFailsWith<NameNotFoundException> {
+ Utils.getPackageInfoForComponentName(context, testComponent)
+ }
+ }
+
+ @Test
+ fun getPermissionGroupDescriptionString_undefinedPermissionGroup() {
+ val description = "test permission group description"
+ val resultString =
+ context.getString(R.string.permission_description_summary_generic, description)
+ assertThat(Utils.getPermissionGroupDescriptionString(context, UNDEFINED, description))
+ .isEqualTo(resultString)
+ }
+
+ @Test
+ fun getPermissionGroupDescriptionString_validPermissionGroup() {
+ val permissionGroupNames = listOf(ACTIVITY_RECOGNITION, CALENDAR, CALL_LOG,
+ CAMERA, CONTACTS, LOCATION, MICROPHONE, NEARBY_DEVICES, PHONE, READ_MEDIA_AURAL,
+ READ_MEDIA_VISUAL, SENSORS, SMS, STORAGE)
+ for (permissionGroupName in permissionGroupNames) {
+ assertThat(Utils.getPermissionGroupDescriptionString(context, permissionGroupName, ""))
+ .isNotNull()
+ }
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_lastAccessSummaryTimestampIsNull() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(null, context, LOCATION)
+ assertThat(result.first).isEqualTo("")
+ assertThat(result.second).isEqualTo(Utils.NOT_IN_LAST_7D)
+ assertThat(result.third).isEqualTo("")
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsToday() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(System.currentTimeMillis(),
+ context, LOCATION)
+ assertThat(result.first).isNotEmpty()
+ assertThat(result.second).isEqualTo(Utils.LAST_24H_SENSOR_TODAY)
+ assertThat(result.third).isNotEmpty()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsYesterday() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis() - 24 * 60 * 60 * 1000, context, LOCATION)
+ assertThat(result.first).isNotEmpty()
+ assertThat(result.second).isEqualTo(Utils.LAST_24H_SENSOR_YESTERDAY)
+ assertThat(result.third).isNotEmpty()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_sensorDataPermission_lastAccessSummaryTimestampIsLast7Days() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis() - 6 * 24 * 60 * 60 * 1000, context, LOCATION)
+ assertThat(result.first).isNotEmpty()
+ assertThat(result.second).isEqualTo(Utils.LAST_7D_SENSOR)
+ assertThat(result.third).isNotEmpty()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIsLast24Hrs() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis(), context, STORAGE)
+ assertThat(result.first).isNotEmpty()
+ assertThat(result.second).isEqualTo(Utils.LAST_24H_CONTENT_PROVIDER)
+ assertThat(result.third).isNotEmpty()
+ }
+
+ @Test
+ fun getPermissionLastAccessSummaryTimestamp_nonSensorDataPermission_lastAccessSummaryTimestampIs7Days() {
+ val result = Utils.getPermissionLastAccessSummaryTimestamp(
+ System.currentTimeMillis() - 5 * 60 * 60 * 24 * 1000, context, STORAGE)
+ assertThat(result.first).isNotEmpty()
+ assertThat(result.second).isEqualTo(Utils.LAST_7D_CONTENT_PROVIDER)
+ assertThat(result.third).isNotEmpty()
+ }
+
+ @Test
+ fun getOrGenerateSessionId_validSessionId() {
val intent = Intent()
intent.putExtra(EXTRA_SESSION_ID, VALID_SESSION_ID)
val sessionId = Utils.getOrGenerateSessionId(intent)
@@ -41,15 +217,15 @@ class UtilsTest {
}
@Test
- fun assertGetOrGenerateSessionIdRandomSessionId() {
+ fun getOrGenerateSessionId_invalidSessionId() {
val intent = Intent()
val sessionId = Utils.getOrGenerateSessionId(intent)
assertThat(sessionId).isNotEqualTo(INVALID_SESSION_ID)
}
@Test
- fun assertGetGroupPermissionInfosValidGroup() {
- val permissionInfos = Utils.getGroupPermissionInfos(GROUP_NAME, context)
+ fun getGroupPermissionInfos_validGroupName_returnsGroupPermissions() {
+ val permissionInfos = Utils.getGroupPermissionInfos(CONTACTS, context)
assertThat(permissionInfos).isNotNull()
val permissions = mutableListOf<String>()
for (permissionInfo in permissionInfos!!) {
@@ -59,25 +235,38 @@ class UtilsTest {
}
@Test
- fun assertGetGroupPermissionInfosInValidGroup() {
+ fun getGroupPermissionInfos_inValidGroup_returnsNull() {
assertThat(Utils.getGroupPermissionInfos(INVALID_GROUP_NAME, context)).isNull()
}
@Test
- fun assertGetColorResIdValidId() {
+ fun getGroupPermissionInfos_undefinedGroup_returnsAllSystemPermissions() {
+ val permissionInfos = Utils.getGroupPermissionInfos(UNDEFINED, context)
+ assertThat(permissionInfos).isNotNull()
+ }
+
+ @Test
+ fun getGroupPermissionInfo_permissionName_returnsSamePermission() {
+ val permissionInfos = Utils.getGroupPermissionInfos(READ_CONTACTS, context)
+ assertThat(permissionInfos).isNotNull()
+ assertThat(permissionInfos!!.size).isEqualTo(1)
+ assertThat(permissionInfos[0].name).isEqualTo(READ_CONTACTS)
+ }
+
+ @Test
+ fun getColorResId_validId_returnsNonZero() {
assertThat(Utils.getColorResId(context, android.R.attr.colorPrimary))
.isNotEqualTo(Resources.ID_NULL)
}
@Test
- fun assertGetColorResIdInValidId() {
+ fun getColorResId_inValidId_returnsZero() {
assertThat(Utils.getColorResId(context, INVALID_ATTR_ID)).isEqualTo(Resources.ID_NULL)
}
companion object {
private const val INVALID_ATTR_ID = 1000
private const val VALID_SESSION_ID = 10000L
- private const val GROUP_NAME = CONTACTS
private const val INVALID_GROUP_NAME = "invalid group name"
}
}
diff --git a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/HealthConnectPrivacySourceTest.kt b/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/HealthConnectPrivacySourceTest.kt
deleted file mode 100644
index c68f1cc67..000000000
--- a/PermissionController/tests/mocking/src/com/android/permissioncontroller/tests/mocking/privacysources/HealthConnectPrivacySourceTest.kt
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2023 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 com.android.permissioncontroller.tests.mocking.privacysources
-
-import android.app.PendingIntent
-import android.app.PendingIntent.FLAG_IMMUTABLE
-import android.app.PendingIntent.FLAG_UPDATE_CURRENT
-import android.content.Context
-import android.content.ContextWrapper
-import android.content.Intent
-import android.os.Build
-import android.provider.DeviceConfig
-import android.provider.DeviceConfig.NAMESPACE_PRIVACY
-import android.safetycenter.SafetyCenterManager
-import android.safetycenter.SafetyCenterManager.ACTION_REFRESH_SAFETY_SOURCES
-import android.safetycenter.SafetyCenterManager.EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID
-import android.safetycenter.SafetyEvent
-import android.safetycenter.SafetyEvent.SAFETY_EVENT_TYPE_REFRESH_REQUESTED
-import android.safetycenter.SafetySourceData
-import android.safetycenter.SafetySourceStatus
-import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SdkSuppress
-import com.android.dx.mockito.inline.extended.ExtendedMockito
-import com.android.permissioncontroller.PermissionControllerApplication
-import com.android.permissioncontroller.permission.utils.Utils
-import com.android.permissioncontroller.privacysources.SafetyCenterReceiver.RefreshEvent.EVENT_REFRESH_REQUESTED
-import com.android.permissioncontroller.privacysources.v34.HealthConnectPrivacySource
-import com.android.permissioncontroller.privacysources.v34.HealthConnectPrivacySource.Companion.HEALTH_CONNECT_SOURCE_ID
-import org.junit.After
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.any
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.ArgumentMatchers.eq
-import org.mockito.Mock
-import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.`when` as whenever
-import org.mockito.MockitoAnnotations
-import org.mockito.MockitoSession
-import org.mockito.quality.Strictness
-
-/** Tests for [HealthConnectPrivacySource]. */
-@RunWith(AndroidJUnit4::class)
-@SdkSuppress(minSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE, codeName = "UpsideDownCake")
-class HealthConnectPrivacySourceTest {
-
- private lateinit var mockitoSession: MockitoSession
- private lateinit var healthConnectPrivacySource: HealthConnectPrivacySource
- private lateinit var context: Context
- @Mock lateinit var mockSafetyCenterManager: SafetyCenterManager
-
- @Before
- fun setup() {
- context = ApplicationProvider.getApplicationContext()
- MockitoAnnotations.initMocks(this)
- mockitoSession =
- ExtendedMockito.mockitoSession()
- .mockStatic(DeviceConfig::class.java)
- .mockStatic(PermissionControllerApplication::class.java)
- .mockStatic(Utils::class.java)
- .strictness(Strictness.LENIENT)
- .startMocking()
- whenever(
- Utils.getSystemServiceSafe(
- any(ContextWrapper::class.java),
- eq(SafetyCenterManager::class.java)
- )
- )
- .thenReturn(mockSafetyCenterManager)
-
- healthConnectPrivacySource = HealthConnectPrivacySource()
- }
-
- @After
- fun cleanup() {
- mockitoSession.finishMocking()
- }
-
- @Test
- fun safetyCenterEnabledChanged_enabled_doesNothing() {
- healthConnectPrivacySource.safetyCenterEnabledChanged(context, true)
-
- verifyZeroInteractions(mockSafetyCenterManager)
- }
-
- @Test
- fun safetyCenterEnabledChanged_disabled_doesNothing() {
- healthConnectPrivacySource.safetyCenterEnabledChanged(context, false)
-
- verifyZeroInteractions(mockSafetyCenterManager)
- }
-
- @Test
- fun rescanAndPushSafetyCenterData_healthPermissionUIEnabled_setsDataWithStatus() {
- val refreshIntent =
- Intent(ACTION_REFRESH_SAFETY_SOURCES)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_ID)
-
- healthConnectPrivacySource.rescanAndPushSafetyCenterData(
- context,
- refreshIntent,
- EVENT_REFRESH_REQUESTED
- )
-
- val expectedSafetySourceData =
- if (Utils.isHealthPermissionUiEnabled()) {
- SafetySourceData.Builder()
- .setStatus(
- SafetySourceStatus.Builder(
- HEALTH_CONNECT_TITLE,
- HEALTH_CONNECT_SUMMARY,
- SafetySourceData.SEVERITY_LEVEL_UNSPECIFIED
- )
- .setPendingIntent(
- PendingIntent.getActivity(
- context,
- /* requestCode= */ 0,
- Intent(HEALTH_CONNECT_INTENT_ACTION),
- FLAG_UPDATE_CURRENT or FLAG_IMMUTABLE
- )
- )
- .build()
- )
- .build()
- } else {
- null
- }
-
- val expectedSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_ID)
- .build()
- verify(mockSafetyCenterManager)
- .setSafetySourceData(
- HEALTH_CONNECT_SOURCE_ID,
- expectedSafetySourceData,
- expectedSafetyEvent
- )
- }
-
- @Test
- fun rescanAndPushSafetyCenterData_healthPermissionUIDisabled_setsNullData() {
- setHealthPermissionUIEnabled(false)
- val refreshIntent =
- Intent(ACTION_REFRESH_SAFETY_SOURCES)
- .putExtra(EXTRA_REFRESH_SAFETY_SOURCES_BROADCAST_ID, REFRESH_ID)
-
- healthConnectPrivacySource.rescanAndPushSafetyCenterData(
- context,
- refreshIntent,
- EVENT_REFRESH_REQUESTED
- )
-
- val expectedSafetyEvent =
- SafetyEvent.Builder(SAFETY_EVENT_TYPE_REFRESH_REQUESTED)
- .setRefreshBroadcastId(REFRESH_ID)
- .build()
- verify(mockSafetyCenterManager)
- .setSafetySourceData(HEALTH_CONNECT_SOURCE_ID, null, expectedSafetyEvent)
- }
-
- /** Companion object for [HealthConnectPrivacySourceTest]. */
- companion object {
- // Real context, used in order to avoid mocking resources.
- const val HEALTH_CONNECT_TITLE: String = "Health Connect"
- const val HEALTH_CONNECT_SUMMARY: String = "Manage app access to health data"
- const val REFRESH_ID: String = "refresh_id"
- const val HEALTH_CONNECT_INTENT_ACTION =
- "android.health.connect.action.HEALTH_HOME_SETTINGS"
-
- /** Sets the value for the Health Permission feature [DeviceConfig] property. */
- private fun setHealthPermissionUIEnabled(enabled: Boolean) {
- whenever(
- DeviceConfig.getBoolean(
- eq(NAMESPACE_PRIVACY),
- eq("health_permission_ui_enabled"),
- anyBoolean()
- )
- )
- .thenReturn(enabled)
- }
- }
-}
diff --git a/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml b/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml
index 5fbf6e9f2..1c3330c63 100644
--- a/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml
+++ b/SafetyCenter/Resources/res/raw-v34/safety_center_config.xml
@@ -67,9 +67,9 @@
<dynamic-safety-source
id="AndroidHealthConnect"
profile="primary_profile_only"
- packageName="com.android.permissioncontroller"
+ packageName="com.android.healthconnect.controller"
initialDisplayState="hidden"
- refreshOnPageOpenAllowed="true"
+ refreshOnPageOpenAllowed="false"
title="@com.android.safetycenter.resources:string/health_connect_title"
searchTerms="@com.android.safetycenter.resources:string/health_connect_search_terms"/>
<dynamic-safety-source