summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityThread.java6
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java2
-rw-r--r--core/java/android/window/ConfigurationHelper.java2
-rw-r--r--core/tests/coretests/src/android/app/activity/ActivityThreadTest.java6
-rw-r--r--packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml1
-rw-r--r--packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml1
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java41
-rw-r--r--packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt84
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt13
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt49
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt10
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java3
-rw-r--r--services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java117
-rw-r--r--services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java33
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/core/java/com/android/server/am/AppExitInfoTracker.java32
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java41
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java3
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java105
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java10
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java31
-rw-r--r--services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java4
-rw-r--r--telecomm/java/android/telecom/CallControlCallback.java31
25 files changed, 523 insertions, 122 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 29e135f8b0e9..4c90d7b225a5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -34,6 +34,7 @@ import static android.view.Display.INVALID_DISPLAY;
import static android.window.ConfigurationHelper.freeTextLayoutCachesIfNeeded;
import static android.window.ConfigurationHelper.isDifferentDisplay;
import static android.window.ConfigurationHelper.shouldUpdateResources;
+import static android.window.ConfigurationHelper.shouldUpdateWindowMetricsBounds;
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.os.SafeZipPathValidatorCallback.VALIDATE_ZIP_PATH_FOR_PATH_TRAVERSAL;
@@ -6116,6 +6117,11 @@ public final class ActivityThread extends ClientTransactionHandler
public static boolean shouldReportChange(@Nullable Configuration currentConfig,
@NonNull Configuration newConfig, @Nullable SizeConfigurationBuckets sizeBuckets,
int handledConfigChanges, boolean alwaysReportChange) {
+ // Always report changes in window configuration bounds
+ if (shouldUpdateWindowMetricsBounds(currentConfig, newConfig)) {
+ return true;
+ }
+
final int publicDiff = currentConfig.diffPublicOnly(newConfig);
// Don't report the change if there's no public diff between current and new config.
if (publicDiff == 0) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e0364cbe1d69..e59901b24a65 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8716,6 +8716,7 @@ public class DevicePolicyManager {
*/
@RequiresPermission(value = SET_TIME, conditional = true)
public void setAutoTimeEnabled(@Nullable ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setAutoTimeEnabled");
if (mService != null) {
try {
mService.setAutoTimeEnabled(admin, mContext.getPackageName(), enabled);
@@ -16938,6 +16939,7 @@ public class DevicePolicyManager {
* android.app.role.RoleManager.ROLE_SYSTEM_SUPERVISION.
*/
public boolean isDeviceFinanced() {
+ throwIfParentInstance("isDeviceFinanced");
if (mService != null) {
try {
return mService.isDeviceFinanced(mContext.getPackageName());
diff --git a/core/java/android/window/ConfigurationHelper.java b/core/java/android/window/ConfigurationHelper.java
index e32adcf23a3b..269ce083d205 100644
--- a/core/java/android/window/ConfigurationHelper.java
+++ b/core/java/android/window/ConfigurationHelper.java
@@ -106,7 +106,7 @@ public class ConfigurationHelper {
* @see WindowManager#getCurrentWindowMetrics()
* @see WindowManager#getMaximumWindowMetrics()
*/
- private static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
+ public static boolean shouldUpdateWindowMetricsBounds(@NonNull Configuration currentConfig,
@NonNull Configuration newConfig) {
final Rect currentBounds = currentConfig.windowConfiguration.getBounds();
final Rect newBounds = newConfig.windowConfiguration.getBounds();
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index af81957d1e03..b73a87c8f0d9 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -451,10 +451,8 @@ public class ActivityThreadTest {
final Rect bounds = activity.getWindowManager().getCurrentWindowMetrics().getBounds();
assertEquals(activityConfigPortrait.windowConfiguration.getBounds(), bounds);
- // Ensure that Activity#onConfigurationChanged() not be called because the changes in
- // WindowConfiguration shouldn't be reported, and we only apply the latest Configuration
- // update in transaction.
- assertEquals(numOfConfig, activity.mNumOfConfigChanges);
+ // Ensure changes in window configuration bounds are reported
+ assertEquals(numOfConfig + 1, activity.mNumOfConfigChanges);
}
@Test
diff --git a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
index eecb4bff16ae..685e2595119a 100644
--- a/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/layout/illustration_preference.xml
@@ -19,7 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:background="?android:attr/colorBackground"
android:importantForAccessibility="noHideDescendants"
android:gravity="center"
android:orientation="horizontal">
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
index ab0cf3138d9c..d2e9fbeef073 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v33/settingslib_main_switch_bar.xml
@@ -19,7 +19,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
- android:background="?android:attr/colorBackground"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
index f5dddc39b21e..bcbd1caa45d3 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPickerActivity.java
@@ -108,6 +108,12 @@ public class AvatarPickerActivity extends Activity {
mWaitingForActivityResult);
}
+ @Override
+ protected void onResume() {
+ super.onResume();
+ mAdapter.onAdapterResume();
+ }
+
private void setUpButtons() {
GlifLayout glifLayout = findViewById(R.id.glif_layout);
FooterBarMixin mixin = glifLayout.getMixin(FooterBarMixin.class);
@@ -198,6 +204,8 @@ public class AvatarPickerActivity extends Activity {
private final int[] mUserIconColors;
private int mSelectedPosition = NONE;
+ private int mLastSelectedPosition = NONE;
+
AvatarAdapter() {
final boolean canTakePhoto =
PhotoCapabilityUtils.canTakePhoto(AvatarPickerActivity.this);
@@ -226,12 +234,10 @@ public class AvatarPickerActivity extends Activity {
if (position == mTakePhotoPosition) {
viewHolder.setDrawable(getDrawable(R.drawable.avatar_take_photo_circled));
viewHolder.setContentDescription(getString(R.string.user_image_take_photo));
- viewHolder.setClickListener(view -> mAvatarPhotoController.takePhoto());
} else if (position == mChoosePhotoPosition) {
viewHolder.setDrawable(getDrawable(R.drawable.avatar_choose_photo_circled));
viewHolder.setContentDescription(getString(R.string.user_image_choose_photo));
- viewHolder.setClickListener(view -> mAvatarPhotoController.choosePhoto());
} else if (position >= mPreselectedImageStartPosition) {
int index = indexFromPosition(position);
@@ -240,17 +246,30 @@ public class AvatarPickerActivity extends Activity {
if (mImageDescriptions != null) {
viewHolder.setContentDescription(mImageDescriptions.get(index));
} else {
- viewHolder.setContentDescription(
- getString(R.string.default_user_icon_description));
+ viewHolder.setContentDescription(getString(
+ R.string.default_user_icon_description));
+ }
+ }
+ viewHolder.setClickListener(view -> onViewHolderSelected(position));
+ }
+
+ private void onViewHolderSelected(int position) {
+ if ((mTakePhotoPosition == position) && (mLastSelectedPosition != position)) {
+ mAvatarPhotoController.takePhoto();
+ } else if ((mChoosePhotoPosition == position) && (mLastSelectedPosition != position)) {
+ mAvatarPhotoController.choosePhoto();
+ } else {
+ if (mSelectedPosition == position) {
+ deselect(position);
+ } else {
+ select(position);
}
- viewHolder.setClickListener(view -> {
- if (mSelectedPosition == position) {
- deselect(position);
- } else {
- select(position);
- }
- });
}
+ mLastSelectedPosition = position;
+ }
+
+ public void onAdapterResume() {
+ mLastSelectedPosition = NONE;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
index c9579d5e1356..e79b3f4bf3ad 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/fontscaling/FontScalingDialog.kt
@@ -15,11 +15,12 @@
*/
package com.android.systemui.accessibility.fontscaling
-import android.annotation.WorkerThread
import android.content.Context
import android.content.pm.ActivityInfo
import android.content.res.Configuration
+import android.database.ContentObserver
import android.os.Bundle
+import android.os.Handler
import android.provider.Settings
import android.util.TypedValue
import android.view.LayoutInflater
@@ -27,13 +28,18 @@ import android.widget.Button
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
+import androidx.annotation.MainThread
+import androidx.annotation.WorkerThread
import com.android.systemui.R
import com.android.systemui.common.ui.view.SeekBarWithIconButtonsView
import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SystemSettings
-import java.util.concurrent.Executor
+import com.android.systemui.util.time.SystemClock
+import java.util.concurrent.atomic.AtomicInteger
import kotlin.math.roundToInt
/** The Dialog that contains a seekbar for changing the font size. */
@@ -41,17 +47,31 @@ class FontScalingDialog(
context: Context,
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
- @Background private val backgroundExecutor: Executor
+ private val systemClock: SystemClock,
+ @Main mainHandler: Handler,
+ @Background private val backgroundDelayableExecutor: DelayableExecutor
) : SystemUIDialog(context) {
+ private val MIN_UPDATE_INTERVAL_MS: Long = 800
+ private val CHANGE_BY_SEEKBAR_DELAY_MS: Long = 100
+ private val CHANGE_BY_BUTTON_DELAY_MS: Long = 300
private val strEntryValues: Array<String> =
context.resources.getStringArray(com.android.settingslib.R.array.entryvalues_font_size)
private lateinit var title: TextView
private lateinit var doneButton: Button
private lateinit var seekBarWithIconButtonsView: SeekBarWithIconButtonsView
- private var lastProgress: Int = -1
+ private var lastProgress: AtomicInteger = AtomicInteger(-1)
+ private var lastUpdateTime: Long = 0
+ private var cancelUpdateFontScaleRunnable: Runnable? = null
private val configuration: Configuration = Configuration(context.resources.configuration)
+ private val fontSizeObserver =
+ object : ContentObserver(mainHandler) {
+ override fun onChange(selfChange: Boolean) {
+ lastUpdateTime = systemClock.elapsedRealtime()
+ }
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
setTitle(R.string.font_scaling_dialog_title)
setView(LayoutInflater.from(context).inflate(R.layout.font_scaling_dialog, null))
@@ -79,21 +99,21 @@ class FontScalingDialog(
seekBarWithIconButtonsView.setMax((strEntryValues).size - 1)
val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, 1.0f)
- lastProgress = fontSizeValueToIndex(currentScale)
- seekBarWithIconButtonsView.setProgress(lastProgress)
+ lastProgress.set(fontSizeValueToIndex(currentScale))
+ seekBarWithIconButtonsView.setProgress(lastProgress.get())
seekBarWithIconButtonsView.setOnSeekBarChangeListener(
object : OnSeekBarChangeListener {
var isTrackingTouch = false
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
+ // Always provide preview configuration for text first when there is a change
+ // in the seekbar progress.
+ createTextPreview(progress)
+
if (!isTrackingTouch) {
// The seekbar progress is changed by icon buttons
- changeFontSize(progress)
- } else {
- // Provide preview configuration for text instead of changing the system
- // font scale before users release their finger from the seekbar.
- createTextPreview(progress)
+ changeFontSize(progress, CHANGE_BY_BUTTON_DELAY_MS)
}
}
@@ -103,26 +123,50 @@ class FontScalingDialog(
override fun onStopTrackingTouch(seekBar: SeekBar) {
isTrackingTouch = false
- changeFontSize(seekBar.progress)
+ changeFontSize(seekBar.progress, CHANGE_BY_SEEKBAR_DELAY_MS)
}
}
)
doneButton.setOnClickListener { dismiss() }
+ systemSettings.registerContentObserver(Settings.System.FONT_SCALE, fontSizeObserver)
+ }
+
+ /**
+ * Avoid SeekBar flickers when changing font scale. See the description from Setting at {@link
+ * TextReadingPreviewController#postCommitDelayed} for the reasons of flickers.
+ */
+ @MainThread
+ fun updateFontScaleDelayed(delayMsFromSource: Long) {
+ var delayMs = delayMsFromSource
+ if (systemClock.elapsedRealtime() - lastUpdateTime < MIN_UPDATE_INTERVAL_MS) {
+ delayMs += MIN_UPDATE_INTERVAL_MS
+ }
+ cancelUpdateFontScaleRunnable?.run()
+ cancelUpdateFontScaleRunnable =
+ backgroundDelayableExecutor.executeDelayed({ updateFontScale() }, delayMs)
+ }
+
+ override fun stop() {
+ cancelUpdateFontScaleRunnable?.run()
+ cancelUpdateFontScaleRunnable = null
+ systemSettings.unregisterContentObserver(fontSizeObserver)
}
- private fun changeFontSize(progress: Int) {
- if (progress != lastProgress) {
+ @MainThread
+ private fun changeFontSize(progress: Int, changedWithDelay: Long) {
+ if (progress != lastProgress.get()) {
+ lastProgress.set(progress)
+
if (!fontSizeHasBeenChangedFromTile) {
- backgroundExecutor.execute { updateSecureSettingsIfNeeded() }
+ backgroundDelayableExecutor.execute { updateSecureSettingsIfNeeded() }
fontSizeHasBeenChangedFromTile = true
}
- backgroundExecutor.execute { updateFontScale(strEntryValues[progress]) }
-
- lastProgress = progress
+ updateFontScaleDelayed(changedWithDelay)
}
}
+ @WorkerThread
private fun fontSizeValueToIndex(value: Float): Int {
var lastValue = strEntryValues[0].toFloat()
for (i in 1 until strEntryValues.size) {
@@ -150,8 +194,8 @@ class FontScalingDialog(
}
@WorkerThread
- fun updateFontScale(newScale: String) {
- systemSettings.putString(Settings.System.FONT_SCALE, newScale)
+ fun updateFontScale() {
+ systemSettings.putString(Settings.System.FONT_SCALE, strEntryValues[lastProgress.get()])
}
@WorkerThread
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 20666344ade8..f2e47018bf4e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -31,6 +31,10 @@ open class AuthBiometricFingerprintView(
context: Context,
attrs: AttributeSet? = null
) : AuthBiometricView(context, attrs) {
+ /** If this view is for a SFPS sensor. */
+ var isSfps = false
+ private set
+
/** If this view is for a UDFPS sensor. */
var isUdfps = false
private set
@@ -40,6 +44,7 @@ open class AuthBiometricFingerprintView(
/** Set the [sensorProps] of this sensor so the view can be customized prior to layout. */
fun setSensorProperties(sensorProps: FingerprintSensorPropertiesInternal) {
+ isSfps = sensorProps.isAnySidefpsType
isUdfps = sensorProps.isAnyUdfpsType
udfpsAdapter = if (isUdfps) UdfpsDialogMeasureAdapter(this, sensorProps) else null
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt
index e776ab44ee42..ae0cf3771ed3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/AuthBiometricFingerprintViewBinder.kt
@@ -36,7 +36,9 @@ object AuthBiometricFingerprintViewBinder {
viewModel.setRotation(view.context.display?.orientation ?: Surface.ROTATION_0)
launch {
viewModel.iconAsset.collect { iconAsset ->
- view.updateIconViewAnimation(iconAsset)
+ if (view.isSfps) {
+ view.updateIconViewAnimation(iconAsset)
+ }
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
index 12d98473ff07..c013486b83e4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FontScalingTile.kt
@@ -17,7 +17,6 @@ package com.android.systemui.qs.tiles
import android.content.Intent
import android.os.Handler
-import android.os.HandlerExecutor
import android.os.Looper
import android.provider.Settings
import android.view.View
@@ -40,8 +39,10 @@ import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSTileImpl
import com.android.systemui.statusbar.phone.SystemUIDialog
+import com.android.systemui.util.concurrency.DelayableExecutor
import com.android.systemui.util.settings.SecureSettings
import com.android.systemui.util.settings.SystemSettings
+import com.android.systemui.util.time.SystemClock
import javax.inject.Inject
class FontScalingTile
@@ -50,7 +51,7 @@ constructor(
host: QSHost,
uiEventLogger: QsEventLogger,
@Background backgroundLooper: Looper,
- @Main mainHandler: Handler,
+ @Main private val mainHandler: Handler,
falsingManager: FalsingManager,
metricsLogger: MetricsLogger,
statusBarStateController: StatusBarStateController,
@@ -59,7 +60,9 @@ constructor(
private val dialogLaunchAnimator: DialogLaunchAnimator,
private val systemSettings: SystemSettings,
private val secureSettings: SecureSettings,
- private val featureFlags: FeatureFlags
+ private val systemClock: SystemClock,
+ private val featureFlags: FeatureFlags,
+ @Background private val backgroundDelayableExecutor: DelayableExecutor
) :
QSTileImpl<QSTile.State?>(
host,
@@ -89,7 +92,9 @@ constructor(
mContext,
systemSettings,
secureSettings,
- HandlerExecutor(mHandler)
+ systemClock,
+ mainHandler,
+ backgroundDelayableExecutor
)
if (view != null) {
dialogLaunchAnimator.showFromView(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
index 353a7c370ab6..f10c21bc514a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/fontscaling/FontScalingDialogTest.kt
@@ -50,10 +50,14 @@ private const val OFF: Int = 0
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper(setAsMainLooper = true)
class FontScalingDialogTest : SysuiTestCase() {
+ private val MIN_UPDATE_INTERVAL_MS: Long = 800
+ private val CHANGE_BY_SEEKBAR_DELAY_MS: Long = 100
+ private val CHANGE_BY_BUTTON_DELAY_MS: Long = 300
private lateinit var fontScalingDialog: FontScalingDialog
private lateinit var systemSettings: SystemSettings
private lateinit var secureSettings: SecureSettings
- private lateinit var backgroundExecutor: FakeExecutor
+ private lateinit var systemClock: FakeSystemClock
+ private lateinit var backgroundDelayableExecutor: FakeExecutor
private val fontSizeValueArray: Array<String> =
mContext
.getResources()
@@ -67,10 +71,20 @@ class FontScalingDialogTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
val mainHandler = Handler(TestableLooper.get(this).getLooper())
systemSettings = FakeSettings()
+ // Guarantee that the systemSettings always starts with the default font scale.
+ systemSettings.putFloat(Settings.System.FONT_SCALE, 1.0f)
secureSettings = FakeSettings()
- backgroundExecutor = FakeExecutor(FakeSystemClock())
+ systemClock = FakeSystemClock()
+ backgroundDelayableExecutor = FakeExecutor(systemClock)
fontScalingDialog =
- spy(FontScalingDialog(mContext, systemSettings, secureSettings, backgroundExecutor))
+ FontScalingDialog(
+ mContext,
+ systemSettings,
+ secureSettings,
+ systemClock,
+ mainHandler,
+ backgroundDelayableExecutor
+ )
}
@Test
@@ -96,9 +110,14 @@ class FontScalingDialogTest : SysuiTestCase() {
val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
seekBarWithIconButtonsView.setProgress(0)
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
iconEndFrame.performClick()
- backgroundExecutor.runAllReady()
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
assertThat(seekBar.getProgress()).isEqualTo(1)
@@ -117,9 +136,14 @@ class FontScalingDialogTest : SysuiTestCase() {
val seekBar: SeekBar = fontScalingDialog.findViewById(R.id.seekbar)!!
seekBarWithIconButtonsView.setProgress(fontSizeValueArray.size - 1)
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
iconStartFrame.performClick()
- backgroundExecutor.runAllReady()
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
val currentScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
assertThat(seekBar.getProgress()).isEqualTo(fontSizeValueArray.size - 2)
@@ -139,7 +163,7 @@ class FontScalingDialogTest : SysuiTestCase() {
// Default seekbar progress for font size is 1, set it to another progress 0
seekBarWithIconButtonsView.setProgress(0)
- backgroundExecutor.runAllReady()
+ backgroundDelayableExecutor.runAllReady()
val currentSettings =
secureSettings.getInt(
@@ -153,6 +177,7 @@ class FontScalingDialogTest : SysuiTestCase() {
@Test
fun dragSeekbar_systemFontSizeSettingsDoesNotChange() {
+ fontScalingDialog = spy(fontScalingDialog)
val slider: SeekBarWithIconButtonsView = spy(SeekBarWithIconButtonsView(mContext))
whenever(
fontScalingDialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider)
@@ -169,7 +194,9 @@ class FontScalingDialogTest : SysuiTestCase() {
// OnSeekBarChangeListener and the seekbar could get updated progress value
// in onStopTrackingTouch.
seekBar.progress = 0
- backgroundExecutor.runAllReady()
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
// Verify that the scale of font size remains the default value 1.0f.
var systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
@@ -177,7 +204,9 @@ class FontScalingDialogTest : SysuiTestCase() {
// Simulate releasing the finger from the seekbar.
seekBarChangeCaptor.value.onStopTrackingTouch(seekBar)
- backgroundExecutor.runAllReady()
+ backgroundDelayableExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
// Verify that the scale of font size has been updated.
systemScale = systemSettings.getFloat(Settings.System.FONT_SCALE, /* def= */ 1.0f)
@@ -188,6 +217,7 @@ class FontScalingDialogTest : SysuiTestCase() {
@Test
fun dragSeekBar_createTextPreview() {
+ fontScalingDialog = spy(fontScalingDialog)
val slider: SeekBarWithIconButtonsView = spy(SeekBarWithIconButtonsView(mContext))
whenever(
fontScalingDialog.findViewById<SeekBarWithIconButtonsView>(R.id.font_scaling_slider)
@@ -205,7 +235,8 @@ class FontScalingDialogTest : SysuiTestCase() {
/* progress= */ 0,
/* fromUser= */ false
)
- backgroundExecutor.runAllReady()
+ backgroundDelayableExecutor.advanceClockToNext()
+ backgroundDelayableExecutor.runAllReady()
verify(fontScalingDialog).createTextPreview(/* index= */ 0)
fontScalingDialog.dismiss()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
index 1d6f225dd0a3..ddbfca57e688 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/FontScalingTileTest.kt
@@ -33,10 +33,12 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.qs.QSHost
import com.android.systemui.qs.QsEventLogger
import com.android.systemui.qs.logging.QSLogger
+import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.eq
import com.android.systemui.util.mockito.nullable
import com.android.systemui.util.settings.FakeSettings
+import com.android.systemui.util.time.FakeSystemClock
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -61,6 +63,8 @@ class FontScalingTileTest : SysuiTestCase() {
@Mock private lateinit var uiEventLogger: QsEventLogger
private lateinit var testableLooper: TestableLooper
+ private lateinit var systemClock: FakeSystemClock
+ private lateinit var backgroundDelayableExecutor: FakeExecutor
private lateinit var fontScalingTile: FontScalingTile
val featureFlags = FakeFeatureFlags()
@@ -70,6 +74,8 @@ class FontScalingTileTest : SysuiTestCase() {
MockitoAnnotations.initMocks(this)
testableLooper = TestableLooper.get(this)
`when`(qsHost.getContext()).thenReturn(mContext)
+ systemClock = FakeSystemClock()
+ backgroundDelayableExecutor = FakeExecutor(systemClock)
fontScalingTile =
FontScalingTile(
@@ -85,7 +91,9 @@ class FontScalingTileTest : SysuiTestCase() {
dialogLaunchAnimator,
FakeSettings(),
FakeSettings(),
- featureFlags
+ FakeSystemClock(),
+ featureFlags,
+ backgroundDelayableExecutor,
)
fontScalingTile.initialize()
testableLooper.processAllMessages()
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index c8db662a7f49..7975e49541a0 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -922,7 +922,8 @@ public class CompanionDeviceManagerService extends SystemService {
String[] args, ShellCallback callback, ResultReceiver resultReceiver)
throws RemoteException {
new CompanionDeviceShellCommand(CompanionDeviceManagerService.this, mAssociationStore,
- mDevicePresenceMonitor, mTransportManager, mSystemDataTransferRequestStore)
+ mDevicePresenceMonitor, mTransportManager, mSystemDataTransferRequestStore,
+ mAssociationRequestsProcessor)
.exec(this, in, out, err, args, callback, resultReceiver);
}
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
index 669686adddb8..c511429a37d8 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceShellCommand.java
@@ -17,14 +17,19 @@
package com.android.server.companion;
import android.companion.AssociationInfo;
+import android.companion.ContextSyncMessage;
+import android.companion.Telecom;
import android.companion.datatransfer.PermissionSyncRequest;
import android.net.MacAddress;
import android.os.Binder;
import android.os.ShellCommand;
+import android.util.proto.ProtoOutputStream;
import com.android.server.companion.datatransfer.SystemDataTransferRequestStore;
+import com.android.server.companion.datatransfer.contextsync.CrossDeviceSyncController;
import com.android.server.companion.presence.CompanionDevicePresenceMonitor;
import com.android.server.companion.transport.CompanionTransportManager;
+import com.android.server.companion.transport.Transport;
import java.io.PrintWriter;
import java.util.List;
@@ -33,22 +38,25 @@ class CompanionDeviceShellCommand extends ShellCommand {
private static final String TAG = "CDM_CompanionDeviceShellCommand";
private final CompanionDeviceManagerService mService;
- private final AssociationStore mAssociationStore;
+ private final AssociationStoreImpl mAssociationStore;
private final CompanionDevicePresenceMonitor mDevicePresenceMonitor;
private final CompanionTransportManager mTransportManager;
private final SystemDataTransferRequestStore mSystemDataTransferRequestStore;
+ private final AssociationRequestsProcessor mAssociationRequestsProcessor;
CompanionDeviceShellCommand(CompanionDeviceManagerService service,
- AssociationStore associationStore,
+ AssociationStoreImpl associationStore,
CompanionDevicePresenceMonitor devicePresenceMonitor,
CompanionTransportManager transportManager,
- SystemDataTransferRequestStore systemDataTransferRequestStore) {
+ SystemDataTransferRequestStore systemDataTransferRequestStore,
+ AssociationRequestsProcessor associationRequestsProcessor) {
mService = service;
mAssociationStore = associationStore;
mDevicePresenceMonitor = devicePresenceMonitor;
mTransportManager = transportManager;
mSystemDataTransferRequestStore = systemDataTransferRequestStore;
+ mAssociationRequestsProcessor = associationRequestsProcessor;
}
@Override
@@ -117,12 +125,107 @@ class CompanionDeviceShellCommand extends ShellCommand {
}
break;
- case "create-dummy-transport":
+ case "create-emulated-transport":
// This command creates a RawTransport in order to test Transport listeners
associationId = getNextIntArgRequired();
- mTransportManager.createDummyTransport(associationId);
+ mTransportManager.createEmulatedTransport(associationId);
break;
+ case "send-context-sync-empty-message": {
+ associationId = getNextIntArgRequired();
+ mTransportManager.createEmulatedTransport(associationId)
+ .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ /* sequence= */ 0,
+ CrossDeviceSyncController.createEmptyMessage());
+ break;
+ }
+
+ case "send-context-sync-call-create-message": {
+ associationId = getNextIntArgRequired();
+ String callId = getNextArgRequired();
+ String address = getNextArgRequired();
+ String facilitator = getNextArgRequired();
+ mTransportManager.createEmulatedTransport(associationId)
+ .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ /* sequence= */ 0,
+ CrossDeviceSyncController.createCallCreateMessage(callId,
+ address, facilitator));
+ break;
+ }
+
+ case "send-context-sync-call-control-message": {
+ associationId = getNextIntArgRequired();
+ String callId = getNextArgRequired();
+ int control = getNextIntArgRequired();
+ mTransportManager.createEmulatedTransport(associationId)
+ .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ /* sequence= */ 0,
+ CrossDeviceSyncController.createCallControlMessage(callId,
+ control));
+ break;
+ }
+
+ case "send-context-sync-call-facilitators-message": {
+ associationId = getNextIntArgRequired();
+ int numberOfFacilitators = getNextIntArgRequired();
+ final ProtoOutputStream pos = new ProtoOutputStream();
+ pos.write(ContextSyncMessage.VERSION, 1);
+ final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
+ for (int i = 0; i < numberOfFacilitators; i++) {
+ final long facilitatorsToken = pos.start(Telecom.FACILITATORS);
+ pos.write(Telecom.CallFacilitator.NAME, "Call Facilitator App #" + i);
+ pos.write(Telecom.CallFacilitator.IDENTIFIER, "com.android.test" + i);
+ pos.end(facilitatorsToken);
+ }
+ pos.end(telecomToken);
+ mTransportManager.createEmulatedTransport(associationId)
+ .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ /* sequence= */ 0, pos.getBytes());
+ break;
+ }
+
+ case "send-context-sync-call-message": {
+ associationId = getNextIntArgRequired();
+ String callId = getNextArgRequired();
+ String facilitatorId = getNextArgRequired();
+ final ProtoOutputStream pos = new ProtoOutputStream();
+ pos.write(ContextSyncMessage.VERSION, 1);
+ final long telecomToken = pos.start(ContextSyncMessage.TELECOM);
+ final long callsToken = pos.start(Telecom.CALLS);
+ pos.write(Telecom.Call.ID, callId);
+ final long originToken = pos.start(Telecom.Call.ORIGIN);
+ pos.write(Telecom.Call.Origin.CALLER_ID, "Caller Name");
+ final long facilitatorToken = pos.start(
+ Telecom.Request.CreateAction.FACILITATOR);
+ pos.write(Telecom.CallFacilitator.NAME, "Test App Name");
+ pos.write(Telecom.CallFacilitator.IDENTIFIER, facilitatorId);
+ pos.end(facilitatorToken);
+ pos.end(originToken);
+ pos.write(Telecom.Call.STATUS, Telecom.Call.RINGING);
+ pos.write(Telecom.Call.CONTROLS, Telecom.ACCEPT);
+ pos.write(Telecom.Call.CONTROLS, Telecom.REJECT);
+ pos.end(callsToken);
+ pos.end(telecomToken);
+ mTransportManager.createEmulatedTransport(associationId)
+ .processMessage(Transport.MESSAGE_REQUEST_CONTEXT_SYNC,
+ /* sequence= */ 0, pos.getBytes());
+ break;
+ }
+
+ case "disable-context-sync": {
+ associationId = getNextIntArgRequired();
+ int flag = getNextIntArgRequired();
+ mAssociationRequestsProcessor.disableSystemDataSync(associationId, flag);
+ break;
+ }
+
+ case "enable-context-sync": {
+ associationId = getNextIntArgRequired();
+ int flag = getNextIntArgRequired();
+ mAssociationRequestsProcessor.enableSystemDataSync(associationId, flag);
+ break;
+ }
+
case "allow-permission-sync": {
int userId = getNextIntArgRequired();
associationId = getNextIntArgRequired();
@@ -202,7 +305,7 @@ class CompanionDeviceShellCommand extends ShellCommand {
pw.println(" \"debug.cdm.cdmservice.cleanup_time_window\" system property). ");
pw.println(" USE FOR DEBUGGING AND/OR TESTING PURPOSES ONLY.");
- pw.println(" create-dummy-transport <ASSOCIATION_ID>");
- pw.println(" Create a dummy RawTransport for testing puspose only");
+ pw.println(" create-emulated-transport <ASSOCIATION_ID>");
+ pw.println(" Create an EmulatedTransport for testing purposes only");
}
}
diff --git a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
index a3e095e4475b..17bdb6085c45 100644
--- a/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
+++ b/services/companion/java/com/android/server/companion/transport/CompanionTransportManager.java
@@ -360,15 +360,42 @@ public class CompanionTransportManager {
/**
* For testing purpose only.
*
- * Create a dummy RawTransport and notify onTransportChanged listeners.
+ * Create an emulated RawTransport and notify onTransportChanged listeners.
*/
- public void createDummyTransport(int associationId) {
+ public EmulatedTransport createEmulatedTransport(int associationId) {
synchronized (mTransports) {
FileDescriptor fd = new FileDescriptor();
ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
- Transport transport = new RawTransport(associationId, pfd, mContext);
+ EmulatedTransport transport = new EmulatedTransport(associationId, pfd, mContext);
+ addMessageListenersToTransport(transport);
mTransports.put(associationId, transport);
notifyOnTransportsChanged();
+ return transport;
+ }
+ }
+
+ /**
+ * For testing purposes only.
+ *
+ * Emulates a transport for incoming messages but black-holes all messages sent back through it.
+ */
+ public static class EmulatedTransport extends RawTransport {
+
+ EmulatedTransport(int associationId, ParcelFileDescriptor fd, Context context) {
+ super(associationId, fd, context);
+ }
+
+ /** Process an incoming message for testing purposes. */
+ public void processMessage(int messageType, int sequence, byte[] data) throws IOException {
+ handleMessage(messageType, sequence, data);
+ }
+
+ @Override
+ protected void sendMessage(int messageType, int sequence, @NonNull byte[] data)
+ throws IOException {
+ Slog.e(TAG, "Black-holing emulated message type 0x" + Integer.toHexString(messageType)
+ + " sequence " + sequence + " length " + data.length
+ + " to association " + mAssociationId);
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 117f7473252f..a888a0b5d7d9 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9502,11 +9502,20 @@ public class ActivityManagerService extends IActivityManager.Stub
* Check if the calling process has the permission to dump given package,
* throw SecurityException if it doesn't have the permission.
*
- * @return The UID of the given package, or {@link android.os.Process#INVALID_UID}
+ * @return The real UID of process that can be dumped, or {@link android.os.Process#INVALID_UID}
* if the package is not found.
*/
int enforceDumpPermissionForPackage(String packageName, int userId, int callingUid,
String function) {
+ // Allow SDK sandbox process to dump for its own process (under SDK sandbox package)
+ try {
+ if (Process.isSdkSandboxUid(callingUid)
+ && getPackageManager().getSdkSandboxPackageName().equals(packageName)) {
+ return callingUid;
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not get SDK sandbox package name");
+ }
final long identity = Binder.clearCallingIdentity();
int uid = INVALID_UID;
try {
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index 4c0dd115a3cc..666e5600a8b6 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -467,6 +467,13 @@ public final class AppExitInfoTracker {
addExitInfoInnerLocked(packages[i], uid, info, recoverable);
}
+ // SDK sandbox exits are stored under both real and package UID
+ if (Process.isSdkSandboxUid(uid)) {
+ for (int i = 0; i < packages.length; i++) {
+ addExitInfoInnerLocked(packages[i], raw.getPackageUid(), info, recoverable);
+ }
+ }
+
schedulePersistProcessExitInfo(false);
return info;
@@ -1400,11 +1407,20 @@ public final class AppExitInfoTracker {
}
}
// Claim the state information if there is any
- final int uid = info.getPackageUid();
+ int uid = info.getPackageUid();
+ // SDK sandbox app states and app traces are stored under real UID
+ if (Process.isSdkSandboxUid(info.getRealUid())) {
+ uid = info.getRealUid();
+ }
final int pid = info.getPid();
- info.setProcessStateSummary(findAndRemoveFromSparse2dArray(
- mActiveAppStateSummary, uid, pid));
- info.setTraceFile(findAndRemoveFromSparse2dArray(mActiveAppTraces, uid, pid));
+ if (info.getProcessStateSummary() == null) {
+ info.setProcessStateSummary(findAndRemoveFromSparse2dArray(
+ mActiveAppStateSummary, uid, pid));
+ }
+ if (info.getTraceFile() == null) {
+ info.setTraceFile(findAndRemoveFromSparse2dArray(mActiveAppTraces, uid, pid));
+ }
+
info.setAppTraceRetriever(mAppTraceRetriever);
map.append(pid, info);
}
@@ -1905,15 +1921,15 @@ public final class AppExitInfoTracker {
}
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
- final int callingUserId = UserHandle.getCallingUserId();
final int userId = UserHandle.getUserId(uid);
mService.mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
ALLOW_NON_FULL, "getTraceFileDescriptor", null);
- if (mService.enforceDumpPermissionForPackage(packageName, userId,
- callingUid, "getTraceFileDescriptor") != Process.INVALID_UID) {
+ final int filterUid = mService.enforceDumpPermissionForPackage(packageName, userId,
+ callingUid, "getTraceFileDescriptor");
+ if (filterUid != Process.INVALID_UID) {
synchronized (mLock) {
- final ApplicationExitInfo info = getExitInfoLocked(packageName, uid, pid);
+ final ApplicationExitInfo info = getExitInfoLocked(packageName, filterUid, pid);
if (info == null) {
return null;
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
index c681b884d2ed..522ee341010b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyCacheImpl.java
@@ -25,7 +25,9 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
@@ -48,6 +50,13 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
@GuardedBy("mLock")
private int mScreenCaptureDisallowedUser = UserHandle.USER_NULL;
+ /**
+ * Indicates if screen capture is disallowed on a specific user or all users if
+ * it contains {@link UserHandle#USER_ALL}.
+ */
+ @GuardedBy("mLock")
+ private Set<Integer> mScreenCaptureDisallowedUsers = new HashSet<>();
+
@GuardedBy("mLock")
private final SparseIntArray mPasswordQuality = new SparseIntArray();
@@ -70,9 +79,21 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
@Override
public boolean isScreenCaptureAllowed(int userHandle) {
+ if (DevicePolicyManagerService.isPolicyEngineForFinanceFlagEnabled()) {
+ return isScreenCaptureAllowedInPolicyEngine(userHandle);
+ } else {
+ synchronized (mLock) {
+ return mScreenCaptureDisallowedUser != UserHandle.USER_ALL
+ && mScreenCaptureDisallowedUser != userHandle;
+ }
+ }
+ }
+
+ private boolean isScreenCaptureAllowedInPolicyEngine(int userHandle) {
+ // This won't work if resolution mechanism is not strictest applies, but it's ok for now.
synchronized (mLock) {
- return mScreenCaptureDisallowedUser != UserHandle.USER_ALL
- && mScreenCaptureDisallowedUser != userHandle;
+ return !mScreenCaptureDisallowedUsers.contains(userHandle)
+ && !mScreenCaptureDisallowedUsers.contains(UserHandle.USER_ALL);
}
}
@@ -88,6 +109,16 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
}
}
+ public void setScreenCaptureDisallowedUser(int userHandle, boolean disallowed) {
+ synchronized (mLock) {
+ if (disallowed) {
+ mScreenCaptureDisallowedUsers.add(userHandle);
+ } else {
+ mScreenCaptureDisallowedUsers.remove(userHandle);
+ }
+ }
+ }
+
@Override
public int getPasswordQuality(@UserIdInt int userHandle) {
synchronized (mLock) {
@@ -151,7 +182,11 @@ public class DevicePolicyCacheImpl extends DevicePolicyCache {
synchronized (mLock) {
pw.println("Device policy cache:");
pw.increaseIndent();
- pw.println("Screen capture disallowed user: " + mScreenCaptureDisallowedUser);
+ if (DevicePolicyManagerService.isPolicyEngineForFinanceFlagEnabled()) {
+ pw.println("Screen capture disallowed users: " + mScreenCaptureDisallowedUsers);
+ } else {
+ pw.println("Screen capture disallowed user: " + mScreenCaptureDisallowedUser);
+ }
pw.println("Password quality: " + mPasswordQuality);
pw.println("Permission policy: " + mPermissionPolicy);
pw.println("Admin can grant sensors permission: " + mCanGrantSensorsPermissions.get());
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index 0c4830afafcc..641a03b931c4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -546,8 +546,7 @@ final class DevicePolicyEngine {
if (hasLocalPolicyLocked(policyDefinition, userId)) {
resolvedValue = getLocalPolicyStateLocked(
policyDefinition, userId).getCurrentResolvedPolicy();
- }
- if (hasGlobalPolicyLocked(policyDefinition)) {
+ } else if (hasGlobalPolicyLocked(policyDefinition)) {
resolvedValue = getGlobalPolicyStateLocked(
policyDefinition).getCurrentResolvedPolicy();
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 3578b16d62c6..97987096fa86 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8642,7 +8642,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
CallerIdentity caller;
- if (isPermissionCheckFlagEnabled()) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
caller = getCallerIdentity(who, callerPackage);
} else {
Objects.requireNonNull(who, "ComponentName is null");
@@ -8656,23 +8656,47 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
- synchronized (getLockObject()) {
- ActiveAdmin ap;
- if (isPermissionCheckFlagEnabled()) {
- int callerUserId = Binder.getCallingUserHandle().getIdentifier();
- int targetUserId = parent ? getProfileParentId(callerUserId) : callerUserId;
- ap = enforcePermissionAndGetEnforcingAdmin(
- who, MANAGE_DEVICE_POLICY_SCREEN_CAPTURE, caller.getPackageName(),
- targetUserId).getActiveAdmin();
+ if (isPolicyEngineForFinanceFlagEnabled()) {
+ int callerUserId = Binder.getCallingUserHandle().getIdentifier();
+ int targetUserId = parent ? getProfileParentId(callerUserId) : callerUserId;
+ EnforcingAdmin admin = enforcePermissionAndGetEnforcingAdmin(
+ who, MANAGE_DEVICE_POLICY_SCREEN_CAPTURE, caller.getPackageName(),
+ targetUserId);
+ if ((parent && isProfileOwnerOfOrganizationOwnedDevice(caller))
+ || isDefaultDeviceOwner(caller)) {
+ if (disabled) {
+ mDevicePolicyEngine.setGlobalPolicy(
+ PolicyDefinition.SCREEN_CAPTURE_DISABLED,
+ admin,
+ new BooleanPolicyValue(disabled));
+ } else {
+ mDevicePolicyEngine.removeGlobalPolicy(
+ PolicyDefinition.SCREEN_CAPTURE_DISABLED,
+ admin);
+ }
} else {
- ap = getParentOfAdminIfRequired(
- getProfileOwnerOrDefaultDeviceOwnerLocked(caller.getUserId()), parent);
+ if (disabled) {
+ mDevicePolicyEngine.setLocalPolicy(
+ PolicyDefinition.SCREEN_CAPTURE_DISABLED,
+ admin,
+ new BooleanPolicyValue(disabled),
+ callerUserId);
+ } else {
+ mDevicePolicyEngine.removeLocalPolicy(
+ PolicyDefinition.SCREEN_CAPTURE_DISABLED,
+ admin,
+ callerUserId);
+ }
}
-
- if (ap.disableScreenCapture != disabled) {
- ap.disableScreenCapture = disabled;
- saveSettingsLocked(caller.getUserId());
- pushScreenCapturePolicy(caller.getUserId());
+ } else {
+ synchronized (getLockObject()) {
+ ActiveAdmin ap = getParentOfAdminIfRequired(
+ getProfileOwnerOrDefaultDeviceOwnerLocked(caller.getUserId()), parent);
+ if (ap.disableScreenCapture != disabled) {
+ ap.disableScreenCapture = disabled;
+ saveSettingsLocked(caller.getUserId());
+ pushScreenCapturePolicy(caller.getUserId());
+ }
}
}
DevicePolicyEventLogger
@@ -8686,6 +8710,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// DO or COPE PO on the parent profile, then this takes precedence as screen capture will
// be disabled device-wide.
private void pushScreenCapturePolicy(int adminUserId) {
+ if (isPolicyEngineForFinanceFlagEnabled()) {
+ return;
+ }
// Update screen capture device-wide if disabled by the DO or COPE PO on the parent profile.
// TODO(b/261999445): remove
ActiveAdmin admin;
@@ -8727,8 +8754,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
- * Returns whether or not screen capture is disabled for a given admin, or disabled for any
- * active admin (if given admin is null).
+ * Returns whether or not screen capture is disabled for any active admin.
*/
@Override
public boolean getScreenCaptureDisabled(ComponentName who, int userHandle, boolean parent) {
@@ -8742,7 +8768,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
Preconditions.checkCallAuthorization(
isProfileOwnerOfOrganizationOwnedDevice(getCallerIdentity().getUserId()));
}
- return !mPolicyCache.isScreenCaptureAllowed(userHandle);
+ if (isPolicyEngineForFinanceFlagEnabled()) {
+ Boolean disallowed = mDevicePolicyEngine.getResolvedPolicy(
+ PolicyDefinition.SCREEN_CAPTURE_DISABLED,
+ userHandle);
+ return disallowed != null && disallowed;
+ } else {
+ return !mPolicyCache.isScreenCaptureAllowed(userHandle);
+ }
}
private void updateScreenCaptureDisabled() {
@@ -16306,17 +16339,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return result;
}
} else if (DevicePolicyManager.POLICY_DISABLE_SCREEN_CAPTURE.equals(restriction)) {
- synchronized (getLockObject()) {
- final DevicePolicyData policy = getUserData(userId);
- final int N = policy.mAdminList.size();
- for (int i = 0; i < N; i++) {
- final ActiveAdmin admin = policy.mAdminList.get(i);
- if (admin.disableScreenCapture) {
- result = new Bundle();
- result.putInt(Intent.EXTRA_USER_ID, userId);
- result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
- admin.info.getComponent());
- return result;
+ if (isPolicyEngineForFinanceFlagEnabled()) {
+ Boolean value = mDevicePolicyEngine.getResolvedPolicy(
+ PolicyDefinition.SCREEN_CAPTURE_DISABLED, userId);
+ if (value != null && value) {
+ result = new Bundle();
+ result.putInt(Intent.EXTRA_USER_ID, userId);
+ return result;
+ }
+ } else {
+ synchronized (getLockObject()) {
+ final DevicePolicyData policy = getUserData(userId);
+ final int N = policy.mAdminList.size();
+ for (int i = 0; i < N; i++) {
+ final ActiveAdmin admin = policy.mAdminList.get(i);
+ if (admin.disableScreenCapture) {
+ result = new Bundle();
+ result.putInt(Intent.EXTRA_USER_ID, userId);
+ result.putParcelable(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
+ admin.info.getComponent());
+ return result;
+ }
}
}
}
@@ -23646,7 +23689,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
DEFAULT_VALUE_PERMISSION_BASED_ACCESS_FLAG);
}
- private boolean isPolicyEngineForFinanceFlagEnabled() {
+ static boolean isPolicyEngineForFinanceFlagEnabled() {
return DeviceConfig.getBoolean(
NAMESPACE_DEVICE_POLICY_MANAGER,
ENABLE_DEVICE_POLICY_ENGINE_FOR_FINANCE_FLAG,
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
index 43a2c9bbf5c5..17c84f9916dd 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyDefinition.java
@@ -315,6 +315,14 @@ final class PolicyDefinition<V> {
(Set<String> value, Context context, Integer userId, PolicyKey policyKey) -> true,
new StringSetPolicySerializer());
+
+ static PolicyDefinition<Boolean> SCREEN_CAPTURE_DISABLED = new PolicyDefinition<>(
+ new NoArgsPolicyKey(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY),
+ TRUE_MORE_RESTRICTIVE,
+ /* flags= */ 0,
+ PolicyEnforcerCallbacks::setScreenCaptureDisabled,
+ new BooleanPolicySerializer());
+
private static final Map<String, PolicyDefinition<?>> POLICY_DEFINITIONS = new HashMap<>();
private static Map<String, Integer> USER_RESTRICTION_FLAGS = new HashMap<>();
@@ -342,6 +350,8 @@ final class PolicyDefinition<V> {
GENERIC_ACCOUNT_MANAGEMENT_DISABLED);
POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.PERMITTED_INPUT_METHODS_POLICY,
PERMITTED_INPUT_METHODS);
+ POLICY_DEFINITIONS.put(DevicePolicyIdentifiers.SCREEN_CAPTURE_DISABLED_POLICY,
+ SCREEN_CAPTURE_DISABLED);
// User Restriction Policies
USER_RESTRICTION_FLAGS.put(UserManager.DISALLOW_MODIFY_ACCOUNTS, /* flags= */ 0);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
index 289098e87550..816a9848d5b3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/PolicyEnforcerCallbacks.java
@@ -19,6 +19,7 @@ package com.android.server.devicepolicy;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.AppGlobals;
+import android.app.admin.DevicePolicyCache;
import android.app.admin.DevicePolicyManager;
import android.app.admin.IntentFilterPolicyKey;
import android.app.admin.LockTaskPolicy;
@@ -35,13 +36,16 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.UserHandle;
import android.permission.AdminPermissionControlParams;
import android.permission.PermissionControllerManager;
import android.provider.Settings;
import android.util.ArraySet;
import android.util.Slog;
+import android.view.IWindowManager;
+import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
import com.android.server.utils.Slogf;
@@ -244,4 +248,31 @@ final class PolicyEnforcerCallbacks {
packageName, hide != null && hide, userId);
}));
}
+
+ static boolean setScreenCaptureDisabled(
+ @Nullable Boolean disabled, @NonNull Context context, int userId,
+ @NonNull PolicyKey policyKey) {
+ Binder.withCleanCallingIdentity(() -> {
+ DevicePolicyCache cache = DevicePolicyCache.getInstance();
+ if (cache instanceof DevicePolicyCacheImpl) {
+ DevicePolicyCacheImpl parsedCache = (DevicePolicyCacheImpl) cache;
+ parsedCache.setScreenCaptureDisallowedUser(
+ userId, disabled != null && disabled);
+ updateScreenCaptureDisabled();
+ }
+ });
+ return true;
+ }
+
+ private static void updateScreenCaptureDisabled() {
+ BackgroundThread.getHandler().post(() -> {
+ try {
+ IWindowManager.Stub
+ .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE))
+ .refreshScreenCaptureDisabled();
+ } catch (RemoteException e) {
+ Slogf.w(LOG_TAG, "Unable to notify WindowManager.", e);
+ }
+ });
+ }
}
diff --git a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
index 475966ea00b8..8f23ae4ff33b 100644
--- a/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
+++ b/services/profcollect/src/com/android/server/profcollect/ProfcollectForwardingService.java
@@ -72,7 +72,7 @@ public final class ProfcollectForwardingService extends SystemService {
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction() == INTENT_UPLOAD_PROFILES) {
+ if (INTENT_UPLOAD_PROFILES.equals(intent.getAction())) {
Log.d(LOG_TAG, "Received broadcast to pack and upload reports");
packAndUploadReport();
}
@@ -89,7 +89,7 @@ public final class ProfcollectForwardingService extends SystemService {
final IntentFilter filter = new IntentFilter();
filter.addAction(INTENT_UPLOAD_PROFILES);
- context.registerReceiver(mBroadcastReceiver, filter);
+ context.registerReceiver(mBroadcastReceiver, filter, Context.RECEIVER_NOT_EXPORTED);
}
/**
diff --git a/telecomm/java/android/telecom/CallControlCallback.java b/telecomm/java/android/telecom/CallControlCallback.java
index 35e2fd43efdd..eac2e64aa2ab 100644
--- a/telecomm/java/android/telecom/CallControlCallback.java
+++ b/telecomm/java/android/telecom/CallControlCallback.java
@@ -44,9 +44,11 @@ public interface CallControlCallback {
*
* @param wasCompleted The {@link Consumer} to be completed. If the client can set the call
* active on their end, the {@link Consumer#accept(Object)} should be
- * called with {@link Boolean#TRUE}. Otherwise,
- * {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#FALSE}.
+ * called with {@link Boolean#TRUE}.
+ *
+ * Otherwise, {@link Consumer#accept(Object)} should be called with
+ * {@link Boolean#FALSE}. Telecom will effectively ignore the remote
+ * setActive request and the call will remain in whatever state it is in.
*/
void onSetActive(@NonNull Consumer<Boolean> wasCompleted);
@@ -56,9 +58,11 @@ public interface CallControlCallback {
*
* @param wasCompleted The {@link Consumer} to be completed. If the client can set the call
* inactive on their end, the {@link Consumer#accept(Object)} should be
- * called with {@link Boolean#TRUE}. Otherwise,
- * {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#FALSE}.
+ * called with {@link Boolean#TRUE}.
+ *
+ * Otherwise, {@link Consumer#accept(Object)} should be called with
+ * {@link Boolean#FALSE}. Telecom will effectively ignore the remote
+ * setInactive request and the call will remain in whatever state it is in.
*/
void onSetInactive(@NonNull Consumer<Boolean> wasCompleted);
@@ -68,8 +72,11 @@ public interface CallControlCallback {
* @param videoState see {@link android.telecom.CallAttributes.CallType} for valid states
* @param wasCompleted The {@link Consumer} to be completed. If the client can answer the call
* on their end, {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#TRUE}. Otherwise, {@link Consumer#accept(Object)} should
- * be called with {@link Boolean#FALSE}.
+ * {@link Boolean#TRUE}.
+ *
+ * Otherwise,{@link Consumer#accept(Object)} should be called with
+ * {@link Boolean#FALSE}. However, Telecom will still disconnect
+ * the call and remove it from tracking.
*/
void onAnswer(@android.telecom.CallAttributes.CallType int videoState,
@NonNull Consumer<Boolean> wasCompleted);
@@ -80,9 +87,11 @@ public interface CallControlCallback {
* @param disconnectCause represents the cause for disconnecting the call.
* @param wasCompleted The {@link Consumer} to be completed. If the client can disconnect
* the call on their end, {@link Consumer#accept(Object)} should be
- * called with {@link Boolean#TRUE}. Otherwise,
- * {@link Consumer#accept(Object)} should be called with
- * {@link Boolean#FALSE}.
+ * called with {@link Boolean#TRUE}.
+ *
+ * Otherwise,{@link Consumer#accept(Object)} should be called with
+ * {@link Boolean#FALSE}. However, Telecom will still disconnect
+ * the call and remove it from tracking.
*/
void onDisconnect(@NonNull DisconnectCause disconnectCause,
@NonNull Consumer<Boolean> wasCompleted);