Merge "Ambient Activation p2.1" into main
diff --git a/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java b/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java
new file mode 100644
index 0000000..9699757
--- /dev/null
+++ b/apex/jobscheduler/framework/java/android/os/WearModeManagerInternal.java
@@ -0,0 +1,85 @@
+/*
+ * 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 android.os;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.NonNull;
+import android.annotation.StringDef;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+/**
+ * Mode Manager local service interface.
+ * Example usage: LocalServices.get(WearModeManagerInternal.class).
+ *
+ * TODO(b/288115060): consolidate with {@link com.android.server.policy.WearModeServiceInternal}
+ *
+ * @hide
+ */
+public interface WearModeManagerInternal {
+
+ /**
+ * Mode manager quick doze request identifier.
+ *
+ * <p>Unique identifier that can be used as identifier parameter in
+ * registerInternalStateObserver
+ * to listen to changes in quick doze request state from mode manager.
+ *
+ * TODO(b/288276510): convert to int constant
+ */
+ String QUICK_DOZE_REQUEST_IDENTIFIER = "quick_doze_request";
+
+ /**
+ * StringDef for Mode manager identifiers.
+ *
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @StringDef({
+ QUICK_DOZE_REQUEST_IDENTIFIER
+ })
+ @Target(ElementType.TYPE_USE)
+ @interface Identifier {
+ }
+
+ /**
+ * Method to register a callback in Mode manager.
+ *
+ * <p>Callback is executed when there is a change of active state for the
+ * provided identifier.
+ *
+ * <p>Mode manager has active states and configured states where active state is the state of a
+ * mode/feature as reflected on the device,
+ * configured state refers to the configured value of the state of the mode / feature.
+ * For e.g.: Quick doze might be configured to be disabled by default but in certain modes, it
+ * can be overridden to be enabled. At that point active=enabled, configured=disabled.
+ *
+ * <p>
+ *
+ * @param identifier Observer listens for changes to this {@link Identifier}
+ * @param executor Executor used to execute the callback.
+ * @param callback Boolean consumer callback.
+ */
+ <T> void addActiveStateChangeListener(@NonNull @Identifier String identifier,
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull Consumer<T> callback);
+}
diff --git a/core/api/current.txt b/core/api/current.txt
index 36c2f01..3392d25 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -7662,7 +7662,7 @@
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_EXTERNAL_STORAGE, "android.permission.READ_WALLPAPER_INTERNAL"}) public android.graphics.drawable.Drawable peekFastDrawable();
method @Nullable @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_EXTERNAL_STORAGE, "android.permission.READ_WALLPAPER_INTERNAL"}) public android.graphics.drawable.Drawable peekFastDrawable(int);
method public void removeOnColorsChangedListener(@NonNull android.app.WallpaperManager.OnColorsChangedListener);
- method public void sendWallpaperCommand(android.os.IBinder, String, int, int, int, android.os.Bundle);
+ method @RequiresPermission(value="android.permission.ALWAYS_UPDATE_WALLPAPER", conditional=true) public void sendWallpaperCommand(android.os.IBinder, String, int, int, int, android.os.Bundle);
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public void setBitmap(android.graphics.Bitmap) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean) throws java.io.IOException;
method @RequiresPermission(android.Manifest.permission.SET_WALLPAPER) public int setBitmap(android.graphics.Bitmap, android.graphics.Rect, boolean, int) throws java.io.IOException;
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 0185080..a02fd84 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -36,6 +36,7 @@
field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
field public static final String ALLOW_PLACE_IN_MULTI_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_MULTI_PANE_SETTINGS";
field public static final String ALLOW_SLIPPERY_TOUCHES = "android.permission.ALLOW_SLIPPERY_TOUCHES";
+ field public static final String ALWAYS_UPDATE_WALLPAPER = "android.permission.ALWAYS_UPDATE_WALLPAPER";
field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES";
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 5d7993d..c31aa01 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -2670,6 +2670,8 @@
* @param z Arbitrary integer argument based on command.
* @param extras Optional additional information for the command, or null.
*/
+ @RequiresPermission(value = android.Manifest.permission.ALWAYS_UPDATE_WALLPAPER,
+ conditional = true)
public void sendWallpaperCommand(IBinder windowToken, String action,
int x, int y, int z, Bundle extras) {
try {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b29a4e6..86cf80e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4032,6 +4032,13 @@
<permission android:name="android.permission.READ_WALLPAPER_INTERNAL"
android:protectionLevel="signature|privileged" />
+ <!-- Allow apps to always update wallpaper by sending data.
+ @SystemApi
+ @hide
+ -->
+ <permission android:name="android.permission.ALWAYS_UPDATE_WALLPAPER"
+ android:protectionLevel="internal|role" />
+
<!-- ===================================================== -->
<!-- Permissions for changing the system clock / time zone -->
<!-- ===================================================== -->
diff --git a/core/res/res/values-television/config.xml b/core/res/res/values-television/config.xml
index eaadc20..c3db87b 100644
--- a/core/res/res/values-television/config.xml
+++ b/core/res/res/values-television/config.xml
@@ -45,29 +45,29 @@
<!-- Component name of the activity used to inform a user about a sensory being blocked because
of privacy settings. -->
<string name="config_sensorUseStartedActivity" translatable="false">
- com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
+ com.android.systemui/com.android.systemui.tv.sensorprivacy.TvUnblockSensorActivity
</string>
<!-- Component name of the activity used to inform a user about a sensory being blocked because
of hardware privacy switches. -->
<string name="config_sensorUseStartedActivity_hwToggle" translatable="false">
- com.android.systemui/com.android.systemui.sensorprivacy.television.TvUnblockSensorActivity
+ com.android.systemui/com.android.systemui.tv.sensorprivacy.TvUnblockSensorActivity
</string>
<!-- Component name of the activity used to inform a user about a sensor privacy update from
SW/HW privacy switches. -->
<string name="config_sensorStateChangedActivity" translatable="false">
- com.android.systemui/com.android.systemui.sensorprivacy.television.TvSensorPrivacyChangedActivity
+ com.android.systemui/com.android.systemui.tv.sensorprivacy.TvSensorPrivacyChangedActivity
</string>
<!-- Component name of the activity that shows the request for access to a usb device. -->
<string name="config_usbPermissionActivity" translatable="false">
- com.android.systemui/com.android.systemui.usb.tv.TvUsbPermissionActivity
+ com.android.systemui/com.android.systemui.tv.usb.TvUsbPermissionActivity
</string>
<!-- Component name of the activity that confirms the activity to start when a usb device is
plugged in. -->
<string name="config_usbConfirmActivity" translatable="false">
- com.android.systemui/com.android.systemui.usb.tv.TvUsbConfirmActivity
+ com.android.systemui/com.android.systemui.tv.usb.TvUsbConfirmActivity
</string>
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 38da090..71630cb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3212,8 +3212,9 @@
<!-- Component name of the activity used to ask a user to confirm system language change after
receiving <Set Menu Language> CEC message. -->
- <string name="config_hdmiCecSetMenuLanguageActivity"
- >com.android.systemui/com.android.systemui.hdmi.HdmiCecSetMenuLanguageActivity</string>
+ <string name="config_hdmiCecSetMenuLanguageActivity">
+ com.android.systemui/com.android.systemui.tv.hdmi.HdmiCecSetMenuLanguageActivity
+ </string>
<!-- Name of the dialog that is used to request the user's consent for a Platform VPN -->
<string name="config_platformVpnConfirmDialogComponent" translatable="false"
diff --git a/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg.xml b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg.xml
new file mode 100644
index 0000000..d3d324b
--- /dev/null
+++ b/packages/SettingsLib/MainSwitchPreference/res/drawable-v31/settingslib_switch_bar_bg.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:state_enabled="false"
+ android:drawable="@drawable/settingslib_switch_bar_bg_disabled"/>
+ <item
+ android:state_activated="true"
+ android:drawable="@drawable/settingslib_switch_bar_bg_on"/>
+ <item
+ android:state_activated="false"
+ android:drawable="@drawable/settingslib_switch_bar_bg_off"/>
+</selector>
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
index b1c26e8..e3f8fbb 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v31/settingslib_main_switch_bar.xml
@@ -32,7 +32,8 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:paddingEnd="@dimen/settingslib_switchbar_padding_right"
+ android:background="@drawable/settingslib_switch_bar_bg">
<TextView
android:id="@+id/switch_text"
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 d2e9fbe..255b2c9 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
@@ -32,7 +32,8 @@
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingStart="@dimen/settingslib_switchbar_padding_left"
- android:paddingEnd="@dimen/settingslib_switchbar_padding_right">
+ android:paddingEnd="@dimen/settingslib_switchbar_padding_right"
+ android:background="@drawable/settingslib_switch_bar_bg">
<TextView
android:id="@+id/switch_text"
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
index 864a8bb..d1703c3 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchBar.java
@@ -18,7 +18,6 @@
import android.content.Context;
import android.content.res.TypedArray;
-import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.AttributeSet;
@@ -52,9 +51,6 @@
protected TextView mTextView;
protected Switch mSwitch;
- private Drawable mBackgroundOn;
- private Drawable mBackgroundOff;
- private Drawable mBackgroundDisabled;
private View mFrameView;
public MainSwitchBar(Context context) {
@@ -89,12 +85,6 @@
mFrameView = findViewById(R.id.frame);
mTextView = (TextView) findViewById(R.id.switch_text);
mSwitch = (Switch) findViewById(android.R.id.switch_widget);
- if (BuildCompatUtils.isAtLeastS()) {
- mBackgroundOn = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_on);
- mBackgroundOff = getContext().getDrawable(R.drawable.settingslib_switch_bar_bg_off);
- mBackgroundDisabled = getContext().getDrawable(
- R.drawable.settingslib_switch_bar_bg_disabled);
- }
addOnSwitchChangeListener((switchView, isChecked) -> setChecked(isChecked));
if (mSwitch.getVisibility() == VISIBLE) {
@@ -217,17 +207,15 @@
/**
* Enable or disable the text and switch.
*/
+ @Override
public void setEnabled(boolean enabled) {
super.setEnabled(enabled);
mTextView.setEnabled(enabled);
mSwitch.setEnabled(enabled);
if (BuildCompatUtils.isAtLeastS()) {
- if (enabled) {
- mFrameView.setBackground(isChecked() ? mBackgroundOn : mBackgroundOff);
- } else {
- mFrameView.setBackground(mBackgroundDisabled);
- }
+ mFrameView.setEnabled(enabled);
+ mFrameView.setActivated(isChecked());
}
}
@@ -244,7 +232,7 @@
if (!BuildCompatUtils.isAtLeastS()) {
setBackgroundColor(isChecked ? mBackgroundActivatedColor : mBackgroundColor);
} else {
- mFrameView.setBackground(isChecked ? mBackgroundOn : mBackgroundOff);
+ mFrameView.setActivated(isChecked);
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
index 3011d31..8d03f70 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/CreateUserDialogController.java
@@ -80,6 +80,7 @@
private Bitmap mSavedPhoto;
private String mSavedName;
private Drawable mSavedDrawable;
+ private String mCachedDrawablePath;
private String mUserName;
private Drawable mNewUserIcon;
private Boolean mIsAdmin;
@@ -117,6 +118,7 @@
mUserNameView = null;
mSuccessCallback = null;
mCancelCallback = null;
+ mCachedDrawablePath = null;
mCurrentState = INITIAL_DIALOG;
}
@@ -124,13 +126,7 @@
* Notifies that the containing activity or fragment was reinitialized.
*/
public void onRestoreInstanceState(Bundle savedInstanceState) {
- String pendingPhoto = savedInstanceState.getString(KEY_SAVED_PHOTO);
- if (pendingPhoto != null) {
- ThreadUtils.postOnBackgroundThread(() -> {
- mSavedPhoto = EditUserPhotoController.loadNewUserPhotoBitmap(
- new File(pendingPhoto));
- });
- }
+ mCachedDrawablePath = savedInstanceState.getString(KEY_SAVED_PHOTO);
mCurrentState = savedInstanceState.getInt(KEY_CURRENT_STATE);
if (savedInstanceState.containsKey(KEY_IS_ADMIN)) {
mIsAdmin = savedInstanceState.getBoolean(KEY_IS_ADMIN);
@@ -143,15 +139,12 @@
* Notifies that the containing activity or fragment is saving its state for later use.
*/
public void onSaveInstanceState(Bundle savedInstanceState) {
- if (mUserCreationDialog != null && mEditUserPhotoController != null) {
- // Bitmap cannot be stored into bundle because it may exceed parcel limit
- // Store it in a temporary file instead
- ThreadUtils.postOnBackgroundThread(() -> {
- File file = mEditUserPhotoController.saveNewUserPhotoBitmap();
- if (file != null) {
- savedInstanceState.putString(KEY_SAVED_PHOTO, file.getPath());
- }
- });
+ if (mUserCreationDialog != null && mEditUserPhotoController != null
+ && mCachedDrawablePath == null) {
+ mCachedDrawablePath = mEditUserPhotoController.getCachedDrawablePath();
+ }
+ if (mCachedDrawablePath != null) {
+ savedInstanceState.putString(KEY_SAVED_PHOTO, mCachedDrawablePath);
}
if (mIsAdmin != null) {
savedInstanceState.putBoolean(KEY_IS_ADMIN, Boolean.TRUE.equals(mIsAdmin));
@@ -271,9 +264,10 @@
mGrantAdminView.setVisibility(View.GONE);
break;
case CREATE_USER_AND_CLOSE:
- mNewUserIcon = mEditUserPhotoController != null
+ mNewUserIcon = (mEditUserPhotoController != null
+ && mEditUserPhotoController.getNewUserPhotoDrawable() != null)
? mEditUserPhotoController.getNewUserPhotoDrawable()
- : null;
+ : mSavedDrawable;
String newName = mUserNameView.getText().toString().trim();
String defaultName = mActivity.getString(R.string.user_new_user_name);
@@ -295,12 +289,17 @@
}
}
- private Drawable getUserIcon(Drawable defaultUserIcon) {
- if (mSavedPhoto != null) {
- mSavedDrawable = CircleFramedDrawable.getInstance(mActivity, mSavedPhoto);
- return mSavedDrawable;
+ private void setUserIcon(Drawable defaultUserIcon, ImageView userPhotoView) {
+ if (mCachedDrawablePath != null) {
+ ThreadUtils.postOnBackgroundThread(() -> {
+ mSavedPhoto = EditUserPhotoController.loadNewUserPhotoBitmap(
+ new File(mCachedDrawablePath));
+ mSavedDrawable = CircleFramedDrawable.getInstance(mActivity, mSavedPhoto);
+ ThreadUtils.postOnMainThread(() -> userPhotoView.setImageDrawable(mSavedDrawable));
+ });
+ } else {
+ userPhotoView.setImageDrawable(defaultUserIcon);
}
- return defaultUserIcon;
}
private void addUserInfoEditView() {
@@ -312,10 +311,7 @@
// if oldUserIcon param is null then we use a default gray user icon
Drawable defaultUserIcon = UserIcons.getDefaultUserIcon(
mActivity.getResources(), UserHandle.USER_NULL, false);
- // in case a new photo was selected and the activity got recreated we have to load the image
- Drawable userIcon = getUserIcon(defaultUserIcon);
- userPhotoView.setImageDrawable(userIcon);
-
+ setUserIcon(defaultUserIcon, userPhotoView);
if (isChangePhotoRestrictedByBase(mActivity)) {
// some users can't change their photos so we need to remove the suggestive icon
mEditUserInfoView.findViewById(R.id.add_a_photo_icon).setVisibility(View.GONE);
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
index 38cf383..3fb2f60 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/EditUserPhotoController.java
@@ -60,6 +60,7 @@
private final File mImagesDir;
private Bitmap mNewUserPhotoBitmap;
private Drawable mNewUserPhotoDrawable;
+ private String mCachedDrawablePath;
public EditUserPhotoController(Activity activity, ActivityStarter activityStarter,
ImageView view, Bitmap savedBitmap, Drawable savedDrawable, String fileAuthority) {
@@ -156,6 +157,9 @@
private void onPhotoProcessed(Bitmap bitmap) {
if (bitmap != null) {
mNewUserPhotoBitmap = bitmap;
+ ThreadUtils.postOnBackgroundThread(() -> {
+ mCachedDrawablePath = saveNewUserPhotoBitmap().getPath();
+ });
mNewUserPhotoDrawable = CircleFramedDrawable
.getInstance(mImageView.getContext(), mNewUserPhotoBitmap);
mImageView.setImageDrawable(mNewUserPhotoDrawable);
@@ -186,4 +190,8 @@
void removeNewUserPhotoBitmapFile() {
new File(mImagesDir, NEW_USER_PHOTO_FILE_NAME).delete();
}
+
+ String getCachedDrawablePath() {
+ return mCachedDrawablePath;
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index 00f2d0e..ffaebf4 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -40,8 +40,12 @@
import com.android.internal.util.FastPrintWriter;
+import java.io.File;
import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.InputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Field;
@@ -49,14 +53,22 @@
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Scanner;
/**
* Receives shell commands from the command line related to device config flags, and dispatches them
* to the SettingsProvider.
*/
public final class DeviceConfigService extends Binder {
+ private static final List<String> aconfigTextProtoFilesOnDevice = List.of(
+ "/system/etc/aconfig_flags.textproto",
+ "/system_ext/etc/aconfig_flags.textproto",
+ "/system_ext/etc/aconfig_flags.textproto",
+ "/vendor/etc/aconfig_flags.textproto");
+
final SettingsProvider mProvider;
public DeviceConfigService(SettingsProvider provider) {
@@ -78,10 +90,61 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
final IContentProvider iprovider = mProvider.getIContentProvider();
- pw.println("device config properties:");
+ pw.println("DeviceConfig flags:");
for (String line : MyShellCommand.listAll(iprovider)) {
pw.println(line);
}
+
+ ArrayList<String> missingFiles = new ArrayList<String>();
+ for (String fileName : aconfigTextProtoFilesOnDevice) {
+ File aconfigFile = new File(fileName);
+ if (!aconfigFile.exists()) {
+ missingFiles.add(fileName);
+ }
+ }
+
+ if (missingFiles.isEmpty()) {
+ pw.println("\nAconfig flags:");
+ for (String name : MyShellCommand.listAllAconfigFlags(iprovider)) {
+ pw.println(name);
+ }
+ } else {
+ pw.println("\nFailed to dump aconfig flags due to missing files:");
+ for (String fileName : missingFiles) {
+ pw.println(fileName);
+ }
+ }
+ }
+
+ private static HashSet<String> getAconfigFlagNamesInDeviceConfig() {
+ HashSet<String> nameSet = new HashSet<String>();
+ for (String fileName : aconfigTextProtoFilesOnDevice) {
+ try{
+ File aconfigFile = new File(fileName);
+ String packageName = "";
+ String namespace = "";
+ String name = "";
+
+ try (Scanner scanner = new Scanner(aconfigFile)) {
+ while (scanner.hasNextLine()) {
+ String data = scanner.nextLine().replaceAll("\\s+","");
+ if (data.startsWith("package:\"")) {
+ packageName = data.substring(9, data.length()-1);
+ } else if (data.startsWith("name:\"")) {
+ name = data.substring(6, data.length()-1);
+ } else if (data.startsWith("namespace:\"")) {
+ namespace = data.substring(11, data.length()-1);
+ nameSet.add(namespace + "/" + packageName + "." + name);
+ }
+ }
+ }
+
+ } catch (FileNotFoundException e) {
+ continue;
+ }
+ }
+
+ return nameSet;
}
private void callUpdableDeviceConfigShellCommandHandler(FileDescriptor in, FileDescriptor out,
@@ -120,31 +183,51 @@
mProvider = provider;
}
- public static List<String> listAll(IContentProvider provider) {
- final ArrayList<String> lines = new ArrayList<>();
-
- try {
- Bundle args = new Bundle();
- args.putInt(Settings.CALL_METHOD_USER_KEY,
- ActivityManager.getService().getCurrentUser().id);
- Bundle b = provider.call(new AttributionSource(Process.myUid(),
- resolveCallingPackage(), null), Settings.AUTHORITY,
- Settings.CALL_METHOD_LIST_CONFIG, null, args);
- if (b != null) {
- Map<String, String> flagsToValues =
- (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
- for (String key : flagsToValues.keySet()) {
- lines.add(key + "=" + flagsToValues.get(key));
- }
- }
-
- Collections.sort(lines);
- } catch (RemoteException e) {
- throw new RuntimeException("Failed in IPC", e);
+ public static HashMap<String, String> getAllFlags(IContentProvider provider) {
+ HashMap<String, String> allFlags = new HashMap<String, String>();
+ try {
+ Bundle args = new Bundle();
+ args.putInt(Settings.CALL_METHOD_USER_KEY,
+ ActivityManager.getService().getCurrentUser().id);
+ Bundle b = provider.call(new AttributionSource(Process.myUid(),
+ resolveCallingPackage(), null), Settings.AUTHORITY,
+ Settings.CALL_METHOD_LIST_CONFIG, null, args);
+ if (b != null) {
+ Map<String, String> flagsToValues =
+ (HashMap) b.getSerializable(Settings.NameValueTable.VALUE);
+ allFlags.putAll(flagsToValues);
}
- return lines;
+ } catch (RemoteException e) {
+ throw new RuntimeException("Failed in IPC", e);
}
+ return allFlags;
+ }
+
+ public static List<String> listAll(IContentProvider provider) {
+ HashMap<String, String> allFlags = getAllFlags(provider);
+ final ArrayList<String> lines = new ArrayList<>();
+ for (String key : allFlags.keySet()) {
+ lines.add(key + "=" + allFlags.get(key));
+ }
+ Collections.sort(lines);
+ return lines;
+ }
+
+ public static List<String> listAllAconfigFlags(IContentProvider provider) {
+ HashMap<String, String> allFlags = getAllFlags(provider);
+ HashSet<String> aconfigFlagNames = getAconfigFlagNamesInDeviceConfig();
+ final ArrayList<String> lines = new ArrayList<>();
+ for (String key : aconfigFlagNames) {
+ String val = allFlags.get(key);
+ if (val != null) {
+ lines.add(key + "=" + val);
+ }
+ }
+ Collections.sort(lines);
+ return lines;
+ }
+
@SuppressLint("AndroidFrameworkRequiresPermission")
@Override
public int onCommand(String cmd) {
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 215cc8e..323f65f 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -849,11 +849,15 @@
<!-- Permission required for accessing all content provider mime types -->
<uses-permission android:name="android.permission.GET_ANY_PROVIDER_TYPE" />
+ <!-- Permission required for CTS test - CtsWallpaperTestCases -->
+ <uses-permission android:name="android.permission.ALWAYS_UPDATE_WALLPAPER" />
+
<application
android:label="@string/app_label"
android:theme="@android:style/Theme.DeviceDefault.DayNight"
android:defaultToDeviceProtectedStorage="true"
android:directBootAware="true">
+
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.android.shell"
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index b49c5fb..1845ae8 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -16,6 +16,7 @@
package com.android.server.wm;
+import static android.Manifest.permission.ALWAYS_UPDATE_WALLPAPER;
import static android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
import static android.Manifest.permission.HIDE_OVERLAY_WINDOWS;
import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
@@ -112,6 +113,7 @@
final boolean mCanCreateSystemApplicationOverlay;
final boolean mCanHideNonSystemOverlayWindows;
final boolean mCanSetUnrestrictedGestureExclusion;
+ final boolean mCanAlwaysUpdateWallpaper;
private AlertWindowNotification mAlertWindowNotification;
private boolean mShowingAlertWindowNotificationAllowed;
private boolean mClientDead = false;
@@ -144,6 +146,9 @@
mCanSetUnrestrictedGestureExclusion =
service.mContext.checkCallingOrSelfPermission(SET_UNRESTRICTED_GESTURE_EXCLUSION)
== PERMISSION_GRANTED;
+ mCanAlwaysUpdateWallpaper =
+ service.mContext.checkCallingOrSelfPermission(ALWAYS_UPDATE_WALLPAPER)
+ == PERMISSION_GRANTED;
mShowingAlertWindowNotificationAllowed = mService.mShowAlertWindowNotifications;
mDragDropController = mService.mDragDropController;
StringBuilder sb = new StringBuilder();
@@ -621,8 +626,15 @@
final long ident = Binder.clearCallingIdentity();
try {
final WindowState windowState = mService.windowForClientLocked(this, window, true);
- return windowState.getDisplayContent().mWallpaperController
- .sendWindowWallpaperCommand(windowState, action, x, y, z, extras, sync);
+ WallpaperController wallpaperController =
+ windowState.getDisplayContent().mWallpaperController;
+ if (mCanAlwaysUpdateWallpaper
+ || windowState == wallpaperController.getWallpaperTarget()
+ || windowState == wallpaperController.getPrevWallpaperTarget()) {
+ return wallpaperController.sendWindowWallpaperCommandUnchecked(
+ windowState, action, x, y, z, extras, sync);
+ }
+ return null;
} finally {
Binder.restoreCallingIdentity(ident);
}
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index af770e2..7e5dabb 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -298,6 +298,10 @@
return mWallpaperTarget;
}
+ WindowState getPrevWallpaperTarget() {
+ return mPrevWallpaperTarget;
+ }
+
boolean isWallpaperTarget(WindowState win) {
return win == mWallpaperTarget;
}
@@ -565,12 +569,10 @@
}
}
- Bundle sendWindowWallpaperCommand(
- WindowState window, String action, int x, int y, int z, Bundle extras, boolean sync) {
- if (window == mWallpaperTarget || window == mPrevWallpaperTarget) {
- sendWindowWallpaperCommand(action, x, y, z, extras, sync);
- }
-
+ Bundle sendWindowWallpaperCommandUnchecked(
+ WindowState window, String action, int x, int y, int z,
+ Bundle extras, boolean sync) {
+ sendWindowWallpaperCommand(action, x, y, z, extras, sync);
return null;
}
diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp
index ce3d514..2a2fa7a 100644
--- a/services/incremental/ServiceWrappers.cpp
+++ b/services/incremental/ServiceWrappers.cpp
@@ -315,11 +315,22 @@
std::unique_lock lock(mMutex);
for (;;) {
const TimePoint nextJobTs = mJobs.empty() ? kInfinityTs : mJobs.begin()->when;
- mCondition.wait_until(lock, nextJobTs, [this, oldNextJobTs = nextJobTs]() {
+ auto conditionPredicate = [this, oldNextJobTs = nextJobTs]() {
const auto now = Clock::now();
const auto newFirstJobTs = !mJobs.empty() ? mJobs.begin()->when : kInfinityTs;
return newFirstJobTs <= now || newFirstJobTs < oldNextJobTs || !mRunning;
- });
+ };
+ // libcxx's implementation of wait_until() recalculates the 'until' time into
+ // the wait duration and then goes back to the absolute timestamp when calling
+ // pthread_cond_timedwait(); this back-and-forth calculation sometimes loses
+ // the 'infinity' value because enough time passes in between, and instead
+ // passes incorrect timestamp into the syscall, causing a crash.
+ // Mitigating it by explicitly calling the non-timed wait here.
+ if (mJobs.empty()) {
+ mCondition.wait(lock, conditionPredicate);
+ } else {
+ mCondition.wait_until(lock, nextJobTs, conditionPredicate);
+ }
if (!mRunning) {
return;
}
diff --git a/services/tests/powerservicetests/Android.bp b/services/tests/powerservicetests/Android.bp
index 9384015..7351fc5f 100644
--- a/services/tests/powerservicetests/Android.bp
+++ b/services/tests/powerservicetests/Android.bp
@@ -17,6 +17,7 @@
"services.core",
"servicestests-utils",
"testables",
+ "TestParameterInjector",
],
libs: [
diff --git a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
index 9bce536..0b1e338 100644
--- a/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/powerservicetests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -111,6 +111,9 @@
import com.android.server.power.batterysaver.BatterySavingStats;
import com.android.server.testutils.OffsettableClock;
+import com.google.testing.junit.testparameterinjector.TestParameter;
+import com.google.testing.junit.testparameterinjector.TestParameterInjector;
+
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
@@ -119,6 +122,7 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestRule;
+import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.ArgumentMatcher;
import org.mockito.Mock;
@@ -140,6 +144,7 @@
* atest FrameworksServicesTests:PowerManagerServiceTest
*/
@SuppressWarnings("GuardedBy")
+@RunWith(TestParameterInjector.class)
public class PowerManagerServiceTest {
private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";
@@ -2768,12 +2773,13 @@
}
@Test
- public void testFeatureEnabledProcStateUncachedToCached_fullWakeLockDisabled() {
+ public void testFeatureEnabledProcStateUncachedToCached_screenWakeLockDisabled(
+ @TestParameter PowerManagerServiceTest.ScreenWakeLockTestParameter param) {
doReturn(true).when(mDeviceParameterProvider)
.isDisableScreenWakeLocksWhileCachedFeatureEnabled();
createService();
startSystem();
- WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ WakeLock wakeLock = acquireWakeLock(param.mDescr, param.mFlags);
setUncachedUidProcState(wakeLock.mOwnerUid);
setCachedUidProcState(wakeLock.mOwnerUid);
@@ -2781,12 +2787,13 @@
}
@Test
- public void testFeatureDisabledProcStateUncachedToCached_fullWakeLockEnabled() {
+ public void testFeatureDisabledProcStateUncachedToCached_screenWakeLockEnabled(
+ @TestParameter PowerManagerServiceTest.ScreenWakeLockTestParameter param) {
doReturn(false).when(mDeviceParameterProvider)
.isDisableScreenWakeLocksWhileCachedFeatureEnabled();
createService();
startSystem();
- WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ WakeLock wakeLock = acquireWakeLock(param.mDescr, param.mFlags);
setUncachedUidProcState(wakeLock.mOwnerUid);
setCachedUidProcState(wakeLock.mOwnerUid);
@@ -2794,68 +2801,27 @@
}
@Test
- public void testFeatureEnabledProcStateUncachedToCached_screenBrightWakeLockDisabled() {
+ public void testFeatureEnabledProcStateCachedToUncached_screenWakeLockEnabled(
+ @TestParameter PowerManagerServiceTest.ScreenWakeLockTestParameter param) {
doReturn(true).when(mDeviceParameterProvider)
.isDisableScreenWakeLocksWhileCachedFeatureEnabled();
createService();
startSystem();
- WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
- setUncachedUidProcState(wakeLock.mOwnerUid);
-
+ WakeLock wakeLock = acquireWakeLock(param.mDescr, param.mFlags);
setCachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isTrue();
+
+ setUncachedUidProcState(wakeLock.mOwnerUid);
+ assertThat(wakeLock.mDisabled).isFalse();
}
@Test
- public void testFeatureDisabledProcStateUncachedToCached_screenBrightWakeLockEnabled() {
+ public void testFeatureDisabledProcStateCachedToUncached_screenWakeLockEnabled(
+ @TestParameter PowerManagerServiceTest.ScreenWakeLockTestParameter param) {
doReturn(false).when(mDeviceParameterProvider)
.isDisableScreenWakeLocksWhileCachedFeatureEnabled();
createService();
startSystem();
- WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
- setUncachedUidProcState(wakeLock.mOwnerUid);
-
- setCachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureEnabledProcStateUncachedToCached_screenDimWakeLockDisabled() {
- doReturn(true).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
- PowerManager.SCREEN_DIM_WAKE_LOCK);
- setUncachedUidProcState(wakeLock.mOwnerUid);
-
- setCachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isTrue();
- }
-
- @Test
- public void testFeatureDisabledProcStateUncachedToCached_screenDimWakeLockEnabled() {
- doReturn(false).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
- PowerManager.SCREEN_DIM_WAKE_LOCK);
- setUncachedUidProcState(wakeLock.mOwnerUid);
-
- setCachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureEnabledProcStateCachedToUncached_fullWakeLockEnabled() {
- doReturn(true).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
+ WakeLock wakeLock = acquireWakeLock(param.mDescr, param.mFlags);
setCachedUidProcState(wakeLock.mOwnerUid);
setUncachedUidProcState(wakeLock.mOwnerUid);
@@ -2863,76 +2829,7 @@
}
@Test
- public void testFeatureDisabledProcStateCachedToUncached_fullWakeLockEnabled() {
- doReturn(false).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("fullWakeLock", PowerManager.FULL_WAKE_LOCK);
- setCachedUidProcState(wakeLock.mOwnerUid);
-
- setUncachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureEnabledProcStateCachedToUncached_screenBrightWakeLockEnabled() {
- doReturn(true).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
- setCachedUidProcState(wakeLock.mOwnerUid);
-
- setUncachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureDisabledProcStateCachedToUncached_screenBrightWakeLockEnabled() {
- doReturn(false).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("screenBrightWakeLock",
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK);
- setCachedUidProcState(wakeLock.mOwnerUid);
-
- setUncachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureEnabledProcStateCachedToUncached_screenDimWakeLockEnabled() {
- doReturn(true).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
- PowerManager.SCREEN_DIM_WAKE_LOCK);
- setCachedUidProcState(wakeLock.mOwnerUid);
-
- setUncachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureDisabledProcStateCachedToUncached_screenDimWakeLockEnabled() {
- doReturn(false).when(mDeviceParameterProvider)
- .isDisableScreenWakeLocksWhileCachedFeatureEnabled();
- createService();
- startSystem();
- WakeLock wakeLock = acquireWakeLock("screenDimWakeLock",
- PowerManager.SCREEN_DIM_WAKE_LOCK);
- setCachedUidProcState(wakeLock.mOwnerUid);
-
- setUncachedUidProcState(wakeLock.mOwnerUid);
- assertThat(wakeLock.mDisabled).isFalse();
- }
-
- @Test
- public void testFeatureDynamicallyDisabledProcStateUncachedToCached_fullWakeLockEnabled() {
+ public void testFeatureDynamicallyDisabledProcStateUncachedToCached_screenWakeLockEnabled() {
doReturn(true).when(mDeviceParameterProvider)
.isDisableScreenWakeLocksWhileCachedFeatureEnabled();
ArgumentCaptor<DeviceConfig.OnPropertiesChangedListener> listenerCaptor =
@@ -2960,4 +2857,18 @@
private void setUncachedUidProcState(int uid) {
mService.updateUidProcStateInternal(uid, PROCESS_STATE_RECEIVER);
}
+
+ private enum ScreenWakeLockTestParameter {
+ FULL_WAKE_LOCK("fullWakeLock", PowerManager.FULL_WAKE_LOCK),
+ SCREEN_BRIGHT_WAKE_LOCK("screenBrightWakeLock", PowerManager.SCREEN_BRIGHT_WAKE_LOCK),
+ SCREEN_DIM_WAKE_LOCK("screenDimWakeLock", PowerManager.SCREEN_DIM_WAKE_LOCK);
+
+ final String mDescr;
+ final int mFlags;
+
+ ScreenWakeLockTestParameter(String descr, int flags) {
+ this.mDescr = descr;
+ this.mFlags = flags;
+ }
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
index 4f45d5c2..9a93746 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceControlTests.java
@@ -39,6 +39,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.server.wm.utils.CommonUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -131,18 +133,29 @@
final Activity activity = instrumentation.startActivitySync(intent);
final SurfaceView sv = new SurfaceView(activity);
final AtomicInteger surfaceChangedCount = new AtomicInteger();
+ final boolean[] unexpectedTransformHint = new boolean[1];
instrumentation.runOnMainSync(() -> activity.setContentView(sv));
sv.getHolder().addCallback(new SurfaceHolder.Callback() {
+ int mInitialTransformHint = -1;
+
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder) {
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width,
int height) {
+ final int transformHint =
+ sv.getViewRootImpl().getSurfaceControl().getTransformHint();
+ if (mInitialTransformHint == -1) {
+ mInitialTransformHint = transformHint;
+ } else if (mInitialTransformHint == transformHint) {
+ // For example, the initial hint is from portrait, so the later changes from
+ // landscape should not receive the same hint.
+ unexpectedTransformHint[0] = true;
+ }
surfaceChangedCount.getAndIncrement();
Log.i("surfaceChanged", "width=" + width + " height=" + height
- + " getTransformHint="
- + sv.getViewRootImpl().getSurfaceControl().getTransformHint());
+ + " transformHint=" + transformHint);
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
@@ -160,7 +173,7 @@
.windowConfiguration.getRotation();
if (rotation == newRotation) {
// The device might not support requested orientation.
- activity.finishAndRemoveTask();
+ CommonUtils.waitUntilActivityRemoved(activity);
return;
}
final int count = surfaceChangedCount.get();
@@ -169,11 +182,12 @@
context.startActivity(intent);
instrumentation.getUiAutomation().syncInputTransactions();
final int countAfterToFront = count - surfaceChangedCount.get();
- activity.finishAndRemoveTask();
+ CommonUtils.waitUntilActivityRemoved(activity);
// The first count is triggered from creation, so the target number is 2.
- if (count > 2) {
- fail("More than once surfaceChanged for rotation change: " + count);
+ if (count > 2 && unexpectedTransformHint[0]) {
+ fail("Received transform hint in previous orientation with more than once"
+ + " surfaceChanged for rotation change: " + count);
}
if (countAfterToFront > 1) {
fail("More than once surfaceChanged for app transition with rotation change: "
diff --git a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
index df11a44..f173d66 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TrustedPresentationCallbackTest.java
@@ -30,6 +30,9 @@
import androidx.test.ext.junit.rules.ActivityScenarioRule;
+import com.android.server.wm.utils.CommonUtils;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -61,6 +64,11 @@
mActivityRule.getScenario().onActivity(activity -> mActivity = activity);
}
+ @After
+ public void tearDown() {
+ CommonUtils.waitUntilActivityRemoved(mActivity);
+ }
+
@Test
public void testAddTrustedPresentationListenerOnWindow() throws InterruptedException {
boolean[] results = new boolean[1];