Merge "bt: Add late bonding confirmation mechanism" into udc-dev
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 3249b41..4e2b6fa 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -261,6 +261,9 @@
void cancelTaskWindowTransition(int taskId);
/**
+ * Fetches the snapshot for the task with the given id, taking a new snapshot if it is not in
+ * the task snapshot cache and it is requested.
+ *
* @param taskId the id of the task to retrieve the sAutoapshots for
* @param isLowResolution if set, if the snapshot needs to be loaded from disk, this will load
* a reduced resolution of it, which is much faster
@@ -272,10 +275,14 @@
int taskId, boolean isLowResolution, boolean takeSnapshotIfNeeded);
/**
+ * Requests for a new snapshot to be taken for the task with the given id, storing it in the
+ * task snapshot cache only if requested.
+ *
* @param taskId the id of the task to take a snapshot of
+ * @param updateCache whether to store the new snapshot in the system's task snapshot cache
* @return a graphic buffer representing a screenshot of a task
*/
- android.window.TaskSnapshot takeTaskSnapshot(int taskId);
+ android.window.TaskSnapshot takeTaskSnapshot(int taskId, boolean updateCache);
/**
* Return the user id of last resumed activity.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index d802b46..47a5db8 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -791,4 +791,6 @@
void setKeepUninstalledPackages(in List<String> packageList);
boolean[] canPackageQuery(String sourcePackageName, in String[] targetPackageNames, int userId);
+
+ boolean waitForHandler(long timeoutMillis, boolean forBackgroundHandler);
}
diff --git a/core/java/android/view/autofill/AutofillFeatureFlags.java b/core/java/android/view/autofill/AutofillFeatureFlags.java
index ba54686..5ad74c8 100644
--- a/core/java/android/view/autofill/AutofillFeatureFlags.java
+++ b/core/java/android/view/autofill/AutofillFeatureFlags.java
@@ -280,7 +280,7 @@
private static final boolean DEFAULT_AFAA_ON_IMPORTANT_VIEW_ENABLED = true;
private static final String DEFAULT_AFAA_DENYLIST = "";
private static final String DEFAULT_AFAA_ALLOWLIST = "";
- private static final String DEFAULT_AFAA_NON_AUTOFILLABLE_IME_ACTIONS = "2,3,4";
+ private static final String DEFAULT_AFAA_NON_AUTOFILLABLE_IME_ACTIONS = "3,4";
private static final boolean DEFAULT_AFAA_SHOULD_ENABLE_AUTOFILL_ON_ALL_VIEW_TYPES = true;
private static final boolean DEFAULT_AFAA_SHOULD_ENABLE_MULTILINE_FILTER = true;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a554d0e..92cfa67 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -50,7 +50,6 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.os.storage.StorageManager;
-import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -723,15 +722,13 @@
}
/**
- * Whether the auto pin feature logic is available or not.
- * @return true, if deviceConfig flag is set to true or the flag is not propagated and
- * defaultValue is true.
+ * Whether the auto pin feature is available or not.
+ * @return true. This method is always returning true due to feature flags not working
+ * properly (b/282246482). Ideally, this should check if deviceConfig flag is set to true
+ * and then return the appropriate value.
*/
public static boolean isAutoPinConfirmFeatureAvailable() {
- return DeviceConfig.getBoolean(
- DeviceConfig.NAMESPACE_AUTO_PIN_CONFIRMATION,
- FLAG_ENABLE_AUTO_PIN_CONFIRMATION,
- /* defaultValue= */ true);
+ return true;
}
/** Returns if the given quality maps to an alphabetic password */
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index a99ba15..5b0dd30 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -72,9 +72,9 @@
<item name="secondary_content_alpha_material_dark" format="float" type="dimen">.7</item>
<item name="secondary_content_alpha_material_light" format="float" type="dimen">0.60</item>
- <item name="highlight_alpha_material_light" format="float" type="dimen">0.5</item>
- <item name="highlight_alpha_material_dark" format="float" type="dimen">0.5</item>
- <item name="highlight_alpha_material_colored" format="float" type="dimen">0.10</item>
+ <item name="highlight_alpha_material_light" format="float" type="dimen">0.20</item>
+ <item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
+ <item name="highlight_alpha_material_colored" format="float" type="dimen">0.20</item>
<!-- Primary & accent colors -->
<eat-comment />
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 4d0a058..641a2ae 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -1013,7 +1013,8 @@
}
p.setShader(shader);
p.setColorFilter(null);
- p.setColor(color);
+ // Alpha is handled by the shader (and color is a no-op because there's a shader)
+ p.setColor(0xFF000000);
return properties;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 9a2ec15..ab8e7e6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -709,7 +709,8 @@
return context.getSystemService(WindowManager.class)
.getMaximumWindowMetrics()
.getWindowInsets()
- .getInsets(WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout())
+ .getInsetsIgnoringVisibility(WindowInsets.Type.systemBars()
+ | WindowInsets.Type.displayCutout())
.toRect();
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 74ef57e..5a9c25f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -732,10 +732,11 @@
@WMSingleton
@Provides
- static ShellController provideShellController(ShellInit shellInit,
+ static ShellController provideShellController(Context context,
+ ShellInit shellInit,
ShellCommandHandler shellCommandHandler,
@ShellMainThread ShellExecutor mainExecutor) {
- return new ShellController(shellInit, shellCommandHandler, mainExecutor);
+ return new ShellController(context, shellInit, shellCommandHandler, mainExecutor);
}
//
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
index 78de5f3..3906599 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/IPip.aidl
@@ -57,27 +57,35 @@
in Rect destinationBounds, in SurfaceControl overlay) = 2;
/**
+ * Notifies the swiping Activity to PiP onto home transition is aborted
+ *
+ * @param taskId the Task id that the Activity and overlay are currently in.
+ * @param componentName ComponentName represents the Activity
+ */
+ oneway void abortSwipePipToHome(int taskId, in ComponentName componentName) = 3;
+
+ /**
* Sets listener to get pinned stack animation callbacks.
*/
- oneway void setPipAnimationListener(IPipAnimationListener listener) = 3;
+ oneway void setPipAnimationListener(IPipAnimationListener listener) = 4;
/**
* Sets the shelf height and visibility.
*/
- oneway void setShelfHeight(boolean visible, int shelfHeight) = 4;
+ oneway void setShelfHeight(boolean visible, int shelfHeight) = 5;
/**
* Sets the next pip animation type to be the alpha animation.
*/
- oneway void setPipAnimationTypeToAlpha() = 5;
+ oneway void setPipAnimationTypeToAlpha() = 6;
/**
* Sets the height and visibility of the Launcher keep clear area.
*/
- oneway void setLauncherKeepClearAreaHeight(boolean visible, int height) = 6;
+ oneway void setLauncherKeepClearAreaHeight(boolean visible, int height) = 7;
/**
* Sets the app icon size in pixel used by Launcher
*/
- oneway void setLauncherAppIconSize(int iconSizePx) = 7;
+ oneway void setLauncherAppIconSize(int iconSizePx) = 8;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 58bc81d..db7c3fc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -462,13 +462,29 @@
// to the actual Task surface now.
// PipTransition is responsible to fade it out and cleanup when finishing the enter PIP
// transition.
- final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ final SurfaceControl.Transaction t = mSurfaceControlTransactionFactory.getTransaction();
mTaskOrganizer.reparentChildSurfaceToTask(taskId, overlay, t);
t.setLayer(overlay, Integer.MAX_VALUE);
t.apply();
}
}
+ /**
+ * Callback when launcher aborts swipe-pip-to-home operation.
+ */
+ public void abortSwipePipToHome(int taskId, ComponentName componentName) {
+ if (!mPipTransitionState.getInSwipePipToHomeTransition()) {
+ return;
+ }
+ ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+ "Abort swipe-pip-to-home for %s", componentName);
+ sendOnPipTransitionCancelled(TRANSITION_DIRECTION_TO_PIP);
+ // Cleanup internal states
+ mPipTransitionState.setInSwipePipToHomeTransition(false);
+ mPictureInPictureParams = null;
+ mPipTransitionState.setTransitionState(PipTransitionState.UNDEFINED);
+ }
+
public ActivityManager.RunningTaskInfo getTaskInfo() {
return mTaskInfo;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 9e6bd47..63181da 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -1017,6 +1017,10 @@
mPipTaskOrganizer.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
}
+ private void abortSwipePipToHome(int taskId, ComponentName componentName) {
+ mPipTaskOrganizer.abortSwipePipToHome(taskId, componentName);
+ }
+
private String getTransitionTag(int direction) {
switch (direction) {
case TRANSITION_DIRECTION_TO_PIP:
@@ -1313,6 +1317,12 @@
}
@Override
+ public void abortSwipePipToHome(int taskId, ComponentName componentName) {
+ executeRemoteCallWithTaskPermission(mController, "abortSwipePipToHome",
+ (controller) -> controller.abortSwipePipToHome(taskId, componentName));
+ }
+
+ @Override
public void setShelfHeight(boolean visible, int height) {
executeRemoteCallWithTaskPermission(mController, "setShelfHeight",
(controller) -> controller.setShelfHeight(visible, height));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
index 387d390..a9ad3c9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentsTransitionHandler.java
@@ -301,7 +301,7 @@
try {
for (int i = 0; i < mPausingTasks.size(); ++i) {
snapshots[i] = ActivityTaskManager.getService().takeTaskSnapshot(
- mPausingTasks.get(0).mTaskInfo.taskId);
+ mPausingTasks.get(0).mTaskInfo.taskId, false /* updateCache */);
}
} catch (RemoteException e) {
taskIds = null;
@@ -671,7 +671,8 @@
try {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENTS_TRANSITION,
"[%d] RecentsController.screenshotTask: taskId=%d", mInstanceId, taskId);
- return ActivityTaskManager.getService().takeTaskSnapshot(taskId);
+ return ActivityTaskManager.getService().takeTaskSnapshot(taskId,
+ true /* updateCache */);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to screenshot task", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
index 3f944cb..0eb7c2d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java
@@ -32,6 +32,7 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.ArrayMap;
+import android.view.SurfaceControlRegistry;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
@@ -52,6 +53,7 @@
public class ShellController {
private static final String TAG = ShellController.class.getSimpleName();
+ private final Context mContext;
private final ShellInit mShellInit;
private final ShellCommandHandler mShellCommandHandler;
private final ShellExecutor mMainExecutor;
@@ -72,8 +74,11 @@
private Configuration mLastConfiguration;
- public ShellController(ShellInit shellInit, ShellCommandHandler shellCommandHandler,
+ public ShellController(Context context,
+ ShellInit shellInit,
+ ShellCommandHandler shellCommandHandler,
ShellExecutor mainExecutor) {
+ mContext = context;
mShellInit = shellInit;
mShellCommandHandler = shellCommandHandler;
mMainExecutor = mainExecutor;
@@ -254,6 +259,16 @@
}
}
+ private void handleInit() {
+ SurfaceControlRegistry.createProcessInstance(mContext);
+ mShellInit.init();
+ }
+
+ private void handleDump(PrintWriter pw) {
+ mShellCommandHandler.dump(pw);
+ SurfaceControlRegistry.dump(100 /* limit */, false /* runGc */, pw);
+ }
+
public void dump(@NonNull PrintWriter pw, String prefix) {
final String innerPrefix = prefix + " ";
pw.println(prefix + TAG);
@@ -279,7 +294,7 @@
@Override
public void onInit() {
try {
- mMainExecutor.executeBlocking(() -> mShellInit.init());
+ mMainExecutor.executeBlocking(() -> ShellController.this.handleInit());
} catch (InterruptedException e) {
throw new RuntimeException("Failed to initialize the Shell in 2s", e);
}
@@ -344,7 +359,7 @@
@Override
public void dump(PrintWriter pw) {
try {
- mMainExecutor.executeBlocking(() -> mShellCommandHandler.dump(pw));
+ mMainExecutor.executeBlocking(() -> ShellController.this.handleDump(pw));
} catch (InterruptedException e) {
throw new RuntimeException("Failed to dump the Shell in 2s", e);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
index 5d7b629..bb0eba6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/UnfoldTransitionHandler.java
@@ -18,6 +18,8 @@
import static android.view.WindowManager.TRANSIT_CHANGE;
+import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TRANSITIONS;
+
import android.os.IBinder;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
@@ -27,6 +29,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.internal.protolog.common.ProtoLog;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.sysui.ShellInit;
import com.android.wm.shell.transition.Transitions;
@@ -36,6 +39,7 @@
import com.android.wm.shell.unfold.animation.FullscreenUnfoldTaskAnimator;
import com.android.wm.shell.unfold.animation.SplitTaskUnfoldAnimator;
import com.android.wm.shell.unfold.animation.UnfoldTaskAnimator;
+import com.android.wm.shell.util.TransitionUtil;
import java.util.ArrayList;
import java.util.List;
@@ -105,8 +109,14 @@
animator.clearTasks();
info.getChanges().forEach(change -> {
- if (change.getTaskInfo() != null
- && change.getMode() == TRANSIT_CHANGE
+ if (change.getTaskInfo() != null) {
+ ProtoLog.v(WM_SHELL_TRANSITIONS,
+ "startAnimation, check taskInfo: %s, mode: %s, isApplicableTask: %s",
+ change.getTaskInfo(), TransitionInfo.modeToString(change.getMode()),
+ animator.isApplicableTask(change.getTaskInfo()));
+ }
+ if (change.getTaskInfo() != null && (change.getMode() == TRANSIT_CHANGE
+ || TransitionUtil.isOpeningType(change.getMode()))
&& animator.isApplicableTask(change.getTaskInfo())) {
animator.onTaskAppeared(change.getTaskInfo(), change.getLeash());
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
index 123bf3b..a4cf149 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/unfold/animation/SplitTaskUnfoldAnimator.java
@@ -213,7 +213,7 @@
@Override
public boolean isApplicableTask(TaskInfo taskInfo) {
return taskInfo.hasParentTask()
- && taskInfo.isVisible
+ && taskInfo.isRunning
&& taskInfo.realActivity != null // to filter out parents created by organizer
&& taskInfo.getWindowingMode() == WINDOWING_MODE_MULTI_WINDOW;
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 04f2c99..85167cb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -129,7 +129,7 @@
return null;
}).when(mMockExecutor).execute(any());
mShellInit = spy(new ShellInit(mMockExecutor));
- mShellController = spy(new ShellController(mShellInit, mMockShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mMockShellCommandHandler,
mMockExecutor));
mPipController = new PipController(mContext, mShellInit, mMockShellCommandHandler,
mShellController, mMockDisplayController, mMockPipAnimationController,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index b542fae..2c69522 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -107,7 +107,7 @@
mMainExecutor = new TestShellExecutor();
when(mContext.getPackageManager()).thenReturn(mock(PackageManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
- mShellController = spy(new ShellController(mShellInit, mShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mMainExecutor));
mRecentTasksControllerReal = new RecentTasksController(mContext, mShellInit,
mShellController, mShellCommandHandler, mTaskStackListener, mActivityTaskManager,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
index c37a497..9189d3d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitScreenControllerTests.java
@@ -111,7 +111,7 @@
public void setup() {
assumeTrue(ActivityTaskManager.supportsSplitScreenMultiWindow(mContext));
MockitoAnnotations.initMocks(this);
- mShellController = spy(new ShellController(mShellInit, mShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mMainExecutor));
mSplitScreenController = spy(new SplitScreenController(mContext, mShellInit,
mShellCommandHandler, mShellController, mTaskOrganizer, mSyncQueue,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
index 10dec9e..a9082a6 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingWindowControllerTests.java
@@ -81,7 +81,7 @@
doReturn(mock(Display.class)).when(mDisplayManager).getDisplay(anyInt());
doReturn(mDisplayManager).when(mContext).getSystemService(eq(DisplayManager.class));
mShellInit = spy(new ShellInit(mMainExecutor));
- mShellController = spy(new ShellController(mShellInit, mShellCommandHandler,
+ mShellController = spy(new ShellController(mContext, mShellInit, mShellCommandHandler,
mMainExecutor));
mController = new StartingWindowController(mContext, mShellInit, mShellController,
mTaskOrganizer, mMainExecutor, mTypeAlgorithm, mIconProvider, mTransactionPool);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
index 8d92d08..7c520c3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java
@@ -78,7 +78,7 @@
mConfigChangeListener = new TestConfigurationChangeListener();
mUserChangeListener = new TestUserChangeListener();
mExecutor = new TestShellExecutor();
- mController = new ShellController(mShellInit, mShellCommandHandler, mExecutor);
+ mController = new ShellController(mContext, mShellInit, mShellCommandHandler, mExecutor);
mController.onConfigurationChanged(getConfigurationCopy());
}
diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp
index 4194a22..45dde74 100644
--- a/media/jni/soundpool/Stream.cpp
+++ b/media/jni/soundpool/Stream.cpp
@@ -282,8 +282,6 @@
priority, loop, rate, playerIId);
// initialize track
- const audio_stream_type_t streamType =
- AudioSystem::attributesToStreamType(*mStreamManager->getAttributes());
const int32_t channelCount = sound->getChannelCount();
const auto sampleRate = (uint32_t)lround(double(sound->getSampleRate()) * rate);
size_t frameCount = 0;
@@ -328,8 +326,8 @@
attributionSource.token = sp<BBinder>::make();
mCallback = sp<StreamCallback>::make(this, toggle),
// TODO b/182469354 make consistent with AudioRecord, add util for native source
- mAudioTrack = new AudioTrack(streamType, sampleRate, sound->getFormat(),
- channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_FAST,
+ mAudioTrack = new AudioTrack(AUDIO_STREAM_DEFAULT, sampleRate, sound->getFormat(),
+ channelMask, sound->getIMemory(), AUDIO_OUTPUT_FLAG_NONE,
mCallback,
0 /*default notification frames*/, AUDIO_SESSION_ALLOCATE,
AudioTrack::TRANSFER_DEFAULT,
diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp
index acd4bad..52060f1 100644
--- a/media/jni/soundpool/StreamManager.cpp
+++ b/media/jni/soundpool/StreamManager.cpp
@@ -109,7 +109,10 @@
int32_t streams, size_t threads, const audio_attributes_t& attributes,
std::string opPackageName)
: StreamMap(streams)
- , mAttributes(attributes)
+ , mAttributes([attributes](){
+ audio_attributes_t attr = attributes;
+ attr.flags = static_cast<audio_flags_mask_t>(attr.flags | AUDIO_FLAG_LOW_LATENCY);
+ return attr; }())
, mOpPackageName(std::move(opPackageName))
, mLockStreamManagerStop(streams == 1 || kForceLockStreamManagerStop)
{
diff --git a/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml b/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml
index 6f504ef..9d53e39 100644
--- a/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml
+++ b/packages/SettingsLib/BannerMessagePreference/res/layout-v31/settingslib_banner_message.xml
@@ -50,6 +50,8 @@
android:id="@+id/banner_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingTop="0dp"
android:paddingBottom="4dp"
android:textAppearance="@style/Banner.Title.SettingsLib"/>
@@ -58,6 +60,8 @@
android:id="@+id/banner_subtitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingTop="0dp"
android:paddingBottom="4dp"
android:textAppearance="@style/Banner.Subtitle.SettingsLib"
@@ -67,6 +71,8 @@
android:id="@+id/banner_summary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingTop="4dp"
android:paddingBottom="8dp"
android:textAppearance="@style/Banner.Summary.SettingsLib"/>
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
index 42700b3..470a83d 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v31/preference_footer.xml
@@ -50,6 +50,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingTop="16dp"
android:paddingBottom="8dp"
android:textColor="?android:attr/textColorSecondary"
@@ -60,6 +62,8 @@
android:text="@string/settingslib_learn_more_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingBottom="8dp"
android:clickable="true"
android:visibility="gone"
diff --git a/packages/SettingsLib/FooterPreference/res/layout-v33/preference_footer.xml b/packages/SettingsLib/FooterPreference/res/layout-v33/preference_footer.xml
index a2f2510..4b5fd44 100644
--- a/packages/SettingsLib/FooterPreference/res/layout-v33/preference_footer.xml
+++ b/packages/SettingsLib/FooterPreference/res/layout-v33/preference_footer.xml
@@ -50,6 +50,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingTop="16dp"
android:paddingBottom="8dp"
android:textColor="?android:attr/textColorSecondary"
@@ -62,6 +64,8 @@
android:text="@string/settingslib_learn_more_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:paddingBottom="8dp"
android:clickable="true"
android:visibility="gone"
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
index 23aa993..dda7517c 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v31/settingslib_preference.xml
@@ -42,6 +42,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:maxLines="2"
android:textAppearance="?android:attr/textAppearanceListItem"
android:ellipsize="marquee"/>
diff --git a/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml b/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml
index 70ce374..fedcc77 100644
--- a/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml
+++ b/packages/SettingsLib/SettingsTheme/res/layout-v33/settingslib_preference.xml
@@ -42,6 +42,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:maxLines="2"
android:hyphenationFrequency="normalFast"
android:lineBreakWordStyle="phrase"
diff --git a/packages/SettingsLib/TopIntroPreference/res/layout-v33/top_intro_preference.xml b/packages/SettingsLib/TopIntroPreference/res/layout-v33/top_intro_preference.xml
index 6046d91..195d45f 100644
--- a/packages/SettingsLib/TopIntroPreference/res/layout-v33/top_intro_preference.xml
+++ b/packages/SettingsLib/TopIntroPreference/res/layout-v33/top_intro_preference.xml
@@ -30,6 +30,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:clickable="false"
android:longClickable="false"
android:maxLines="10"
diff --git a/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml b/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml
index 4d6e1b7..bee6bc7 100644
--- a/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml
+++ b/packages/SettingsLib/TopIntroPreference/res/layout/top_intro_preference.xml
@@ -30,6 +30,8 @@
android:id="@android:id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_gravity="start"
+ android:textAlignment="viewStart"
android:clickable="false"
android:longClickable="false"
android:maxLines="10"
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index e846480..8d4aa9a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -67,6 +67,10 @@
static final String STORAGE_MANAGER_ENABLED_PROPERTY =
"ro.storage_manager.enabled";
+ @VisibleForTesting
+ static final String INCOMPATIBLE_CHARGER_WARNING_DISABLED =
+ "incompatible_charger_warning_disabled";
+
private static Signature[] sSystemSignature;
private static String sPermissionControllerPackageName;
private static String sServicesSystemSharedLibPackageName;
@@ -652,6 +656,19 @@
/** Whether there is any incompatible chargers in the current UsbPort? */
public static boolean containsIncompatibleChargers(Context context, String tag) {
+ // Avoid the caller doesn't have permission to read the "Settings.Secure" data.
+ try {
+ // Whether the incompatible charger warning is disabled or not
+ if (Settings.Secure.getInt(context.getContentResolver(),
+ INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0) == 1) {
+ Log.d(tag, "containsIncompatibleChargers: disabled");
+ return false;
+ }
+ } catch (Exception e) {
+ Log.e(tag, "containsIncompatibleChargers()", e);
+ return false;
+ }
+
final List<UsbPort> usbPortList =
context.getSystemService(UsbManager.class).getPorts();
if (usbPortList == null || usbPortList.isEmpty()) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
index dce1e20..0637e5d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/UtilsTest.java
@@ -43,6 +43,7 @@
import android.telephony.ServiceState;
import android.text.TextUtils;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -65,6 +66,7 @@
@Config(shadows = {UtilsTest.ShadowSecure.class, UtilsTest.ShadowLocationManager.class})
public class UtilsTest {
private static final double[] TEST_PERCENTAGES = {0, 0.4, 0.5, 0.6, 49, 49.3, 49.8, 50, 100};
+ private static final String TAG = "UtilsTest";
private static final String PERCENTAGE_0 = "0%";
private static final String PERCENTAGE_1 = "1%";
private static final String PERCENTAGE_49 = "49%";
@@ -96,6 +98,12 @@
mAudioManager = mContext.getSystemService(AudioManager.class);
}
+ @After
+ public void reset() {
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Utils.INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0);
+ }
+
@Test
public void testUpdateLocationEnabled() {
int currentUserId = ActivityManager.getCurrentUser();
@@ -427,13 +435,13 @@
@Test
public void containsIncompatibleChargers_nullPorts_returnFalse() {
when(mUsbManager.getPorts()).thenReturn(null);
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isFalse();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
@Test
public void containsIncompatibleChargers_emptyPorts_returnFalse() {
when(mUsbManager.getPorts()).thenReturn(new ArrayList<>());
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isFalse();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
@Test
@@ -443,13 +451,13 @@
when(mUsbManager.getPorts()).thenReturn(usbPorts);
when(mUsbPort.getStatus()).thenReturn(null);
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isFalse();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
@Test
public void containsIncompatibleChargers_returnTrue() {
setupIncompatibleCharging();
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isTrue();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isTrue();
}
@Test
@@ -457,7 +465,7 @@
setupIncompatibleCharging();
when(mUsbPortStatus.getComplianceWarnings()).thenReturn(new int[1]);
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isFalse();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
@Test
@@ -465,7 +473,7 @@
setupIncompatibleCharging();
when(mUsbPort.supportsComplianceWarnings()).thenReturn(false);
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isFalse();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
@Test
@@ -473,7 +481,16 @@
setupIncompatibleCharging();
when(mUsbPortStatus.isConnected()).thenReturn(false);
- assertThat(Utils.containsIncompatibleChargers(mContext, "tag")).isFalse();
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
+ }
+
+ @Test
+ public void containsIncompatibleChargers_disableWarning_returnFalse() {
+ setupIncompatibleCharging();
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Utils.INCOMPATIBLE_CHARGER_WARNING_DISABLED, 1);
+
+ assertThat(Utils.containsIncompatibleChargers(mContext, TAG)).isFalse();
}
private void setupIncompatibleCharging() {
diff --git a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/shared/page/SceneModule.kt b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
similarity index 94%
rename from packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/shared/page/SceneModule.kt
rename to packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
index 18c9513..24064b1 100644
--- a/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/shared/page/SceneModule.kt
+++ b/packages/SystemUI/compose/facade/disabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.scene.shared.page
+package com.android.systemui.scene.ui.composable
import com.android.systemui.scene.shared.model.Scene
import dagger.Module
diff --git a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
index 530706e..ee53ece 100644
--- a/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
+++ b/packages/SystemUI/compose/facade/enabled/src/com/android/systemui/scene/ui/composable/SceneModule.kt
@@ -17,7 +17,7 @@
package com.android.systemui.scene.ui.composable
import com.android.systemui.bouncer.ui.composable.BouncerScene
-import com.android.systemui.keyguard.ui.composable.LockScreenScene
+import com.android.systemui.keyguard.ui.composable.LockscreenScene
import com.android.systemui.qs.ui.composable.QuickSettingsScene
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.shade.ui.composable.ShadeScene
@@ -30,7 +30,7 @@
fun scenes(
bouncer: BouncerScene,
gone: GoneScene,
- lockScreen: LockScreenScene,
+ lockScreen: LockscreenScene,
qs: QuickSettingsScene,
shade: ShadeScene,
): Set<Scene> {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
index 6f6d0f9..f48bab9 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt
@@ -55,11 +55,13 @@
class BouncerScene
@Inject
constructor(
- private val viewModel: BouncerViewModel,
+ private val viewModelFactory: BouncerViewModel.Factory,
) : ComposableScene {
override val key = SceneKey.Bouncer
- override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(
+ containerName: String,
+ ): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
UserAction.Back to SceneModel(SceneKey.Lockscreen),
@@ -67,7 +69,11 @@
)
.asStateFlow()
- @Composable override fun Content(modifier: Modifier) = BouncerScene(viewModel, modifier)
+ @Composable
+ override fun Content(
+ containerName: String,
+ modifier: Modifier,
+ ) = BouncerScene(viewModelFactory.create(containerName), modifier)
}
@Composable
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index ab7bc26..7c07a8b 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -52,25 +52,32 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val viewModel: LockscreenSceneViewModel,
+ private val viewModelFactory: LockscreenSceneViewModel.Factory,
) : ComposableScene {
override val key = SceneKey.Lockscreen
- override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
- viewModel.upDestinationSceneKey
- .map { pageKey -> destinationScenes(up = pageKey) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value)
- )
+ private var unsafeViewModel: LockscreenSceneViewModel? = null
+
+ override fun destinationScenes(
+ containerName: String,
+ ): StateFlow<Map<UserAction, SceneModel>> =
+ getOrCreateViewModelSingleton(containerName).let { viewModel ->
+ viewModel.upDestinationSceneKey
+ .map { pageKey -> destinationScenes(up = pageKey) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value)
+ )
+ }
@Composable
override fun Content(
+ containerName: String,
modifier: Modifier,
) {
LockscreenScene(
- viewModel = viewModel,
+ viewModel = getOrCreateViewModelSingleton(containerName),
modifier = modifier,
)
}
@@ -83,6 +90,13 @@
UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade)
)
}
+
+ private fun getOrCreateViewModelSingleton(
+ containerName: String,
+ ): LockscreenSceneViewModel {
+ return unsafeViewModel
+ ?: viewModelFactory.create(containerName).also { unsafeViewModel = it }
+ }
}
@Composable
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index 130395a..58db37e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -44,11 +44,13 @@
class QuickSettingsScene
@Inject
constructor(
- private val viewModel: QuickSettingsSceneViewModel,
+ private val viewModelFactory: QuickSettingsSceneViewModel.Factory,
) : ComposableScene {
override val key = SceneKey.QuickSettings
- override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(
+ containerName: String,
+ ): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
UserAction.Swipe(Direction.UP) to SceneModel(SceneKey.Shade),
@@ -58,10 +60,11 @@
@Composable
override fun Content(
+ containerName: String,
modifier: Modifier,
) {
QuickSettingsScene(
- viewModel = viewModel,
+ viewModel = viewModelFactory.create(containerName),
modifier = modifier,
)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
index a213666..6f3363e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/ComposableScene.kt
@@ -22,5 +22,5 @@
/** Compose-capable extension of [Scene]. */
interface ComposableScene : Scene {
- @Composable fun Content(modifier: Modifier)
+ @Composable fun Content(containerName: String, modifier: Modifier)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index 0070552..b387463 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -41,7 +41,9 @@
class GoneScene @Inject constructor() : ComposableScene {
override val key = SceneKey.Gone
- override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
+ override fun destinationScenes(
+ containerName: String,
+ ): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow<Map<UserAction, SceneModel>>(
mapOf(
UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.Shade),
@@ -51,6 +53,7 @@
@Composable
override fun Content(
+ containerName: String,
modifier: Modifier,
) {
/*
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
index f8a73d5..5e07610 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt
@@ -75,6 +75,7 @@
if (key == currentSceneKey) {
Scene(
scene = composableScene,
+ containerName = viewModel.containerName,
onSceneChanged = viewModel::setCurrentScene,
modifier = Modifier.fillMaxSize(),
)
@@ -87,6 +88,7 @@
@Composable
private fun Scene(
scene: ComposableScene,
+ containerName: String,
onSceneChanged: (SceneModel) -> Unit,
modifier: Modifier = Modifier,
) {
@@ -97,11 +99,12 @@
modifier = Modifier.align(Alignment.Center),
) {
scene.Content(
+ containerName = containerName,
modifier = Modifier,
)
val destinationScenes: Map<UserAction, SceneModel> by
- scene.destinationScenes().collectAsState()
+ scene.destinationScenes(containerName).collectAsState()
val swipeLeftDestinationScene = destinationScenes[UserAction.Swipe(Direction.LEFT)]
val swipeUpDestinationScene = destinationScenes[UserAction.Swipe(Direction.UP)]
val swipeRightDestinationScene = destinationScenes[UserAction.Swipe(Direction.RIGHT)]
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index 5a09204..e4513d0 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -48,25 +48,32 @@
@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val viewModel: ShadeSceneViewModel,
+ private val viewModelFactory: ShadeSceneViewModel.Factory,
) : ComposableScene {
override val key = SceneKey.Shade
- override fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
- viewModel.upDestinationSceneKey
- .map { sceneKey -> destinationScenes(up = sceneKey) }
- .stateIn(
- scope = applicationScope,
- started = SharingStarted.Eagerly,
- initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value),
- )
+ private var unsafeViewModel: ShadeSceneViewModel? = null
+
+ override fun destinationScenes(
+ containerName: String,
+ ): StateFlow<Map<UserAction, SceneModel>> =
+ getOrCreateViewModelSingleton(containerName).let { viewModel ->
+ viewModel.upDestinationSceneKey
+ .map { sceneKey -> destinationScenes(up = sceneKey) }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = destinationScenes(up = viewModel.upDestinationSceneKey.value),
+ )
+ }
@Composable
override fun Content(
+ containerName: String,
modifier: Modifier,
) {
ShadeScene(
- viewModel = viewModel,
+ viewModel = getOrCreateViewModelSingleton(containerName),
modifier = modifier,
)
}
@@ -79,6 +86,13 @@
UserAction.Swipe(Direction.DOWN) to SceneModel(SceneKey.QuickSettings),
)
}
+
+ private fun getOrCreateViewModelSingleton(
+ containerName: String,
+ ): ShadeSceneViewModel {
+ return unsafeViewModel
+ ?: viewModelFactory.create(containerName).also { unsafeViewModel = it }
+ }
}
@Composable
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
index 2dd146c5..a4b1cee 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/WeatherData.kt
@@ -1,6 +1,7 @@
package com.android.systemui.plugins
import android.os.Bundle
+import android.util.Log
import androidx.annotation.VisibleForTesting
class WeatherData
@@ -11,6 +12,7 @@
val temperature: Int,
) {
companion object {
+ const val DEBUG = true
private const val TAG = "WeatherData"
@VisibleForTesting const val DESCRIPTION_KEY = "description"
@VisibleForTesting const val STATE_KEY = "state"
@@ -23,20 +25,29 @@
val state =
WeatherStateIcon.fromInt(extras.getInt(STATE_KEY, INVALID_WEATHER_ICON_STATE))
val temperature = readIntFromBundle(extras, TEMPERATURE_KEY)
- return if (
+ if (
description == null ||
state == null ||
!extras.containsKey(USE_CELSIUS_KEY) ||
temperature == null
- )
- null
- else
- WeatherData(
- description = description,
- state = state,
- useCelsius = extras.getBoolean(USE_CELSIUS_KEY),
- temperature = temperature
- )
+ ) {
+ if (DEBUG) {
+ Log.w(TAG, "Weather data did not parse from $extras")
+ }
+ return null
+ } else {
+ val result =
+ WeatherData(
+ description = description,
+ state = state,
+ useCelsius = extras.getBoolean(USE_CELSIUS_KEY),
+ temperature = temperature
+ )
+ if (DEBUG) {
+ Log.i(TAG, "Weather data parsed $result from $extras")
+ }
+ return result
+ }
}
private fun readIntFromBundle(extras: Bundle, key: String): Int? =
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml
index 751b07a..dc58d50 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_security_container_view.xml
@@ -19,9 +19,7 @@
<com.android.keyguard.KeyguardSecurityContainer
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:id="@+id/keyguard_security_container"
- android:background="?androidprv:attr/materialColorSurfaceContainer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 7dc8afe..003f9b0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -295,9 +295,8 @@
<string name="screenrecord_save_title">Screen recording saved</string>
<!-- Subtext for a notification shown after saving a screen recording to prompt the user to view it [CHAR_LIMIT=100] -->
<string name="screenrecord_save_text">Tap to view</string>
- <!-- A toast message shown when there is an error deleting a screen recording [CHAR LIMIT=NONE] -->
- <string name="screenrecord_delete_error">Error deleting screen recording</string>
- <!-- A toast message shown when the screen recording cannot be started due to insufficient permissions [CHAR LIMIT=NONE] -->
+ <!-- A toast message shown when there is an error saving a screen recording [CHAR LIMIT=NONE] -->
+ <string name="screenrecord_save_error">Error saving screen recording</string>
<!-- A toast message shown when the screen recording cannot be started due to a generic error [CHAR LIMIT=NONE] -->
<string name="screenrecord_start_error">Error starting screen recording</string>
diff --git a/packages/SystemUI/res/xml/media_session_collapsed.xml b/packages/SystemUI/res/xml/media_session_collapsed.xml
index 5129fc0..c053b33 100644
--- a/packages/SystemUI/res/xml/media_session_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_session_collapsed.xml
@@ -63,8 +63,8 @@
android:layout_marginEnd="@dimen/qs_media_padding"
app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
app:layout_constrainedWidth="true"
- app:layout_constraintTop_toBottomOf="@id/icon"
app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintBottom_toTopOf="@id/header_artist"
app:layout_constraintHorizontal_bias="0" />
<Constraint
@@ -87,11 +87,12 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/qs_media_padding"
+ android:layout_marginBottom="@dimen/qs_media_padding"
android:layout_marginTop="0dp"
app:layout_constraintEnd_toStartOf="@id/action_button_guideline"
app:layout_constrainedWidth="true"
- app:layout_constraintTop_toBottomOf="@id/header_title"
app:layout_constraintStart_toEndOf="@id/media_explicit_indicator"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0" />
<Constraint
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index 1fbf743..74c325d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -352,7 +352,8 @@
@Override public TaskSnapshot screenshotTask(int taskId) {
try {
- return ActivityTaskManager.getService().takeTaskSnapshot(taskId);
+ return ActivityTaskManager.getService().takeTaskSnapshot(taskId,
+ true /* updateCache */);
} catch (RemoteException e) {
Log.e(TAG, "Failed to screenshot task", e);
}
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index a8f2804..8ea4c31a 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -23,6 +23,7 @@
import android.content.res.Resources
import android.text.format.DateFormat
import android.util.TypedValue
+import android.util.Log
import android.view.View
import android.view.View.OnAttachStateChangeListener
import android.view.ViewTreeObserver
@@ -101,7 +102,12 @@
}
updateFontSizes()
updateTimeListeners()
- cachedWeatherData?.let { value.events.onWeatherDataChanged(it) }
+ cachedWeatherData?.let {
+ if (WeatherData.DEBUG) {
+ Log.i(TAG, "Pushing cached weather data to new clock: $it")
+ }
+ value.events.onWeatherDataChanged(it)
+ }
value.smallClock.view.addOnAttachStateChangeListener(
object : OnAttachStateChangeListener {
override fun onViewAttachedToWindow(p0: View?) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 794eeda..1db0ab6 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -315,6 +315,14 @@
}
/**
+ * Returns true if the large clock will block the notification shelf in AOD
+ */
+ public boolean isLargeClockBlockingNotificationShelf() {
+ ClockController clock = mKeyguardClockSwitchController.getClock();
+ return clock != null && clock.getLargeClock().getConfig().getHasCustomWeatherDataDisplay();
+ }
+
+ /**
* Updates the alignment of the KeyguardStatusView and animates the transition if requested.
*/
public void updateAlignment(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 3add8c8..cabe900 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -115,7 +115,7 @@
private var overlayTouchListener: TouchExplorationStateChangeListener? = null
private val coreLayoutParams = WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
+ WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
0 /* flags set in computeLayoutParams() */,
PixelFormat.TRANSLUCENT
).apply {
diff --git a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
index eaa8ed5..c6528d0 100644
--- a/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bouncer/ui/viewmodel/BouncerViewModel.kt
@@ -20,6 +20,8 @@
import com.android.systemui.authentication.shared.model.AuthenticationMethodModel
import com.android.systemui.bouncer.domain.interactor.BouncerInteractor
import com.android.systemui.dagger.qualifiers.Application
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -34,7 +36,7 @@
@Application private val applicationContext: Context,
@Application private val applicationScope: CoroutineScope,
interactorFactory: BouncerInteractor.Factory,
- containerName: String,
+ @Assisted containerName: String,
) {
private val interactor: BouncerInteractor = interactorFactory.create(containerName)
@@ -94,4 +96,11 @@
else -> null
}
}
+
+ @AssistedFactory
+ interface Factory {
+ fun create(
+ containerName: String,
+ ): BouncerViewModel
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
index 691017b..b2bcb05 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/BrightLineFalsingManager.java
@@ -232,8 +232,7 @@
// check for false tap if it is a seekbar interaction
if (interactionType == MEDIA_SEEKBAR) {
- localResult[0] &= isFalseTap(mFeatureFlags.isEnabled(Flags.MEDIA_FALSING_PENALTY)
- ? FalsingManager.MODERATE_PENALTY : FalsingManager.LOW_PENALTY);
+ localResult[0] &= isFalseTap(FalsingManager.MODERATE_PENALTY);
}
logDebug("False Gesture (type: " + interactionType + "): " + localResult[0]);
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
index f71a46c..c8485dc 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.kt
@@ -88,8 +88,7 @@
// TODO(b/278873737): Tracking Bug
@JvmField
val LOAD_NOTIFICATIONS_BEFORE_THE_USER_SWITCH_IS_COMPLETE =
- unreleasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete",
- teamfood = true)
+ releasedFlag(278873737, "load_notifications_before_the_user_switch_is_complete")
// TODO(b/277338665): Tracking Bug
@JvmField
@@ -392,8 +391,6 @@
// TODO(b/254513168): Tracking Bug
@JvmField val UMO_SURFACE_RIPPLE = releasedFlag(907, "umo_surface_ripple")
- @JvmField val MEDIA_FALSING_PENALTY = releasedFlag(908, "media_falsing_media")
-
// TODO(b/261734857): Tracking Bug
@JvmField val UMO_TURBULENCE_NOISE = releasedFlag(909, "umo_turbulence_noise")
@@ -720,8 +717,4 @@
@JvmField
val SPLIT_SHADE_SUBPIXEL_OPTIMIZATION =
unreleasedFlag(2805, "split_shade_subpixel_optimization", teamfood = true)
-
- // TODO(b/278761837): Tracking Bug
- @JvmField
- val USE_NEW_ACTIVITY_STARTER = releasedFlag(2801, name = "use_new_activity_starter")
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
index 5e806b6..1f421fa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinator.kt
@@ -21,41 +21,44 @@
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogContentViewModel
import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
+private fun defaultCreateDialog(context: Context): (Int, Int) -> KeyboardBacklightDialog {
+ return { currentLevel: Int, maxLevel: Int ->
+ KeyboardBacklightDialog(context, currentLevel, maxLevel)
+ }
+}
+
/**
* Based on the state produced from [BacklightDialogViewModel] shows or hides keyboard backlight
* indicator
*/
@SysUISingleton
class KeyboardBacklightDialogCoordinator
-@Inject
constructor(
@Application private val applicationScope: CoroutineScope,
- private val context: Context,
private val viewModel: BacklightDialogViewModel,
+ private val createDialog: (Int, Int) -> KeyboardBacklightDialog
) {
+ @Inject
+ constructor(
+ @Application applicationScope: CoroutineScope,
+ context: Context,
+ viewModel: BacklightDialogViewModel
+ ) : this(applicationScope, viewModel, defaultCreateDialog(context))
+
var dialog: KeyboardBacklightDialog? = null
fun startListening() {
applicationScope.launch {
- viewModel.dialogContent.collect { dialogViewModel ->
- if (dialogViewModel != null) {
- if (dialog == null) {
- dialog =
- KeyboardBacklightDialog(
- context,
- initialCurrentLevel = dialogViewModel.currentValue,
- initialMaxLevel = dialogViewModel.maxValue
- )
- dialog?.show()
- } else {
- dialog?.updateState(dialogViewModel.currentValue, dialogViewModel.maxValue)
- }
+ viewModel.dialogContent.collect { contentModel ->
+ if (contentModel != null) {
+ showDialog(contentModel)
} else {
dialog?.dismiss()
dialog = null
@@ -63,4 +66,15 @@
}
}
}
+
+ private fun showDialog(model: BacklightDialogContentViewModel) {
+ if (dialog == null) {
+ dialog = createDialog(model.currentValue, model.maxValue)
+ } else {
+ dialog?.updateState(model.currentValue, model.maxValue)
+ }
+ // let's always show dialog - even if we're just updating it, it might have been dismissed
+ // externally by tapping finger outside of it
+ dialog?.show()
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
index 5079487..1469d96 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/pipeline/MediaDataManager.kt
@@ -786,10 +786,10 @@
// Song name
var song: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE)
- if (song == null) {
+ if (song.isNullOrBlank()) {
song = metadata?.getString(MediaMetadata.METADATA_KEY_TITLE)
}
- if (song == null) {
+ if (song.isNullOrBlank()) {
song = HybridGroupManager.resolveTitle(notif)
}
if (song.isNullOrBlank()) {
@@ -846,7 +846,7 @@
// Artist name
var artist: CharSequence? = metadata?.getString(MediaMetadata.METADATA_KEY_ARTIST)
- if (artist == null) {
+ if (artist.isNullOrBlank()) {
artist = HybridGroupManager.resolveText(notif)
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
index f8e3ecb..32a7935 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/MediaControlPanel.java
@@ -617,10 +617,7 @@
seamlessView.setContentDescription(deviceString);
seamlessView.setOnClickListener(
v -> {
- if (mFalsingManager.isFalseTap(
- mFeatureFlags.isEnabled(Flags.MEDIA_FALSING_PENALTY)
- ? FalsingManager.MODERATE_PENALTY :
- FalsingManager.LOW_PENALTY)) {
+ if (mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)) {
return;
}
@@ -1130,10 +1127,7 @@
} else {
button.setEnabled(true);
button.setOnClickListener(v -> {
- if (!mFalsingManager.isFalseTap(
- mFeatureFlags.isEnabled(Flags.MEDIA_FALSING_PENALTY)
- ? FalsingManager.MODERATE_PENALTY :
- FalsingManager.LOW_PENALTY)) {
+ if (!mFalsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)) {
mLogger.logTapAction(button.getId(), mUid, mPackageName, mInstanceId);
logSmartspaceCardReported(SMARTSPACE_CARD_CLICK_EVENT);
action.run();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index b476521..b936c41 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -522,7 +522,7 @@
return mExpanded;
}
- void addTile(QSPanelControllerBase.TileRecord tileRecord) {
+ final void addTile(QSPanelControllerBase.TileRecord tileRecord) {
final QSTile.Callback callback = new QSTile.Callback() {
@Override
public void onStateChanged(QSTile.State state) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
index fdab9b1..20f0352 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanelControllerBase.java
@@ -199,7 +199,7 @@
mMediaHost.removeVisibilityChangeListener(mMediaHostVisibilityListener);
for (TileRecord record : mRecords) {
- record.tile.removeCallbacks();
+ record.tile.removeCallback(record.callback);
}
mRecords.clear();
mDumpManager.unregisterDumpable(mView.getDumpableTag());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
index 91c6e8b..c579f5c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractor.kt
@@ -318,7 +318,6 @@
// We have a handful of different cases
qsTile !is CustomTile -> {
// The tile is not a custom tile. Make sure they are reset to the correct user
- qsTile.removeCallbacks()
if (userChanged) {
qsTile.userSwitch(user)
logger.logTileUserChanged(tileSpec, user)
@@ -327,7 +326,6 @@
}
qsTile.user == user -> {
// The tile is a custom tile for the same user, just return it
- qsTile.removeCallbacks()
qsTile
}
else -> {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
index 0ed8b21..6d7455f 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/SceneContainerFrameworkModule.kt
@@ -16,7 +16,7 @@
package com.android.systemui.scene
-import com.android.systemui.scene.shared.page.SceneModule
+import com.android.systemui.scene.ui.composable.SceneModule
import dagger.Module
@Module(
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
index 435ff4b..354de8a 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/Scene.kt
@@ -59,7 +59,7 @@
* The API is designed such that it's possible to emit ever-changing values for each
* [UserAction] to enable, disable, or change the destination scene of a given user action.
*/
- fun destinationScenes(): StateFlow<Map<UserAction, SceneModel>> =
+ fun destinationScenes(containerName: String): StateFlow<Map<UserAction, SceneModel>> =
MutableStateFlow(emptyMap<UserAction, SceneModel>()).asStateFlow()
}
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
index afc0531..a4daafc 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/SceneContainerViewModel.kt
@@ -29,7 +29,7 @@
@AssistedInject
constructor(
private val interactor: SceneInteractor,
- @Assisted private val containerName: String,
+ @Assisted val containerName: String,
) {
/**
* Keys of all scenes in the container.
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
index 84f358c..e1ac0fd 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java
@@ -453,9 +453,9 @@
postGroupNotification(currentUser);
mNotificationManager.notifyAsUser(null, mNotificationId, notification,
currentUser);
- } catch (IOException e) {
+ } catch (IOException | IllegalStateException e) {
Log.e(TAG, "Error saving screen recording: " + e.getMessage());
- showErrorToast(R.string.screenrecord_delete_error);
+ showErrorToast(R.string.screenrecord_save_error);
mNotificationManager.cancelAsUser(null, mNotificationId, currentUser);
}
});
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
index b8d96f7..b80a01212 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenMediaRecorder.java
@@ -52,8 +52,9 @@
import android.view.WindowManager;
import com.android.systemui.media.MediaProjectionCaptureTarget;
-import java.io.File;
+
import java.io.Closeable;
+import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.file.Files;
@@ -321,7 +322,7 @@
/**
* Store recorded video
*/
- protected SavedRecording save() throws IOException {
+ protected SavedRecording save() throws IOException, IllegalStateException {
String fileName = new SimpleDateFormat("'screen-'yyyyMMdd-HHmmss'.mp4'")
.format(new Date());
diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
index 7ffcfd4..dc3310d 100644
--- a/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
+++ b/packages/SystemUI/src/com/android/systemui/screenrecord/ScreenRecordingMuxer.java
@@ -52,9 +52,8 @@
/**
* RUN IN THE BACKGROUND THREAD!
*/
- public void mux() throws IOException {
- MediaMuxer muxer = null;
- muxer = new MediaMuxer(mOutFile, mFormat);
+ public void mux() throws IOException, IllegalStateException {
+ MediaMuxer muxer = new MediaMuxer(mOutFile, mFormat);
// Add extractors
for (String file: mFiles) {
MediaExtractor extractor = new MediaExtractor();
@@ -74,7 +73,10 @@
}
}
+ // This may throw IllegalStateException if no tracks were added above
+ // Let the error propagate up so we can notify the user.
muxer.start();
+
for (Pair<MediaExtractor, Integer> pair: mExtractorIndexToMuxerIndex.keySet()) {
MediaExtractor extractor = pair.first;
extractor.selectTrack(pair.second);
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
index 67e9a87..2e47ab6 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ImageCaptureImpl.kt
@@ -48,7 +48,9 @@
}
override suspend fun captureTask(taskId: Int): Bitmap? {
- val snapshot = withContext(bgContext) { atmService.takeTaskSnapshot(taskId) } ?: return null
+ val snapshot = withContext(bgContext) {
+ atmService.takeTaskSnapshot(taskId, false /* updateCache */)
+ } ?: return null
return Bitmap.wrapHardwareBuffer(snapshot.hardwareBuffer, snapshot.colorSpace)
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
index fbf134d..5fb3c01 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/UserTrackerImpl.kt
@@ -166,21 +166,19 @@
}
override fun onUserSwitching(newUserId: Int, reply: IRemoteCallback?) {
- backgroundHandler.run {
- handleUserSwitching(newUserId)
- reply?.sendResult(null)
- }
+ handleUserSwitching(newUserId)
+ reply?.sendResult(null)
}
override fun onUserSwitchComplete(newUserId: Int) {
- backgroundHandler.run {
- handleUserSwitchComplete(newUserId)
- }
+ handleUserSwitchComplete(newUserId)
}
}, TAG)
}
+ @WorkerThread
protected open fun handleBeforeUserSwitching(newUserId: Int) {
+ Assert.isNotMainThread()
setUserIdInternal(newUserId)
}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 0fdd7ca..784a360 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1570,6 +1570,12 @@
// When media is visible, it overlaps with the large clock. Use small clock instead.
return SMALL;
}
+ // To prevent the weather clock from overlapping with the notification shelf on AOD, we use
+ // the small clock here
+ if (mKeyguardStatusViewController.isLargeClockBlockingNotificationShelf()
+ && hasVisibleNotifications() && isOnAod()) {
+ return SMALL;
+ }
return LARGE;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index 9ede6ce..ed8050a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -140,7 +140,13 @@
}
protected boolean shouldHeadsUpBecomePinned(@NonNull NotificationEntry entry) {
- return hasFullScreenIntent(entry);
+ final HeadsUpEntry headsUpEntry = getHeadsUpEntry(entry.getKey());
+ if (headsUpEntry == null) {
+ // This should not happen since shouldHeadsUpBecomePinned is always called after adding
+ // the NotificationEntry into AlertingNotificationManager's mAlertEntries map.
+ return hasFullScreenIntent(entry);
+ }
+ return hasFullScreenIntent(entry) && !headsUpEntry.wasUnpinned;
}
protected boolean hasFullScreenIntent(@NonNull NotificationEntry entry) {
@@ -151,6 +157,9 @@
@NonNull HeadsUpManager.HeadsUpEntry headsUpEntry, boolean isPinned) {
mLogger.logSetEntryPinned(headsUpEntry.mEntry, isPinned);
NotificationEntry entry = headsUpEntry.mEntry;
+ if (!isPinned) {
+ headsUpEntry.wasUnpinned = true;
+ }
if (entry.isRowPinned() != isPinned) {
entry.setRowPinned(isPinned);
updatePinnedMode();
@@ -177,7 +186,9 @@
protected void onAlertEntryAdded(AlertEntry alertEntry) {
NotificationEntry entry = alertEntry.mEntry;
entry.setHeadsUp(true);
- setEntryPinned((HeadsUpEntry) alertEntry, shouldHeadsUpBecomePinned(entry));
+
+ final boolean shouldPin = shouldHeadsUpBecomePinned(entry);
+ setEntryPinned((HeadsUpEntry) alertEntry, shouldPin);
EventLogTags.writeSysuiHeadsUpStatus(entry.getKey(), 1 /* visible */);
for (OnHeadsUpChangedListener listener : mListeners) {
listener.onHeadsUpStateChanged(entry, true);
@@ -411,6 +422,7 @@
protected class HeadsUpEntry extends AlertEntry {
public boolean remoteInputActive;
protected boolean expanded;
+ protected boolean wasUnpinned;
@Override
public boolean isSticky() {
diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
index c72853e..7b652c1 100644
--- a/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
+++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/SysUIConcurrencyModule.java
@@ -29,18 +29,28 @@
import com.android.systemui.dagger.qualifiers.LongRunning;
import com.android.systemui.dagger.qualifiers.Main;
+import dagger.Module;
+import dagger.Provides;
+
import java.util.concurrent.Executor;
import javax.inject.Named;
-import dagger.Module;
-import dagger.Provides;
-
/**
* Dagger Module for classes found within the concurrent package.
*/
@Module
public abstract class SysUIConcurrencyModule {
+
+ // Slow BG executor can potentially affect UI if UI is waiting for an updated state from this
+ // thread
+ private static final Long BG_SLOW_DISPATCH_THRESHOLD = 1000L;
+ private static final Long BG_SLOW_DELIVERY_THRESHOLD = 1000L;
+ private static final Long LONG_SLOW_DISPATCH_THRESHOLD = 2500L;
+ private static final Long LONG_SLOW_DELIVERY_THRESHOLD = 2500L;
+ private static final Long BROADCAST_SLOW_DISPATCH_THRESHOLD = 1000L;
+ private static final Long BROADCAST_SLOW_DELIVERY_THRESHOLD = 1000L;
+
/** Background Looper */
@Provides
@SysUISingleton
@@ -49,6 +59,8 @@
HandlerThread thread = new HandlerThread("SysUiBg",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
+ thread.getLooper().setSlowLogThresholdMs(BG_SLOW_DISPATCH_THRESHOLD,
+ BG_SLOW_DELIVERY_THRESHOLD);
return thread.getLooper();
}
@@ -60,6 +72,8 @@
HandlerThread thread = new HandlerThread("BroadcastRunning",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
+ thread.getLooper().setSlowLogThresholdMs(BROADCAST_SLOW_DISPATCH_THRESHOLD,
+ BROADCAST_SLOW_DELIVERY_THRESHOLD);
return thread.getLooper();
}
@@ -71,6 +85,8 @@
HandlerThread thread = new HandlerThread("SysUiLng",
Process.THREAD_PRIORITY_BACKGROUND);
thread.start();
+ thread.getLooper().setSlowLogThresholdMs(LONG_SLOW_DISPATCH_THRESHOLD,
+ LONG_SLOW_DELIVERY_THRESHOLD);
return thread.getLooper();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
index 4cb99a2..6afbde0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/classifier/BrightLineClassifierTest.java
@@ -120,7 +120,6 @@
gestureCompleteListenerCaptor.capture());
mGestureFinalizedListener = gestureCompleteListenerCaptor.getValue();
- mFakeFeatureFlags.set(Flags.MEDIA_FALSING_PENALTY, true);
mFakeFeatureFlags.set(Flags.FALSING_OFF_FOR_UNFOLDED, true);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
new file mode 100644
index 0000000..7207fbf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/KeyboardBacklightDialogCoordinatorTest.kt
@@ -0,0 +1,158 @@
+/*
+ * 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.keyboard.backlight.ui
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
+import com.android.systemui.keyboard.backlight.ui.view.KeyboardBacklightDialog
+import com.android.systemui.keyboard.backlight.ui.viewmodel.BacklightDialogViewModel
+import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
+import com.android.systemui.keyboard.shared.model.BacklightModel
+import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.StandardTestDispatcher
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.advanceTimeBy
+import kotlinx.coroutines.test.runCurrent
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.mockito.Mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.MockitoAnnotations
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@SmallTest
+@RunWith(JUnit4::class)
+class KeyboardBacklightDialogCoordinatorTest : SysuiTestCase() {
+
+ @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
+ @Mock private lateinit var dialog: KeyboardBacklightDialog
+
+ private val keyboardRepository = FakeKeyboardRepository()
+ private lateinit var underTest: KeyboardBacklightDialogCoordinator
+ private val timeoutMillis = 3000L
+ private val testScope = TestScope(StandardTestDispatcher())
+
+ private val createDialog = { value: Int, maxValue: Int ->
+ dialogCreationValue = value
+ dialogCreationMaxValue = maxValue
+ dialog
+ }
+ private var dialogCreationValue = -1
+ private var dialogCreationMaxValue = -1
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
+ .thenReturn(timeoutMillis.toInt())
+ val viewModel =
+ BacklightDialogViewModel(
+ KeyboardBacklightInteractor(keyboardRepository),
+ accessibilityManagerWrapper
+ )
+ underTest =
+ KeyboardBacklightDialogCoordinator(testScope.backgroundScope, viewModel, createDialog)
+ underTest.startListening()
+ keyboardRepository.setIsAnyKeyboardConnected(true)
+ }
+
+ @Test
+ fun showsDialog_afterBacklightChange() =
+ testScope.runTest {
+ setBacklightValue(1)
+
+ verify(dialog).show()
+ }
+
+ @Test
+ fun updatesDialog_withLatestValues_afterBacklightChange() =
+ testScope.runTest {
+ setBacklightValue(value = 1, maxValue = 5)
+ setBacklightValue(value = 2, maxValue = 5)
+
+ verify(dialog).updateState(2, 5)
+ }
+
+ @Test
+ fun showsDialog_withDataFromBacklightChange() =
+ testScope.runTest {
+ setBacklightValue(value = 4, maxValue = 5)
+
+ Truth.assertThat(dialogCreationValue).isEqualTo(4)
+ Truth.assertThat(dialogCreationMaxValue).isEqualTo(5)
+ }
+
+ @Test
+ fun dismissesDialog_afterTimeout() =
+ testScope.runTest {
+ setBacklightValue(1)
+
+ advanceTimeBy(timeoutMillis + 1)
+
+ verify(dialog).dismiss()
+ }
+
+ @Test
+ fun dismissesDialog_onlyAfterTimeout_fromLastBacklightChange() =
+ testScope.runTest {
+ setBacklightValue(1)
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // majority of timeout passed
+
+ // this should restart timeout
+ setBacklightValue(2)
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ verify(dialog, never()).dismiss()
+
+ advanceTimeBy(timeoutMillis * 2 / 3)
+ // finally timeout reached and dialog was dismissed
+ verify(dialog, times(1)).dismiss()
+ }
+
+ @Test
+ fun showsDialog_ifItWasAlreadyShownAndDismissedBySomethingElse() =
+ testScope.runTest {
+ setBacklightValue(1)
+ // let's pretend dialog is dismissed e.g. by user tapping on the screen
+ whenever(dialog.isShowing).thenReturn(false)
+
+ // no advancing time, we're still in timeout period
+ setBacklightValue(2)
+
+ verify(dialog, times(2)).show()
+ }
+
+ private fun TestScope.setBacklightValue(value: Int, maxValue: Int = MAX_BACKLIGHT) {
+ keyboardRepository.setBacklight(BacklightModel(value, maxValue))
+ runCurrent()
+ }
+
+ private companion object {
+ const val MAX_BACKLIGHT = 5
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
deleted file mode 100644
index 1fec5a4..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/keyboard/backlight/ui/viewmodel/BacklightDialogViewModelTest.kt
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
-
-package com.android.systemui.keyboard.backlight.ui.viewmodel
-
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.keyboard.backlight.domain.interactor.KeyboardBacklightInteractor
-import com.android.systemui.keyboard.data.repository.FakeKeyboardRepository
-import com.android.systemui.keyboard.shared.model.BacklightModel
-import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.ExperimentalCoroutinesApi
-import kotlinx.coroutines.flow.first
-import kotlinx.coroutines.test.advanceTimeBy
-import kotlinx.coroutines.test.runTest
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.JUnit4
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@OptIn(ExperimentalCoroutinesApi::class)
-@SmallTest
-@RunWith(JUnit4::class)
-class BacklightDialogViewModelTest : SysuiTestCase() {
-
- private val keyboardRepository = FakeKeyboardRepository()
- private lateinit var underTest: BacklightDialogViewModel
- @Mock private lateinit var accessibilityManagerWrapper: AccessibilityManagerWrapper
- private val timeoutMillis = 3000L
-
- @Before
- fun setUp() {
- MockitoAnnotations.initMocks(this)
- whenever(accessibilityManagerWrapper.getRecommendedTimeoutMillis(any(), any()))
- .thenReturn(timeoutMillis.toInt())
- underTest =
- BacklightDialogViewModel(
- KeyboardBacklightInteractor(keyboardRepository),
- accessibilityManagerWrapper
- )
- keyboardRepository.setIsAnyKeyboardConnected(true)
- }
-
- @Test
- fun emitsViewModel_whenBacklightChanged() = runTest {
- keyboardRepository.setBacklight(BacklightModel(1, 5))
-
- assertThat(underTest.dialogContent.first()).isEqualTo(BacklightDialogContentViewModel(1, 5))
- }
-
- @Test
- fun emitsNull_afterTimeout() = runTest {
- val latest by collectLastValue(underTest.dialogContent)
- keyboardRepository.setBacklight(BacklightModel(1, 5))
-
- assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
- advanceTimeBy(timeoutMillis + 1)
- assertThat(latest).isNull()
- }
-
- @Test
- fun emitsNull_after5secDelay_fromLastBacklightChange() = runTest {
- val latest by collectLastValue(underTest.dialogContent)
- keyboardRepository.setIsAnyKeyboardConnected(true)
-
- keyboardRepository.setBacklight(BacklightModel(1, 5))
- assertThat(latest).isEqualTo(BacklightDialogContentViewModel(1, 5))
-
- advanceTimeBy(timeoutMillis * 2 / 3)
- // timeout yet to pass, no new emission
- keyboardRepository.setBacklight(BacklightModel(2, 5))
- assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
-
- advanceTimeBy(timeoutMillis * 2 / 3)
- // timeout refreshed because of last `setBacklight`, still content present
- assertThat(latest).isEqualTo(BacklightDialogContentViewModel(2, 5))
-
- advanceTimeBy(timeoutMillis * 2 / 3)
- // finally timeout reached and null emitted
- assertThat(latest).isNull()
- }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
index fd6e457..3bcefcf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/pipeline/MediaDataManagerTest.kt
@@ -716,6 +716,48 @@
}
@Test
+ fun testOnNotificationAdded_emptyMetadata_usesNotificationTitle() {
+ // When the app sets the metadata title fields to empty strings, but does include a
+ // non-blank notification title
+ val mockPackageManager = mock(PackageManager::class.java)
+ context.setMockPackageManager(mockPackageManager)
+ whenever(mockPackageManager.getApplicationLabel(any())).thenReturn(APP_NAME)
+ whenever(mediaFlags.isMediaTitleRequired(any(), any())).thenReturn(true)
+ whenever(controller.metadata)
+ .thenReturn(
+ metadataBuilder
+ .putString(MediaMetadata.METADATA_KEY_TITLE, SESSION_EMPTY_TITLE)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, SESSION_EMPTY_TITLE)
+ .build()
+ )
+ mediaNotification =
+ SbnBuilder().run {
+ setPkg(PACKAGE_NAME)
+ modifyNotification(context).also {
+ it.setSmallIcon(android.R.drawable.ic_media_pause)
+ it.setContentTitle(SESSION_TITLE)
+ it.setStyle(MediaStyle().apply { setMediaSession(session.sessionToken) })
+ }
+ build()
+ }
+ mediaDataManager.onNotificationAdded(KEY, mediaNotification)
+
+ // Then the media control is added using the notification's title
+ assertThat(backgroundExecutor.runAllReady()).isEqualTo(1)
+ assertThat(foregroundExecutor.runAllReady()).isEqualTo(1)
+ verify(listener)
+ .onMediaDataLoaded(
+ eq(KEY),
+ eq(null),
+ capture(mediaDataCaptor),
+ eq(true),
+ eq(0),
+ eq(false)
+ )
+ assertThat(mediaDataCaptor.value.song).isEqualTo(SESSION_TITLE)
+ }
+
+ @Test
fun testOnNotificationRemoved_emptyTitle_notConverted() {
// GIVEN that the manager has a notification with a resume action and empty title.
addNotificationAndLoad()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
index ba6f536..f030a03 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/MediaControlPanelTest.kt
@@ -230,7 +230,6 @@
FakeFeatureFlags().apply {
this.set(Flags.UMO_SURFACE_RIPPLE, false)
this.set(Flags.UMO_TURBULENCE_NOISE, false)
- this.set(Flags.MEDIA_FALSING_PENALTY, true)
this.set(Flags.MEDIA_EXPLICIT_INDICATOR, true)
this.set(Flags.MEDIA_RECOMMENDATION_CARD_UPDATE, false)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
index 3d55c51..6720dae 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelControllerBaseTest.java
@@ -321,4 +321,30 @@
assertThat(mController.shouldUseHorizontalLayout()).isFalse();
verify(mHorizontalLayoutListener).run();
}
+
+ @Test
+ public void changeTiles_callbackRemovedOnOldOnes() {
+ // Start with one tile
+ assertThat(mController.mRecords.size()).isEqualTo(1);
+ QSPanelControllerBase.TileRecord record = mController.mRecords.get(0);
+
+ assertThat(record.tile).isEqualTo(mQSTile);
+
+ // Change to a different tile
+ when(mQSHost.getTiles()).thenReturn(List.of(mOtherTile));
+ mController.setTiles();
+
+ verify(mQSTile).removeCallback(record.callback);
+ verify(mOtherTile, never()).removeCallback(any());
+ verify(mOtherTile, never()).removeCallbacks();
+ }
+
+ @Test
+ public void onViewDetached_removesJustTheAssociatedCallback() {
+ QSPanelControllerBase.TileRecord record = mController.mRecords.get(0);
+
+ mController.onViewDetached();
+ verify(mQSTile).removeCallback(record.callback);
+ verify(mQSTile, never()).removeCallbacks();
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
index 93cebe2..a60dad4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.kt
@@ -27,6 +27,8 @@
import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.plugins.qs.QSTile
+import com.android.systemui.plugins.qs.QSTileView
+import com.android.systemui.qs.QSPanelControllerBase.TileRecord
import com.android.systemui.qs.logging.QSLogger
import com.android.systemui.qs.tileimpl.QSIconViewImpl
import com.android.systemui.qs.tileimpl.QSTileViewImpl
@@ -192,6 +194,18 @@
verify(accessibilityInfo, never()).addAction(actionCollapse)
}
+ @Test
+ fun addTile_callbackAdded() {
+ val tile = mock(QSTile::class.java)
+ val tileView = mock(QSTileView::class.java)
+
+ val record = TileRecord(tile, tileView)
+
+ qsPanel.addTile(record)
+
+ verify(tile).addCallback(record.callback)
+ }
+
private infix fun View.isLeftOf(other: View): Boolean {
val rect = Rect()
getBoundsOnScreen(rect)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
index 7ecb4dc..426ff67 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/CurrentTilesInteractorImplTest.kt
@@ -589,6 +589,26 @@
.isTrue()
}
+ @Test
+ fun retainedTiles_callbackNotRemoved() =
+ testScope.runTest(USER_INFO_0) {
+ val tiles by collectLastValue(underTest.currentTiles)
+ tileSpecRepository.setTiles(USER_INFO_0.id, listOf(TileSpec.create("a")))
+
+ val tileA = tiles!![0].tile
+ val callback = mock<QSTile.Callback>()
+ tileA.addCallback(callback)
+
+ tileSpecRepository.setTiles(
+ USER_INFO_0.id,
+ listOf(TileSpec.create("a"), CUSTOM_TILE_SPEC)
+ )
+ val newTileA = tiles!![0].tile
+ assertThat(tileA).isSameInstanceAs(newTileA)
+
+ assertThat((tileA as FakeQSTile).callbacks).containsExactly(callback)
+ }
+
private fun QSTile.State.fillIn(state: Int, label: CharSequence, secondaryLabel: CharSequence) {
this.state = state
this.label = label
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.kt
index e509696..013c925 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/pipeline/domain/interactor/FakeQSTile.kt
@@ -29,6 +29,7 @@
private var tileSpec: String? = null
var destroyed = false
private val state = QSTile.State()
+ val callbacks = mutableListOf<QSTile.Callback>()
override fun getTileSpec(): String? {
return tileSpec
@@ -45,11 +46,17 @@
override fun refreshState() {}
- override fun addCallback(callback: QSTile.Callback?) {}
+ override fun addCallback(callback: QSTile.Callback) {
+ callbacks.add(callback)
+ }
- override fun removeCallback(callback: QSTile.Callback?) {}
+ override fun removeCallback(callback: QSTile.Callback) {
+ callbacks.remove(callback)
+ }
- override fun removeCallbacks() {}
+ override fun removeCallbacks() {
+ callbacks.clear()
+ }
override fun createTileView(context: Context?): QSIconView? {
return null
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
index 7c30843b..3def6ba 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java
@@ -46,6 +46,8 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -73,6 +75,8 @@
private Handler mHandler;
@Mock
private UserContextProvider mUserContextTracker;
+ @Captor
+ private ArgumentCaptor<Runnable> mRunnableCaptor;
private KeyguardDismissUtil mKeyguardDismissUtil = new KeyguardDismissUtil() {
public void executeWhenUnlocked(ActivityStarter.OnDismissAction action,
boolean requiresShadeOpen) {
@@ -209,4 +213,19 @@
verify(mScreenMediaRecorder).release();
}
+
+ @Test
+ public void testOnErrorSaving() throws IOException {
+ // When the screen recording does not save properly
+ doThrow(new IllegalStateException("fail")).when(mScreenMediaRecorder).save();
+
+ Intent startIntent = RecordingService.getStopIntent(mContext);
+ mRecordingService.onStartCommand(startIntent, 0, 0);
+ verify(mExecutor).execute(mRunnableCaptor.capture());
+ mRunnableCaptor.getValue().run();
+
+ // Then the state is set to not recording and we cancel the notification
+ verify(mController).updateState(false);
+ verify(mNotificationManager).cancelAsUser(any(), anyInt(), any());
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
index 13a2baa..487d26d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/HeadsUpManagerTest.java
@@ -114,6 +114,54 @@
}
@Test
+ public void testShouldHeadsUpBecomePinned_hasFSI_notUnpinned_true() {
+ // Set up NotifEntry with FSI
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+ notifEntry.getSbn().getNotification().fullScreenIntent = PendingIntent.getActivity(
+ getContext(), 0, new Intent(getContext(), this.getClass()),
+ PendingIntent.FLAG_MUTABLE_UNAUDITED);
+
+ // Add notifEntry to ANM mAlertEntries map and make it NOT unpinned
+ mHeadsUpManager.showNotification(notifEntry);
+ HeadsUpManager.HeadsUpEntry headsUpEntry =
+ mHeadsUpManager.getHeadsUpEntry(notifEntry.getKey());
+ headsUpEntry.wasUnpinned = false;
+
+ assertTrue(mHeadsUpManager.shouldHeadsUpBecomePinned(notifEntry));
+ }
+
+ @Test
+ public void testShouldHeadsUpBecomePinned_wasUnpinned_false() {
+ // Set up NotifEntry with FSI
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+ notifEntry.getSbn().getNotification().fullScreenIntent = PendingIntent.getActivity(
+ getContext(), 0, new Intent(getContext(), this.getClass()),
+ PendingIntent.FLAG_MUTABLE_UNAUDITED);
+
+ // Add notifEntry to ANM mAlertEntries map and make it unpinned
+ mHeadsUpManager.showNotification(notifEntry);
+ HeadsUpManager.HeadsUpEntry headsUpEntry =
+ mHeadsUpManager.getHeadsUpEntry(notifEntry.getKey());
+ headsUpEntry.wasUnpinned = true;
+
+ assertFalse(mHeadsUpManager.shouldHeadsUpBecomePinned(notifEntry));
+ }
+
+ @Test
+ public void testShouldHeadsUpBecomePinned_noFSI_false() {
+ // Set up NotifEntry with no FSI
+ NotificationEntry notifEntry = new NotificationEntryBuilder()
+ .setSbn(createNewNotification(/* id= */ 0))
+ .build();
+
+ assertFalse(mHeadsUpManager.shouldHeadsUpBecomePinned(notifEntry));
+ }
+
+ @Test
public void testShowNotification_autoDismissesWithAccessibilityTimeout() {
doReturn(TEST_A11Y_AUTO_DISMISS_TIME).when(mAccessibilityMgr)
.getRecommendedTimeoutMillis(anyInt(), anyInt());
diff --git a/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java
index fc5fb1a..a69e33a 100644
--- a/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/FillResponseEventLogger.java
@@ -26,6 +26,9 @@
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__AUTHENTICATION_TYPE_UNKNOWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__DATASET_AUTHENTICATION;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__AUTHENTICATION_TYPE__FULL_AUTHENTICATION;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__DIALOG;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__INLINE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__MENU;
@@ -40,6 +43,7 @@
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.os.SystemClock;
import android.service.autofill.Dataset;
import android.util.Slog;
import android.view.autofill.AutofillId;
@@ -57,6 +61,9 @@
public final class FillResponseEventLogger {
private static final String TAG = "FillResponseEventLogger";
+ private static final long UNINITIALIZED_TIMESTAMP = -1;
+ private long startResponseProcessingTimestamp = UNINITIALIZED_TIMESTAMP;
+
/**
* Reasons why presentation was not shown. These are wrappers around
* {@link com.android.os.AtomsProto.AutofillFillRequestReported.RequestTriggerReason}.
@@ -114,6 +121,20 @@
public @interface AuthenticationResult {
}
+
+ /**
+ * Reasons why presentation was not shown. These are wrappers around
+ * {@link com.android.os.AtomsProto.AutofillFillResponseReported.DetectionPreference}.
+ */
+ @IntDef(prefix = {"DETECTION_PREFER"}, value = {
+ DETECTION_PREFER_UNKNOWN,
+ DETECTION_PREFER_AUTOFILL_PROVIDER,
+ DETECTION_PREFER_PCC
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DetectionPreference {
+ }
+
public static final int DISPLAY_PRESENTATION_TYPE_UNKNOWN =
AUTOFILL_FILL_RESPONSE_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
public static final int DISPLAY_PRESENTATION_TYPE_MENU =
@@ -148,6 +169,15 @@
public static final int RESPONSE_STATUS_UNKNOWN =
AUTOFILL_FILL_RESPONSE_REPORTED__RESPONSE_STATUS__RESPONSE_STATUS_UNKNOWN;
+ // Values for AutofillFillResponseReported.detection_preference
+ public static final int DETECTION_PREFER_UNKNOWN =
+ AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
+ public static final int DETECTION_PREFER_AUTOFILL_PROVIDER =
+ AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
+ public static final int DETECTION_PREFER_PCC =
+ AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
+
+
// Log a magic number when FillRequest failed or timeout to differentiate with FillRequest
// succeeded.
public static final int AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT = -1;
@@ -221,15 +251,21 @@
public void maybeSetAvailableCount(int val) {
mEventInternal.ifPresent(event -> {
+ event.mAvailableCount = val;
+ });
+ }
+
+ public void maybeSetTotalDatasetsProvided(int val) {
+ mEventInternal.ifPresent(event -> {
// Don't reset if it's already populated.
// This is just a technical limitation of not having complicated logic.
// Autofill Provider may return some datasets which are applicable to data types.
// In such a case, we set available count to the number of datasets provided.
// However, it's possible that those data types aren't detected by PCC, so in effect, there
// are 0 datasets. In the codebase, we treat it as null response, which may call this again
- // to set 0. But we don't want to overwrite this value.
- if (event.mAvailableCount == 0) {
- event.mAvailableCount = val;
+ // to set 0. But we don't want to overwrite already set value.
+ if (event.mTotalDatasetsProvided == -1) {
+ event.mTotalDatasetsProvided = val;
}
});
}
@@ -321,12 +357,20 @@
});
}
+ public void startResponseProcessingTime() {
+ startResponseProcessingTimestamp = SystemClock.elapsedRealtime();
+ }
+
/**
* Set latency_response_processing_millis as long as mEventInternal presents.
*/
- public void maybeSetLatencyResponseProcessingMillis(int val) {
+ public void maybeSetLatencyResponseProcessingMillis() {
mEventInternal.ifPresent(event -> {
- event.mLatencyResponseProcessingMillis = val;
+ if (startResponseProcessingTimestamp == UNINITIALIZED_TIMESTAMP && sVerbose) {
+ Slog.v(TAG, "uninitialized startResponseProcessingTimestamp");
+ }
+ event.mLatencyResponseProcessingMillis
+ = SystemClock.elapsedRealtime() - startResponseProcessingTimestamp;
});
}
@@ -351,11 +395,13 @@
/**
* Set available_pcc_count.
*/
- public void maybeSetAvailableDatasetsPccCount(@Nullable List<Dataset> datasetList) {
+ public void maybeSetDatasetsCountAfterPotentialPccFiltering(@Nullable List<Dataset> datasetList) {
mEventInternal.ifPresent(event -> {
int pccOnlyCount = 0;
int pccCount = 0;
+ int totalCount = 0;
if (datasetList != null) {
+ totalCount = datasetList.size();
for (int i = 0; i < datasetList.size(); i++) {
Dataset dataset = datasetList.get(i);
if (dataset != null) {
@@ -371,9 +417,18 @@
}
event.mAvailablePccOnlyCount = pccOnlyCount;
event.mAvailablePccCount = pccCount;
+ event.mAvailableCount = totalCount;
});
}
+ /**
+ * Set detection_pref
+ */
+ public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) {
+ mEventInternal.ifPresent(event -> {
+ event.mDetectionPref = detectionPreference;
+ });
+ }
/**
* Log an AUTOFILL_FILL_RESPONSE_REPORTED event.
@@ -402,7 +457,9 @@
+ " mResponseStatus=" + event.mResponseStatus
+ " mLatencyResponseProcessingMillis=" + event.mLatencyResponseProcessingMillis
+ " mAvailablePccCount=" + event.mAvailablePccCount
- + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount);
+ + " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount
+ + " mTotalDatasetsProvided=" + event.mTotalDatasetsProvided
+ + " mDetectionPref=" + event.mDetectionPref);
}
FrameworkStatsLog.write(
AUTOFILL_FILL_RESPONSE_REPORTED,
@@ -421,7 +478,9 @@
event.mResponseStatus,
event.mLatencyResponseProcessingMillis,
event.mAvailablePccCount,
- event.mAvailablePccOnlyCount);
+ event.mAvailablePccOnlyCount,
+ event.mTotalDatasetsProvided,
+ event.mDetectionPref);
mEventInternal = Optional.empty();
}
@@ -431,16 +490,19 @@
int mDisplayPresentationType = DISPLAY_PRESENTATION_TYPE_UNKNOWN;
int mAvailableCount = 0;
int mSaveUiTriggerIds = -1;
- int mLatencyFillResponseReceivedMillis = 0;
+ int mLatencyFillResponseReceivedMillis = (int) UNINITIALIZED_TIMESTAMP;
int mAuthenticationType = AUTHENTICATION_TYPE_UNKNOWN;
int mAuthenticationResult = AUTHENTICATION_RESULT_UNKNOWN;
int mAuthenticationFailureReason = -1;
- int mLatencyAuthenticationUiDisplayMillis = 0;
- int mLatencyDatasetDisplayMillis = 0;
+ int mLatencyAuthenticationUiDisplayMillis = (int) UNINITIALIZED_TIMESTAMP;
+ int mLatencyDatasetDisplayMillis = (int) UNINITIALIZED_TIMESTAMP;
int mResponseStatus = RESPONSE_STATUS_UNKNOWN;
- int mLatencyResponseProcessingMillis = 0;
- int mAvailablePccCount;
- int mAvailablePccOnlyCount;
+ long mLatencyResponseProcessingMillis = UNINITIALIZED_TIMESTAMP;
+ int mAvailablePccCount = -1;
+ int mAvailablePccOnlyCount = -1;
+ int mTotalDatasetsProvided = -1;
+ @DetectionPreference
+ int mDetectionPref = DETECTION_PREFER_UNKNOWN;
FillResponseEventInternal() {
}
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index b2f9a93..11b45db 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -16,8 +16,6 @@
package com.android.server.autofill;
-import static android.service.autofill.Dataset.PICK_REASON_PCC_DETECTION_ONLY;
-import static android.service.autofill.Dataset.PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_DIALOG;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_INLINE;
import static android.service.autofill.FillEventHistory.Event.UI_TYPE_MENU;
@@ -27,6 +25,9 @@
import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_CLICKED;
import static android.view.autofill.AutofillManager.COMMIT_REASON_VIEW_COMMITTED;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
+import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_FAILURE;
import static com.android.internal.util.FrameworkStatsLog.AUTOFILL_PRESENTATION_EVENT_REPORTED__AUTHENTICATION_RESULT__AUTHENTICATION_RESULT_UNKNOWN;
@@ -140,6 +141,19 @@
@Retention(RetentionPolicy.SOURCE)
public @interface DatasetPickedReason {}
+ /**
+ * The type of detection that was preferred. These are wrappers around
+ * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.DetectionPreference}.
+ */
+ @IntDef(prefix = {"DETECTION_PREFER"}, value = {
+ DETECTION_PREFER_UNKNOWN,
+ DETECTION_PREFER_AUTOFILL_PROVIDER,
+ DETECTION_PREFER_PCC
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface DetectionPreference {
+ }
+
public static final int NOT_SHOWN_REASON_ANY_SHOWN =
AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED =
@@ -187,6 +201,15 @@
AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_ONLY;
public static final int PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER =
AUTOFILL_PRESENTATION_EVENT_REPORTED__SELECTED_DATASET_PICKED_REASON__PICK_REASON_PCC_DETECTION_PREFERRED_WITH_PROVIDER;
+
+
+ // Values for AutofillFillResponseReported.detection_preference
+ public static final int DETECTION_PREFER_UNKNOWN =
+ AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_UNKONWN;
+ public static final int DETECTION_PREFER_AUTOFILL_PROVIDER =
+ AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_AUTOFILL_PROVIDER;
+ public static final int DETECTION_PREFER_PCC =
+ AUTOFILL_FILL_RESPONSE_REPORTED__DETECTION_PREFERENCE__DETECTION_PREFER_PCC;
private final int mSessionId;
private Optional<PresentationStatsEventInternal> mEventInternal;
@@ -463,6 +486,15 @@
});
}
+ /**
+ * Set detection_pref
+ */
+ public void maybeSetDetectionPreference(@DetectionPreference int detectionPreference) {
+ mEventInternal.ifPresent(event -> {
+ event.mDetectionPreference = detectionPreference;
+ });
+ }
+
private int convertDatasetPickReason(@Dataset.DatasetEligibleReason int val) {
switch (val) {
case 0:
@@ -514,7 +546,8 @@
+ " mLatencyDatasetDisplayMillis=" + event.mLatencyDatasetDisplayMillis
+ " mAvailablePccCount=" + event.mAvailablePccCount
+ " mAvailablePccOnlyCount=" + event.mAvailablePccOnlyCount
- + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason);
+ + " mSelectedDatasetPickedReason=" + event.mSelectedDatasetPickedReason
+ + " mDetectionPreference=" + event.mDetectionPreference);
}
// TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
@@ -550,7 +583,8 @@
event.mLatencyDatasetDisplayMillis,
event.mAvailablePccCount,
event.mAvailablePccOnlyCount,
- event.mSelectedDatasetPickedReason);
+ event.mSelectedDatasetPickedReason,
+ event.mDetectionPreference);
mEventInternal = Optional.empty();
}
@@ -582,6 +616,7 @@
int mAvailablePccCount = -1;
int mAvailablePccOnlyCount = -1;
@DatasetPickedReason int mSelectedDatasetPickedReason = PICK_REASON_UNKNOWN;
+ @DetectionPreference int mDetectionPreference = DETECTION_PREFER_UNKNOWN;
PresentationStatsEventInternal() {}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 5d6eab7..0a8f474 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -52,6 +52,9 @@
import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_PRE_TRIGGER;
import static com.android.server.autofill.FillRequestEventLogger.TRIGGER_REASON_SERVED_FROM_CACHED_RESPONSE;
import static com.android.server.autofill.FillResponseEventLogger.AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT;
+import static com.android.server.autofill.FillResponseEventLogger.DETECTION_PREFER_AUTOFILL_PROVIDER;
+import static com.android.server.autofill.FillResponseEventLogger.DETECTION_PREFER_UNKNOWN;
+import static com.android.server.autofill.FillResponseEventLogger.DETECTION_PREFER_PCC;
import static com.android.server.autofill.FillResponseEventLogger.HAVE_SAVE_TRIGGER_ID;
import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_FAILURE;
import static com.android.server.autofill.FillResponseEventLogger.RESPONSE_STATUS_SESSION_DESTROYED;
@@ -1460,6 +1463,7 @@
mFillResponseEventLogger.maybeSetRequestId(requestId);
mFillResponseEventLogger.maybeSetAppPackageUid(uid);
mFillResponseEventLogger.maybeSetResponseStatus(RESPONSE_STATUS_SUCCESS);
+ mFillResponseEventLogger.startResponseProcessingTime();
// Time passed since session was created
final long fillRequestReceivedRelativeTimestamp =
SystemClock.elapsedRealtime() - mLatencyBaseTime;
@@ -1467,6 +1471,7 @@
(int) (fillRequestReceivedRelativeTimestamp));
mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
(int) (fillRequestReceivedRelativeTimestamp));
+ mFillResponseEventLogger.maybeSetDetectionPreference(getDetectionPreferenceForLogging());
synchronized (mLock) {
if (mDestroyed) {
@@ -1485,6 +1490,7 @@
Slog.w(TAG, "onFillRequestSuccess(): no request log for id " + requestId);
}
if (response == null) {
+ mFillResponseEventLogger.maybeSetTotalDatasetsProvided(0);
if (requestLog != null) {
requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
}
@@ -1584,13 +1590,16 @@
}
}
- mFillResponseEventLogger.maybeSetAvailableCount(
- datasetList == null ? 0 : datasetList.size());
+ int datasetCount = (datasetList == null) ? 0 : datasetList.size();
+ mFillResponseEventLogger.maybeSetTotalDatasetsProvided(datasetCount);
+ // It's possible that this maybe overwritten later on after PCC filtering.
+ mFillResponseEventLogger.maybeSetAvailableCount(datasetCount);
// TODO(b/266379948): Ideally wait for PCC request to finish for a while more
// (say 100ms) before proceeding further on.
processResponseLockedForPcc(response, response.getClientState(), requestFlags);
+ mFillResponseEventLogger.maybeSetLatencyResponseProcessingMillis();
}
@@ -1993,7 +2002,7 @@
null,
dataset.getId(),
dataset.getAuthentication());
- dataset.setEligibleReasonReason(pickReason);
+ newDataset.setEligibleReasonReason(pickReason);
eligibleDatasets.add(newDataset);
Set<Dataset> newDatasets;
for (AutofillId autofillId : datasetAutofillIds) {
@@ -2036,7 +2045,10 @@
mFillResponseEventLogger.maybeSetRequestId(requestId);
mFillResponseEventLogger.maybeSetAppPackageUid(uid);
mFillResponseEventLogger.maybeSetAvailableCount(
- AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
+ AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
+ mFillResponseEventLogger.maybeSetTotalDatasetsProvided(
+ AVAILABLE_COUNT_WHEN_FILL_REQUEST_FAILED_OR_TIMEOUT);
+ mFillResponseEventLogger.maybeSetDetectionPreference(getDetectionPreferenceForLogging());
final long fillRequestReceivedRelativeTimestamp =
SystemClock.elapsedRealtime() - mLatencyBaseTime;
mFillResponseEventLogger.maybeSetLatencyFillResponseReceivedMillis(
@@ -3887,8 +3899,7 @@
// View is triggering autofill.
mCurrentViewId = viewState.id;
viewState.update(value, virtualBounds, flags);
- mPresentationStatsEventLogger.startNewEvent();
- mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
+ startNewEventForPresentationStatsEventLogger();
mPresentationStatsEventLogger.maybeSetIsNewRequest(true);
if (!isRequestSupportFillDialog(flags)) {
mSessionFlags.mFillDialogDisabled = true;
@@ -4021,9 +4032,7 @@
}
// If previous request was FillDialog request, a logger event was already started
if (!wasPreviouslyFillDialog) {
- mPresentationStatsEventLogger.startNewEvent();
- mPresentationStatsEventLogger.maybeSetAutofillServiceUid(
- getAutofillServiceUid());
+ startNewEventForPresentationStatsEventLogger();
}
if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
// If a new request was issued even if previously it was fill dialog request,
@@ -4032,9 +4041,7 @@
// lock guarded, we should be safe.
if (wasPreviouslyFillDialog) {
mPresentationStatsEventLogger.logAndEndEvent();
- mPresentationStatsEventLogger.startNewEvent();
- mPresentationStatsEventLogger.maybeSetAutofillServiceUid(
- getAutofillServiceUid());
+ startNewEventForPresentationStatsEventLogger();
}
return;
}
@@ -4966,7 +4973,7 @@
List<Dataset> datasetList = newResponse.getDatasets();
mPresentationStatsEventLogger.maybeSetAvailableCount(datasetList, mCurrentViewId);
- mFillResponseEventLogger.maybeSetAvailableDatasetsPccCount(datasetList);
+ mFillResponseEventLogger.maybeSetDatasetsCountAfterPotentialPccFiltering(datasetList);
setViewStatesLocked(newResponse, ViewState.STATE_FILLABLE, false);
updateFillDialogTriggerIdsLocked();
@@ -5154,6 +5161,25 @@
};
}
+ private int getDetectionPreferenceForLogging() {
+ if (mService.isPccClassificationEnabled()) {
+ if (mService.getMaster().preferProviderOverPcc()) {
+ return DETECTION_PREFER_AUTOFILL_PROVIDER;
+ }
+ return DETECTION_PREFER_PCC;
+ }
+ return DETECTION_PREFER_UNKNOWN;
+ }
+
+ private void startNewEventForPresentationStatsEventLogger() {
+ synchronized (mLock) {
+ mPresentationStatsEventLogger.startNewEvent();
+ mPresentationStatsEventLogger.maybeSetDetectionPreference(
+ getDetectionPreferenceForLogging());
+ mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
+ }
+ }
+
private void startAuthentication(int authenticationId, IntentSender intent,
Intent fillInIntent, boolean authenticateInline) {
try {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ca4a253..3d02c96 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17236,12 +17236,6 @@
}
}
- void onProcessFreezableChangedLocked(ProcessRecord app) {
- if (mEnableModernQueue) {
- mBroadcastQueues[0].onProcessFreezableChangedLocked(app);
- }
- }
-
@VisibleForTesting
public final class LocalService extends ActivityManagerInternal
implements ActivityManagerLocal {
@@ -18347,16 +18341,17 @@
@Override
public boolean hasRunningForegroundService(int uid, int foregroundServicetype) {
synchronized (ActivityManagerService.this) {
- return mProcessList.searchEachLruProcessesLOSP(true, app -> {
- if (app.uid != uid) {
- return null;
- }
-
+ final UidRecord uidRec = mProcessList.mActiveUids.get(uid);
+ if (uidRec == null) {
+ return false;
+ }
+ for (int i = uidRec.getNumOfProcs() - 1; i >= 0; i--) {
+ final ProcessRecord app = uidRec.getProcessRecordByIndex(i);
if ((app.mServices.containsAnyForegroundServiceTypes(foregroundServicetype))) {
- return Boolean.TRUE;
+ return true;
}
- return null;
- }) != null;
+ }
+ return false;
}
}
@@ -19043,8 +19038,11 @@
long delayedDurationMs) {
Objects.requireNonNull(targetPackage);
Preconditions.checkArgumentNonnegative(delayedDurationMs);
- Preconditions.checkState(mEnableModernQueue, "Not valid in legacy queue");
enforceCallingPermission(permission.DUMP, "forceDelayBroadcastDelivery()");
+ // Ignore request if modern queue is not enabled
+ if (!mEnableModernQueue) {
+ return;
+ }
for (BroadcastQueue queue : mBroadcastQueues) {
queue.forceDelayBroadcastDelivery(targetPackage, delayedDurationMs);
diff --git a/services/core/java/com/android/server/am/BroadcastProcessQueue.java b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
index 142a5dc..3ac2b2b 100644
--- a/services/core/java/com/android/server/am/BroadcastProcessQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastProcessQueue.java
@@ -201,7 +201,7 @@
private boolean mLastDeferredStates;
private boolean mUidForeground;
- private boolean mProcessFreezable;
+ private boolean mUidCached;
private boolean mProcessInstrumented;
private boolean mProcessPersistent;
@@ -411,7 +411,7 @@
*/
@CheckResult
public boolean setProcessAndUidState(@Nullable ProcessRecord app, boolean uidForeground,
- boolean processFreezable) {
+ boolean uidCached) {
this.app = app;
// Since we may have just changed our PID, invalidate cached strings
@@ -420,13 +420,13 @@
boolean didSomething = false;
if (app != null) {
+ didSomething |= setUidCached(uidCached);
didSomething |= setUidForeground(uidForeground);
- didSomething |= setProcessFreezable(processFreezable);
didSomething |= setProcessInstrumented(app.getActiveInstrumentation() != null);
didSomething |= setProcessPersistent(app.isPersistent());
} else {
+ didSomething |= setUidCached(uidCached);
didSomething |= setUidForeground(false);
- didSomething |= setProcessFreezable(false);
didSomething |= setProcessInstrumented(false);
didSomething |= setProcessPersistent(false);
}
@@ -450,13 +450,13 @@
}
/**
- * Update if this process is in the "freezable" state, typically signaling that
+ * Update if this process is in the "cached" state, typically signaling that
* broadcast dispatch should be paused or delayed.
*/
@CheckResult
- private boolean setProcessFreezable(boolean freezable) {
- if (mProcessFreezable != freezable) {
- mProcessFreezable = freezable;
+ private boolean setUidCached(boolean uidCached) {
+ if (mUidCached != uidCached) {
+ mUidCached = uidCached;
invalidateRunnableAt();
return true;
} else {
@@ -1115,7 +1115,7 @@
} else if (mCountManifest > 0) {
mRunnableAt = runnableAt;
mRunnableAtReason = REASON_CONTAINS_MANIFEST;
- } else if (mProcessFreezable) {
+ } else if (mUidCached) {
if (r.deferUntilActive) {
// All enqueued broadcasts are deferrable, defer
if (mCountDeferred == mCountEnqueued) {
@@ -1185,7 +1185,7 @@
// When all we have pending is deferred broadcasts, and we're cached,
// then we want everything to be marked deferred
final boolean wantDeferredStates = (mCountDeferred > 0)
- && (mCountDeferred == mCountEnqueued) && mProcessFreezable;
+ && (mCountDeferred == mCountEnqueued) && mUidCached;
if (mLastDeferredStates != wantDeferredStates) {
mLastDeferredStates = wantDeferredStates;
@@ -1372,9 +1372,9 @@
if (mUidForeground) {
sb.append("FG");
}
- if (mProcessFreezable) {
+ if (mUidCached) {
if (sb.length() > 0) sb.append("|");
- sb.append("FRZN");
+ sb.append("CACHED");
}
if (mProcessInstrumented) {
if (sb.length() > 0) sb.append("|");
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 93bde6f..8e76e5b 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -173,13 +173,6 @@
public abstract void onApplicationCleanupLocked(@NonNull ProcessRecord app);
/**
- * Signal from OS internals that the given process is in a freezable state and will be
- * freezed soon after.
- */
- @GuardedBy("mService")
- public abstract void onProcessFreezableChangedLocked(@NonNull ProcessRecord app);
-
- /**
* Signal from OS internals that the given package (or some subset of that
* package) has been disabled or uninstalled, and that any pending
* broadcasts should be cleaned up.
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index ce635f1..e389821 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -18,6 +18,7 @@
import static android.app.ActivityManager.RESTRICTION_LEVEL_RESTRICTED_BUCKET;
import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_START_RECEIVER;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_APP_FREEZING_DELAYED;
import static android.os.Process.ZYGOTE_POLICY_FLAG_EMPTY;
import static android.os.Process.ZYGOTE_POLICY_FLAG_LATENCY_SENSITIVE;
import static android.text.TextUtils.formatSimple;
@@ -384,6 +385,16 @@
maybeReportBroadcastDispatchedEventLocked(r, r.curReceiver.applicationInfo.uid);
r.intent.setComponent(r.curComponent);
+ // See if we need to delay the freezer based on BroadcastOptions
+ if (r.options != null
+ && r.options.getTemporaryAppAllowlistDuration() > 0
+ && r.options.getTemporaryAppAllowlistType()
+ == TEMPORARY_ALLOW_LIST_TYPE_APP_FREEZING_DELAYED) {
+ mService.mOomAdjuster.mCachedAppOptimizer.unfreezeTemporarily(app,
+ CachedAppOptimizer.UNFREEZE_REASON_START_RECEIVER,
+ r.options.getTemporaryAppAllowlistDuration());
+ }
+
boolean started = false;
try {
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
@@ -449,10 +460,6 @@
skipCurrentOrPendingReceiverLocked(app);
}
- public void onProcessFreezableChangedLocked(ProcessRecord app) {
- // Not supported; ignore
- }
-
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
final BroadcastRecord br = mPendingBroadcast;
@@ -934,8 +941,13 @@
Slog.v(TAG, "Broadcast temp allowlist uid=" + uid + " duration=" + duration
+ " type=" + type + " : " + b.toString());
}
- mService.tempAllowlistUidLocked(uid, duration, reasonCode, b.toString(), type,
- r.callingUid);
+
+ // Only add to temp allowlist if it's not the APP_FREEZING_DELAYED type. That will be
+ // handled when the broadcast is actually being scheduled on the app thread.
+ if (type != TEMPORARY_ALLOW_LIST_TYPE_APP_FREEZING_DELAYED) {
+ mService.tempAllowlistUidLocked(uid, duration, reasonCode, b.toString(), type,
+ r.callingUid);
+ }
}
private void processNextBroadcast(boolean fromMsg) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
index 331efaa..d6e692c 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueModernImpl.java
@@ -223,6 +223,16 @@
@GuardedBy("mService")
private final SparseBooleanArray mUidForeground = new SparseBooleanArray();
+ /**
+ * Map from UID to its last known "cached" state.
+ * <p>
+ * We manually maintain this data structure since the lifecycle of
+ * {@link ProcessRecord} and {@link BroadcastProcessQueue} can be
+ * mismatched.
+ */
+ @GuardedBy("mService")
+ private final SparseBooleanArray mUidCached = new SparseBooleanArray();
+
private final BroadcastConstants mConstants;
private final BroadcastConstants mFgConstants;
private final BroadcastConstants mBgConstants;
@@ -565,13 +575,6 @@
}
@Override
- public void onProcessFreezableChangedLocked(@NonNull ProcessRecord app) {
- synchronized (mService) {
- refreshProcessQueueLocked(app);
- }
- }
-
- @Override
public int getPreferredSchedulingGroupLocked(@NonNull ProcessRecord app) {
final BroadcastProcessQueue queue = getProcessQueue(app);
if ((queue != null) && getRunningIndexOf(queue) >= 0) {
@@ -1302,6 +1305,7 @@
};
broadcastPredicate = BROADCAST_PREDICATE_ANY;
+ cleanupUserStateLocked(mUidCached, userId);
cleanupUserStateLocked(mUidForeground, userId);
}
return forEachMatchingBroadcast(queuePredicate, broadcastPredicate,
@@ -1444,7 +1448,20 @@
refreshProcessQueuesLocked(uid);
}
}
- }, ActivityManager.UID_OBSERVER_PROCSTATE, ActivityManager.PROCESS_STATE_TOP, "android");
+
+ @Override
+ public void onUidCachedChanged(int uid, boolean cached) {
+ synchronized (mService) {
+ if (cached) {
+ mUidCached.put(uid, true);
+ } else {
+ mUidCached.delete(uid);
+ }
+ refreshProcessQueuesLocked(uid);
+ }
+ }
+ }, ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CACHED,
+ ActivityManager.PROCESS_STATE_TOP, "android");
// Kick off periodic health checks
mLocalHandler.sendEmptyMessage(MSG_CHECK_HEALTH);
@@ -1633,9 +1650,10 @@
// warm via this operation, we're going to immediately promote it to
// be running, and any side effect of this operation will then apply
// after it's finished and is returned to the runnable list.
- final ProcessRecord app = mService.getProcessRecordLocked(queue.processName, queue.uid);
- queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
- isProcessFreezable(app));
+ queue.setProcessAndUidState(
+ mService.getProcessRecordLocked(queue.processName, queue.uid),
+ mUidForeground.get(queue.uid, false),
+ mUidCached.get(queue.uid, false));
}
}
@@ -1647,21 +1665,11 @@
private void setQueueProcess(@NonNull BroadcastProcessQueue queue,
@Nullable ProcessRecord app) {
if (queue.setProcessAndUidState(app, mUidForeground.get(queue.uid, false),
- isProcessFreezable(app))) {
+ mUidCached.get(queue.uid, false))) {
updateRunnableList(queue);
}
}
- @GuardedBy("mService")
- private boolean isProcessFreezable(@Nullable ProcessRecord app) {
- if (app == null) {
- return false;
- }
- synchronized (mService.mProcLock) {
- return app.mOptRecord.isPendingFreeze() || app.mOptRecord.isFrozen();
- }
- }
-
/**
* Refresh the process queues with the latest process state so that runnableAt
* can be updated.
@@ -1679,20 +1687,6 @@
}
/**
- * Refresh the process queue corresponding to {@code app} with the latest process state
- * so that runnableAt can be updated.
- */
- @GuardedBy("mService")
- private void refreshProcessQueueLocked(@NonNull ProcessRecord app) {
- final BroadcastProcessQueue queue = getProcessQueue(app.processName, app.uid);
- if (queue == null || queue.app == null || queue.app.getPid() != app.getPid()) {
- return;
- }
- setQueueProcess(queue, queue.app);
- enqueueUpdateRunningList();
- }
-
- /**
* Inform other parts of OS that the given broadcast queue has started
* running, typically for internal bookkeeping.
*/
@@ -2011,6 +2005,12 @@
ipw.decreaseIndent();
ipw.println();
+ ipw.println("Cached UIDs:");
+ ipw.increaseIndent();
+ ipw.println(mUidCached);
+ ipw.decreaseIndent();
+ ipw.println();
+
ipw.println("Foreground UIDs:");
ipw.increaseIndent();
ipw.println(mUidForeground);
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index e5a1759..7773190 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -300,7 +300,6 @@
static final int COMPACT_NATIVE_MSG = 5;
static final int UID_FROZEN_STATE_CHANGED_MSG = 6;
static final int DEADLOCK_WATCHDOG_MSG = 7;
- static final int REPORT_PROCESS_FREEZABLE_CHANGED = 8;
// When free swap falls below this percentage threshold any full (file + anon)
// compactions will be downgraded to file only compactions to reduce pressure
@@ -1353,7 +1352,6 @@
}
}
}
- postProcessFreezableChangedMessage(app);
mFreezeHandler.sendMessageDelayed(
mFreezeHandler.obtainMessage(SET_FROZEN_PROCESS_MSG, DO_FREEZE, 0, app),
delayMillis);
@@ -1391,7 +1389,6 @@
uidRec.setFrozen(false);
postUidFrozenMessage(uidRec.getUid(), false);
}
- postProcessFreezableChangedMessage(app);
opt.setFreezerOverride(false);
if (pid == 0 || !opt.isFrozen()) {
@@ -2069,21 +2066,6 @@
0, uidObj));
}
- private void reportProcessFreezableChanged(ProcessRecord app) {
- synchronized (mAm) {
- mAm.onProcessFreezableChangedLocked(app);
- }
- }
-
- @GuardedBy("mAm")
- private void postProcessFreezableChangedMessage(ProcessRecord app) {
- if (app.getPid() == 0) {
- return;
- }
- mFreezeHandler.obtainMessage(REPORT_PROCESS_FREEZABLE_CHANGED, 0, 0, app)
- .sendToTarget();
- }
-
private final class FreezeHandler extends Handler implements
ProcLocksReader.ProcLocksReaderCallback {
private FreezeHandler() {
@@ -2093,7 +2075,7 @@
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case SET_FROZEN_PROCESS_MSG: {
+ case SET_FROZEN_PROCESS_MSG:
ProcessRecord proc = (ProcessRecord) msg.obj;
synchronized (mAm) {
freezeProcess(proc);
@@ -2103,8 +2085,8 @@
removeMessages(DEADLOCK_WATCHDOG_MSG);
sendEmptyMessageDelayed(DEADLOCK_WATCHDOG_MSG, FREEZE_DEADLOCK_TIMEOUT_MS);
}
- } break;
- case REPORT_UNFREEZE_MSG: {
+ break;
+ case REPORT_UNFREEZE_MSG:
int pid = msg.arg1;
int frozenDuration = msg.arg2;
Pair<String, Integer> obj = (Pair<String, Integer>) msg.obj;
@@ -2112,13 +2094,13 @@
int reason = obj.second;
reportUnfreeze(pid, frozenDuration, processName, reason);
- } break;
- case UID_FROZEN_STATE_CHANGED_MSG: {
+ break;
+ case UID_FROZEN_STATE_CHANGED_MSG:
final boolean frozen = (msg.arg1 == 1);
final int uid = (int) msg.obj;
reportOneUidFrozenStateChanged(uid, frozen);
- } break;
- case DEADLOCK_WATCHDOG_MSG: {
+ break;
+ case DEADLOCK_WATCHDOG_MSG:
try {
// post-check to prevent deadlock
if (DEBUG_FREEZER) {
@@ -2128,11 +2110,7 @@
} catch (IOException e) {
Slog.w(TAG_AM, "Unable to check file locks");
}
- } break;
- case REPORT_PROCESS_FREEZABLE_CHANGED: {
- final ProcessRecord app = (ProcessRecord) msg.obj;
- reportProcessFreezableChanged(app);
- } break;
+ break;
default:
return;
}
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 844f175..7482e64 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -97,10 +97,6 @@
sGlobalSettingToTypeMap.put(
Settings.Global.ANGLE_EGL_FEATURES, String.class);
sGlobalSettingToTypeMap.put(
- Settings.Global.ANGLE_DEFERLIST, String.class);
- sGlobalSettingToTypeMap.put(
- Settings.Global.ANGLE_DEFERLIST_MODE, String.class);
- sGlobalSettingToTypeMap.put(
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
sGlobalSettingToTypeMap.put(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, int.class);
sGlobalSettingToTypeMap.put(Settings.Global.GPU_DEBUG_APP, String.class);
diff --git a/services/core/java/com/android/server/am/DropboxRateLimiter.java b/services/core/java/com/android/server/am/DropboxRateLimiter.java
index 727d4df9..b5c7215 100644
--- a/services/core/java/com/android/server/am/DropboxRateLimiter.java
+++ b/services/core/java/com/android/server/am/DropboxRateLimiter.java
@@ -40,7 +40,7 @@
// If a process is rate limited twice in a row we consider it crash-looping and rate limit it
// more aggressively.
private static final int STRICT_RATE_LIMIT_ALLOWED_ENTRIES = 1;
- private static final long STRICT_RATE_LIMIT_BUFFER_DURATION = 60 * DateUtils.MINUTE_IN_MILLIS;
+ private static final long STRICT_RATE_LIMIT_BUFFER_DURATION = 20 * DateUtils.MINUTE_IN_MILLIS;
@GuardedBy("mErrorClusterRecords")
private final ArrayMap<String, ErrorRecord> mErrorClusterRecords = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index cb26c13..ab4fb46 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -42,6 +42,7 @@
import android.os.IBinder;
import android.os.PowerWhitelistManager;
import android.os.PowerWhitelistManager.ReasonCode;
+import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.TransactionTooLargeException;
@@ -382,6 +383,14 @@
})
public static BackgroundStartPrivileges getDefaultBackgroundStartPrivileges(
int callingUid) {
+ if (UserHandle.getAppId(callingUid) == Process.SYSTEM_UID) {
+ // We temporarily allow BAL for system processes, while we verify that all valid use
+ // cases are opted in explicitly to grant their BAL permission.
+ // Background: In many cases devices are running additional apps that share UID with
+ // the system. If one of these apps targets a lower SDK the change is not active, but
+ // as soon as that app is upgraded (or removed) BAL would be blocked. (b/283138430)
+ return BackgroundStartPrivileges.ALLOW_BAL;
+ }
boolean isChangeEnabledForApp = CompatChanges.isChangeEnabled(
DEFAULT_RESCIND_BAL_PRIVILEGES_FROM_PENDING_INTENT_SENDER, callingUid);
if (isChangeEnabledForApp) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 9b1149a..335d676 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1192,9 +1192,6 @@
"Killing " + toShortString() + " (adj " + mState.getSetAdj()
+ "): " + reason, info.uid);
}
- // Since the process is getting killed, reset the freezable related state.
- mOptRecord.setPendingFreeze(false);
- mOptRecord.setFrozen(false);
if (mPid > 0) {
mService.mProcessList.noteAppKill(this, reasonCode, subReason, description);
EventLog.writeEvent(EventLogTags.AM_KILL,
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 334c145..12bb5d2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -3567,6 +3567,8 @@
if (mUserSwitchingDialog != null) {
mUserSwitchingDialog.dismiss(onDismissed);
mUserSwitchingDialog = null;
+ } else if (onDismissed != null) {
+ onDismissed.run();
}
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
index 055c63d..46c77e8 100644
--- a/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/AcquisitionClient.java
@@ -206,17 +206,6 @@
}
}
- protected final void vibrateError() {
- Vibrator vibrator = getContext().getSystemService(Vibrator.class);
- if (vibrator != null && mShouldVibrate) {
- vibrator.vibrate(Process.myUid(),
- getContext().getOpPackageName(),
- ERROR_VIBRATION_EFFECT,
- getClass().getSimpleName() + "::error",
- HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES);
- }
- }
-
@Override
public boolean isInterruptable() {
return true;
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index 9dc1782..a529fb9 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -72,7 +72,7 @@
boolean isStrongBiometric, SensorPrivacyManager sensorPrivacyManager) {
super(context, lazyDaemon, token, listener, options.getUserId(),
options.getOpPackageName(), 0 /* cookie */, options.getSensorId(),
- true /* shouldVibrate */, logger, biometricContext);
+ false /* shouldVibrate */, logger, biometricContext);
setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
mSensorPrivacyManager = sensorPrivacyManager;
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 38631c8..a97126c 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -232,7 +232,10 @@
return;
}
- if ((serviceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION) != 0) {
+ if (mActivityManagerInternal.hasRunningForegroundService(
+ uid, ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION)) {
+ // If there is any process within this UID running a FGS
+ // with the mediaProjection type, that's Okay.
return;
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
index cd457b7..feb75ef 100644
--- a/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
+++ b/services/core/java/com/android/server/notification/NotificationRecordLoggerImpl.java
@@ -74,7 +74,8 @@
notificationReported.is_ongoing,
notificationReported.is_foreground_service,
notificationReported.timeout_millis,
- notificationReported.is_non_dismissible);
+ notificationReported.is_non_dismissible,
+ notificationReported.post_duration_millis);
}
@Override
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index 0bb05aa..1b34c70 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -231,6 +231,14 @@
return;
}
+ // the installers without INSTALL_PACKAGES perm can't perform
+ // the installation in background. So we can just filter out them.
+ if (mPermissionManager.checkPermission(installerPackageName,
+ android.Manifest.permission.INSTALL_PACKAGES,
+ userId) != PackageManager.PERMISSION_GRANTED) {
+ return;
+ }
+
// convert up-time to current time.
final long installTimestamp = System.currentTimeMillis()
- (SystemClock.uptimeMillis() - appInfo.createTimestamp);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ae520c0..bba8043 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -279,6 +279,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@@ -6295,6 +6296,36 @@
}
}
+ /**
+ * Wait for the handler to finish handling all pending messages.
+ * @param timeoutMillis Maximum time in milliseconds to wait.
+ * @param forBackgroundHandler Whether to wait for the background handler instead.
+ * @return True if all the waiting messages in the handler has been handled.
+ * False if timeout.
+ */
+ @Override
+ public boolean waitForHandler(long timeoutMillis, boolean forBackgroundHandler) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ if (forBackgroundHandler) {
+ mBackgroundHandler.post(latch::countDown);
+ } else {
+ mHandler.post(latch::countDown);
+ }
+ final long endTimeMillis = System.currentTimeMillis() + timeoutMillis;
+ while (latch.getCount() > 0) {
+ try {
+ final long remainingTimeMillis = endTimeMillis - System.currentTimeMillis();
+ if (remainingTimeMillis <= 0) {
+ return false;
+ }
+ return latch.await(remainingTimeMillis, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // ignore and retry
+ }
+ }
+ return true;
+ }
+
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 05bfec4..e1f010f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -354,6 +354,10 @@
return runSetSilentUpdatesPolicy();
case "get-app-metadata":
return runGetAppMetadata();
+ case "wait-for-handler":
+ return runWaitForHandler(/* forBackgroundHandler= */ false);
+ case "wait-for-background-handler":
+ return runWaitForHandler(/* forBackgroundHandler= */ true);
default: {
if (ART_SERVICE_COMMANDS.contains(cmd)) {
if (DexOptHelper.useArtService()) {
@@ -3601,6 +3605,40 @@
return 1;
}
+ private int runWaitForHandler(boolean forBackgroundHandler) {
+ final PrintWriter pw = getOutPrintWriter();
+ long timeoutMillis = 60000; // default timeout is 60 seconds
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--timeout":
+ timeoutMillis = Long.parseLong(getNextArgRequired());
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+ if (timeoutMillis <= 0) {
+ pw.println("Error: --timeout value must be positive: " + timeoutMillis);
+ return -1;
+ }
+ final boolean success;
+ try {
+ success = mInterface.waitForHandler(timeoutMillis, forBackgroundHandler);
+ } catch (RemoteException e) {
+ pw.println("Failure [" + e.getClass().getName() + " - " + e.getMessage() + "]");
+ return -1;
+ }
+ if (success) {
+ pw.println("Success");
+ return 0;
+ } else {
+ pw.println("Timeout. PackageManager handlers are still busy.");
+ return -1;
+ }
+ }
+
private int runArtServiceCommand() {
try (var in = ParcelFileDescriptor.dup(getInFileDescriptor());
var out = ParcelFileDescriptor.dup(getOutFileDescriptor());
@@ -4427,6 +4465,18 @@
pw.println(" --reset: restore the installer and throttle time to the default, and");
pw.println(" clear tracks of silent updates in the system.");
pw.println("");
+ pw.println(" wait-for-handler --timeout <MILLIS>");
+ pw.println(" Wait for a given amount of time till the package manager handler finishes");
+ pw.println(" handling all pending messages.");
+ pw.println(" --timeout: wait for a given number of milliseconds. If the handler(s)");
+ pw.println(" fail to finish before the timeout, the command returns error.");
+ pw.println("");
+ pw.println(" wait-for-background-handler --timeout <MILLIS>");
+ pw.println(" Wait for a given amount of time till the package manager's background");
+ pw.println(" handler finishes handling all pending messages.");
+ pw.println(" --timeout: wait for a given number of milliseconds. If the handler(s)");
+ pw.println(" fail to finish before the timeout, the command returns error.");
+ pw.println("");
if (DexOptHelper.useArtService()) {
printArtServiceHelp();
} else {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
index f41d964..3e7ae33 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceImpl.java
@@ -2810,29 +2810,55 @@
+ pkg.getPackageName());
}
- if ((bp.isNormal() && shouldGrantNormalPermission)
- || (bp.isSignature()
- && (!bp.isPrivileged() || CollectionUtils.contains(
- isPrivilegedPermissionAllowlisted, permName))
- && (CollectionUtils.contains(shouldGrantSignaturePermission,
- permName)
- || (((bp.isPrivileged() && CollectionUtils.contains(
- shouldGrantPrivilegedPermissionIfWasGranted,
- permName)) || bp.isDevelopment() || bp.isRole())
- && origState.isPermissionGranted(permName))))
- || (bp.isInternal()
- && (!bp.isPrivileged() || CollectionUtils.contains(
- isPrivilegedPermissionAllowlisted, permName))
- && (CollectionUtils.contains(shouldGrantInternalPermission,
- permName)
- || (((bp.isPrivileged() && CollectionUtils.contains(
- shouldGrantPrivilegedPermissionIfWasGranted,
- permName)) || bp.isDevelopment() || bp.isRole())
- && origState.isPermissionGranted(permName))))) {
- // Grant an install permission.
- if (uidState.grantPermission(bp)) {
- installPermissionsChangedForUser = true;
+ if (bp.isNormal() || bp.isSignature() || bp.isInternal()) {
+ if ((bp.isNormal() && shouldGrantNormalPermission)
+ || (bp.isSignature()
+ && (!bp.isPrivileged() || CollectionUtils.contains(
+ isPrivilegedPermissionAllowlisted, permName))
+ && (CollectionUtils.contains(shouldGrantSignaturePermission,
+ permName)
+ || (((bp.isPrivileged() && CollectionUtils.contains(
+ shouldGrantPrivilegedPermissionIfWasGranted,
+ permName)) || bp.isDevelopment()
+ || bp.isRole())
+ && origState.isPermissionGranted(
+ permName))))
+ || (bp.isInternal()
+ && (!bp.isPrivileged() || CollectionUtils.contains(
+ isPrivilegedPermissionAllowlisted, permName))
+ && (CollectionUtils.contains(shouldGrantInternalPermission,
+ permName)
+ || (((bp.isPrivileged() && CollectionUtils.contains(
+ shouldGrantPrivilegedPermissionIfWasGranted,
+ permName)) || bp.isDevelopment()
+ || bp.isRole())
+ && origState.isPermissionGranted(
+ permName))))) {
+ // Grant an install permission.
+ if (uidState.grantPermission(bp)) {
+ installPermissionsChangedForUser = true;
+ }
+ } else {
+ if (DEBUG_PERMISSIONS) {
+ boolean wasGranted = uidState.isPermissionGranted(bp.getName());
+ if (wasGranted || bp.isAppOp()) {
+ Slog.i(TAG, (wasGranted ? "Un-granting" : "Not granting")
+ + " permission " + perm
+ + " from package " + friendlyName
+ + " (protectionLevel=" + bp.getProtectionLevel()
+ + " flags=0x"
+ + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg,
+ ps))
+ + ")");
+ }
+ }
+ if (uidState.revokePermission(bp)) {
+ installPermissionsChangedForUser = true;
+ }
}
+ PermissionState origPermState = origState.getPermissionState(perm);
+ int flags = origPermState != null ? origPermState.getFlags() : 0;
+ uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL, flags);
} else if (bp.isRuntime()) {
boolean hardRestricted = bp.isHardRestricted();
boolean softRestricted = bp.isSoftRestricted();
@@ -2956,22 +2982,8 @@
uidState.updatePermissionFlags(bp, MASK_PERMISSION_FLAGS_ALL,
flags);
} else {
- if (DEBUG_PERMISSIONS) {
- boolean wasGranted = uidState.isPermissionGranted(bp.getName());
- if (wasGranted || bp.isAppOp()) {
- Slog.i(TAG, (wasGranted ? "Un-granting" : "Not granting")
- + " permission " + perm
- + " from package " + friendlyName
- + " (protectionLevel=" + bp.getProtectionLevel()
- + " flags=0x"
- + Integer.toHexString(PackageInfoUtils.appInfoFlags(pkg,
- ps))
- + ")");
- }
- }
- if (uidState.removePermissionState(bp.getName())) {
- installPermissionsChangedForUser = true;
- }
+ Slog.wtf(LOG_TAG, "Unknown permission protection " + bp.getProtection()
+ + " for permission " + bp.getName());
}
}
diff --git a/services/core/java/com/android/server/uri/UriPermission.java b/services/core/java/com/android/server/uri/UriPermission.java
index 6db781a..f3eeab0 100644
--- a/services/core/java/com/android/server/uri/UriPermission.java
+++ b/services/core/java/com/android/server/uri/UriPermission.java
@@ -207,7 +207,9 @@
if (mReadOwners != null && includingOwners) {
ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
for (UriPermissionOwner r : mReadOwners) {
- r.removeReadPermission(this);
+ if (r != null) {
+ r.removeReadPermission(this);
+ }
}
mReadOwners = null;
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 6b90181..aafff2c 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
import static android.app.Activity.FULLSCREEN_MODE_REQUEST_ENTER;
+import static android.app.ActivityOptions.ANIM_SCENE_TRANSITION;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.INVALID_WINDOWING_MODE;
import static android.app.FullscreenRequestHandler.REMOTE_CALLBACK_RESULT_KEY;
@@ -818,6 +819,13 @@
null /*startTask */, null /* remoteTransition */,
null /* displayChange */);
r.mTransitionController.setReady(r.getDisplayContent());
+ if (under != null && under.returningOptions != null
+ && under.returningOptions.getAnimationType()
+ == ANIM_SCENE_TRANSITION) {
+ // Pass along the scene-transition animation-type
+ transition.setOverrideAnimation(TransitionInfo.AnimationOptions
+ .makeSceneTransitionAnimOptions(), null, null);
+ }
} else {
transition.abort();
}
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index acfa30c..d84c013 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3560,7 +3560,7 @@
// Note that RecentsAnimation will handle task snapshot while switching apps with
// the best capture timing (e.g. IME window capture),
// No need additional task capture while task is controlled by RecentsAnimation.
- if (mAtmService.mWindowManager.mTaskSnapshotController != null
+ if (!mTransitionController.isShellTransitionsEnabled()
&& !task.isAnimatingByRecents()) {
final ArraySet<Task> tasks = Sets.newArraySet(task);
mAtmService.mWindowManager.mTaskSnapshotController.snapshotTasks(tasks);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index cff6554..1360a95 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -3789,7 +3789,7 @@
TaskSnapshot taskSnapshot = mWindowManager.mTaskSnapshotController.getSnapshot(taskId,
task.mUserId, true /* restoreFromDisk */, isLowResolution);
if (taskSnapshot == null && takeSnapshotIfNeeded) {
- taskSnapshot = takeTaskSnapshot(taskId);
+ taskSnapshot = takeTaskSnapshot(taskId, false /* updateCache */);
}
return taskSnapshot;
} finally {
@@ -3798,7 +3798,7 @@
}
@Override
- public TaskSnapshot takeTaskSnapshot(int taskId) {
+ public TaskSnapshot takeTaskSnapshot(int taskId, boolean updateCache) {
mAmInternal.enforceCallingPermission(READ_FRAME_BUFFER, "takeTaskSnapshot()");
final long ident = Binder.clearCallingIdentity();
try {
@@ -3809,8 +3809,13 @@
Slog.w(TAG, "takeTaskSnapshot: taskId=" + taskId + " not found or not visible");
return null;
}
- return mWindowManager.mTaskSnapshotController.captureSnapshot(
- task, true /* snapshotHome */);
+ if (updateCache) {
+ return mWindowManager.mTaskSnapshotController.recordSnapshot(task,
+ true /* snapshotHome */);
+ } else {
+ return mWindowManager.mTaskSnapshotController.captureSnapshot(task,
+ true /* snapshotHome */);
+ }
}
} finally {
Binder.restoreCallingIdentity(ident);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index b67ccd2..cea886f 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -440,7 +440,8 @@
if (app != null) {
mDisplayContent.removeImeSurfaceImmediately();
if (app.getTask() != null) {
- mDisplayContent.mAtmService.takeTaskSnapshot(app.getTask().mTaskId);
+ mDisplayContent.mAtmService.takeTaskSnapshot(app.getTask().mTaskId,
+ true /* updateCache */);
}
}
} else {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 4d0bff9..7e20b3b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -28,6 +28,7 @@
import android.os.Environment;
import android.os.Handler;
import android.util.ArraySet;
+import android.util.IntArray;
import android.util.Slog;
import android.view.Display;
import android.window.ScreenCapture;
@@ -37,8 +38,6 @@
import com.android.server.policy.WindowManagerPolicy.ScreenOffListener;
import com.android.server.wm.BaseAppSnapshotPersister.PersistInfoProvider;
-import com.google.android.collect.Sets;
-
import java.util.Set;
/**
@@ -58,7 +57,7 @@
static final String SNAPSHOTS_DIRNAME = "snapshots";
private final TaskSnapshotPersister mPersister;
- private final ArraySet<Task> mSkipClosingAppSnapshotTasks = new ArraySet<>();
+ private final IntArray mSkipClosingAppSnapshotTasks = new IntArray();
private final ArraySet<Task> mTmpTasks = new ArraySet<>();
private final Handler mHandler = new Handler();
@@ -135,26 +134,6 @@
}
/**
- * Called when the visibility of an app changes outside of the regular app transition flow.
- */
- void notifyAppVisibilityChanged(ActivityRecord appWindowToken, boolean visible) {
- if (!visible) {
- handleClosingApps(Sets.newArraySet(appWindowToken));
- }
- }
-
- private void handleClosingApps(ArraySet<ActivityRecord> closingApps) {
- if (shouldDisableSnapshots()) {
- return;
- }
- // We need to take a snapshot of the task if and only if all activities of the task are
- // either closing or hidden.
- getClosingTasks(closingApps, mTmpTasks);
- snapshotTasks(mTmpTasks);
- mSkipClosingAppSnapshotTasks.clear();
- }
-
- /**
* Adds the given {@param tasks} to the list of tasks which should not have their snapshots
* taken upon the next processing of the set of closing apps. The caller is responsible for
* calling {@link #snapshotTasks} to ensure that the task has an up-to-date snapshot.
@@ -164,20 +143,23 @@
if (shouldDisableSnapshots()) {
return;
}
- mSkipClosingAppSnapshotTasks.addAll(tasks);
+ for (Task task : tasks) {
+ mSkipClosingAppSnapshotTasks.add(task.mTaskId);
+ }
}
void snapshotTasks(ArraySet<Task> tasks) {
snapshotTasks(tasks, false /* allowSnapshotHome */);
}
- void recordSnapshot(Task task, boolean allowSnapshotHome) {
+ TaskSnapshot recordSnapshot(Task task, boolean allowSnapshotHome) {
final boolean snapshotHome = allowSnapshotHome && task.isActivityTypeHome();
final TaskSnapshot snapshot = recordSnapshotInner(task, allowSnapshotHome);
if (!snapshotHome && snapshot != null) {
mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
task.onSnapshotChanged(snapshot);
}
+ return snapshot;
}
private void snapshotTasks(ArraySet<Task> tasks, boolean allowSnapshotHome) {
@@ -271,31 +253,16 @@
return source.getTaskDescription();
}
- /**
- * Retrieves all closing tasks based on the list of closing apps during an app transition.
- */
- @VisibleForTesting
- void getClosingTasks(ArraySet<ActivityRecord> closingApps, ArraySet<Task> outClosingTasks) {
- outClosingTasks.clear();
- for (int i = closingApps.size() - 1; i >= 0; i--) {
- final ActivityRecord activity = closingApps.valueAt(i);
- final Task task = activity.getTask();
- if (task == null) continue;
-
- getClosingTasksInner(task, outClosingTasks);
- }
- }
-
void getClosingTasksInner(Task task, ArraySet<Task> outClosingTasks) {
// Since RecentsAnimation will handle task snapshot while switching apps with the
// best capture timing (e.g. IME window capture),
// No need additional task capture while task is controlled by RecentsAnimation.
if (isAnimatingByRecents(task)) {
- mSkipClosingAppSnapshotTasks.add(task);
+ mSkipClosingAppSnapshotTasks.add(task.mTaskId);
}
// If the task of the app is not visible anymore, it means no other app in that task
// is opening. Thus, the task is closing.
- if (!task.isVisible() && !mSkipClosingAppSnapshotTasks.contains(task)) {
+ if (!task.isVisible() && mSkipClosingAppSnapshotTasks.indexOf(task.mTaskId) < 0) {
outClosingTasks.add(task);
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 09312ba..7e34d15 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -845,11 +845,14 @@
case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: {
final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer());
final Task task = wc != null ? wc.asTask() : null;
- if (task != null) {
+ if (task == null) {
+ throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
+ } else if (task.getTaskDisplayArea() == null) {
+ throw new IllegalArgumentException("Cannot set a task without display area as "
+ + "launch root: " + wc);
+ } else {
task.getDisplayArea().setLaunchRootTask(task,
hop.getWindowingModes(), hop.getActivityTypes());
- } else {
- throw new IllegalArgumentException("Cannot set non-task as launch root: " + wc);
}
break;
}
diff --git a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
index cb6a5d0..d828349 100644
--- a/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
+++ b/services/credentials/java/com/android/server/credentials/metrics/ApiName.java
@@ -30,6 +30,7 @@
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_REGISTER_CREDENTIAL_DESCRIPTION;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_SET_ENABLED_PROVIDERS;
import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNKNOWN;
+import static com.android.internal.util.FrameworkStatsLog.CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNREGISTER_CREDENTIAL_DESCRIPTION;
import android.credentials.ui.RequestInfo;
import android.util.Slog;
@@ -61,7 +62,7 @@
),
UNREGISTER_CREDENTIAL_DESCRIPTION(
- CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_REGISTER_CREDENTIAL_DESCRIPTION
+ CREDENTIAL_MANAGER_INITIAL_PHASE_REPORTED__API_NAME__API_NAME_UNREGISTER_CREDENTIAL_DESCRIPTION
);
private static final String TAG = "ApiName";
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
index cf7c718..79c0349 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyEngine.java
@@ -1092,12 +1092,9 @@
if (policies.get(admin).getValue() != null
&& policies.get(admin).getValue().getPackageName().equals(packageName)) {
try {
- if (packageManager.getPackageInfo(
- packageName, 0, userId) == null
- || packageManager.getReceiverInfo(policies.get(admin).getValue(),
- PackageManager.MATCH_DIRECT_BOOT_AWARE
- | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
- userId) == null) {
+ if (packageManager.getPackageInfo(packageName, 0, userId) == null
+ || packageManager.getActivityInfo(
+ policies.get(admin).getValue(), 0, userId) == null) {
Slogf.e(TAG, String.format(
"Persistent preferred activity in package %s not found for "
+ "user %d, removing policy for admin",
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
index 2b44615..f47954b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java
@@ -393,9 +393,9 @@
List.of(makeMockRegisteredReceiver()), false);
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
- queue.setProcessAndUidState(mProcess, false, false);
+ queue.setProcessAndUidState(null, false, false);
final long notCachedRunnableAt = queue.getRunnableAt();
- queue.setProcessAndUidState(mProcess, false, true);
+ queue.setProcessAndUidState(null, false, true);
final long cachedRunnableAt = queue.getRunnableAt();
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertFalse(queue.isRunnable());
@@ -420,9 +420,9 @@
List.of(makeMockRegisteredReceiver()), false);
enqueueOrReplaceBroadcast(queue, airplaneRecord, 0);
- queue.setProcessAndUidState(mProcess, false, false);
+ queue.setProcessAndUidState(null, false, false);
final long notCachedRunnableAt = queue.getRunnableAt();
- queue.setProcessAndUidState(mProcess, false, true);
+ queue.setProcessAndUidState(null, false, true);
final long cachedRunnableAt = queue.getRunnableAt();
assertThat(cachedRunnableAt).isGreaterThan(notCachedRunnableAt);
assertTrue(queue.isRunnable());
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
index 615b4c1..ad5f0d7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueTest.java
@@ -399,12 +399,6 @@
UserHandle.USER_SYSTEM);
}
- private ProcessRecord makeActiveProcessRecord(String packageName, String processName)
- throws Exception {
- return makeActiveProcessRecord(packageName, processName, ProcessBehavior.NORMAL,
- UserHandle.USER_SYSTEM);
- }
-
private ProcessRecord makeActiveProcessRecord(String packageName,
ProcessBehavior behavior) throws Exception {
return makeActiveProcessRecord(packageName, packageName, behavior, UserHandle.USER_SYSTEM);
@@ -602,11 +596,6 @@
BackgroundStartPrivileges.NONE, false, null);
}
- private void setProcessFreezable(ProcessRecord app, boolean pendingFreeze, boolean frozen) {
- app.mOptRecord.setPendingFreeze(pendingFreeze);
- app.mOptRecord.setFrozen(frozen);
- }
-
private void assertHealth() {
if (mImpl == Impl.MODERN) {
// If this fails, it'll throw a clear reason message
@@ -1670,10 +1659,8 @@
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
final ProcessRecord receiverOrangeApp = makeActiveProcessRecord(PACKAGE_ORANGE);
- setProcessFreezable(receiverGreenApp, true, false);
- mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
- setProcessFreezable(receiverBlueApp, false, true);
- mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -1717,14 +1704,12 @@
eq(UserHandle.USER_SYSTEM), anyInt(), anyInt(), any());
// Shift blue to be active and confirm that deferred broadcast is delivered
- setProcessFreezable(receiverBlueApp, false, false);
- mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), false);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverBlueApp, timeTick);
// Shift green to be active and confirm that deferred broadcast is delivered
- setProcessFreezable(receiverGreenApp, false, false);
- mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, timeTick);
}
@@ -2121,12 +2106,9 @@
final ProcessRecord receiverBlueApp = makeActiveProcessRecord(PACKAGE_BLUE);
final ProcessRecord receiverYellowApp = makeActiveProcessRecord(PACKAGE_YELLOW);
- setProcessFreezable(receiverGreenApp, true, true);
- mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
- setProcessFreezable(receiverBlueApp, true, false);
- mQueue.onProcessFreezableChangedLocked(receiverBlueApp);
- setProcessFreezable(receiverYellowApp, false, false);
- mQueue.onProcessFreezableChangedLocked(receiverYellowApp);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), true);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_BLUE), true);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_YELLOW), false);
final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
final BroadcastOptions opts = BroadcastOptions.makeBasic()
@@ -2149,50 +2131,11 @@
verifyScheduleRegisteredReceiver(times(1), receiverYellowApp, airplane);
// Shift green to be active and confirm that deferred broadcast is delivered
- setProcessFreezable(receiverGreenApp, false, false);
- mQueue.onProcessFreezableChangedLocked(receiverGreenApp);
+ mUidObserver.onUidCachedChanged(getUidForPackage(PACKAGE_GREEN), false);
waitForIdle();
verifyScheduleRegisteredReceiver(times(1), receiverGreenApp, airplane);
}
- /**
- * Verify broadcasts to a runtime receiver in cached process is deferred even when a different
- * process in the same package is not cached.
- */
- @Test
- public void testDeferralPolicy_UntilActive_WithMultiProcessUid() throws Exception {
- // Legacy stack doesn't support deferral
- Assume.assumeTrue(mImpl == Impl.MODERN);
-
- final ProcessRecord callerApp = makeActiveProcessRecord(PACKAGE_RED);
- final ProcessRecord receiverGreenApp1 = makeActiveProcessRecord(PACKAGE_GREEN);
- final ProcessRecord receiverGreenApp2 = makeActiveProcessRecord(PACKAGE_GREEN,
- PACKAGE_GREEN + "_proc2");
-
- setProcessFreezable(receiverGreenApp1, true, true);
- mQueue.onProcessFreezableChangedLocked(receiverGreenApp1);
-
- final Intent airplane = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- final BroadcastOptions opts = BroadcastOptions.makeBasic()
- .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE);
- enqueueBroadcast(makeBroadcastRecord(airplane, callerApp, opts,
- List.of(makeRegisteredReceiver(receiverGreenApp1),
- makeRegisteredReceiver(receiverGreenApp2))));
- waitForIdle();
-
- // 1st process in Green package is ignored since it is in a cached state
- // but the 2nd process should still receive the broadcast.
- verifyScheduleRegisteredReceiver(never(), receiverGreenApp1, airplane);
- verifyScheduleRegisteredReceiver(times(1), receiverGreenApp2, airplane);
-
- // Shift the 1st process in Green package to be active and confirm that deferred broadcast
- // is delivered
- setProcessFreezable(receiverGreenApp1, false, false);
- mQueue.onProcessFreezableChangedLocked(receiverGreenApp1);
- waitForIdle();
- verifyScheduleRegisteredReceiver(times(1), receiverGreenApp1, airplane);
- }
-
@Test
public void testBroadcastDelivery_uidForeground() throws Exception {
// Legacy stack doesn't support prioritization to foreground app.
diff --git a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
index 01563e2..36a565e 100644
--- a/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/DropboxRateLimiterTest.java
@@ -140,19 +140,19 @@
// Repeated crashes after the last reset being rate limited should be restricted faster.
assertTrue(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
- // We now need to wait 61 minutes for the buffer should be empty again.
- mClock.setOffsetMillis(83 * 60 * 1000);
+ // We now need to wait 21 minutes for the buffer should be empty again.
+ mClock.setOffsetMillis(43 * 60 * 1000);
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
- // After yet another 61 minutes, this time without triggering rate limiting, the strict
+ // After yet another 21 minutes, this time without triggering rate limiting, the strict
// limiting should be turnd off.
- mClock.setOffsetMillis(144 * 60 * 1000);
+ mClock.setOffsetMillis(64 * 60 * 1000);
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
// As rate limiting was not triggered in the last reset, after another 11 minutes the
// buffer should still act as normal.
- mClock.setOffsetMillis(155 * 60 * 1000);
+ mClock.setOffsetMillis(75 * 60 * 1000);
// The first 6 entries should not be rate limited.
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
assertFalse(mRateLimiter.shouldRateLimit("tag", "process").shouldRateLimit());
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
index c26eee9..ade3e82 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/face/aidl/FaceDetectClientTest.java
@@ -24,6 +24,7 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.same;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.hardware.biometrics.common.AuthenticateReason;
@@ -34,6 +35,7 @@
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
+import android.os.Vibrator;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;
@@ -75,6 +77,8 @@
@Mock
private IBinder mToken;
@Mock
+ private Vibrator mVibrator;
+ @Mock
private ClientMonitorCallbackConverter mClientMonitorCallbackConverter;
@Mock
private BiometricLogger mBiometricLogger;
@@ -94,6 +98,8 @@
@Before
public void setup() {
+ mContext.addMockSystemService(Vibrator.class, mVibrator);
+
when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
i -> i.getArgument(0));
}
@@ -147,6 +153,16 @@
verify(mBiometricContext).unsubscribe(same(mOperationContextCaptor.getValue()));
}
+ @Test
+ public void doesNotPlayHapticOnInteractionDetected() throws Exception {
+ final FaceDetectClient client = createClient();
+ client.start(mCallback);
+ client.onInteractionDetected();
+ client.stopHalOperation();
+
+ verifyZeroInteractions(mVibrator);
+ }
+
private FaceDetectClient createClient() throws RemoteException {
return createClient(100 /* version */);
}
diff --git a/services/tests/servicestests/src/com/android/server/credentials/MetricUtilitiesTest.java b/services/tests/servicestests/src/com/android/server/credentials/MetricUtilitiesTest.java
new file mode 100644
index 0000000..b46f1a6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/credentials/MetricUtilitiesTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.credentials;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.credentials.metrics.InitialPhaseMetric;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Given the secondary-system nature of the MetricUtilities, we expect absolutely nothing to
+ * throw an error. If one presents itself, that is problematic.
+ *
+ * atest FrameworksServicesTests:com.android.server.credentials.MetricUtilitiesTest
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public final class MetricUtilitiesTest {
+
+ @Test
+ public void logApiCalledInitialPhase_nullInitPhaseMetricAndNegativeSequence_success() {
+ MetricUtilities.logApiCalledInitialPhase(null, -1);
+ }
+
+ @Test
+ public void logApiCalledInitialPhase_invalidInitPhaseMetricAndPositiveSequence_success() {
+ MetricUtilities.logApiCalledInitialPhase(new InitialPhaseMetric(-1), 1);
+ }
+
+ @Test
+ public void logApiCalledInitialPhase_validInitPhaseMetric_success() {
+ InitialPhaseMetric validInitPhaseMetric = new InitialPhaseMetric(
+ MetricUtilities.getHighlyUniqueInteger());
+ MetricUtilities.logApiCalledInitialPhase(validInitPhaseMetric, 1);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/credentials/metrics/ApiNameTest.java b/services/tests/servicestests/src/com/android/server/credentials/metrics/ApiNameTest.java
new file mode 100644
index 0000000..8093b18
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/credentials/metrics/ApiNameTest.java
@@ -0,0 +1,48 @@
+/*
+ * 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.credentials.metrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ApiNameTest {
+
+ @Test
+ public void getMetricCode_matchesWestWorldMetricCode_success() {
+ // com.android.os is only visible in cts tests, so we need to mimic it for server side unit
+ // tests. aidegen can identify it but builds will not. Thus, this is the workaround.
+ Set<Integer> expectedApiNames = new HashSet<>();
+ for (int i = 0; i < 10; i++) {
+ expectedApiNames.add(i);
+ }
+ Set<Integer> actualServerApiNames = Arrays.stream(ApiName.values())
+ .map(ApiName::getMetricCode).collect(Collectors.toSet());
+
+ assertThat(actualServerApiNames).containsExactlyElementsIn(expectedApiNames);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/credentials/metrics/ApiStatusTest.java b/services/tests/servicestests/src/com/android/server/credentials/metrics/ApiStatusTest.java
new file mode 100644
index 0000000..3bf4814
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/credentials/metrics/ApiStatusTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.credentials.metrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ApiStatusTest {
+
+ @Test
+ public void getMetricCode_matchesWestWorldMetricCode_success() {
+ Set<Integer> expectedApiStatus = new HashSet<>();
+ for (int i = 1; i < 5; i++) {
+ expectedApiStatus.add(i);
+ }
+ Set<Integer> actualServerApiStatus = Arrays.stream(ApiStatus.values())
+ .map(ApiStatus::getMetricCode).collect(Collectors.toSet());
+
+ assertThat(actualServerApiStatus).containsExactlyElementsIn(expectedApiStatus);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/credentials/metrics/EntryEnumTest.java b/services/tests/servicestests/src/com/android/server/credentials/metrics/EntryEnumTest.java
new file mode 100644
index 0000000..3104cc2
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/credentials/metrics/EntryEnumTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.credentials.metrics;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class EntryEnumTest {
+
+ @Test
+ public void getMetricCode_matchesWestWorldMetricCode_success() {
+ Set<Integer> expectedEntryEnum = new HashSet<>();
+ for (int i = 0; i < 5; i++) {
+ expectedEntryEnum.add(i);
+ }
+ Set<Integer> actualServerEntryEnum = Arrays.stream(EntryEnum.values())
+ .map(EntryEnum::getMetricCode).collect(Collectors.toSet());
+
+ assertThat(actualServerEntryEnum).containsExactlyElementsIn(expectedEntryEnum);
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 7092b0b..6e52af1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -298,8 +298,6 @@
assertTrue(mController.isAnimatingTask(activity.getTask()));
spyOn(mWm.mTaskSnapshotController);
- doNothing().when(mWm.mTaskSnapshotController).notifyAppVisibilityChanged(any(),
- anyBoolean());
doReturn(mMockTaskSnapshot).when(mWm.mTaskSnapshotController).getSnapshot(anyInt(),
anyInt(), eq(false) /* restoreFromDisk */, eq(false) /* isLowResolution */);
mController.setDeferredCancel(true /* deferred */, true /* screenshot */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
index 4c7b0aa0..91256ee 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskSnapshotControllerTest.java
@@ -75,7 +75,7 @@
final ArraySet<ActivityRecord> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mActivityRecord);
final ArraySet<Task> closingTasks = new ArraySet<>();
- mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ getClosingTasks(closingApps, closingTasks);
assertEquals(1, closingTasks.size());
assertEquals(closingWindow.mActivityRecord.getTask(), closingTasks.valueAt(0));
}
@@ -93,7 +93,7 @@
final ArraySet<ActivityRecord> closingApps = new ArraySet<>();
closingApps.add(closingWindow.mActivityRecord);
final ArraySet<Task> closingTasks = new ArraySet<>();
- mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ getClosingTasks(closingApps, closingTasks);
assertEquals(0, closingTasks.size());
}
@@ -108,10 +108,23 @@
final ArraySet<Task> closingTasks = new ArraySet<>();
mWm.mTaskSnapshotController.addSkipClosingAppSnapshotTasks(
Sets.newArraySet(closingWindow.mActivityRecord.getTask()));
- mWm.mTaskSnapshotController.getClosingTasks(closingApps, closingTasks);
+ getClosingTasks(closingApps, closingTasks);
assertEquals(0, closingTasks.size());
}
+ /** Retrieves all closing tasks based on the list of closing apps during an app transition. */
+ private void getClosingTasks(ArraySet<ActivityRecord> closingApps,
+ ArraySet<Task> outClosingTasks) {
+ outClosingTasks.clear();
+ for (int i = closingApps.size() - 1; i >= 0; i--) {
+ final ActivityRecord activity = closingApps.valueAt(i);
+ final Task task = activity.getTask();
+ if (task == null) continue;
+
+ mWm.mTaskSnapshotController.getClosingTasksInner(task, outClosingTasks);
+ }
+ }
+
@Test
public void testGetSnapshotMode() {
final WindowState disabledWindow = createWindow(null,