summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java34
-rw-r--r--core/java/android/app/TaskInfo.java16
-rw-r--r--core/java/android/app/backup/BackupManagerMonitor.java51
-rw-r--r--core/res/res/layout/autofill_fill_dialog.xml2
-rw-r--r--core/res/res/layout/autofill_save.xml84
-rw-r--r--core/res/res/values-sw640dp/dimens.xml20
-rw-r--r--core/res/res/values-w640dp/bools.xml21
-rw-r--r--core/res/res/values-w640dp/dimens.xml20
-rw-r--r--core/res/res/values/bools.xml2
-rw-r--r--core/res/res/values/dimens.xml5
-rw-r--r--core/res/res/values/symbols.xml5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java60
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java24
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java163
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java3
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/flags/Flags.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt165
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java47
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java12
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt22
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/BottomSheetLayout.java108
-rw-r--r--services/autofill/java/com/android/server/autofill/ui/SaveUi.java8
-rw-r--r--services/backup/java/com/android/server/backup/UserBackupManagerService.java26
-rw-r--r--services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java117
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java255
-rw-r--r--services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java17
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java11
-rw-r--r--services/core/java/com/android/server/am/BroadcastQueueModernImpl.java11
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerShellCommand.java4
-rw-r--r--services/core/java/com/android/server/wm/Task.java1
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java243
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java27
-rw-r--r--wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java1
35 files changed, 1451 insertions, 183 deletions
diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
index b6dc32a29f04..088372702ebc 100644
--- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
+++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java
@@ -1246,6 +1246,40 @@ public class Bmgr {
return "TRANSPORT_IS_NULL";
case BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS:
return "AGENT_LOGGING_RESULTS";
+ case BackupManagerMonitor.LOG_EVENT_ID_START_SYSTEM_RESTORE:
+ return "START_SYSTEM_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_START_RESTORE_AT_INSTALL:
+ return "START_RESTORE_AT_INSTALL";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_DURING_START_RESTORE:
+ return "TRANSPORT_ERROR_DURING_START_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_CANNOT_GET_NEXT_PKG_NAME:
+ return "CANNOT_GET_NEXT_PKG_NAME";
+ case BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_RESTORE_TYPE:
+ return "UNKNOWN_RESTORE_TYPE";
+ case BackupManagerMonitor.LOG_EVENT_ID_KV_RESTORE:
+ return "KV_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE:
+ return "FULL_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_NEXT_RESTORE_TARGET:
+ return "NO_NEXT_RESTORE_TARGET";
+ case BackupManagerMonitor.LOG_EVENT_ID_KV_AGENT_ERROR:
+ return "KV_AGENT_ERROR";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_RESTORE_FINISHED:
+ return "PACKAGE_RESTORE_FINISHED";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_KV_RESTORE:
+ return "TRANSPORT_ERROR_KV_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_FEEDER_THREAD:
+ return "NO_FEEDER_THREAD";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_AGENT_ERROR:
+ return "FULL_AGENT_ERROR";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE:
+ return "TRANSPORT_ERROR_FULL_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_COMPLETE:
+ return "RESTORE_COMPLETE";
+ case BackupManagerMonitor.LOG_EVENT_ID_START_PACKAGE_RESTORE:
+ return "START_PACKAGE_RESTORE";
+ case BackupManagerMonitor.LOG_EVENT_ID_AGENT_FAILURE:
+ return "AGENT_FAILURE";
default:
return "UNKNOWN_ID";
}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index 634089b73618..5f8b76508ef3 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -255,6 +255,12 @@ public class TaskInfo {
public boolean isUserFullscreenOverrideEnabled;
/**
+ * Whether the top activity fillsParent() is false
+ * @hide
+ */
+ public boolean isTopActivityTransparent;
+
+ /**
* Hint about the letterbox state of the top activity.
* @hide
*/
@@ -551,7 +557,8 @@ public class TaskInfo {
&& Objects.equals(mTopActivityLocusId, that.mTopActivityLocusId)
&& parentTaskId == that.parentTaskId
&& Objects.equals(topActivity, that.topActivity)
- && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled;
+ && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled
+ && isTopActivityTransparent == that.isTopActivityTransparent;
}
/**
@@ -583,7 +590,9 @@ public class TaskInfo {
== that.configuration.getLayoutDirection())
&& (!hasCompatUI() || configuration.uiMode == that.configuration.uiMode)
&& (!hasCompatUI() || isVisible == that.isVisible)
- && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled;
+ && isFocused == that.isFocused
+ && isUserFullscreenOverrideEnabled == that.isUserFullscreenOverrideEnabled
+ && isTopActivityTransparent == that.isTopActivityTransparent;
}
/**
@@ -640,6 +649,7 @@ public class TaskInfo {
topActivityLetterboxWidth = source.readInt();
topActivityLetterboxHeight = source.readInt();
isUserFullscreenOverrideEnabled = source.readBoolean();
+ isTopActivityTransparent = source.readBoolean();
}
/**
@@ -697,6 +707,7 @@ public class TaskInfo {
dest.writeInt(topActivityLetterboxWidth);
dest.writeInt(topActivityLetterboxHeight);
dest.writeBoolean(isUserFullscreenOverrideEnabled);
+ dest.writeBoolean(isTopActivityTransparent);
}
@Override
@@ -744,6 +755,7 @@ public class TaskInfo {
+ " topActivityLetterboxWidth=" + topActivityLetterboxWidth
+ " topActivityLetterboxHeight=" + topActivityLetterboxHeight
+ " isUserFullscreenOverrideEnabled=" + isUserFullscreenOverrideEnabled
+ + " isTopActivityTransparent=" + isTopActivityTransparent
+ " locusId=" + mTopActivityLocusId
+ " displayAreaFeatureId=" + displayAreaFeatureId
+ " cameraCompatControlState="
diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java
index f73366b6af0c..812bf8e6be6a 100644
--- a/core/java/android/app/backup/BackupManagerMonitor.java
+++ b/core/java/android/app/backup/BackupManagerMonitor.java
@@ -18,6 +18,7 @@ package android.app.backup;
import android.annotation.SystemApi;
import android.app.backup.BackupAnnotations.OperationType;
+import android.content.pm.PackageInfo;
import android.os.Bundle;
/**
@@ -190,6 +191,56 @@ public class BackupManagerMonitor {
public static final int LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED = 51;
public static final int LOG_EVENT_ID_AGENT_LOGGING_RESULTS = 52;
+ /** @hide */
+ public static final int LOG_EVENT_ID_START_SYSTEM_RESTORE = 53;
+ /** @hide */
+ public static final int LOG_EVENT_ID_START_RESTORE_AT_INSTALL = 54;
+ /** A transport error happened during {@link PerformUnifiedRestoreTask#startRestore()}
+ @hide */
+ public static final int LOG_EVENT_ID_TRANSPORT_ERROR_DURING_START_RESTORE = 55;
+ /** Unable to get the name of the next package in the queue during a restore operation
+ @hide */
+ public static final int LOG_EVENT_ID_CANNOT_GET_NEXT_PKG_NAME = 56;
+ /** Attempting a restore operation that is neither KV nor full
+ @hide */
+ public static final int LOG_EVENT_ID_UNKNOWN_RESTORE_TYPE = 57;
+ /** The package is part of KeyValue restore
+ @hide */
+ public static final int LOG_EVENT_ID_KV_RESTORE = 58;
+ /** The package is part of Full restore
+ @hide */
+ public static final int LOG_EVENT_ID_FULL_RESTORE = 59;
+ /** Unable to fetch the nest restore target in the queue
+ @hide */
+ public static final int LOG_EVENT_ID_NO_NEXT_RESTORE_TARGET = 60;
+ /** An error occurred while attempting KeyValueRestore
+ @hide */
+ public static final int LOG_EVENT_ID_KV_AGENT_ERROR = 61;
+ /** Restore operation finished for the given package
+ @hide */
+ public static final int LOG_EVENT_ID_PACKAGE_RESTORE_FINISHED= 62;
+ /** A transport error happened during
+ * {@link PerformUnifiedRestoreTask#initiateOneRestore(PackageInfo, long)}
+ @hide */
+ public static final int LOG_EVENT_ID_TRANSPORT_ERROR_KV_RESTORE = 63;
+ /** Unable to instantiate the feeder thread in full restore
+ @hide */
+ public static final int LOG_EVENT_ID_NO_FEEDER_THREAD = 64;
+ /** An error occurred while attempting Full restore
+ @hide */
+ public static final int LOG_EVENT_ID_FULL_AGENT_ERROR = 65;
+ /** A transport error happened during a full restore
+ @hide */
+ public static final int LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE = 66;
+ /** Start restore operation for a given package
+ @hide */
+ public static final int LOG_EVENT_ID_START_PACKAGE_RESTORE = 67;
+ /** Whole restore operation is complete
+ @hide */
+ public static final int LOG_EVENT_ID_RESTORE_COMPLETE = 68;
+ /** Agent error during {@link PerformUnifiedRestoreTask#restoreFinished()}
+ @hide */
+ public static final int LOG_EVENT_ID_AGENT_FAILURE = 69;
/**
* This method will be called each time something important happens on BackupManager.
diff --git a/core/res/res/layout/autofill_fill_dialog.xml b/core/res/res/layout/autofill_fill_dialog.xml
index 37d2fa0540f0..196af6dfb6df 100644
--- a/core/res/res/layout/autofill_fill_dialog.xml
+++ b/core/res/res/layout/autofill_fill_dialog.xml
@@ -27,7 +27,7 @@
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
- android:layout_marginTop="@dimen/autofill_save_outer_top_margin"
+ android:layout_marginTop="@dimen/autofill_save_outer_margin"
android:layout_marginBottom="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
diff --git a/core/res/res/layout/autofill_save.xml b/core/res/res/layout/autofill_save.xml
index bed19a87eb16..8b6c90141bb7 100644
--- a/core/res/res/layout/autofill_save.xml
+++ b/core/res/res/layout/autofill_save.xml
@@ -22,59 +22,66 @@
android:background="@drawable/autofill_bottomsheet_background"
android:orientation="vertical">
- <LinearLayout
+ <com.android.server.autofill.ui.BottomSheetLayout
android:id="@+id/autofill_save"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/autofill_save_outer_top_margin"
- android:layout_marginStart="24dp"
- android:layout_marginEnd="24dp"
+ android:layout_marginTop="@dimen/autofill_save_outer_margin"
android:background="?android:attr/colorSurface"
android:gravity="center_horizontal"
android:orientation="vertical">
-
- <LinearLayout
+ <ScrollView
android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <ImageView
- android:id="@+id/autofill_save_icon"
- android:scaleType="fitCenter"
- android:layout_gravity="center"
- android:layout_height="@dimen/autofill_save_icon_max_height"
- android:layout_width="fill_parent"/>
-
- <TextView
- android:id="@+id/autofill_save_title"
+ android:layout_height="0dp"
+ android:fillViewport="true"
+ android:layout_weight="1"
+ android:layout_marginBottom="8dp">
+ <LinearLayout
+ android:layout_marginStart="@dimen/autofill_save_outer_margin"
+ android:layout_marginEnd="@dimen/autofill_save_outer_margin"
android:layout_width="fill_parent"
+ android:orientation="vertical"
android:layout_height="wrap_content"
- android:text="@string/autofill_save_title"
- android:layout_marginTop="16dp"
- android:paddingBottom="24dp"
- android:gravity="center"
- android:textAppearance="@style/AutofillSaveUiTitle">
- </TextView>
-
- <com.android.server.autofill.ui.CustomScrollView
- android:id="@+id/autofill_save_custom_subtitle"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:visibility="gone"/>
-
- </LinearLayout>
+ >
+ <ImageView
+ android:id="@+id/autofill_save_icon"
+ android:scaleType="fitCenter"
+ android:layout_gravity="center"
+ android:layout_height="@dimen/autofill_save_icon_max_height"
+ android:layout_width="fill_parent"/>
+
+ <TextView
+ android:id="@+id/autofill_save_title"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/autofill_save_title"
+ android:layout_marginTop="16dp"
+ android:paddingBottom="24dp"
+ android:gravity="center"
+ android:textAppearance="@style/AutofillSaveUiTitle">
+ </TextView>
+ <LinearLayout
+ android:id="@+id/autofill_save_custom_subtitle"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:visibility="gone"/>
+
+ </LinearLayout>
+ </ScrollView>
<com.android.internal.widget.ButtonBarLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="end"
android:clipToPadding="false"
- android:layout_marginTop="32dp"
- android:layout_marginBottom="18dp"
+ android:layout_marginTop="16dp"
+ android:layout_marginBottom="8dp"
android:theme="@style/Theme.DeviceDefault.AutofillHalfScreenDialogButton"
android:orientation="horizontal"
- android:gravity="center_vertical">
-
+ android:gravity="center_vertical"
+ android:layout_marginStart="@dimen/autofill_save_outer_margin"
+ android:layout_marginEnd="@dimen/autofill_save_outer_margin"
+ >
<Button
android:id="@+id/autofill_save_no"
android:layout_width="wrap_content"
@@ -106,6 +113,5 @@
</com.android.internal.widget.ButtonBarLayout>
- </LinearLayout>
-
-</LinearLayout>
+ </com.android.server.autofill.ui.BottomSheetLayout>
+</LinearLayout> \ No newline at end of file
diff --git a/core/res/res/values-sw640dp/dimens.xml b/core/res/res/values-sw640dp/dimens.xml
new file mode 100644
index 000000000000..c632176ba1dd
--- /dev/null
+++ b/core/res/res/values-sw640dp/dimens.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+<resources>
+ <!-- Top and side margins for autofill dialog on tablets -->
+ <dimen name="autofill_save_outer_margin">32dp</dimen>
+</resources> \ No newline at end of file
diff --git a/core/res/res/values-w640dp/bools.xml b/core/res/res/values-w640dp/bools.xml
new file mode 100644
index 000000000000..64b20f7eaa96
--- /dev/null
+++ b/core/res/res/values-w640dp/bools.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+
+<resources>
+ <!-- Whether or not to include horizontal space around the dialog -->
+ <bool name="autofill_dialog_horizontal_space_included">true</bool>
+</resources> \ No newline at end of file
diff --git a/core/res/res/values-w640dp/dimens.xml b/core/res/res/values-w640dp/dimens.xml
new file mode 100644
index 000000000000..1f0c0b878610
--- /dev/null
+++ b/core/res/res/values-w640dp/dimens.xml
@@ -0,0 +1,20 @@
+<?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.
+ -->
+<resources>
+ <!-- How much extra space should be left around the autofill dialog -->
+ <dimen name="autofill_dialog_offset">56dp</dimen>
+</resources> \ No newline at end of file
diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml
index fe296c704095..b097a613ebc1 100644
--- a/core/res/res/values/bools.xml
+++ b/core/res/res/values/bools.xml
@@ -30,4 +30,6 @@
lockscreen, setting this to true should come with customized drawables. -->
<bool name="use_lock_pattern_drawable">false</bool>
<bool name="resolver_landscape_phone">true</bool>
+ <!-- Whether or not to include horizontal space around the dialog -->
+ <bool name="autofill_dialog_horizontal_space_included">false</bool>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index b129321008d8..190b7a62e2e0 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -871,7 +871,7 @@
<dimen name="autofill_dataset_picker_max_height">90%</dimen>
<!-- Autofill save dialog padding -->
- <dimen name="autofill_save_outer_top_margin">24dp</dimen>
+ <dimen name="autofill_save_outer_margin">24dp</dimen>
<dimen name="autofill_save_outer_top_padding">16dp</dimen>
<dimen name="autofill_elevation">32dp</dimen>
<dimen name="autofill_save_inner_padding">16dp</dimen>
@@ -882,6 +882,9 @@
<dimen name="autofill_save_button_bar_padding">16dp</dimen>
<dimen name="autofill_dialog_corner_radius">24dp</dimen>
+ <!-- How much extra space should be left around the autofill dialog -->
+ <dimen name="autofill_dialog_offset">72dp</dimen>
+
<!-- Max height of the the autofill save custom subtitle as a fraction of the screen width/height -->
<dimen name="autofill_save_custom_subtitle_max_height">20%</dimen>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index be43a4fc238d..e661eda96a02 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3629,6 +3629,7 @@
<java-symbol type="layout" name="autofill_dataset_picker_fullscreen"/>
<java-symbol type="layout" name="autofill_dataset_picker_header_footer"/>
<java-symbol type="layout" name="autofill_fill_dialog"/>
+ <java-symbol type="id" name="autofill_save_icon"/>
<java-symbol type="id" name="autofill" />
<java-symbol type="id" name="autofill_dataset_footer"/>
<java-symbol type="id" name="autofill_dataset_header"/>
@@ -3685,6 +3686,10 @@
<java-symbol type="dimen" name="autofill_save_custom_subtitle_max_height"/>
<java-symbol type="integer" name="autofill_max_visible_datasets" />
<java-symbol type="dimen" name="autofill_dialog_max_width" />
+ <java-symbol type="dimen" name="autofill_dialog_offset"/>
+ <java-symbol type="dimen" name="autofill_save_outer_margin"/>
+
+ <java-symbol type="bool" name="autofill_dialog_horizontal_space_included"/>
<java-symbol type="style" name="Theme.DeviceDefault.Autofill" />
<java-symbol type="style" name="Theme.DeviceDefault.Light.Autofill" />
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
index 0e6b20332a4f..953efa78326c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/CompatUIController.java
@@ -176,6 +176,18 @@ public class CompatUIController implements OnDisplaysChangedListener,
// be shown.
private boolean mKeyguardShowing;
+ /**
+ * The id of the task for the application we're currently attempting to show the user aspect
+ * ratio settings button for, or have most recently shown the button for.
+ */
+ private int mTopActivityTaskId;
+
+ /**
+ * Whether the user aspect ratio settings button has been shown for the current application
+ * associated with the task id stored in {@link CompatUIController#mTopActivityTaskId}.
+ */
+ private boolean mHasShownUserAspectRatioSettingsButton = false;
+
public CompatUIController(@NonNull Context context,
@NonNull ShellInit shellInit,
@NonNull ShellController shellController,
@@ -230,6 +242,11 @@ public class CompatUIController implements OnDisplaysChangedListener,
if (taskInfo != null && !taskInfo.topActivityInSizeCompat) {
mSetOfTaskIdsShowingRestartDialog.remove(taskInfo.taskId);
}
+
+ if (taskInfo != null && taskListener != null) {
+ updateActiveTaskInfo(taskInfo);
+ }
+
if (taskInfo.configuration == null || taskListener == null) {
// Null token means the current foreground activity is not in compatibility mode.
removeLayouts(taskInfo.taskId);
@@ -322,6 +339,46 @@ public class CompatUIController implements OnDisplaysChangedListener,
forAllLayouts(layout -> layout.updateVisibility(showOnDisplay(layout.getDisplayId())));
}
+ /**
+ * Invoked when a new task is created or the info of an existing task has changed. Updates the
+ * shown status of the user aspect ratio settings button and the task id it relates to.
+ */
+ void updateActiveTaskInfo(@NonNull TaskInfo taskInfo) {
+ // If the activity belongs to the task we are currently tracking, don't update any variables
+ // as they are still relevant. Else, if the activity is visible and focused (the one the
+ // user can see and is using), the user aspect ratio button can potentially be displayed so
+ // start tracking the buttons visibility for this task.
+ if (mTopActivityTaskId != taskInfo.taskId && !taskInfo.isTopActivityTransparent
+ && taskInfo.isVisible && taskInfo.isFocused) {
+ mTopActivityTaskId = taskInfo.taskId;
+ setHasShownUserAspectRatioSettingsButton(false);
+ }
+ }
+
+ /**
+ * Informs the system that the user aspect ratio button has been displayed for the application
+ * associated with the task id in {@link CompatUIController#mTopActivityTaskId}.
+ */
+ void setHasShownUserAspectRatioSettingsButton(boolean state) {
+ mHasShownUserAspectRatioSettingsButton = state;
+ }
+
+ /**
+ * Returns whether the user aspect ratio settings button has been show for the application
+ * associated with the task id in {@link CompatUIController#mTopActivityTaskId}.
+ */
+ boolean hasShownUserAspectRatioSettingsButton() {
+ return mHasShownUserAspectRatioSettingsButton;
+ }
+
+ /**
+ * Returns the task id of the application we are currently attempting to show, of have most
+ * recently shown, the user aspect ratio settings button for.
+ */
+ int getTopActivityTaskId() {
+ return mTopActivityTaskId;
+ }
+
private boolean showOnDisplay(int displayId) {
return !mKeyguardShowing && !isImeShowingOnDisplay(displayId);
}
@@ -572,7 +629,8 @@ public class CompatUIController implements OnDisplaysChangedListener,
return new UserAspectRatioSettingsWindowManager(context, taskInfo, mSyncQueue,
taskListener, mDisplayController.getDisplayLayout(taskInfo.displayId),
mCompatUIHintsState, this::launchUserAspectRatioSettings, mMainExecutor,
- mDisappearTimeSupplier);
+ mDisappearTimeSupplier, this::hasShownUserAspectRatioSettingsButton,
+ this::setHasShownUserAspectRatioSettingsButton);
}
private void launchUserAspectRatioSettings(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
index 77aefc8f7e4a..c2dec623416b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManager.java
@@ -37,7 +37,9 @@ import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.compatui.CompatUIController.CompatUIHintsState;
import java.util.function.BiConsumer;
+import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Supplier;
/**
* Window manager for the user aspect ratio settings button which allows users to go to
@@ -55,6 +57,12 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
private final ShellExecutor mShellExecutor;
+ @NonNull
+ private final Supplier<Boolean> mUserAspectRatioButtonShownChecker;
+
+ @NonNull
+ private final Consumer<Boolean> mUserAspectRatioButtonStateConsumer;
+
@VisibleForTesting
@NonNull
final CompatUIHintsState mCompatUIHintsState;
@@ -72,9 +80,13 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
@NonNull DisplayLayout displayLayout, @NonNull CompatUIHintsState compatUIHintsState,
@NonNull BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener> onButtonClicked,
@NonNull ShellExecutor shellExecutor,
- @NonNull Function<Integer, Integer> disappearTimeSupplier) {
+ @NonNull Function<Integer, Integer> disappearTimeSupplier,
+ @NonNull Supplier<Boolean> userAspectRatioButtonStateChecker,
+ @NonNull Consumer<Boolean> userAspectRatioButtonShownConsumer) {
super(context, taskInfo, syncQueue, taskListener, displayLayout);
mShellExecutor = shellExecutor;
+ mUserAspectRatioButtonShownChecker = userAspectRatioButtonStateChecker;
+ mUserAspectRatioButtonStateConsumer = userAspectRatioButtonShownConsumer;
mHasUserAspectRatioSettingsButton = getHasUserAspectRatioSettingsButton(taskInfo);
mCompatUIHintsState = compatUIHintsState;
mOnButtonClicked = onButtonClicked;
@@ -180,11 +192,18 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
}
}
+ @VisibleForTesting
+ boolean isShowingButton() {
+ return (mUserAspectRatioButtonShownChecker.get()
+ && !isHideDelayReached(mNextButtonHideTimeMs));
+ }
+
private void showUserAspectRatioButton() {
if (mLayout == null) {
return;
}
mLayout.setUserAspectRatioButtonVisibility(true);
+ mUserAspectRatioButtonStateConsumer.accept(true);
// Only show by default for the first time.
if (!mCompatUIHintsState.mHasShownUserAspectRatioSettingsButtonHint) {
mLayout.setUserAspectRatioSettingsHintVisibility(/* show= */ true);
@@ -210,7 +229,8 @@ class UserAspectRatioSettingsWindowManager extends CompatUIWindowManagerAbstract
private boolean getHasUserAspectRatioSettingsButton(@NonNull TaskInfo taskInfo) {
return taskInfo.topActivityEligibleForUserAspectRatioButton
&& (taskInfo.topActivityBoundsLetterboxed
- || taskInfo.isUserFullscreenOverrideEnabled);
+ || taskInfo.isUserFullscreenOverrideEnabled)
+ && (!mUserAspectRatioButtonShownChecker.get() || isShowingButton());
}
private long getDisappearTimeMs() {
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
index 9b9600e4a51e..f85d707d55f9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/CompatUIControllerTest.java
@@ -61,6 +61,7 @@ import com.android.wm.shell.transition.Transitions;
import dagger.Lazy;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -523,13 +524,175 @@ public class CompatUIControllerTest extends ShellTestCase {
.createLayout(anyBoolean());
}
+ @Test
+ public void testUpdateActiveTaskInfo_newTask_visibleAndFocused_updated() {
+ // Simulate user aspect ratio button being shown for previous task
+ mController.setHasShownUserAspectRatioSettingsButton(true);
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Create new task
+ final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true,
+ /* isFocused */ true);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo);
+
+ // Check topActivityTaskId is updated to the taskId of the new task and
+ // hasShownUserAspectRatioSettingsButton has been reset to false
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertFalse(mController.hasShownUserAspectRatioSettingsButton());
+ }
+
+ @Test
+ public void testUpdateActiveTaskInfo_newTask_notVisibleOrFocused_notUpdated() {
+ // Create new task
+ final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true,
+ /* isFocused */ true);
+
+ // Simulate task being shown
+ mController.updateActiveTaskInfo(taskInfo);
+
+ // Check topActivityTaskId is updated to the taskId of the new task and
+ // hasShownUserAspectRatioSettingsButton has been reset to false
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertFalse(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Simulate user aspect ratio button being shown
+ mController.setHasShownUserAspectRatioSettingsButton(true);
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+
+ final int newTaskId = TASK_ID + 1;
+
+ // Create visible but NOT focused task
+ final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true,
+ /* isFocused */ false);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo1);
+
+ // Check topActivityTaskId is NOT updated and hasShownUserAspectRatioSettingsButton
+ // remains true
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Create focused but NOT visible task
+ final TaskInfo taskInfo2 = createTaskInfo(DISPLAY_ID, newTaskId,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ false,
+ /* isFocused */ true);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo2);
+
+ // Check topActivityTaskId is NOT updated and hasShownUserAspectRatioSettingsButton
+ // remains true
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Create NOT focused but NOT visible task
+ final TaskInfo taskInfo3 = createTaskInfo(DISPLAY_ID, newTaskId,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ false,
+ /* isFocused */ false);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo3);
+
+ // Check topActivityTaskId is NOT updated and hasShownUserAspectRatioSettingsButton
+ // remains true
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+ }
+
+ @Test
+ public void testUpdateActiveTaskInfo_sameTask_notUpdated() {
+ // Create new task
+ final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true,
+ /* isFocused */ true);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo);
+
+ // Check topActivityTaskId is updated to the taskId of the new task and
+ // hasShownUserAspectRatioSettingsButton has been reset to false
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertFalse(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Simulate user aspect ratio button being shown
+ mController.setHasShownUserAspectRatioSettingsButton(true);
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Simulate same task being re-shown
+ mController.updateActiveTaskInfo(taskInfo);
+
+ // Check topActivityTaskId is NOT updated and hasShownUserAspectRatioSettingsButton
+ // remains true
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+ }
+
+ @Test
+ public void testUpdateActiveTaskInfo_transparentTask_notUpdated() {
+ // Create new task
+ final TaskInfo taskInfo = createTaskInfo(DISPLAY_ID, TASK_ID,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true,
+ /* isFocused */ true);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo);
+
+ // Check topActivityTaskId is updated to the taskId of the new task and
+ // hasShownUserAspectRatioSettingsButton has been reset to false
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertFalse(mController.hasShownUserAspectRatioSettingsButton());
+
+ // Simulate user aspect ratio button being shown
+ mController.setHasShownUserAspectRatioSettingsButton(true);
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+
+ final int newTaskId = TASK_ID + 1;
+
+ // Create transparent task
+ final TaskInfo taskInfo1 = createTaskInfo(DISPLAY_ID, newTaskId,
+ /* hasSizeCompat= */ true, CAMERA_COMPAT_CONTROL_HIDDEN, /* isVisible */ true,
+ /* isFocused */ true, /* isTopActivityTransparent */ true);
+
+ // Simulate new task being shown
+ mController.updateActiveTaskInfo(taskInfo1);
+
+ // Check topActivityTaskId is NOT updated and hasShownUserAspectRatioSettingsButton
+ // remains true
+ Assert.assertEquals(TASK_ID, mController.getTopActivityTaskId());
+ Assert.assertTrue(mController.hasShownUserAspectRatioSettingsButton());
+ }
+
private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat,
@CameraCompatControlState int cameraCompatControlState) {
+ return createTaskInfo(displayId, taskId, hasSizeCompat, cameraCompatControlState,
+ /* isVisible */ false, /* isFocused */ false,
+ /* isTopActivityTransparent */ false);
+ }
+
+ private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat,
+ @CameraCompatControlState int cameraCompatControlState, boolean isVisible,
+ boolean isFocused) {
+ return createTaskInfo(displayId, taskId, hasSizeCompat, cameraCompatControlState,
+ isVisible, isFocused, /* isTopActivityTransparent */ false);
+ }
+
+ private static TaskInfo createTaskInfo(int displayId, int taskId, boolean hasSizeCompat,
+ @CameraCompatControlState int cameraCompatControlState, boolean isVisible,
+ boolean isFocused, boolean isTopActivityTransparent) {
RunningTaskInfo taskInfo = new RunningTaskInfo();
taskInfo.taskId = taskId;
taskInfo.displayId = displayId;
taskInfo.topActivityInSizeCompat = hasSizeCompat;
taskInfo.cameraCompatControlState = cameraCompatControlState;
+ taskInfo.isVisible = isVisible;
+ taskInfo.isFocused = isFocused;
+ taskInfo.isTopActivityTransparent = isTopActivityTransparent;
return taskInfo;
}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
index ce1290b38830..f460d1b09e34 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsLayoutTest.java
@@ -93,7 +93,8 @@ public class UserAspectRatioSettingsLayoutTest extends ShellTestCase {
mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
mSyncTransactionQueue, mTaskListener, new DisplayLayout(),
new CompatUIController.CompatUIHintsState(),
- mOnUserAspectRatioSettingsButtonClicked, new TestShellExecutor(), flags -> 0);
+ mOnUserAspectRatioSettingsButtonClicked, new TestShellExecutor(), flags -> 0,
+ () -> false, s -> {});
mLayout = (UserAspectRatioSettingsLayout) LayoutInflater.from(mContext).inflate(
R.layout.user_aspect_ratio_settings_layout, null);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
index 08cc2f763135..5a4d6c812c17 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/compatui/UserAspectRatioSettingsWindowManagerTest.java
@@ -36,6 +36,7 @@ import android.content.ComponentName;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
import android.util.Pair;
import android.view.DisplayInfo;
import android.view.InsetsSource;
@@ -66,6 +67,7 @@ import org.mockito.MockitoAnnotations;
import java.util.HashSet;
import java.util.Set;
import java.util.function.BiConsumer;
+import java.util.function.Supplier;
/**
* Tests for {@link UserAspectRatioSettingsWindowManager}.
@@ -74,6 +76,7 @@ import java.util.function.BiConsumer;
* atest WMShellUnitTests:UserAspectRatioSettingsWindowManagerTest
*/
@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
@SmallTest
public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
@@ -81,6 +84,8 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
@Mock private SyncTransactionQueue mSyncTransactionQueue;
@Mock
+ private Supplier<Boolean> mUserAspectRatioButtonShownChecker;
+ @Mock
private BiConsumer<TaskInfo, ShellTaskOrganizer.TaskListener>
mOnUserAspectRatioSettingsButtonClicked;
@Mock private ShellTaskOrganizer.TaskListener mTaskListener;
@@ -106,10 +111,12 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
false, /* topActivityBoundsLetterboxed */ true);
mWindowManager = new UserAspectRatioSettingsWindowManager(mContext, mTaskInfo,
mSyncTransactionQueue, mTaskListener, new DisplayLayout(), new CompatUIHintsState(),
- mOnUserAspectRatioSettingsButtonClicked, mExecutor, flags -> 0);
+ mOnUserAspectRatioSettingsButtonClicked, mExecutor, flags -> 0,
+ mUserAspectRatioButtonShownChecker, s -> {});
spyOn(mWindowManager);
doReturn(mLayout).when(mWindowManager).inflateLayout();
doReturn(mViewHost).when(mWindowManager).createSurfaceViewHost();
+ doReturn(false).when(mUserAspectRatioButtonShownChecker).get();
}
@Test
@@ -293,6 +300,39 @@ public class UserAspectRatioSettingsWindowManagerTest extends ShellTestCase {
}
@Test
+ public void testLayoutHasUserAspectRatioSettingsButton() {
+ clearInvocations(mWindowManager);
+ spyOn(mWindowManager);
+ TaskInfo taskInfo = createTaskInfo(/* eligibleForUserAspectRatioButton= */
+ true, /* topActivityBoundsLetterboxed */ true);
+
+ // User aspect ratio settings button has not yet been shown.
+ doReturn(false).when(mUserAspectRatioButtonShownChecker).get();
+
+ // Check the layout has the user aspect ratio settings button.
+ mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+ assertTrue(mWindowManager.mHasUserAspectRatioSettingsButton);
+
+ // User aspect ratio settings button has been shown and is still visible.
+ spyOn(mWindowManager);
+ doReturn(true).when(mWindowManager).isShowingButton();
+ doReturn(true).when(mUserAspectRatioButtonShownChecker).get();
+
+ // Check the layout still has the user aspect ratio settings button.
+ mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+ assertTrue(mWindowManager.mHasUserAspectRatioSettingsButton);
+
+ // User aspect ratio settings button has been shown and has timed out so is no longer
+ // visible.
+ doReturn(false).when(mWindowManager).isShowingButton();
+ doReturn(true).when(mUserAspectRatioButtonShownChecker).get();
+
+ // Check the layout no longer has the user aspect ratio button.
+ mWindowManager.updateCompatInfo(taskInfo, mTaskListener, /* canShow= */ true);
+ assertFalse(mWindowManager.mHasUserAspectRatioSettingsButton);
+ }
+
+ @Test
public void testAttachToParentSurface() {
final SurfaceControl.Builder b = new SurfaceControl.Builder();
mWindowManager.attachToParentSurface(b);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index c29f884c848d..3472a859ac82 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -562,7 +562,9 @@ public class UdfpsController implements DozeReceiver, Dumpable {
+ mOverlay.getRequestId());
return false;
}
- if (mLockscreenShadeTransitionController.getQSDragProgress() != 0f
+
+ if ((mLockscreenShadeTransitionController.getQSDragProgress() != 0f
+ && !mAlternateBouncerInteractor.isVisibleState())
|| mPrimaryBouncerInteractor.isInTransit()) {
return false;
}
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index b6c50f7603c7..f2d9144c2461 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -389,7 +389,8 @@ object Flags {
@JvmField val NEW_BLUETOOTH_REPOSITORY = releasedFlag("new_bluetooth_repository")
// TODO(b/292533677): Tracking Bug
- val WIFI_TRACKER_LIB_FOR_WIFI_ICON = releasedFlag("wifi_tracker_lib_for_wifi_icon")
+ val WIFI_TRACKER_LIB_FOR_WIFI_ICON =
+ unreleasedFlag("wifi_tracker_lib_for_wifi_icon", teamfood = true)
// TODO(b/293863612): Tracking Bug
@JvmField val INCOMPATIBLE_CHARGING_BATTERY_ICON =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
index 6483b7c647e8..7ec8e12e557e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/ui/binder/MobileIconBinder.kt
@@ -25,6 +25,7 @@ import android.widget.ImageView
import android.widget.Space
import androidx.core.view.isVisible
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import com.android.settingslib.graph.SignalDrawable
import com.android.systemui.R
@@ -62,7 +63,7 @@ object MobileIconBinder {
val roamingSpace = view.requireViewById<Space>(R.id.mobile_roaming_space)
val dotView = view.requireViewById<StatusBarIconView>(R.id.status_bar_dot)
- view.isVisible = true
+ view.isVisible = viewModel.isVisible.value
iconView.isVisible = true
// TODO(b/238425913): We should log this visibility state.
@@ -75,99 +76,113 @@ object MobileIconBinder {
var isCollecting = false
view.repeatWhenAttached {
- repeatOnLifecycle(Lifecycle.State.STARTED) {
- logger.logCollectionStarted(view, viewModel)
- isCollecting = true
-
- launch {
- visibilityState.collect { state ->
- ModernStatusBarViewVisibilityHelper.setVisibilityState(
- state,
- mobileGroupView,
- dotView,
- )
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ // isVisible controls the visibility state of the outer group, and thus it needs
+ // to run in the CREATED lifecycle so it can continue to watch while invisible
+ // See (b/291031862) for details
+ launch {
+ viewModel.isVisible.collect { isVisible ->
+ viewModel.verboseLogger?.logBinderReceivedVisibility(
+ view,
+ viewModel.subscriptionId,
+ isVisible
+ )
+ view.isVisible = isVisible
+ // [StatusIconContainer] can get out of sync sometimes. Make sure to
+ // request another layout when this changes.
+ view.requestLayout()
+ }
}
}
+ }
- launch {
- viewModel.isVisible.collect { isVisible ->
- viewModel.verboseLogger?.logBinderReceivedVisibility(
- view,
- viewModel.subscriptionId,
- isVisible
- )
- view.isVisible = isVisible
+ lifecycleScope.launch {
+ repeatOnLifecycle(Lifecycle.State.STARTED) {
+ logger.logCollectionStarted(view, viewModel)
+ isCollecting = true
+
+ launch {
+ visibilityState.collect { state ->
+ ModernStatusBarViewVisibilityHelper.setVisibilityState(
+ state,
+ mobileGroupView,
+ dotView,
+ )
+ }
}
- }
- // Set the icon for the triangle
- launch {
- viewModel.icon.distinctUntilChanged().collect { icon ->
- viewModel.verboseLogger?.logBinderReceivedSignalIcon(
- view,
- viewModel.subscriptionId,
- icon,
- )
- mobileDrawable.level = icon.toSignalDrawableState()
+ // Set the icon for the triangle
+ launch {
+ viewModel.icon.distinctUntilChanged().collect { icon ->
+ viewModel.verboseLogger?.logBinderReceivedSignalIcon(
+ view,
+ viewModel.subscriptionId,
+ icon,
+ )
+ mobileDrawable.level = icon.toSignalDrawableState()
+ }
}
- }
- launch {
- viewModel.contentDescription.distinctUntilChanged().collect {
- ContentDescriptionViewBinder.bind(it, view)
+ launch {
+ viewModel.contentDescription.distinctUntilChanged().collect {
+ ContentDescriptionViewBinder.bind(it, view)
+ }
}
- }
- // Set the network type icon
- launch {
- viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
- viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
- view,
- viewModel.subscriptionId,
- dataTypeId,
- )
- dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
- networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
+ // Set the network type icon
+ launch {
+ viewModel.networkTypeIcon.distinctUntilChanged().collect { dataTypeId ->
+ viewModel.verboseLogger?.logBinderReceivedNetworkTypeIcon(
+ view,
+ viewModel.subscriptionId,
+ dataTypeId,
+ )
+ dataTypeId?.let { IconViewBinder.bind(dataTypeId, networkTypeView) }
+ networkTypeView.visibility = if (dataTypeId != null) VISIBLE else GONE
+ }
}
- }
- // Set the roaming indicator
- launch {
- viewModel.roaming.distinctUntilChanged().collect { isRoaming ->
- roamingView.isVisible = isRoaming
- roamingSpace.isVisible = isRoaming
+ // Set the roaming indicator
+ launch {
+ viewModel.roaming.distinctUntilChanged().collect { isRoaming ->
+ roamingView.isVisible = isRoaming
+ roamingSpace.isVisible = isRoaming
+ }
}
- }
- // Set the activity indicators
- launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
+ // Set the activity indicators
+ launch { viewModel.activityInVisible.collect { activityIn.isVisible = it } }
- launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
+ launch { viewModel.activityOutVisible.collect { activityOut.isVisible = it } }
- launch {
- viewModel.activityContainerVisible.collect { activityContainer.isVisible = it }
- }
+ launch {
+ viewModel.activityContainerVisible.collect {
+ activityContainer.isVisible = it
+ }
+ }
- // Set the tint
- launch {
- iconTint.collect { tint ->
- val tintList = ColorStateList.valueOf(tint)
- iconView.imageTintList = tintList
- networkTypeView.imageTintList = tintList
- roamingView.imageTintList = tintList
- activityIn.imageTintList = tintList
- activityOut.imageTintList = tintList
- dotView.setDecorColor(tint)
+ // Set the tint
+ launch {
+ iconTint.collect { tint ->
+ val tintList = ColorStateList.valueOf(tint)
+ iconView.imageTintList = tintList
+ networkTypeView.imageTintList = tintList
+ roamingView.imageTintList = tintList
+ activityIn.imageTintList = tintList
+ activityOut.imageTintList = tintList
+ dotView.setDecorColor(tint)
+ }
}
- }
- launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
+ launch { decorTint.collect { tint -> dotView.setDecorColor(tint) } }
- try {
- awaitCancellation()
- } finally {
- isCollecting = false
- logger.logCollectionStopped(view, viewModel)
+ try {
+ awaitCancellation()
+ } finally {
+ isCollecting = false
+ logger.logCollectionStopped(view, viewModel)
+ }
}
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 7dd88b437f17..e7fc870fab33 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -1597,6 +1597,53 @@ public class UdfpsControllerTest extends SysuiTestCase {
anyBoolean());
}
+
+ @Test
+ public void onTouch_withNewTouchDetection_qsDrag_processesTouchWhenAlternateBouncerVisible()
+ throws RemoteException {
+ final NormalizedTouchData touchData = new NormalizedTouchData(0, 0f, 0f, 0f, 0f, 0f, 0L,
+ 0L);
+ final TouchProcessorResult processorResultMove =
+ new TouchProcessorResult.ProcessedTouch(InteractionEvent.DOWN,
+ 1 /* pointerId */, touchData);
+
+ // Enable new touch detection.
+ when(mFeatureFlags.isEnabled(Flags.UDFPS_NEW_TOUCH_DETECTION)).thenReturn(true);
+
+ // Configure UdfpsController to use FingerprintManager as opposed to AlternateTouchProvider.
+ initUdfpsController(mOpticalProps, false /* hasAlternateTouchProvider */);
+
+ // Configure UdfpsView to accept the ACTION_MOVE event
+ when(mUdfpsView.isDisplayConfigured()).thenReturn(false);
+ when(mUdfpsView.isWithinSensorArea(anyFloat(), anyFloat())).thenReturn(true);
+
+ // GIVEN that the alternate bouncer is showing and a11y touch exploration NOT enabled
+ when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false);
+ when(mAlternateBouncerInteractor.isVisibleState()).thenReturn(true);
+ mOverlayController.showUdfpsOverlay(TEST_REQUEST_ID, mOpticalProps.sensorId,
+ BiometricOverlayConstants.REASON_AUTH_KEYGUARD, mUdfpsOverlayControllerCallback);
+ mFgExecutor.runAllReady();
+
+ verify(mUdfpsView).setOnTouchListener(mTouchListenerCaptor.capture());
+
+ // GIVEN swipe down for QS
+ when(mPrimaryBouncerInteractor.isInTransit()).thenReturn(false);
+ when(mLockscreenShadeTransitionController.getQSDragProgress()).thenReturn(1f);
+
+ // WHEN ACTION_MOVE is received and touch is within sensor
+ when(mSinglePointerTouchProcessor.processTouch(any(), anyInt(), any())).thenReturn(
+ processorResultMove);
+ MotionEvent moveEvent = MotionEvent.obtain(0, 0, ACTION_MOVE, 0, 0, 0);
+ mTouchListenerCaptor.getValue().onTouch(mUdfpsView, moveEvent);
+ mBiometricExecutor.runAllReady();
+ moveEvent.recycle();
+
+ // THEN the touch is still processed
+ verify(mFingerprintManager).onPointerDown(anyLong(), anyInt(), anyInt(),
+ anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyFloat(), anyLong(), anyLong(),
+ anyBoolean());
+ }
+
@Test
public void onAodInterrupt_onAcquiredGood_fingerNoLongerDown() throws RemoteException {
// GIVEN UDFPS overlay is showing
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
index 5fa6b3a15d35..e7056c7b0b9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/carrier/ShadeCarrierGroupControllerTest.java
@@ -58,6 +58,7 @@ import com.android.systemui.statusbar.pipeline.mobile.ui.MobileViewLogger;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel;
import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.ShadeCarrierGroupMobileIconViewModel;
import com.android.systemui.util.CarrierConfigTracker;
+import com.android.systemui.util.kotlin.FlowProviderKt;
import com.android.systemui.utils.leaks.LeakCheckedTest;
import com.android.systemui.utils.os.FakeHandler;
@@ -72,6 +73,8 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import kotlinx.coroutines.flow.MutableStateFlow;
+
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@SmallTest
@@ -105,7 +108,8 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
private ShadeCarrier mShadeCarrier3;
private TestableLooper mTestableLooper;
@Mock
- private ShadeCarrierGroupController.OnSingleCarrierChangedListener mOnSingleCarrierChangedListener;
+ private ShadeCarrierGroupController.OnSingleCarrierChangedListener
+ mOnSingleCarrierChangedListener;
@Mock
private MobileUiAdapter mMobileUiAdapter;
@Mock
@@ -119,6 +123,9 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
@Mock
private StatusBarPipelineFlags mStatusBarPipelineFlags;
+ private final MutableStateFlow<Boolean> mIsVisibleFlow =
+ FlowProviderKt.getMutableStateFlow(true);
+
private FakeSlotIndexResolver mSlotIndexResolver;
private ClickListenerTextView mNoCarrierTextView;
@@ -170,7 +177,7 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
mMobileUiAdapter,
mMobileContextProvider,
mStatusBarPipelineFlags
- )
+ )
.setShadeCarrierGroup(mShadeCarrierGroup)
.build();
@@ -181,6 +188,7 @@ public class ShadeCarrierGroupControllerTest extends LeakCheckedTest {
when(mStatusBarPipelineFlags.useNewShadeCarrierGroupMobileIcons()).thenReturn(true);
when(mMobileContextProvider.getMobileContextForSub(anyInt(), any())).thenReturn(mContext);
when(mMobileIconsViewModel.getLogger()).thenReturn(mMobileViewLogger);
+ when(mShadeCarrierGroupMobileIconViewModel.isVisible()).thenReturn(mIsVisibleFlow);
when(mMobileIconsViewModel.viewModelForSub(anyInt(), any()))
.thenReturn(mShadeCarrierGroupMobileIconViewModel);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt
new file mode 100644
index 000000000000..274acc9a8c23
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowProvider.kt
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.util.kotlin
+
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** Wrapper for flow constructors that can be retrieved from java tests */
+fun <T> getMutableStateFlow(value: T): MutableStateFlow<T> = MutableStateFlow(value)
diff --git a/services/autofill/java/com/android/server/autofill/ui/BottomSheetLayout.java b/services/autofill/java/com/android/server/autofill/ui/BottomSheetLayout.java
new file mode 100644
index 000000000000..06bbc2b0bdcb
--- /dev/null
+++ b/services/autofill/java/com/android/server/autofill/ui/BottomSheetLayout.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.autofill.ui;
+
+import static com.android.server.autofill.Helper.sDebug;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.widget.LinearLayout;
+
+import com.android.internal.R;
+
+/**
+ {@link LinearLayout} that displays content of save dialog.
+ */
+public class BottomSheetLayout extends LinearLayout {
+
+ private static final String TAG = "BottomSheetLayout";
+
+ public BottomSheetLayout(Context context) {
+ super(context);
+ }
+
+ public BottomSheetLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public BottomSheetLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ public void onMeasure(int widthSpec, int heightSpec) {
+ if (getContext() == null || getContext().getResources() == null) {
+ super.onMeasure(widthSpec, heightSpec);
+ Slog.w(TAG, "onMeasure failed due to missing context or missing resources.");
+ return;
+ }
+
+ if (getChildCount() == 0) {
+ // Should not happen
+ super.onMeasure(widthSpec, heightSpec);
+ Slog.wtf(TAG, "onMeasure failed due to missing children views.");
+ return;
+ }
+
+ DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
+
+ final int pxOffset = getContext().getResources().getDimensionPixelSize(
+ R.dimen.autofill_dialog_offset);
+ final int outerMargin = getContext().getResources().getDimensionPixelSize(
+ R.dimen.autofill_save_outer_margin);
+
+ final boolean includeHorizontalSpace =
+ getContext().getResources().getBoolean(
+ R.bool.autofill_dialog_horizontal_space_included);
+
+
+ final int screenHeight = displayMetrics.heightPixels;
+ final int screenWidth = displayMetrics.widthPixels;
+
+ final int maxHeight = screenHeight - pxOffset - outerMargin;
+
+ int maxWidth = screenWidth;
+
+ if (includeHorizontalSpace) {
+ maxWidth -= 2 * pxOffset;
+ }
+
+ maxWidth =
+ Math.min(maxWidth, getContext().getResources().getDimensionPixelSize(
+ R.dimen.autofill_dialog_max_width));
+
+ super.onMeasure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST));
+
+
+ if (sDebug) {
+ Slog.d(TAG, "onMeasure() values in dp:"
+ + " screenHeight: " + screenHeight / displayMetrics.density + ", screenWidth: "
+ + screenWidth / displayMetrics.density
+ + ", maxHeight: " + maxHeight / displayMetrics.density
+ + ", maxWidth: " + maxWidth / displayMetrics.density + ", getMeasuredWidth(): "
+ + getMeasuredWidth() / displayMetrics.density + ", getMeasuredHeight(): "
+ + getMeasuredHeight() / displayMetrics.density);
+ }
+ setMeasuredDimension(getMeasuredWidth(), getMeasuredHeight());
+ }
+
+
+}
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 70382f1d5274..3581db238ff3 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -48,7 +48,6 @@ import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.util.ArraySet;
-import android.util.DisplayMetrics;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
@@ -363,13 +362,6 @@ final class SaveUi {
window.setCloseOnTouchOutside(true);
final WindowManager.LayoutParams params = window.getAttributes();
- DisplayMetrics displayMetrics = new DisplayMetrics();
- window.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
- final int screenWidth = displayMetrics.widthPixels;
- final int maxWidth =
- context.getResources().getDimensionPixelSize(R.dimen.autofill_dialog_max_width);
- params.width = Math.min(screenWidth, maxWidth);
-
params.accessibilityTitle = context.getString(R.string.autofill_save_accessibility_title);
params.windowAnimations = R.style.AutofillSaveAnimation;
params.setTrustedOverlay();
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 5493da6331fa..5bb0f86e1b9b 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -486,6 +486,13 @@ public class UserBackupManagerService {
File baseStateDir,
File dataDir,
TransportManager transportManager) {
+ // check if we are past the retention period for BMM Events,
+ // if so delete expired events and do not print them to dumpsys
+ BackupManagerMonitorDumpsysUtils backupManagerMonitorDumpsysUtils =
+ new BackupManagerMonitorDumpsysUtils();
+ if (backupManagerMonitorDumpsysUtils.deleteExpiredBMMEvents() && DEBUG){
+ Slog.d(TAG, "BMM Events recorded for dumpsys have expired");
+ }
return new UserBackupManagerService(
userId,
context,
@@ -654,6 +661,13 @@ public class UserBackupManagerService {
// the pending backup set
mBackupHandler.postDelayed(this::parseLeftoverJournals, INITIALIZATION_DELAY_MILLIS);
+ // check if we are past the retention period for BMM Events,
+ // if so delete expired events and do not print them to dumpsys
+ BackupManagerMonitorDumpsysUtils backupManagerMonitorDumpsysUtils =
+ new BackupManagerMonitorDumpsysUtils();
+ mBackupHandler.postDelayed(backupManagerMonitorDumpsysUtils::deleteExpiredBMMEvents,
+ INITIALIZATION_DELAY_MILLIS);
+
mBackupPreferences = new UserBackupPreferences(mContext, mBaseStateDir);
// Power management
@@ -4177,7 +4191,19 @@ public class UserBackupManagerService {
private void dumpBMMEvents(PrintWriter pw) {
BackupManagerMonitorDumpsysUtils bm =
new BackupManagerMonitorDumpsysUtils();
+ if (bm.deleteExpiredBMMEvents()) {
+ pw.println("BACKUP MANAGER MONITOR EVENTS HAVE EXPIRED");
+ return;
+ }
File events = bm.getBMMEventsFile();
+ if (events.length() == 0){
+ // We have not recorded BMMEvents yet.
+ pw.println("NO BACKUP MANAGER MONITOR EVENTS");
+ return;
+ } else if (bm.isFileLargerThanSizeLimit(events)){
+ pw.println("BACKUP MANAGER MONITOR EVENTS FILE OVER SIZE LIMIT - "
+ + "future events will not be recorded");
+ }
pw.println("START OF BACKUP MANAGER MONITOR EVENTS");
try (BufferedReader reader = new BufferedReader(new FileReader(events))) {
String line;
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index e04bf11dad9f..bbec79d6cd47 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -394,6 +394,20 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// If we're starting a full-system restore, set up to begin widget ID remapping
if (mIsSystemRestore) {
AppWidgetBackupBridge.systemRestoreStarting(mUserId);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_START_SYSTEM_RESTORE,
+ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
+ } else {
+ //We are either performing RestoreAtInstall or Bmgr.
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_START_RESTORE_AT_INSTALL,
+ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
}
try {
@@ -421,6 +435,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
mStatus = transport.startRestore(mToken, packages);
if (mStatus != BackupTransport.TRANSPORT_OK) {
Slog.e(TAG, "Transport error " + mStatus + "; no restore possible");
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_DURING_START_RESTORE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ monitoringExtras);
mStatus = BackupTransport.TRANSPORT_ERROR;
executeNextState(UnifiedRestoreState.FINAL);
return;
@@ -528,6 +548,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
final String pkgName = (mRestoreDescription != null)
? mRestoreDescription.getPackageName() : null;
if (pkgName == null) {
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_CANNOT_GET_NEXT_PKG_NAME,
+ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ monitoringExtras);
Slog.e(TAG, "Failure getting next package name");
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
nextState = UnifiedRestoreState.FINAL;
@@ -550,6 +576,14 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
Metadata metaInfo = mPmAgent.getRestoredMetadata(pkgName);
if (metaInfo == null) {
+ PackageInfo pkgInfo = new PackageInfo();
+ pkgInfo.packageName = pkgName;
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_PM_AGENT_HAS_NO_METADATA,
+ pkgInfo,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
Slog.e(TAG, "No metadata for " + pkgName);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE, pkgName,
"Package metadata missing");
@@ -560,6 +594,13 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
try {
mCurrentPackage = backupManagerService.getPackageManager().getPackageInfoAsUser(
pkgName, PackageManager.GET_SIGNING_CERTIFICATES, mUserId);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_START_PACKAGE_RESTORE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
+
} catch (NameNotFoundException e) {
// Whoops, we thought we could restore this package but it
// turns out not to be present. Skip it.
@@ -641,12 +682,24 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
} else {
// Unknown restore type; ignore this package and move on
Slog.e(TAG, "Unrecognized restore type " + type);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);;
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_RESTORE_TYPE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
nextState = UnifiedRestoreState.RUNNING_QUEUE;
return;
}
} catch (Exception e) {
Slog.e(TAG, "Can't get next restore target from transport; halting: "
+ e.getMessage());
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);;
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_NO_NEXT_RESTORE_TARGET,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
nextState = UnifiedRestoreState.FINAL;
return;
@@ -663,6 +716,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
final String packageName = mCurrentPackage.packageName;
// Validate some semantic requirements that apply in this way
// only to the key/value restore API flow
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_KV_RESTORE, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ /*monitoringExtras*/ addRestoreOperationTypeToEvent(/*extras*/null));
if (mCurrentPackage.applicationInfo.backupAgentName == null
|| "".equals(mCurrentPackage.applicationInfo.backupAgentName)) {
if (MORE_DEBUG) {
@@ -721,6 +778,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
++mCount;
} catch (Exception e) {
Slog.e(TAG, "Error when attempting restore: " + e.toString());
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_KV_AGENT_ERROR, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ monitoringExtras);
keyValueAgentErrorCleanup(false);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
@@ -759,6 +821,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Transport-level failure. This failure could be specific to package currently in
// restore.
Slog.e(TAG, "Error getting restore data for " + packageName);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_KV_RESTORE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
stage.close();
downloadFile.delete();
@@ -815,6 +883,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
new ArrayList<>(getExcludedKeysForPackage(packageName)));
} catch (Exception e) {
Slog.e(TAG, "Unable to call app for restore: " + packageName, e);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_KV_AGENT_ERROR, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
packageName, e.toString());
// Clears any pending timeout messages as well.
@@ -888,6 +961,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
//
// When finished, StreamFeederThread executes next state as appropriate on the
// backup looper, and the overall unified restore task resumes
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ /*monitoringExtras*/ addRestoreOperationTypeToEvent(/*extras*/null));
try {
StreamFeederThread feeder = new StreamFeederThread();
if (MORE_DEBUG) {
@@ -903,6 +980,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// current target. We haven't asked the transport for data yet, though,
// so we can do that simply by going back to running the restore queue.
Slog.e(TAG, "Unable to construct pipes for stream restore!");
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_NO_FEEDER_THREAD, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
executeNextState(UnifiedRestoreState.RUNNING_QUEUE);
}
}
@@ -927,6 +1009,10 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
} catch (Exception e) {
final String packageName = mCurrentPackage.packageName;
Slog.e(TAG, "Unable to finalize restore of " + packageName);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_AGENT_FAILURE, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT, monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
packageName, e.toString());
keyValueAgentErrorCleanup(true);
@@ -1020,6 +1106,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// handling will deal properly with that.
Slog.e(TAG, "Error " + result + " streaming restore for "
+ mCurrentPackage.packageName);
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
status = result;
}
@@ -1032,6 +1124,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// but potentially recoverable; abandon this package's restore but
// carry on with the next restore target.
Slog.e(TAG, "Unable to route data for restore");
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_FULL_AGENT_ERROR,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_AGENT,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_AGENT_FAILURE,
mCurrentPackage.packageName, "I/O error on pipes");
status = BackupTransport.AGENT_ERROR;
@@ -1040,6 +1138,12 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// the sockets will wake up the engine and it will then tidy up the
// remote end.
Slog.e(TAG, "Transport failed during restore: " + e.getMessage());
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE,
+ mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_TRANSPORT,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE);
status = BackupTransport.TRANSPORT_ERROR;
} finally {
@@ -1213,6 +1317,13 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
}
Slog.i(TAG, "Restore complete.");
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_RESTORE_COMPLETE,
+ null,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
+
mListener.onFinished(callerLogString);
}
@@ -1313,6 +1424,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
@Override
public void operationComplete(long unusedResult) {
mOperationStorage.removeOperation(mEphemeralOpToken);
+
if (MORE_DEBUG) {
Slog.i(TAG, "operationComplete() during restore: target="
+ mCurrentPackage.packageName
@@ -1341,6 +1453,11 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask {
// Okay, we're done with this package. Tidy up and go on to the next
// app in the queue.
int size = (int) mBackupDataName.length();
+ Bundle monitoringExtras = addRestoreOperationTypeToEvent(/*extras*/null);
+ mBackupManagerMonitorEventSender.monitorEvent(
+ BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_RESTORE_FINISHED, mCurrentPackage,
+ BackupManagerMonitor.LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
+ monitoringExtras);
EventLog.writeEvent(EventLogTags.RESTORE_PACKAGE,
mCurrentPackage.packageName, size);
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
index 0b55ca21371b..797aed9297a3 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtils.java
@@ -23,15 +23,22 @@ import android.os.Bundle;
import android.os.Environment;
import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.FastPrintWriter;
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
/*
@@ -46,12 +53,27 @@ public class BackupManagerMonitorDumpsysUtils {
// Name of the subdirectory where the text file containing the BMM events will be stored.
// Same as {@link UserBackupManagerFiles}
private static final String BACKUP_PERSISTENT_DIR = "backup";
+ private static final String INITIAL_SETUP_TIMESTAMP_KEY = "initialSetupTimestamp";
+ // Retention period of 60 days (in millisec) for the BMM Events.
+ // After tha time has passed the text file containing the BMM events will be emptied
+ private static final long LOGS_RETENTION_PERIOD_MILLISEC = 60 * TimeUnit.DAYS.toMillis(1);
+ // Size limit for the text file containing the BMM events
+ private static final long BMM_FILE_SIZE_LIMIT_BYTES = 25 * 1024 * 1000; // 2.5 MB
+
+ // We cache the value of IsAfterRetentionPeriod() to avoid unnecessary disk I/O
+ // mIsAfterRetentionPeriodCached tracks if we have cached the value of IsAfterRetentionPeriod()
+ private boolean mIsAfterRetentionPeriodCached = false;
+ // The cached value of IsAfterRetentionPeriod()
+ private boolean mIsAfterRetentionPeriod;
+ // If isFileLargerThanSizeLimit(bmmEvents) returns true we cache the value to avoid
+ // unnecessary disk I/O
+ private boolean mIsFileLargerThanSizeLimit = false;
/**
* Parses the BackupManagerMonitor bundle for a RESTORE event in a series of strings that
* will be persisted in a text file and printed in the dumpsys.
*
- * If the evenntBundle passed is not a RESTORE event, return early
+ * If the eventBundle passed is not a RESTORE event, return early
*
* Key information related to the event:
* - Timestamp (HAS TO ALWAYS BE THE FIRST LINE OF EACH EVENT)
@@ -62,17 +84,22 @@ public class BackupManagerMonitorDumpsysUtils {
* - Agent logs (if available)
*
* Example of formatting:
- * RESTORE Event: [2023-08-18 17:16:00.735] Agent - Agent logging results
- * Package name: com.android.wallpaperbackup
- * Agent Logs:
- * Data Type: wlp_img_system
- * Item restored: 0/1
- * Agent Error - Category: no_wallpaper, Count: 1
- * Data Type: wlp_img_lock
- * Item restored: 0/1
- * Agent Error - Category: no_wallpaper, Count: 1
+ * [2023-09-21 14:43:33.824] - Agent logging results
+ * Package: com.android.wallpaperbackup
+ * Agent Logs:
+ * Data Type: wlp_img_system
+ * Item restored: 0/1
+ * Agent Error - Category: no_wallpaper, Count: 1
+ * Data Type: wlp_img_lock
+ * Item restored: 0/1
+ * Agent Error - Category: no_wallpaper, Count: 1
*/
public void parseBackupManagerMonitorRestoreEventForDumpsys(Bundle eventBundle) {
+ if (isAfterRetentionPeriod()) {
+ // We only log data for the first 60 days since setup
+ return;
+ }
+
if (eventBundle == null) {
return;
}
@@ -89,8 +116,19 @@ public class BackupManagerMonitorDumpsysUtils {
}
File bmmEvents = getBMMEventsFile();
+ if (bmmEvents.length() == 0) {
+ // We are parsing the first restore event.
+ // Time to also record the setup timestamp of the device
+ recordSetUpTimestamp();
+ }
+
+ if(isFileLargerThanSizeLimit(bmmEvents)){
+ // Do not write more events if the file is over size limit
+ return;
+ }
+
try (FileOutputStream out = new FileOutputStream(bmmEvents, /*append*/ true);
- PrintWriter pw = new FastPrintWriter(out);) {
+ PrintWriter pw = new FastPrintWriter(out);) {
int eventCategory = eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY);
int eventId = eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID);
@@ -101,17 +139,16 @@ public class BackupManagerMonitorDumpsysUtils {
return;
}
- pw.println("RESTORE Event: [" + timestamp() + "] " +
- getCategory(eventCategory) + " - " +
- getId(eventId));
+ pw.println("[" + timestamp() + "] - " + getId(eventId));
if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME)) {
- pw.println("\tPackage name: "
+ pw.println("\tPackage: "
+ eventBundle.getString(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME));
}
// TODO(b/296818666): add extras to the events
addAgentLogsIfAvailable(eventBundle, pw);
+ addExtrasIfAvailable(eventBundle, pw);
} catch (java.io.IOException e) {
Slog.e(TAG, "IO Exception when writing BMM events to file: " + e);
}
@@ -156,6 +193,37 @@ public class BackupManagerMonitorDumpsysUtils {
}
}
+ /**
+ * Extracts some extras (defined in BackupManagerMonitor as EXTRA_LOG_<description>)
+ * from the BackupManagerMonitor event. Not all extras have the same importance. For now only
+ * focus on extras relating to version mismatches between packages on the source and target.
+ *
+ * When an event with ID LOG_EVENT_ID_RESTORE_VERSION_HIGHER (trying to restore from higher to
+ * lower version of a package) parse:
+ * EXTRA_LOG_RESTORE_VERSION [int]: the version of the package on the source
+ * EXTRA_LOG_RESTORE_ANYWAY [bool]: if the package allows restore any version
+ * EXTRA_LOG_RESTORE_VERSION_TARGET [int]: an extra to record the package version on the target
+ */
+ private void addExtrasIfAvailable(Bundle eventBundle, PrintWriter pw) {
+ if (eventBundle.getInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID) ==
+ BackupManagerMonitor.LOG_EVENT_ID_RESTORE_VERSION_HIGHER) {
+ if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY)) {
+ pw.println("\t\tPackage supports RestoreAnyVersion: "
+ + eventBundle.getBoolean(BackupManagerMonitor.EXTRA_LOG_RESTORE_ANYWAY));
+ }
+ if (eventBundle.containsKey(BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION)) {
+ pw.println("\t\tPackage version on source: "
+ + eventBundle.getLong(BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION));
+ }
+ if (eventBundle.containsKey(
+ BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)) {
+ pw.println("\t\tPackage version on target: "
+ + eventBundle.getLong(
+ BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION));
+ }
+ }
+ }
+
/*
* Get the path of the text files which stores the BMM events
*/
@@ -165,6 +233,13 @@ public class BackupManagerMonitorDumpsysUtils {
return fname;
}
+ public boolean isFileLargerThanSizeLimit(File events){
+ if (!mIsFileLargerThanSizeLimit) {
+ mIsFileLargerThanSizeLimit = events.length() > getBMMEventsFileSizeLimit();
+ }
+ return mIsFileLargerThanSizeLimit;
+ }
+
private String timestamp() {
long currentTime = System.currentTimeMillis();
Date date = new Date(currentTime);
@@ -245,6 +320,32 @@ public class BackupManagerMonitorDumpsysUtils {
case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_NON_INCREMENTAL_BACKUP_REQUIRED ->
"Transport non-incremental backup required";
case BackupManagerMonitor.LOG_EVENT_ID_AGENT_LOGGING_RESULTS -> "Agent logging results";
+ case BackupManagerMonitor.LOG_EVENT_ID_START_SYSTEM_RESTORE -> "Start system restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_START_RESTORE_AT_INSTALL ->
+ "Start restore at install";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_DURING_START_RESTORE ->
+ "Transport error during start restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_CANNOT_GET_NEXT_PKG_NAME ->
+ "Cannot get next package name";
+ case BackupManagerMonitor.LOG_EVENT_ID_UNKNOWN_RESTORE_TYPE -> "Unknown restore type";
+ case BackupManagerMonitor.LOG_EVENT_ID_KV_RESTORE -> "KV restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_RESTORE -> "Full restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_NEXT_RESTORE_TARGET ->
+ "No next restore target";
+ case BackupManagerMonitor.LOG_EVENT_ID_KV_AGENT_ERROR -> "KV agent error";
+ case BackupManagerMonitor.LOG_EVENT_ID_PACKAGE_RESTORE_FINISHED ->
+ "Package restore finished";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_KV_RESTORE ->
+ "Transport error KV restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_NO_FEEDER_THREAD -> "No feeder thread";
+ case BackupManagerMonitor.LOG_EVENT_ID_FULL_AGENT_ERROR -> "Full agent error";
+ case BackupManagerMonitor.LOG_EVENT_ID_TRANSPORT_ERROR_FULL_RESTORE ->
+ "Transport error full restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_RESTORE_COMPLETE -> "Restore complete";
+ case BackupManagerMonitor.LOG_EVENT_ID_START_PACKAGE_RESTORE ->
+ "Start package restore";
+ case BackupManagerMonitor.LOG_EVENT_ID_AGENT_FAILURE ->
+ "Agent failure";
default -> "Unknown log event ID: " + code;
};
return id;
@@ -257,4 +358,128 @@ public class BackupManagerMonitorDumpsysUtils {
default -> false;
};
}
+
+ /**
+ * Store the timestamp when the device was set up (date when the first BMM event is parsed)
+ * in a text file.
+ */
+ @VisibleForTesting
+ void recordSetUpTimestamp() {
+ File setupDateFile = getSetUpDateFile();
+ // record setup timestamp only once
+ if (setupDateFile.length() == 0) {
+ try (FileOutputStream out = new FileOutputStream(setupDateFile, /*append*/ true);
+ PrintWriter pw = new FastPrintWriter(out);) {
+ long currentDate = System.currentTimeMillis();
+ pw.println(currentDate);
+ } catch (IOException e) {
+ Slog.w(TAG, "An error occurred while recording the setup date: "
+ + e.getMessage());
+ }
+ }
+
+ }
+
+ @VisibleForTesting
+ String getSetUpDate() {
+ File fname = getSetUpDateFile();
+ try (FileInputStream inputStream = new FileInputStream(fname);
+ InputStreamReader reader = new InputStreamReader(inputStream);
+ BufferedReader bufferedReader = new BufferedReader(reader);) {
+ return bufferedReader.readLine();
+ } catch (Exception e) {
+ Slog.w(TAG, "An error occurred while reading the date: " + e.getMessage());
+ return "Could not retrieve setup date";
+ }
+ }
+
+ @VisibleForTesting
+ static boolean isDateAfterNMillisec(long startTimeStamp, long endTimeStamp, long millisec) {
+ if (startTimeStamp > endTimeStamp) {
+ // Something has gone wrong, timeStamp1 should always precede timeStamp2.
+ // Out of caution return true: we would delete the logs rather than
+ // risking them being kept for longer than the retention period
+ return true;
+ }
+ long timeDifferenceMillis = endTimeStamp - startTimeStamp;
+ return (timeDifferenceMillis >= millisec);
+ }
+
+ /**
+ * Check if current date is after retention period
+ */
+ @VisibleForTesting
+ boolean isAfterRetentionPeriod() {
+ if (mIsAfterRetentionPeriodCached) {
+ return mIsAfterRetentionPeriod;
+ } else {
+ File setUpDateFile = getSetUpDateFile();
+ if (setUpDateFile.length() == 0) {
+ // We are yet to record a setup date. This means we haven't parsed the first event.
+ mIsAfterRetentionPeriod = false;
+ mIsAfterRetentionPeriodCached = true;
+ return false;
+ }
+ try {
+ long setupTimestamp = Long.parseLong(getSetUpDate());
+ long currentTimestamp = System.currentTimeMillis();
+ mIsAfterRetentionPeriod = isDateAfterNMillisec(setupTimestamp, currentTimestamp,
+ getRetentionPeriodInMillisec());
+ mIsAfterRetentionPeriodCached = true;
+ return mIsAfterRetentionPeriod;
+ } catch (NumberFormatException e) {
+ // An error occurred when parsing the setup timestamp.
+ // Out of caution return true: we would delete the logs rather than
+ // risking them being kept for longer than the retention period
+ mIsAfterRetentionPeriod = true;
+ mIsAfterRetentionPeriodCached = true;
+ return true;
+ }
+ }
+ }
+
+ @VisibleForTesting
+ File getSetUpDateFile() {
+ File dataDir = new File(Environment.getDataDirectory(), BACKUP_PERSISTENT_DIR);
+ File setupDateFile = new File(dataDir, INITIAL_SETUP_TIMESTAMP_KEY + ".txt");
+ return setupDateFile;
+ }
+
+ @VisibleForTesting
+ long getRetentionPeriodInMillisec() {
+ return LOGS_RETENTION_PERIOD_MILLISEC;
+ }
+
+ @VisibleForTesting
+ long getBMMEventsFileSizeLimit(){
+ return BMM_FILE_SIZE_LIMIT_BYTES;
+ }
+
+ /**
+ * Delete the BMM Events file after the retention period has passed.
+ *
+ * @return true if the retention period has passed false otherwise.
+ * we want to return true even if we were unable to delete the file, as this will prevent
+ * expired BMM events from being printed to the dumpsys
+ */
+ public boolean deleteExpiredBMMEvents() {
+ try {
+ if (isAfterRetentionPeriod()) {
+ File bmmEvents = getBMMEventsFile();
+ if (bmmEvents.exists()) {
+ if (bmmEvents.delete()) {
+ Slog.i(TAG, "Deleted expired BMM Events");
+ } else {
+ Slog.e(TAG, "Unable to delete expired BMM Events");
+ }
+ }
+ return true;
+ }
+ return false;
+ } catch (Exception e) {
+ // Handle any unexpected exceptions
+ // To be safe we return true as we want to avoid exposing expired BMMEvents
+ return true;
+ }
+ }
}
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
index 92e3107b6977..549d08c03933 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorEventSender.java
@@ -222,4 +222,21 @@ public class BackupManagerMonitorEventSender {
extras.putBoolean(key, value);
return extras;
}
+
+ /**
+ * Adds given key-value pair in the bundle and returns the bundle. If bundle was null it will
+ * be created.
+ *
+ * @param extras - bundle where to add key-value to, if null a new bundle will be created.
+ * @param key - key.
+ * @param value - value.
+ * @return extras if it was not null and new bundle otherwise.
+ */
+ public static Bundle putMonitoringExtra(Bundle extras, String key, int value) {
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putInt(key, value);
+ return extras;
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 47abc1092c49..43dc307d0d99 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -314,7 +314,6 @@ import android.net.ConnectivityManager;
import android.net.Proxy;
import android.net.Uri;
import android.os.AppZygote;
-import android.os.BatteryManager;
import android.os.BatteryStats;
import android.os.Binder;
import android.os.BinderProxy;
@@ -15030,16 +15029,6 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- // STOPSHIP(b/298884211): Remove this logging
- if (Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction())) {
- final int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- if (level < 0) {
- Slog.wtf(BroadcastQueue.TAG, "Unexpected broadcast: " + intent
- + "; callingUid: " + callingUid + ", callingPid: " + callingPid,
- new Throwable());
- }
- }
-
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index d5343a9777a7..5d0fefc75a28 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -59,7 +59,6 @@ import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.os.BatteryManager;
import android.os.Bundle;
import android.os.BundleMerger;
import android.os.Handler;
@@ -1075,16 +1074,6 @@ class BroadcastQueueModernImpl extends BroadcastQueue {
queue.lastProcessState = app.mState.getCurProcState();
if (receiver instanceof BroadcastFilter) {
notifyScheduleRegisteredReceiver(app, r, (BroadcastFilter) receiver);
- // STOPSHIP(b/298884211): Remove this logging
- if (Intent.ACTION_BATTERY_CHANGED.equals(receiverIntent.getAction())) {
- int level = receiverIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1);
- if (level < 0) {
- Slog.wtf(TAG, "Dispatching unexpected broadcast: " + receiverIntent
- + " to " + receiver
- + "; callingUid: " + r.callingUid
- + ", callingPid: " + r.callingPid);
- }
- }
thread.scheduleRegisteredReceiver(
((BroadcastFilter) receiver).receiverList.receiver,
receiverIntent, r.resultCode, r.resultData, r.resultExtras,
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index e1f010f62232..b6f4aeea3704 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -4126,6 +4126,10 @@ class PackageManagerShellCommand extends ShellCommand {
PackageManager.MATCH_DISABLED_COMPONENTS
| PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS
| PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, 0);
+ if (ai == null) {
+ Slog.e(TAG, "Failed to get ApplicationInfo for package name(" + pii.packageName + ").");
+ return null;
+ }
AssetManager am = new AssetManager();
am.addAssetPath(ai.publicSourceDir);
res = new Resources(am, null, null);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 60b6a8879ecf..c322563e9ae1 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -3461,6 +3461,7 @@ class Task extends TaskFragment {
info.topActivityLetterboxHeight = TaskInfo.PROPERTY_VALUE_UNSET;
info.isUserFullscreenOverrideEnabled = top != null
&& top.mLetterboxUiController.shouldApplyUserFullscreenOverride();
+ info.isTopActivityTransparent = top != null && !top.fillsParent();
info.isFromLetterboxDoubleTap = top != null && top.mLetterboxUiController.isFromDoubleTap();
if (info.isLetterboxDoubleTapEnabled) {
info.topActivityLetterboxWidth = top.getBounds().width();
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java
index 8e17b3a58769..dcd531751cd7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorDumpsysUtilsTest.java
@@ -17,26 +17,33 @@
package com.android.server.backup.utils;
import static org.junit.Assert.assertTrue;
-
+import static org.testng.AssertJUnit.assertFalse;
+import android.app.backup.BackupAnnotations;
import android.app.backup.BackupManagerMonitor;
import android.os.Bundle;
-
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
-
import java.io.File;
+import java.io.FileWriter;
public class BackupManagerMonitorDumpsysUtilsTest {
- private File mTempFile;
+ private long mRetentionPeriod;
+ private File mTempBMMEventsFile;
+ private File mTempSetUpDateFile;
+
+ private long mSizeLimit;
private TestBackupManagerMonitorDumpsysUtils mBackupManagerMonitorDumpsysUtils;
@Rule
public TemporaryFolder tmp = new TemporaryFolder();
@Before
public void setUp() throws Exception {
- mTempFile = tmp.newFile("testbmmevents.txt");
+ mRetentionPeriod = 30 * 60 * 1000;
+ mSizeLimit = 25 * 1024 * 1000;
+ mTempBMMEventsFile = tmp.newFile("testbmmevents.txt");
+ mTempSetUpDateFile = tmp.newFile("testSetUpDate.txt");
mBackupManagerMonitorDumpsysUtils = new TestBackupManagerMonitorDumpsysUtils();
}
@@ -46,7 +53,7 @@ public class BackupManagerMonitorDumpsysUtilsTest {
throws Exception {
mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(null);
- assertTrue(mTempFile.length() == 0);
+ assertTrue(mTempBMMEventsFile.length() == 0);
}
@@ -57,7 +64,7 @@ public class BackupManagerMonitorDumpsysUtilsTest {
event.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, 1);
mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
- assertTrue(mTempFile.length() == 0);
+ assertTrue(mTempBMMEventsFile.length() == 0);
}
@Test
@@ -67,18 +74,236 @@ public class BackupManagerMonitorDumpsysUtilsTest {
event.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, 1);
mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
- assertTrue(mTempFile.length() == 0);
+ assertTrue(mTempBMMEventsFile.length() == 0);
+ }
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_eventWithCategoryAndId_eventIsWrittenToFile()
+ throws Exception {
+ Bundle event = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+
+ assertTrue(mTempBMMEventsFile.length() != 0);
+ }
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_firstEvent_recordSetUpTimestamp()
+ throws Exception {
+ assertTrue(mTempBMMEventsFile.length()==0);
+ assertTrue(mTempSetUpDateFile.length()==0);
+
+ Bundle event = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+
+ assertTrue(mTempBMMEventsFile.length() != 0);
+ assertTrue(mTempSetUpDateFile.length()!=0);
+ }
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_notFirstEvent_doNotChangeSetUpTimestamp()
+ throws Exception {
+ Bundle event1 = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event1);
+ String setUpTimestampBefore = mBackupManagerMonitorDumpsysUtils.getSetUpDate();
+
+ Bundle event2 = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event2);
+ String setUpTimestampAfter = mBackupManagerMonitorDumpsysUtils.getSetUpDate();
+
+ assertTrue(setUpTimestampBefore.equals(setUpTimestampAfter));
+ }
+
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_fileOverSizeLimit_doNotRecordEvents()
+ throws Exception {
+ assertTrue(mTempBMMEventsFile.length() == 0);
+ Bundle event = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+ long fileSizeBefore = mTempBMMEventsFile.length();
+
+ mBackupManagerMonitorDumpsysUtils.setTestSizeLimit(0);
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+ long fileSizeAfter = mTempBMMEventsFile.length();
+ assertTrue(mBackupManagerMonitorDumpsysUtils.isFileLargerThanSizeLimit(mTempBMMEventsFile));
+ assertTrue(fileSizeBefore == fileSizeAfter);
+ }
+
+ @Test
+ public void parseBackupManagerMonitorEventForDumpsys_fileUnderSizeLimit_recordEvents()
+ throws Exception {
+ assertTrue(mTempBMMEventsFile.length() == 0);
+ Bundle event = createRestoreBMMEvent();
+
+ mBackupManagerMonitorDumpsysUtils.setTestSizeLimit(25 * 1024 * 1000);
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+ assertFalse(mBackupManagerMonitorDumpsysUtils.isFileLargerThanSizeLimit(mTempBMMEventsFile));
+ assertTrue(mTempBMMEventsFile.length() != 0);
+ }
+
+ @Test
+ public void deleteExpiredBackupManagerMonitorEvent_eventsAreExpired_deleteEventsAndReturnTrue()
+ throws Exception {
+ Bundle event = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+ assertTrue(mTempBMMEventsFile.length() != 0);
+ // Re-initialise the test BackupManagerMonitorDumpsysUtils to
+ // clear the cached value of isAfterRetentionPeriod
+ mBackupManagerMonitorDumpsysUtils = new TestBackupManagerMonitorDumpsysUtils();
+
+ // set a retention period of 0 second
+ mBackupManagerMonitorDumpsysUtils.setTestRetentionPeriod(0);
+
+ assertTrue(mBackupManagerMonitorDumpsysUtils.deleteExpiredBMMEvents());
+ assertFalse(mTempBMMEventsFile.exists());
+ }
+
+ @Test
+ public void deleteExpiredBackupManagerMonitorEvent_eventsAreNotExpired_returnFalse() throws
+ Exception {
+ Bundle event = createRestoreBMMEvent();
+ mBackupManagerMonitorDumpsysUtils.parseBackupManagerMonitorRestoreEventForDumpsys(event);
+ assertTrue(mTempBMMEventsFile.length() != 0);
+
+ // set a retention period of 30 minutes
+ mBackupManagerMonitorDumpsysUtils.setTestRetentionPeriod(30 * 60 * 1000);
+
+ assertFalse(mBackupManagerMonitorDumpsysUtils.deleteExpiredBMMEvents());
+ assertTrue(mTempBMMEventsFile.length() != 0);
+ }
+
+ @Test
+ public void isAfterRetentionPeriod_afterRetentionPeriod_returnTrue() throws
+ Exception {
+ mBackupManagerMonitorDumpsysUtils.recordSetUpTimestamp();
+
+ // set a retention period of 0 second
+ mBackupManagerMonitorDumpsysUtils.setTestRetentionPeriod(0);
+
+ assertTrue(mBackupManagerMonitorDumpsysUtils.isAfterRetentionPeriod());
+ }
+
+ @Test
+ public void isAfterRetentionPeriod_beforeRetentionPeriod_returnFalse() throws
+ Exception {
+ mBackupManagerMonitorDumpsysUtils.recordSetUpTimestamp();
+
+ // set a retention period of 30 minutes
+ mBackupManagerMonitorDumpsysUtils.setTestRetentionPeriod(30 * 60 * 1000);
+
+ assertFalse(mBackupManagerMonitorDumpsysUtils.isAfterRetentionPeriod());
+ }
+
+ @Test
+ public void isAfterRetentionPeriod_noSetupDate_returnFalse() throws
+ Exception {
+ assertTrue(mTempSetUpDateFile.length() == 0);
+
+ assertFalse(mBackupManagerMonitorDumpsysUtils.isAfterRetentionPeriod());
+ }
+
+ @Test
+ public void isDateAfterNMillisec_date1IsAfterThanDate2_returnTrue() throws
+ Exception {
+ long timestamp1 = System.currentTimeMillis();
+ long timestamp2 = timestamp1 - 1;
+
+ assertTrue(mBackupManagerMonitorDumpsysUtils.isDateAfterNMillisec(timestamp1, timestamp2,
+ 0));
+ }
+
+ @Test
+ public void isDateAfterNMillisec_date1IsAfterNMillisecFromDate2_returnTrue() throws
+ Exception {
+ long timestamp1 = System.currentTimeMillis();
+ long timestamp2 = timestamp1 + 10;
+
+ assertTrue(mBackupManagerMonitorDumpsysUtils.isDateAfterNMillisec(timestamp1, timestamp2,
+ 10));
+ }
+
+ @Test
+ public void isDateAfterNMillisec_date1IsLessThanNMillisecFromDate2_returnFalse() throws
+ Exception {
+ long timestamp1 = System.currentTimeMillis();
+ long timestamp2 = timestamp1 + 10;
+
+ assertFalse(mBackupManagerMonitorDumpsysUtils.isDateAfterNMillisec(timestamp1, timestamp2,
+ 11));
+ }
+
+ @Test
+ public void recordSetUpTimestamp_timestampNotSetBefore_setTimestamp() throws
+ Exception {
+ assertTrue(mTempSetUpDateFile.length() == 0);
+
+ mBackupManagerMonitorDumpsysUtils.recordSetUpTimestamp();
+
+ assertTrue(mTempSetUpDateFile.length() != 0);
+ }
+
+ @Test
+ public void recordSetUpTimestamp_timestampSetBefore_doNothing() throws
+ Exception {
+ mBackupManagerMonitorDumpsysUtils.recordSetUpTimestamp();
+ assertTrue(mTempSetUpDateFile.length() != 0);
+ String timestampBefore = mBackupManagerMonitorDumpsysUtils.getSetUpDate();
+
+ mBackupManagerMonitorDumpsysUtils.recordSetUpTimestamp();
+
+ assertTrue(mTempSetUpDateFile.length() != 0);
+ String timestampAfter = mBackupManagerMonitorDumpsysUtils.getSetUpDate();
+ assertTrue(timestampAfter.equals(timestampBefore));
+ }
+
+ private Bundle createRestoreBMMEvent() {
+ Bundle event = new Bundle();
+ event.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_ID, 1);
+ event.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_CATEGORY, 1);
+ event.putInt(BackupManagerMonitor.EXTRA_LOG_OPERATION_TYPE,
+ BackupAnnotations.OperationType.RESTORE);
+ return event;
}
private class TestBackupManagerMonitorDumpsysUtils
extends BackupManagerMonitorDumpsysUtils {
+
+ private long testRetentionPeriod;
+ private long testSizeLimit;
+
TestBackupManagerMonitorDumpsysUtils() {
super();
+ this.testRetentionPeriod = mRetentionPeriod;
+ this.testSizeLimit = mSizeLimit;
+ }
+
+ public void setTestRetentionPeriod(long testRetentionPeriod) {
+ this.testRetentionPeriod = testRetentionPeriod;
+ }
+ public void setTestSizeLimit(long testSizeLimit) {
+ this.testSizeLimit = testSizeLimit;
}
@Override
public File getBMMEventsFile() {
- return mTempFile;
+ return mTempBMMEventsFile;
}
+
+ @Override
+ File getSetUpDateFile() {
+ return mTempSetUpDateFile;
+ }
+
+ @Override
+ long getRetentionPeriodInMillisec() {
+ return testRetentionPeriod;
+ }
+
+ @Override
+ long getBMMEventsFileSizeLimit(){
+ return testSizeLimit;
+ }
+
+
}
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java
index 3af2932ee937..604a68d12f5e 100644
--- a/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/backup/utils/BackupManagerMonitorEventSenderTest.java
@@ -340,8 +340,9 @@ public class BackupManagerMonitorEventSenderTest {
@Test
public void putMonitoringExtraLong_bundleExists_fillsBundleCorrectly() throws Exception {
Bundle bundle = new Bundle();
+ long value = 123;
- Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(bundle, "key", 123);
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(bundle, "key", value);
assertThat(result).isEqualTo(bundle);
assertThat(result.size()).isEqualTo(1);
@@ -350,7 +351,8 @@ public class BackupManagerMonitorEventSenderTest {
@Test
public void putMonitoringExtraLong_bundleDoesNotExist_fillsBundleCorrectly() throws Exception {
- Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(null, "key", 123);
+ long value = 123;
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(null, "key", value);
assertThat(result).isNotNull();
assertThat(result.size()).isEqualTo(1);
@@ -377,4 +379,25 @@ public class BackupManagerMonitorEventSenderTest {
assertThat(result.size()).isEqualTo(1);
assertThat(result.getBoolean("key")).isTrue();
}
+
+ @Test
+ public void putMonitoringExtraInt_bundleExists_fillsBundleCorrectly() throws Exception {
+ Bundle bundle = new Bundle();
+
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(bundle, "key", 1);
+
+ assertThat(result).isEqualTo(bundle);
+ assertThat(result.size()).isEqualTo(1);
+ assertThat(result.getInt("key")).isEqualTo(1);
+ }
+
+ @Test
+ public void putMonitoringExtraInt_bundleDoesNotExist_fillsBundleCorrectly()
+ throws Exception {
+ Bundle result = mBackupManagerMonitorEventSender.putMonitoringExtra(null, "key", 1);
+
+ assertThat(result).isNotNull();
+ assertThat(result.size()).isEqualTo(1);
+ assertThat(result.getInt("key")).isEqualTo(1);
+ }
}
diff --git a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
index bc41829f16d2..71ac94ba2ee4 100644
--- a/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
+++ b/wifi/java/src/android/net/wifi/sharedconnectivity/app/SharedConnectivityManager.java
@@ -334,6 +334,7 @@ public class SharedConnectivityManager {
if (mServiceConnection != null) {
mContext.unbindService(mServiceConnection);
mServiceConnection = null;
+ mService = null;
}
}