Merge "bootanimation: correct logo position and size after resolution changed" into tm-dev
diff --git a/core/api/current.txt b/core/api/current.txt
index e260ad0..c8a43db 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -44254,6 +44254,9 @@
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
+ field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+ field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+ field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
}
public final class ImsReasonInfo implements android.os.Parcelable {
@@ -44475,10 +44478,10 @@
method public void unregisterFeatureProvisioningChangedCallback(@NonNull android.telephony.ims.ProvisioningManager.FeatureProvisioningCallback);
}
- public static class ProvisioningManager.FeatureProvisioningCallback {
+ public abstract static class ProvisioningManager.FeatureProvisioningCallback {
ctor public ProvisioningManager.FeatureProvisioningCallback();
- method public void onFeatureProvisioningChanged(int, int, boolean);
- method public void onRcsFeatureProvisioningChanged(int, int, boolean);
+ method public abstract void onFeatureProvisioningChanged(int, int, boolean);
+ method public abstract void onRcsFeatureProvisioningChanged(int, int, boolean);
}
public class RcsUceAdapter {
@@ -44521,15 +44524,6 @@
field public static final int CAPABILITY_TYPE_VOICE = 1; // 0x1
}
- public class RcsFeature {
- }
-
- public static class RcsFeature.RcsImsCapabilities {
- field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
- field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
- field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
- }
-
}
package android.telephony.ims.stub {
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index b25d1e3..ec4ad8b 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -15024,7 +15024,7 @@
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestAvailability(@NonNull android.net.Uri, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(allOf={android.Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE, android.Manifest.permission.READ_CONTACTS}) public void requestCapabilities(@NonNull java.util.Collection<android.net.Uri>, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RcsUceAdapter.CapabilitiesCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException;
- field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
+ field @Deprecated public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
field public static final int CAPABILITY_UPDATE_TRIGGER_ETAG_EXPIRED = 1; // 0x1
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_2G = 7; // 0x7
field public static final int CAPABILITY_UPDATE_TRIGGER_MOVE_TO_3G = 6; // 0x6
@@ -15307,6 +15307,9 @@
method public void addCapabilities(int);
method public boolean isCapable(int);
method public void removeCapabilities(int);
+ field public static final int CAPABILITY_TYPE_NONE = 0; // 0x0
+ field public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1; // 0x1
+ field public static final int CAPABILITY_TYPE_PRESENCE_UCE = 2; // 0x2
}
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 7d68eb9..b4cabad 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -7030,7 +7030,13 @@
// local, we'll need to wait for the publishing of the provider.
if (holder != null && holder.provider == null && !holder.mLocal) {
synchronized (key.mLock) {
- key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+ if (key.mHolder != null) {
+ if (DEBUG_PROVIDER) {
+ Slog.i(TAG, "already received provider: " + auth);
+ }
+ } else {
+ key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
+ }
holder = key.mHolder;
}
if (holder != null && holder.provider == null) {
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index 714227d..570211e 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -396,7 +396,8 @@
return true;
case MATCH_CARRIER:
case MATCH_MOBILE:
- return !template.getSubscriberIds().isEmpty();
+ return !template.getSubscriberIds().isEmpty()
+ && template.getMeteredness() == METERED_YES;
case MATCH_WIFI:
if (template.getWifiNetworkKeys().isEmpty()
&& template.getSubscriberIds().isEmpty()) {
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
index e20cef2..ca420c6 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitController.java
@@ -40,6 +40,7 @@
import android.os.IBinder;
import android.os.Looper;
import android.util.ArraySet;
+import android.util.Log;
import android.util.SparseArray;
import android.window.TaskFragmentInfo;
import android.window.WindowContainerTransaction;
@@ -59,6 +60,7 @@
*/
public class SplitController implements JetpackTaskFragmentOrganizer.TaskFragmentCallback,
ActivityEmbeddingComponent {
+ private static final String TAG = "SplitController";
@VisibleForTesting
final SplitPresenter mPresenter;
@@ -229,8 +231,8 @@
}
if (taskContainer.isEmpty()) {
// Cleanup the TaskContainer if it becomes empty.
- mPresenter.stopOverrideSplitAnimation(taskContainer.mTaskId);
- mTaskContainers.remove(taskContainer.mTaskId);
+ mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
+ mTaskContainers.remove(taskContainer.getTaskId());
}
return;
}
@@ -241,13 +243,13 @@
if (taskContainer == null) {
return;
}
- final boolean wasInPip = isInPictureInPicture(taskContainer.mConfiguration);
+ final boolean wasInPip = isInPictureInPicture(taskContainer.getConfiguration());
final boolean isInPIp = isInPictureInPicture(config);
- taskContainer.mConfiguration = config;
+ taskContainer.setConfiguration(config);
// We need to check the animation override when enter/exit PIP or has bounds changed.
boolean shouldUpdateAnimationOverride = wasInPip != isInPIp;
- if (onTaskBoundsMayChange(taskContainer, config.windowConfiguration.getBounds())
+ if (taskContainer.setTaskBounds(config.windowConfiguration.getBounds())
&& !isInPIp) {
// We don't care the bounds change when it has already entered PIP.
shouldUpdateAnimationOverride = true;
@@ -257,16 +259,6 @@
}
}
- /** Returns {@code true} if the bounds is changed. */
- private boolean onTaskBoundsMayChange(@NonNull TaskContainer taskContainer,
- @NonNull Rect taskBounds) {
- if (!taskBounds.isEmpty() && !taskContainer.mTaskBounds.equals(taskBounds)) {
- taskContainer.mTaskBounds.set(taskBounds);
- return true;
- }
- return false;
- }
-
/**
* Updates if we should override transition animation. We only want to override if the Task
* bounds is large enough for at least one split rule.
@@ -279,15 +271,15 @@
// We only want to override if it supports split.
if (supportSplit(taskContainer)) {
- mPresenter.startOverrideSplitAnimation(taskContainer.mTaskId);
+ mPresenter.startOverrideSplitAnimation(taskContainer.getTaskId());
} else {
- mPresenter.stopOverrideSplitAnimation(taskContainer.mTaskId);
+ mPresenter.stopOverrideSplitAnimation(taskContainer.getTaskId());
}
}
private boolean supportSplit(@NonNull TaskContainer taskContainer) {
// No split inside PIP.
- if (isInPictureInPicture(taskContainer.mConfiguration)) {
+ if (isInPictureInPicture(taskContainer.getConfiguration())) {
return false;
}
// Check if the parent container bounds can support any split rule.
@@ -295,7 +287,7 @@
if (!(rule instanceof SplitRule)) {
continue;
}
- if (mPresenter.shouldShowSideBySide(taskContainer.mTaskBounds, (SplitRule) rule)) {
+ if (mPresenter.shouldShowSideBySide(taskContainer.getTaskBounds(), (SplitRule) rule)) {
return true;
}
}
@@ -425,21 +417,36 @@
return null;
}
+ TaskFragmentContainer newContainer(@NonNull Activity activity, int taskId) {
+ return newContainer(activity, activity, taskId);
+ }
+
/**
* Creates and registers a new organized container with an optional activity that will be
* re-parented to it in a WCT.
+ *
+ * @param activity the activity that will be reparented to the TaskFragment.
+ * @param activityInTask activity in the same Task so that we can get the Task bounds if
+ * needed.
+ * @param taskId parent Task of the new TaskFragment.
*/
- TaskFragmentContainer newContainer(@Nullable Activity activity, int taskId) {
+ TaskFragmentContainer newContainer(@Nullable Activity activity,
+ @NonNull Activity activityInTask, int taskId) {
+ if (activityInTask == null) {
+ throw new IllegalArgumentException("activityInTask must not be null,");
+ }
final TaskFragmentContainer container = new TaskFragmentContainer(activity, taskId);
if (!mTaskContainers.contains(taskId)) {
mTaskContainers.put(taskId, new TaskContainer(taskId));
}
final TaskContainer taskContainer = mTaskContainers.get(taskId);
taskContainer.mContainers.add(container);
- if (activity != null && !taskContainer.isTaskBoundsInitialized()
- && onTaskBoundsMayChange(taskContainer,
- SplitPresenter.getTaskBoundsFromActivity(activity))) {
- // Initial check before any TaskFragment has appeared.
+ if (!taskContainer.isTaskBoundsInitialized()) {
+ // Get the initial bounds before the TaskFragment has appeared.
+ final Rect taskBounds = SplitPresenter.getTaskBoundsFromActivity(activityInTask);
+ if (!taskContainer.setTaskBounds(taskBounds)) {
+ Log.w(TAG, "Can't find bounds from activity=" + activityInTask);
+ }
updateAnimationOverride(taskContainer);
}
return container;
@@ -887,6 +894,11 @@
return null;
}
+ @Nullable
+ TaskContainer getTaskContainer(int taskId) {
+ return mTaskContainers.get(taskId);
+ }
+
/**
* Returns {@code true} if an Activity with the provided component name should always be
* expanded to occupy full task bounds. Such activity must not be put in a split.
@@ -1211,37 +1223,4 @@
return configuration != null
&& configuration.windowConfiguration.getWindowingMode() == WINDOWING_MODE_PINNED;
}
-
- /** Represents TaskFragments and split pairs below a Task. */
- @VisibleForTesting
- static class TaskContainer {
- /** The unique task id. */
- final int mTaskId;
- /** Active TaskFragments in this Task. */
- final List<TaskFragmentContainer> mContainers = new ArrayList<>();
- /** Active split pairs in this Task. */
- final List<SplitContainer> mSplitContainers = new ArrayList<>();
- /**
- * TaskFragments that the organizer has requested to be closed. They should be removed when
- * the organizer receives {@link #onTaskFragmentVanished(TaskFragmentInfo)} event for them.
- */
- final Set<IBinder> mFinishedContainer = new ArraySet<>();
- /** Available window bounds of this Task. */
- final Rect mTaskBounds = new Rect();
- /** Configuration of the Task. */
- @Nullable
- Configuration mConfiguration;
-
- TaskContainer(int taskId) {
- mTaskId = taskId;
- }
-
- boolean isEmpty() {
- return mContainers.isEmpty() && mFinishedContainer.isEmpty();
- }
-
- boolean isTaskBoundsInitialized() {
- return !mTaskBounds.isEmpty();
- }
- }
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
index 1b49585..716a087 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/SplitPresenter.java
@@ -19,9 +19,9 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
import android.app.Activity;
+import android.app.WindowConfiguration;
import android.content.Context;
import android.content.Intent;
-import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
@@ -111,8 +111,8 @@
primaryActivity, primaryRectBounds, null);
// Create new empty task fragment
- final TaskFragmentContainer secondaryContainer = mController.newContainer(null,
- primaryContainer.getTaskId());
+ final TaskFragmentContainer secondaryContainer = mController.newContainer(
+ null /* activity */, primaryActivity, primaryContainer.getTaskId());
final Rect secondaryRectBounds = getBoundsForPosition(POSITION_END, parentBounds,
rule, isLtr(primaryActivity, rule));
createTaskFragment(wct, secondaryContainer.getTaskFragmentToken(),
@@ -168,8 +168,8 @@
* Creates a new expanded container.
*/
TaskFragmentContainer createNewExpandedContainer(@NonNull Activity launchingActivity) {
- final TaskFragmentContainer newContainer = mController.newContainer(null,
- launchingActivity.getTaskId());
+ final TaskFragmentContainer newContainer = mController.newContainer(null /* activity */,
+ launchingActivity, launchingActivity.getTaskId());
final WindowContainerTransaction wct = new WindowContainerTransaction();
createTaskFragment(wct, newContainer.getTaskFragmentToken(),
@@ -236,8 +236,8 @@
launchingActivity.getTaskId());
}
- TaskFragmentContainer secondaryContainer = mController.newContainer(null,
- primaryContainer.getTaskId());
+ TaskFragmentContainer secondaryContainer = mController.newContainer(null /* activity */,
+ launchingActivity, primaryContainer.getTaskId());
final WindowContainerTransaction wct = new WindowContainerTransaction();
mController.registerSplit(wct, primaryContainer, launchingActivity, secondaryContainer,
rule);
@@ -398,20 +398,12 @@
@NonNull
Rect getParentContainerBounds(@NonNull TaskFragmentContainer container) {
- final Configuration parentConfig = mFragmentParentConfigs.get(
- container.getTaskFragmentToken());
- if (parentConfig != null) {
- return parentConfig.windowConfiguration.getBounds();
+ final int taskId = container.getTaskId();
+ final TaskContainer taskContainer = mController.getTaskContainer(taskId);
+ if (taskContainer == null) {
+ throw new IllegalStateException("Can't find TaskContainer taskId=" + taskId);
}
-
- // If there is no parent yet - then assuming that activities are running in full task bounds
- final Activity topActivity = container.getTopNonFinishingActivity();
- final Rect bounds = topActivity != null ? getParentContainerBounds(topActivity) : null;
-
- if (bounds == null) {
- throw new IllegalStateException("Unknown parent bounds");
- }
- return bounds;
+ return taskContainer.getTaskBounds();
}
@NonNull
@@ -419,22 +411,19 @@
final TaskFragmentContainer container = mController.getContainerWithActivity(
activity.getActivityToken());
if (container != null) {
- final Configuration parentConfig = mFragmentParentConfigs.get(
- container.getTaskFragmentToken());
- if (parentConfig != null) {
- return parentConfig.windowConfiguration.getBounds();
- }
+ return getParentContainerBounds(container);
}
-
return getTaskBoundsFromActivity(activity);
}
@NonNull
static Rect getTaskBoundsFromActivity(@NonNull Activity activity) {
+ final WindowConfiguration windowConfiguration =
+ activity.getResources().getConfiguration().windowConfiguration;
if (!activity.isInMultiWindowMode()) {
// In fullscreen mode the max bounds should correspond to the task bounds.
- return activity.getResources().getConfiguration().windowConfiguration.getMaxBounds();
+ return windowConfiguration.getMaxBounds();
}
- return activity.getResources().getConfiguration().windowConfiguration.getBounds();
+ return windowConfiguration.getBounds();
}
}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
new file mode 100644
index 0000000..be79301
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/embedding/TaskContainer.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2022 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 androidx.window.extensions.embedding;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.util.ArraySet;
+import android.window.TaskFragmentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+/** Represents TaskFragments and split pairs below a Task. */
+class TaskContainer {
+
+ /** The unique task id. */
+ private final int mTaskId;
+
+ /** Available window bounds of this Task. */
+ private final Rect mTaskBounds = new Rect();
+
+ /** Configuration of the Task. */
+ @Nullable
+ private Configuration mConfiguration;
+
+ /** Active TaskFragments in this Task. */
+ final List<TaskFragmentContainer> mContainers = new ArrayList<>();
+
+ /** Active split pairs in this Task. */
+ final List<SplitContainer> mSplitContainers = new ArrayList<>();
+
+ /**
+ * TaskFragments that the organizer has requested to be closed. They should be removed when
+ * the organizer receives {@link SplitController#onTaskFragmentVanished(TaskFragmentInfo)} event
+ * for them.
+ */
+ final Set<IBinder> mFinishedContainer = new ArraySet<>();
+
+ TaskContainer(int taskId) {
+ mTaskId = taskId;
+ }
+
+ int getTaskId() {
+ return mTaskId;
+ }
+
+ @NonNull
+ Rect getTaskBounds() {
+ return mTaskBounds;
+ }
+
+ /** Returns {@code true} if the bounds is changed. */
+ boolean setTaskBounds(@NonNull Rect taskBounds) {
+ if (!taskBounds.isEmpty() && !mTaskBounds.equals(taskBounds)) {
+ mTaskBounds.set(taskBounds);
+ return true;
+ }
+ return false;
+ }
+
+ /** Whether the Task bounds has been initialized. */
+ boolean isTaskBoundsInitialized() {
+ return !mTaskBounds.isEmpty();
+ }
+
+ @Nullable
+ Configuration getConfiguration() {
+ return mConfiguration;
+ }
+
+ void setConfiguration(@Nullable Configuration configuration) {
+ mConfiguration = configuration;
+ }
+
+ /** Whether there is any {@link TaskFragmentContainer} below this Task. */
+ boolean isEmpty() {
+ return mContainers.isEmpty() && mFinishedContainer.isEmpty();
+ }
+}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
index 72519dc..e0fda58 100644
--- a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/SplitControllerTest.java
@@ -21,6 +21,9 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -29,12 +32,12 @@
import android.app.Activity;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.window.TaskFragmentInfo;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
-import androidx.window.extensions.embedding.SplitController.TaskContainer;
import org.junit.Before;
import org.junit.Test;
@@ -53,6 +56,7 @@
@RunWith(AndroidJUnit4.class)
public class SplitControllerTest {
private static final int TASK_ID = 10;
+ private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
@Mock
private Activity mActivity;
@@ -70,8 +74,11 @@
mSplitPresenter = mSplitController.mPresenter;
spyOn(mSplitController);
spyOn(mSplitPresenter);
+ final Configuration activityConfig = new Configuration();
+ activityConfig.windowConfiguration.setBounds(TASK_BOUNDS);
+ activityConfig.windowConfiguration.setMaxBounds(TASK_BOUNDS);
doReturn(mActivityResources).when(mActivity).getResources();
- doReturn(new Configuration()).when(mActivityResources).getConfiguration();
+ doReturn(activityConfig).when(mActivityResources).getConfiguration();
}
@Test
@@ -117,4 +124,20 @@
verify(mSplitController).removeContainer(tf);
verify(mActivity, never()).finish();
}
+
+ @Test
+ public void testNewContainer() {
+ // Must pass in a valid activity.
+ assertThrows(IllegalArgumentException.class, () ->
+ mSplitController.newContainer(null /* activity */, TASK_ID));
+ assertThrows(IllegalArgumentException.class, () ->
+ mSplitController.newContainer(mActivity, null /* launchingActivity */, TASK_ID));
+
+ final TaskFragmentContainer tf = mSplitController.newContainer(null, mActivity, TASK_ID);
+ final TaskContainer taskContainer = mSplitController.getTaskContainer(TASK_ID);
+
+ assertNotNull(tf);
+ assertNotNull(taskContainer);
+ assertEquals(TASK_BOUNDS, taskContainer.getTaskBounds());
+ }
}
diff --git a/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
new file mode 100644
index 0000000..9fb08df
--- /dev/null
+++ b/libs/WindowManager/Jetpack/tests/unittest/src/androidx/window/extensions/embedding/TaskContainerTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2022 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 androidx.window.extensions.embedding;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskContainer}.
+ *
+ * Build/Install/Run:
+ * atest WMJetpackUnitTests:TaskContainerTest
+ */
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class TaskContainerTest {
+ private static final int TASK_ID = 10;
+ private static final Rect TASK_BOUNDS = new Rect(0, 0, 600, 1200);
+
+ @Test
+ public void testIsTaskBoundsInitialized() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+
+ assertFalse(taskContainer.isTaskBoundsInitialized());
+
+ taskContainer.setTaskBounds(TASK_BOUNDS);
+
+ assertTrue(taskContainer.isTaskBoundsInitialized());
+ }
+
+ @Test
+ public void testSetTaskBounds() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+
+ assertFalse(taskContainer.setTaskBounds(new Rect()));
+
+ assertTrue(taskContainer.setTaskBounds(TASK_BOUNDS));
+
+ assertFalse(taskContainer.setTaskBounds(TASK_BOUNDS));
+ }
+
+ @Test
+ public void testIsEmpty() {
+ final TaskContainer taskContainer = new TaskContainer(TASK_ID);
+
+ assertTrue(taskContainer.isEmpty());
+
+ final TaskFragmentContainer tf = new TaskFragmentContainer(null, TASK_ID);
+ taskContainer.mContainers.add(tf);
+
+ assertFalse(taskContainer.isEmpty());
+
+ taskContainer.mFinishedContainer.add(tf.getTaskFragmentToken());
+ taskContainer.mContainers.clear();
+
+ assertFalse(taskContainer.isEmpty());
+ }
+}
diff --git a/libs/WindowManager/Shell/res/layout/split_decor.xml b/libs/WindowManager/Shell/res/layout/split_decor.xml
index 9ffa5e8..dfb90af 100644
--- a/libs/WindowManager/Shell/res/layout/split_decor.xml
+++ b/libs/WindowManager/Shell/res/layout/split_decor.xml
@@ -20,9 +20,10 @@
android:layout_width="match_parent">
<ImageView android:id="@+id/split_resizing_icon"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
+ android:layout_height="@*android:dimen/starting_surface_icon_size"
+ android:layout_width="@*android:dimen/starting_surface_icon_size"
android:layout_gravity="center"
+ android:scaleType="fitCenter"
android:padding="0dp"
android:visibility="gone"
android:background="@null"/>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
index 38870bc..0cea36e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropZoneView.java
@@ -28,6 +28,7 @@
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
@@ -110,10 +111,12 @@
mColorDrawable = new ColorDrawable();
setBackgroundDrawable(mColorDrawable);
+ final int iconSize = context.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.starting_surface_icon_size);
mSplashScreenView = new ImageView(context);
- mSplashScreenView.setScaleType(ImageView.ScaleType.CENTER);
- addView(mSplashScreenView, new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
+ mSplashScreenView.setScaleType(ImageView.ScaleType.FIT_CENTER);
+ addView(mSplashScreenView,
+ new FrameLayout.LayoutParams(iconSize, iconSize, Gravity.CENTER));
mSplashScreenView.setAlpha(0f);
mMarginView = new MarginView(context);
diff --git a/media/Android.bp b/media/Android.bp
index 3516d25..b45d694 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -120,6 +120,13 @@
],
},
},
+ versions_with_info: [
+ {
+ version: "1",
+ imports: [],
+ },
+ ],
+
}
aidl_interface {
diff --git a/native/android/performance_hint.cpp b/native/android/performance_hint.cpp
index 65428de..d627984 100644
--- a/native/android/performance_hint.cpp
+++ b/native/android/performance_hint.cpp
@@ -184,13 +184,13 @@
mTimestampsNanos.push_back(now);
/**
- * Use current sample to determine the rate limit. We can pick a shorter rate limit
- * if any sample underperformed, however, it could be the lower level system is slow
- * to react. So here we explicitly choose the rate limit with the latest sample.
+ * Cache the hint if the hint is not overtime and the mLastUpdateTimestamp is
+ * still in the mPreferredRateNanos duration.
*/
- int64_t rateLimit = actualDurationNanos > mTargetDurationNanos ? mPreferredRateNanos
- : 10 * mPreferredRateNanos;
- if (now - mLastUpdateTimestamp <= rateLimit) return 0;
+ if (actualDurationNanos < mTargetDurationNanos &&
+ now - mLastUpdateTimestamp <= mPreferredRateNanos) {
+ return 0;
+ }
binder::Status ret =
mHintSession->reportActualWorkDuration(mActualDurationsNanos, mTimestampsNanos);
diff --git a/omapi/aidl/Android.bp b/omapi/aidl/Android.bp
index d80317b..58bcd1d 100644
--- a/omapi/aidl/Android.bp
+++ b/omapi/aidl/Android.bp
@@ -29,4 +29,11 @@
enabled: true,
},
},
+ versions_with_info: [
+ {
+ version: "1",
+ imports: [],
+ },
+ ],
+
}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/.hash b/omapi/aidl/aidl_api/android.se.omapi/1/.hash
new file mode 100644
index 0000000..f77182a
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/.hash
@@ -0,0 +1 @@
+894069bcfe4f35ceb2088278ddf87c83adee8014
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementChannel.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementChannel.aidl
new file mode 100644
index 0000000..87fdac0
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementChannel.aidl
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementChannel {
+ void close();
+ boolean isClosed();
+ boolean isBasicChannel();
+ byte[] getSelectResponse();
+ byte[] transmit(in byte[] command);
+ boolean selectNext();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementListener.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementListener.aidl
new file mode 100644
index 0000000..77e1c53f
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementListener.aidl
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementListener {
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementReader.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementReader.aidl
new file mode 100644
index 0000000..2b10c47
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementReader.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementReader {
+ boolean isSecureElementPresent();
+ android.se.omapi.ISecureElementSession openSession();
+ void closeSessions();
+ boolean reset();
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementService.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementService.aidl
new file mode 100644
index 0000000..0c8e431
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementService.aidl
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementService {
+ String[] getReaders();
+ android.se.omapi.ISecureElementReader getReader(in String reader);
+ boolean[] isNfcEventAllowed(in String reader, in byte[] aid, in String[] packageNames, in int userId);
+}
diff --git a/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementSession.aidl b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementSession.aidl
new file mode 100644
index 0000000..06287c5
--- /dev/null
+++ b/omapi/aidl/aidl_api/android.se.omapi/1/android/se/omapi/ISecureElementSession.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017, 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.
+ *//*
+ * Copyright (c) 2015-2017, The Linux Foundation.
+ *//*
+ * Contributed by: Giesecke & Devrient GmbH.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.se.omapi;
+/* @hide */
+@VintfStability
+interface ISecureElementSession {
+ byte[] getAtr();
+ void close();
+ void closeChannels();
+ boolean isClosed();
+ android.se.omapi.ISecureElementChannel openBasicChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+ android.se.omapi.ISecureElementChannel openLogicalChannel(in byte[] aid, in byte p2, in android.se.omapi.ISecureElementListener listener);
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStateWorker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStateWorker.java
new file mode 100644
index 0000000..a0c2698
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiStateWorker.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2022 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.settingslib.wifi;
+
+import static android.net.wifi.WifiManager.EXTRA_WIFI_STATE;
+import static android.net.wifi.WifiManager.WIFI_STATE_CHANGED_ACTION;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+
+import android.annotation.AnyThread;
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.os.HandlerThread;
+import android.os.Process;
+import android.util.Log;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * This is a singleton class for Wi-Fi state worker.
+ */
+public class WifiStateWorker {
+
+ private static final String TAG = "WifiStateWorker";
+ private static final Object sLock = new Object();
+
+ /**
+ * A singleton {@link WifiStateWorker} object is used to share with all sub-settings.
+ */
+ @GuardedBy("sLock")
+ private static WifiStateWorker sInstance;
+ @TestApi
+ @GuardedBy("sLock")
+ private static Map<Context, WifiStateWorker> sTestInstances;
+
+ @VisibleForTesting
+ static WifiManager sWifiManager;
+ private static int sWifiState;
+ private static HandlerThread sWorkerThread;
+
+ /**
+ * Static method to create a singleton class for WifiStateWorker.
+ *
+ * @param context The Context this is associated with.
+ * @return an instance of {@link WifiStateWorker} object.
+ */
+ @NonNull
+ @AnyThread
+ public static WifiStateWorker getInstance(@NonNull Context context) {
+ synchronized (sLock) {
+ if (sTestInstances != null && sTestInstances.containsKey(context)) {
+ WifiStateWorker testInstance = sTestInstances.get(context);
+ Log.w(TAG, "The context owner try to use a test instance:" + testInstance);
+ return testInstance;
+ }
+
+ if (sInstance != null) return sInstance;
+
+ sInstance = new WifiStateWorker();
+ sWorkerThread = new HandlerThread(
+ TAG + ":{" + context.getApplicationInfo().className + "}",
+ Process.THREAD_PRIORITY_DISPLAY);
+ sWorkerThread.start();
+ sWorkerThread.getThreadHandler().post(() -> init(context));
+ return sInstance;
+ }
+ }
+
+ /**
+ * A convenience method to set pre-prepared instance or mock(WifiStateWorker.class) for testing.
+ *
+ * @param context The Context this is associated with.
+ * @param instance of {@link WifiStateWorker} object.
+ * @hide
+ */
+ @TestApi
+ @VisibleForTesting
+ public static void setTestInstance(@NonNull Context context, WifiStateWorker instance) {
+ synchronized (sLock) {
+ if (sTestInstances == null) sTestInstances = new ConcurrentHashMap<>();
+
+ Log.w(TAG, "Try to set a test instance by context:" + context);
+ sTestInstances.put(context, instance);
+ }
+ }
+
+ @WorkerThread
+ private static void init(@NonNull Context context) {
+ final Context appContext = context.getApplicationContext();
+ final IntentReceiver receiver = new IntentReceiver();
+ appContext.registerReceiver(receiver, new IntentFilter(WIFI_STATE_CHANGED_ACTION), null,
+ sWorkerThread.getThreadHandler());
+ sWifiManager = appContext.getSystemService(WifiManager.class);
+ refresh();
+ }
+
+ /**
+ * Refresh Wi-Fi state with WifiManager#getWifiState()
+ */
+ @AnyThread
+ public static void refresh() {
+ if (sWifiManager == null) return;
+ Log.d(TAG, "Start calling WifiManager#getWifiState.");
+ sWifiState = sWifiManager.getWifiState();
+ Log.d(TAG, "WifiManager#getWifiState return state:" + sWifiState);
+ }
+
+ /**
+ * Gets the Wi-Fi enabled state.
+ *
+ * @return One of {@link WifiManager#WIFI_STATE_DISABLED},
+ * {@link WifiManager#WIFI_STATE_DISABLING}, {@link WifiManager#WIFI_STATE_ENABLED},
+ * {@link WifiManager#WIFI_STATE_ENABLING}, {@link WifiManager#WIFI_STATE_UNKNOWN}
+ * @see #isWifiEnabled()
+ */
+ @AnyThread
+ public int getWifiState() {
+ return sWifiState;
+ }
+
+ /**
+ * Return whether Wi-Fi is enabled or disabled.
+ *
+ * @return {@code true} if Wi-Fi is enabled
+ * @see #getWifiState()
+ */
+ @AnyThread
+ public boolean isWifiEnabled() {
+ return sWifiState == WIFI_STATE_ENABLED;
+ }
+
+ @WorkerThread
+ private static class IntentReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (WIFI_STATE_CHANGED_ACTION.equals(intent.getAction())) {
+ sWifiState = intent.getIntExtra(EXTRA_WIFI_STATE, WIFI_STATE_DISABLED);
+ }
+ }
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStateWorkerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStateWorkerTest.java
new file mode 100644
index 0000000..2589a90
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiStateWorkerTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2022 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.settingslib.wifi;
+
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.os.UserHandle;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiStateWorkerTest {
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Spy
+ Context mContext = ApplicationProvider.getApplicationContext();
+ @Mock
+ WifiManager mWifiManager;
+
+ WifiStateWorker mWifiStateWorker;
+
+ @Before
+ public void setUp() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+ WifiStateWorker.sWifiManager = mWifiManager;
+
+ mWifiStateWorker = WifiStateWorker.getInstance(mContext);
+ }
+
+ @Test
+ public void getInstance_diffContext_getSameInstance() {
+ Context context = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+ WifiStateWorker instance = WifiStateWorker.getInstance(context);
+
+ assertThat(mContext).isNotEqualTo(context);
+ assertThat(mWifiStateWorker).isEqualTo(instance);
+ }
+
+ @Test
+ public void getWifiState_wifiStateDisabling_returnWifiStateDisabling() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLING);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLING);
+ }
+
+ @Test
+ public void getWifiState_wifiStateDisabled_returnWifiStateDisabled() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLED);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_DISABLED);
+ }
+
+ @Test
+ public void getWifiState_wifiStateEnabling_returnWifiStateEnabling() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLING);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLING);
+ }
+
+ @Test
+ public void getWifiState_wifiStateEnabled_returnWifiStateEnabled() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.getWifiState()).isEqualTo(WIFI_STATE_ENABLED);
+ }
+
+ @Test
+ public void isWifiEnabled_wifiStateDisabling_returnFalse() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLING);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+ }
+
+ @Test
+ public void isWifiEnabled_wifiStateDisabled_returnFalse() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_DISABLED);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+ }
+
+ @Test
+ public void isWifiEnabled_wifiStateEnabling_returnFalse() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLING);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isFalse();
+ }
+
+ @Test
+ public void isWifiEnabled_wifiStateEnabled_returnTrue() {
+ when(mWifiManager.getWifiState()).thenReturn(WIFI_STATE_ENABLED);
+ WifiStateWorker.refresh();
+
+ assertThat(mWifiStateWorker.isWifiEnabled()).isTrue();
+ }
+}
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index 58adb91..e1b294f 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -21,6 +21,9 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:singleLine="true"
+ android:marqueeRepeatLimit="1"
+ android:ellipsize="marquee"
style="@style/TextAppearance.AuthCredential.Title"/>
<TextView
@@ -28,13 +31,16 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="@integer/biometric_dialog_text_gravity"
+ android:singleLine="true"
+ android:marqueeRepeatLimit="1"
+ android:ellipsize="marquee"
style="@style/TextAppearance.AuthCredential.Subtitle"/>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:gravity="@integer/biometric_dialog_text_gravity"
+ android:scrollbars ="vertical"
style="@style/TextAppearance.AuthCredential.Description"/>
<Space android:id="@+id/space_above_icon"
diff --git a/packages/SystemUI/res/layout/media_carousel.xml b/packages/SystemUI/res/layout/media_carousel.xml
index 52132e8..50d3cc4 100644
--- a/packages/SystemUI/res/layout/media_carousel.xml
+++ b/packages/SystemUI/res/layout/media_carousel.xml
@@ -48,7 +48,7 @@
android:layout_width="wrap_content"
android:layout_height="48dp"
android:layout_marginBottom="4dp"
- android:tint="?android:attr/textColor"
+ android:tint="@color/media_paging_indicator"
android:forceHasOverlappingRendering="false"
/>
</FrameLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 24118d2..02ba271 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -176,6 +176,7 @@
<!-- media -->
<color name="media_seamless_border">?android:attr/colorAccent</color>
+ <color name="media_paging_indicator">@color/material_dynamic_neutral_variant80</color>
<!-- media output dialog-->
<color name="media_dialog_background" android:lstar="98">@color/material_dynamic_neutral90</color>
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
index f182e77..9af8300 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenu.java
@@ -39,10 +39,13 @@
import androidx.annotation.NonNull;
+import com.android.internal.accessibility.dialog.AccessibilityTarget;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.Prefs;
import com.android.systemui.shared.system.SysUiStatsLog;
+import java.util.List;
+
/**
* Contains logic for an accessibility floating menu view.
*/
@@ -120,9 +123,13 @@
if (isShowing()) {
return;
}
+ final List<AccessibilityTarget> targetList = getTargets(mContext, ACCESSIBILITY_BUTTON);
+ if (targetList.isEmpty()) {
+ return;
+ }
mMenuView.show();
- mMenuView.onTargetsChanged(getTargets(mContext, ACCESSIBILITY_BUTTON));
+ mMenuView.onTargetsChanged(targetList);
mMenuView.updateOpacityWith(isFadeEffectEnabled(mContext),
getOpacityValue(mContext));
mMenuView.setSizeType(getSizeType(mContext));
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
index cc5a792..11353f6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuController.java
@@ -51,26 +51,19 @@
private int mBtnMode;
private String mBtnTargets;
private boolean mIsKeyguardVisible;
- private boolean mIsAccessibilityManagerServiceReady;
@VisibleForTesting
final KeyguardUpdateMonitorCallback mKeyguardCallback = new KeyguardUpdateMonitorCallback() {
- // Accessibility floating menu needs to retrieve information from
- // AccessibilityManagerService, and it would be ready before onUserUnlocked().
+
@Override
public void onUserUnlocked() {
- mIsAccessibilityManagerServiceReady = true;
handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
}
- // Keyguard state would be changed before AccessibilityManagerService is ready to retrieve,
- // need to wait until receive onUserUnlocked().
@Override
public void onKeyguardVisibilityChanged(boolean showing) {
mIsKeyguardVisible = showing;
- if (mIsAccessibilityManagerServiceReady) {
- handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
- }
+ handleFloatingMenuVisibility(mIsKeyguardVisible, mBtnMode, mBtnTargets);
}
@Override
@@ -99,7 +92,6 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mIsKeyguardVisible = false;
- mIsAccessibilityManagerServiceReady = false;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index 55da8da..1413f4a 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -34,6 +34,7 @@
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
+import android.text.method.ScrollingMovementMethod;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
@@ -706,6 +707,12 @@
mTitleView.setText(mPromptInfo.getTitle());
+ //setSelected could make marguee work
+ mTitleView.setSelected(true);
+ mSubtitleView.setSelected(true);
+ //make description view become scrollable
+ mDescriptionView.setMovementMethod(new ScrollingMovementMethod());
+
if (isDeviceCredentialAllowed()) {
final CharSequence credentialButtonText;
@Utils.CredentialType final int credentialType =
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
index 6afe420..dbfce2e 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsDialogMeasureAdapter.java
@@ -139,6 +139,9 @@
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(clampedSpacerHeight, MeasureSpec.EXACTLY));
+ } else if (child.getId() == R.id.description) {
+ //skip description view and compute later
+ continue;
} else {
child.measure(
MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
@@ -150,9 +153,27 @@
}
}
+ //re-calculate the height of description
+ View description = mView.findViewById(R.id.description);
+ totalHeight += measureDescription(description, displayHeight, width, totalHeight);
+
return new AuthDialog.LayoutParams(width, totalHeight);
}
+ private int measureDescription(View description, int displayHeight, int currWidth,
+ int currHeight) {
+ //description view should be measured in AuthBiometricFingerprintView#onMeasureInternal
+ //so we could getMeasuredHeight in onMeasureInternalPortrait directly.
+ int newHeight = description.getMeasuredHeight() + currHeight;
+ int limit = (int) (displayHeight * 0.75);
+ if (newHeight > limit) {
+ description.measure(
+ MeasureSpec.makeMeasureSpec(currWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(limit - currHeight, MeasureSpec.EXACTLY));
+ }
+ return description.getMeasuredHeight();
+ }
+
@NonNull
private AuthDialog.LayoutParams onMeasureInternalLandscape(int width, int height) {
final WindowMetrics windowMetrics = mWindowManager.getMaximumWindowMetrics();
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
index 79ac9e8..39f00f4 100644
--- a/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/LogModule.java
@@ -176,7 +176,6 @@
return factory.create("MediaTttReceiver", 20);
}
-
/**
* Provides a logging buffer for logs related to the media mute-await connections. See
* {@link com.android.systemui.media.muteawait.MediaMuteAwaitConnectionManager}.
@@ -199,6 +198,16 @@
return factory.create("NearbyMediaDevicesLog", 20);
}
+ /**
+ * Provides a buffer for logs related to media view events
+ */
+ @Provides
+ @SysUISingleton
+ @MediaViewLog
+ public static LogBuffer provideMediaViewLogBuffer(LogBufferFactory factory) {
+ return factory.create("MediaView", 100);
+ }
+
/** Allows logging buffers to be tweaked via adb on debug builds but not on prod builds. */
@Provides
@SysUISingleton
diff --git a/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
new file mode 100644
index 0000000..75a34fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/log/dagger/MediaViewLog.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 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.log.dagger;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.android.systemui.log.LogBuffer;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+
+import javax.inject.Qualifier;
+
+/**
+ * A {@link LogBuffer} for {@link com.android.systemui.media.MediaViewLogger}
+ */
+@Qualifier
+@Documented
+@Retention(RUNTIME)
+public @interface MediaViewLog {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index ca25a18..7b72ab7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -533,7 +533,9 @@
}
private fun recreatePlayers() {
- pageIndicator.tintList = ColorStateList.valueOf(R.color.material_dynamic_neutral_variant80)
+ pageIndicator.tintList = ColorStateList.valueOf(
+ context.getColor(R.color.media_paging_indicator)
+ )
MediaPlayerData.mediaData().forEach { (key, data, isSsMediaRec) ->
if (isSsMediaRec) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 48a63ed..12369e5 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -176,9 +176,12 @@
private String mPackageName;
private boolean mIsScrubbing = false;
+ private boolean mIsSeekBarEnabled = false;
private final SeekBarViewModel.ScrubbingChangeListener mScrubbingChangeListener =
this::setIsScrubbing;
+ private final SeekBarViewModel.EnabledChangeListener mEnabledChangeListener =
+ this::setIsSeekBarEnabled;
/**
* Initialize a new control panel
@@ -235,8 +238,9 @@
public void onDestroy() {
if (mSeekBarObserver != null) {
mSeekBarViewModel.getProgress().removeObserver(mSeekBarObserver);
- mSeekBarViewModel.removeScrubbingChangeListener(mScrubbingChangeListener);
}
+ mSeekBarViewModel.removeScrubbingChangeListener(mScrubbingChangeListener);
+ mSeekBarViewModel.removeEnabledChangeListener(mEnabledChangeListener);
mSeekBarViewModel.onDestroy();
mMediaViewController.onDestroy();
}
@@ -283,7 +287,7 @@
}
/** Sets whether the user is touching the seek bar to change the track position. */
- public void setIsScrubbing(boolean isScrubbing) {
+ private void setIsScrubbing(boolean isScrubbing) {
if (mMediaData == null || mMediaData.getSemanticActions() == null) {
return;
}
@@ -295,6 +299,14 @@
updateDisplayForScrubbingChange(mMediaData.getSemanticActions()));
}
+ private void setIsSeekBarEnabled(boolean isSeekBarEnabled) {
+ if (isSeekBarEnabled == this.mIsSeekBarEnabled) {
+ return;
+ }
+ this.mIsSeekBarEnabled = isSeekBarEnabled;
+ updateSeekBarVisibility();
+ }
+
/**
* Get the context
*
@@ -313,6 +325,7 @@
mSeekBarViewModel.getProgress().observeForever(mSeekBarObserver);
mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
mSeekBarViewModel.setScrubbingChangeListener(mScrubbingChangeListener);
+ mSeekBarViewModel.setEnabledChangeListener(mEnabledChangeListener);
mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER);
vh.getPlayer().setOnLongClickListener(v -> {
@@ -450,8 +463,8 @@
bindOutputSwitcherChip(data);
bindLongPressMenu(data);
- bindActionButtons(data);
bindScrubbingTime(data);
+ bindActionButtons(data);
boolean isSongUpdated = bindSongMetadata(data);
bindArtworkAndColors(data, isSongUpdated);
@@ -735,13 +748,18 @@
/* showInCompact= */ false);
}
}
+
+ updateSeekBarVisibility();
+ }
+
+ private void updateSeekBarVisibility() {
+ ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
expandedSet.setVisibility(R.id.media_progress_bar, getSeekBarVisibility());
- expandedSet.setAlpha(R.id.media_progress_bar, mSeekBarViewModel.getEnabled() ? 1.0f : 0.0f);
+ expandedSet.setAlpha(R.id.media_progress_bar, mIsSeekBarEnabled ? 1.0f : 0.0f);
}
private int getSeekBarVisibility() {
- boolean seekbarEnabled = mSeekBarViewModel.getEnabled();
- if (seekbarEnabled) {
+ if (mIsSeekBarEnabled) {
return ConstraintSet.VISIBLE;
}
// If disabled and "neighbours" are visible, set progress bar to INVISIBLE instead of GONE
@@ -751,8 +769,7 @@
private boolean areAnyExpandedBottomActionsVisible() {
ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
- int[] referencedIds = mMediaViewHolder.getActionsTopBarrier().getReferencedIds();
- for (int id : referencedIds) {
+ for (int id : MediaViewHolder.Companion.getExpandedBottomActionIds()) {
if (expandedSet.getVisibility(id) == ConstraintSet.VISIBLE) {
return true;
}
@@ -872,7 +889,6 @@
}
/** Updates all the views that might change due to a scrubbing state change. */
- // TODO(b/209656742): Handle scenarios where actionPrev and/or actionNext aren't active.
private void updateDisplayForScrubbingChange(@NonNull MediaButton semanticActions) {
// Update visibilities of the scrubbing time views and the scrubbing-dependent buttons.
bindScrubbingTime(mMediaData);
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
index 5210499..327268b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewController.kt
@@ -35,7 +35,8 @@
class MediaViewController @Inject constructor(
private val context: Context,
private val configurationController: ConfigurationController,
- private val mediaHostStatesManager: MediaHostStatesManager
+ private val mediaHostStatesManager: MediaHostStatesManager,
+ private val logger: MediaViewLogger
) {
/**
@@ -330,6 +331,7 @@
// is cheap
setGutsViewState(result)
viewStates[cacheKey] = result
+ logger.logMediaSize("measured new viewState", result.width, result.height)
} else {
// This is an interpolated state
val startState = state.copy().also { it.expansion = 0.0f }
@@ -344,6 +346,7 @@
startViewState,
endViewState,
state.expansion)
+ logger.logMediaSize("interpolated viewState", result.width, result.height)
}
if (state.squishFraction < 1f) {
return squishViewState(result, state.squishFraction)
@@ -371,6 +374,7 @@
*/
fun attach(transitionLayout: TransitionLayout, type: TYPE) {
updateMediaViewControllerType(type)
+ logger.logMediaLocation("attach", currentStartLocation, currentEndLocation)
this.transitionLayout = transitionLayout
layoutController.attach(transitionLayout)
if (currentEndLocation == -1) {
@@ -409,6 +413,7 @@
currentEndLocation = endLocation
currentStartLocation = startLocation
currentTransitionProgress = transitionProgress
+ logger.logMediaLocation("setCurrentState", startLocation, endLocation)
val shouldAnimate = animateNextStateChange && !applyImmediately
@@ -461,6 +466,7 @@
result = layoutController.getInterpolatedState(startViewState, endViewState,
transitionProgress, tmpState)
}
+ logger.logMediaSize("setCurrentState", result.width, result.height)
layoutController.setState(result, applyImmediately, shouldAnimate, animationDuration,
animationDelay)
}
@@ -478,6 +484,7 @@
result.height = Math.max(it.measuredHeight, result.height)
result.width = Math.max(it.measuredWidth, result.width)
}
+ logger.logMediaSize("update to carousel", result.width, result.height)
return result
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
index 8964d71..b8b7318 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewHolder.kt
@@ -187,5 +187,17 @@
R.id.action3,
R.id.action4
)
+
+ val expandedBottomActionIds = setOf(
+ R.id.actionPrev,
+ R.id.actionNext,
+ R.id.action0,
+ R.id.action1,
+ R.id.action2,
+ R.id.action3,
+ R.id.action4,
+ R.id.media_scrubbing_elapsed_time,
+ R.id.media_scrubbing_total_time
+ )
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt b/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt
new file mode 100644
index 0000000..73868189
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaViewLogger.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 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.media
+
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogLevel
+import com.android.systemui.log.dagger.MediaViewLog
+import javax.inject.Inject
+
+private const val TAG = "MediaView"
+
+/**
+ * A buffered log for media view events that are too noisy for regular logging
+ */
+@SysUISingleton
+class MediaViewLogger @Inject constructor(
+ @MediaViewLog private val buffer: LogBuffer
+) {
+ fun logMediaSize(reason: String, width: Int, height: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = reason
+ int1 = width
+ int2 = height
+ },
+ {
+ "size ($str1): $int1 x $int2"
+ }
+ )
+ }
+
+ fun logMediaLocation(reason: String, startLocation: Int, endLocation: Int) {
+ buffer.log(
+ TAG,
+ LogLevel.DEBUG,
+ {
+ str1 = reason
+ int1 = startLocation
+ int2 = endLocation
+ },
+ {
+ "location ($str1): $int1 -> $int2"
+ }
+ )
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
index 5218492..193166b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt
@@ -76,7 +76,11 @@
) {
private var _data = Progress(false, false, false, false, null, 0)
set(value) {
+ val enabledChanged = value.enabled != field.enabled
field = value
+ if (enabledChanged) {
+ enabledChangeListener?.onEnabledChanged(value.enabled)
+ }
_progress.postValue(value)
}
private val _progress = MutableLiveData<Progress>().apply {
@@ -122,6 +126,7 @@
}
private var scrubbingChangeListener: ScrubbingChangeListener? = null
+ private var enabledChangeListener: EnabledChangeListener? = null
/** Set to true when the user is touching the seek bar to change the position. */
private var scrubbing = false
@@ -136,8 +141,6 @@
lateinit var logSeek: () -> Unit
- fun getEnabled() = _data.enabled
-
/**
* Event indicating that the user has started interacting with the seek bar.
*/
@@ -189,6 +192,9 @@
/**
* Updates media information.
+ *
+ * This function makes a binder call, so it must happen on a worker thread.
+ *
* @param mediaController controller for media session
*/
@WorkerThread
@@ -232,6 +238,7 @@
cancel?.run()
cancel = null
scrubbingChangeListener = null
+ enabledChangeListener = null
}
@WorkerThread
@@ -279,11 +286,26 @@
}
}
+ fun setEnabledChangeListener(listener: EnabledChangeListener) {
+ enabledChangeListener = listener
+ }
+
+ fun removeEnabledChangeListener(listener: EnabledChangeListener) {
+ if (listener == enabledChangeListener) {
+ enabledChangeListener = null
+ }
+ }
+
/** Listener interface to be notified when the user starts or stops scrubbing. */
interface ScrubbingChangeListener {
fun onScrubbingChanged(scrubbing: Boolean)
}
+ /** Listener interface to be notified when the seekbar's enabled status changes. */
+ interface EnabledChangeListener {
+ fun onEnabledChanged(enabled: Boolean)
+ }
+
private class SeekBarChangeListener(
val viewModel: SeekBarViewModel
) : SeekBar.OnSeekBarChangeListener {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 740ecff..72488f3 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -197,7 +197,6 @@
private final Optional<Pip> mPipOptional;
private final Optional<Recents> mRecentsOptional;
private final DeviceConfigProxy mDeviceConfigProxy;
- private final NavigationBarTransitions mNavigationBarTransitions;
private final Optional<BackAnimation> mBackAnimation;
private final Handler mHandler;
private final NavigationBarOverlayController mNavbarOverlayController;
@@ -514,7 +513,6 @@
InputMethodManager inputMethodManager,
DeadZone deadZone,
DeviceConfigProxy deviceConfigProxy,
- NavigationBarTransitions navigationBarTransitions,
Optional<BackAnimation> backAnimation) {
super(navigationBarView);
mFrame = navigationBarFrame;
@@ -539,7 +537,6 @@
mRecentsOptional = recentsOptional;
mDeadZone = deadZone;
mDeviceConfigProxy = deviceConfigProxy;
- mNavigationBarTransitions = navigationBarTransitions;
mBackAnimation = backAnimation;
mHandler = mainHandler;
mNavbarOverlayController = navbarOverlayController;
@@ -564,7 +561,6 @@
public void onInit() {
// TODO: A great deal of this code should probably live in onViewAttached.
// It should also has corresponding cleanup in onViewDetached.
- mView.setBarTransitions(mNavigationBarTransitions);
mView.setTouchHandler(mTouchHandler);
mView.setNavBarMode(mNavBarMode);
mView.updateRotationButton();
@@ -636,7 +632,7 @@
mView.setOnVerticalChangedListener(this::onVerticalChanged);
mView.setOnTouchListener(this::onNavigationTouch);
if (mSavedState != null) {
- getBarTransitions().getLightTransitionsController().restoreState(mSavedState);
+ mView.getLightTransitionsController().restoreState(mSavedState);
}
setNavigationIconHints(mNavigationIconHints);
mView.setWindowVisible(isNavBarWindowVisible());
@@ -709,7 +705,8 @@
mView.getRotationButtonController();
rotationButtonController.setRotationCallback(null);
mView.setUpdateActiveTouchRegionsCallback(null);
- getBarTransitions().destroy();
+ mView.getBarTransitions().destroy();
+ mView.getLightTransitionsController().destroy(mContext);
mOverviewProxyService.removeCallback(mOverviewProxyListener);
mBroadcastDispatcher.unregisterReceiver(mBroadcastReceiver);
if (mOrientationHandle != null) {
@@ -735,7 +732,7 @@
outState.putInt(EXTRA_APPEARANCE, mAppearance);
outState.putInt(EXTRA_BEHAVIOR, mBehavior);
outState.putBoolean(EXTRA_TRANSIENT_STATE, mTransientShown);
- getBarTransitions().getLightTransitionsController().saveState(outState);
+ mView.getLightTransitionsController().saveState(outState);
}
/**
@@ -896,7 +893,7 @@
pw.println(" mTransientShown=" + mTransientShown);
pw.println(" mTransientShownFromGestureOnSystemBar="
+ mTransientShownFromGestureOnSystemBar);
- dumpBarTransitions(pw, "mNavigationBarView", getBarTransitions());
+ dumpBarTransitions(pw, "mNavigationBarView", mView.getBarTransitions());
mView.dump(pw);
}
@@ -1433,7 +1430,7 @@
mLightBarController = lightBarController;
if (mLightBarController != null) {
mLightBarController.setNavigationBar(
- getBarTransitions().getLightTransitionsController());
+ mView.getLightTransitionsController());
}
}
@@ -1475,7 +1472,7 @@
mCentralSurfacesOptionalLazy.get().map(CentralSurfaces::isDeviceInteractive)
.orElse(false)
&& mNavigationBarWindowState != WINDOW_STATE_HIDDEN;
- getBarTransitions().transitionTo(mTransitionMode, anim);
+ mView.getBarTransitions().transitionTo(mTransitionMode, anim);
}
public void disableAnimationsDuringHide(long delay) {
@@ -1495,11 +1492,11 @@
}
public NavigationBarTransitions getBarTransitions() {
- return mNavigationBarTransitions;
+ return mView.getBarTransitions();
}
public void finishBarAnimations() {
- getBarTransitions().finishAnimations();
+ mView.getBarTransitions().finishAnimations();
}
private WindowManager.LayoutParams getBarLayoutParams(int rotation) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
index e625501..58e07db 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarTransitions.java
@@ -31,19 +31,17 @@
import com.android.systemui.Dependency;
import com.android.systemui.R;
-import com.android.systemui.navigationbar.NavigationBarComponent.NavigationBarScope;
import com.android.systemui.navigationbar.buttons.ButtonDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.BarTransitions;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
-import javax.inject.Inject;
-
-/** */
-@NavigationBarScope
public final class NavigationBarTransitions extends BarTransitions implements
LightBarTransitionsController.DarkIntensityApplier {
@@ -83,13 +81,15 @@
}
};
- @Inject
- public NavigationBarTransitions(
- NavigationBarView view,
- LightBarTransitionsController.Factory lightBarTransitionsControllerFactory) {
+ public NavigationBarTransitions(NavigationBarView view, CommandQueue commandQueue) {
super(view, R.drawable.nav_background);
mView = view;
- mLightTransitionsController = lightBarTransitionsControllerFactory.create(this);
+ mLightTransitionsController = new LightBarTransitionsController(
+ view.getContext(),
+ this,
+ commandQueue,
+ Dependency.get(KeyguardStateController.class),
+ Dependency.get(StatusBarStateController.class));
mAllowAutoDimWallpaperNotVisible = view.getContext().getResources()
.getBoolean(R.bool.config_navigation_bar_enable_auto_dim_no_visible_wallpaper);
mDarkIntensityListeners = new ArrayList();
@@ -127,7 +127,6 @@
Display.DEFAULT_DISPLAY);
} catch (RemoteException e) {
}
- mLightTransitionsController.destroy();
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 8878c2d..abff914 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -85,6 +85,7 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.AutoHideController;
import com.android.systemui.statusbar.phone.CentralSurfaces;
import com.android.systemui.statusbar.phone.LightBarTransitionsController;
@@ -139,7 +140,7 @@
private EdgeBackGestureHandler mEdgeBackGestureHandler;
private final DeadZone mDeadZone;
private boolean mDeadZoneConsuming = false;
- private NavigationBarTransitions mBarTransitions;
+ private final NavigationBarTransitions mBarTransitions;
@Nullable
private AutoHideController mAutoHideController;
@@ -369,6 +370,7 @@
mConfiguration.updateFrom(context.getResources().getConfiguration());
mScreenPinningNotify = new ScreenPinningNotify(mContext);
+ mBarTransitions = new NavigationBarTransitions(this, Dependency.get(CommandQueue.class));
mButtonDispatchers.put(R.id.back, new ButtonDispatcher(R.id.back));
mButtonDispatchers.put(R.id.home, new ButtonDispatcher(R.id.home));
@@ -416,14 +418,14 @@
}
}
- void setBarTransitions(NavigationBarTransitions navigationBarTransitions) {
- mBarTransitions = navigationBarTransitions;
- }
-
public void setAutoHideController(AutoHideController autoHideController) {
mAutoHideController = autoHideController;
}
+ public NavigationBarTransitions getBarTransitions() {
+ return mBarTransitions;
+ }
+
public LightBarTransitionsController getLightTransitionsController() {
return mBarTransitions.getLightTransitionsController();
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index 363baaa..cdc6b3b 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -264,7 +264,7 @@
mWindowContext = null;
}
mAutoHideController.setNavigationBar(null);
- mLightBarTransitionsController.destroy();
+ mLightBarTransitionsController.destroy(mContext);
mLightBarController.setNavigationBar(null);
mPipOptional.ifPresent(this::removePipExclusionBoundsChangeListener);
mInitialized = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 673c1a6..18877f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -233,9 +233,6 @@
LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) mSystemIconsContainer.getLayoutParams();
- int marginStart = getResources().getDimensionPixelSize(
- R.dimen.system_icons_super_container_margin_start);
-
// Use status_bar_padding_end to replace original
// system_icons_super_container_avatarless_margin_end to prevent different end alignment
// between PhoneStatusBarView and KeyguardStatusBarView
@@ -248,8 +245,7 @@
// 1. status bar layout: mPadding(consider round_corner + privacy dot)
// 2. icon container: R.dimen.status_bar_padding_end
- if (marginEnd != lp.getMarginEnd() || marginStart != lp.getMarginStart()) {
- lp.setMarginStart(marginStart);
+ if (marginEnd != lp.getMarginEnd()) {
lp.setMarginEnd(marginEnd);
mSystemIconsContainer.setLayoutParams(lp);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 16fddb42..b6ad9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -93,8 +93,7 @@
mDisplayId = mContext.getDisplayId();
}
- /** Call to cleanup the LightBarTransitionsController when done with it. */
- public void destroy() {
+ public void destroy(Context context) {
mCommandQueue.removeCallback(this);
mStatusBarStateController.removeCallback(this);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
index e027a2b7..558261b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/floatingmenu/AccessibilityFloatingMenuTest.java
@@ -87,6 +87,17 @@
assertThat(mMenuView.isShowing()).isFalse();
}
+ @Test
+ public void showMenuView_emptyTarget_notShow() {
+ final List<String> emptyTargets = new ArrayList<>();
+ doReturn(emptyTargets).when(mAccessibilityManager).getAccessibilityShortcutTargets(
+ anyInt());
+
+ mMenu.show();
+
+ assertThat(mMenuView.isShowing()).isFalse();
+ }
+
@After
public void tearDown() {
mMenu.hide();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index 33db993..4e130d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -291,7 +291,7 @@
seamlessButton = View(context)
seamlessIcon = ImageView(context)
seamlessText = TextView(context)
- seekBar = SeekBar(context)
+ seekBar = SeekBar(context).also { it.id = R.id.media_progress_bar }
settings = ImageButton(context)
cancel = View(context)
cancelText = TextView(context)
@@ -539,8 +539,8 @@
}
@Test
- fun bind_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
- whenever(seekBarViewModel.getEnabled()).thenReturn(false)
+ fun bind_seekBarDisabled_hasActions_seekBarVisibilityIsSetToInvisible() {
+ useRealConstraintSets()
val icon = context.getDrawable(android.R.drawable.ic_media_play)
val semanticActions = MediaButton(
@@ -550,21 +550,84 @@
val state = mediaData.copy(semanticActions = semanticActions)
player.attachPlayer(viewHolder)
+ getEnabledChangeListener().onEnabledChanged(enabled = false)
+
player.bindPlayer(state, PACKAGE)
- verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
+ assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.INVISIBLE)
}
@Test
fun bind_seekBarDisabled_noActions_seekBarVisibilityIsSetToGone() {
- whenever(seekBarViewModel.getEnabled()).thenReturn(false)
+ useRealConstraintSets()
+
+ val state = mediaData.copy(semanticActions = MediaButton())
+ player.attachPlayer(viewHolder)
+ getEnabledChangeListener().onEnabledChanged(enabled = false)
+
+ player.bindPlayer(state, PACKAGE)
+
+ assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.GONE)
+ }
+
+ @Test
+ fun bind_seekBarEnabled_seekBarVisible() {
+ useRealConstraintSets()
+
+ val state = mediaData.copy(semanticActions = MediaButton())
+ player.attachPlayer(viewHolder)
+ getEnabledChangeListener().onEnabledChanged(enabled = true)
+
+ player.bindPlayer(state, PACKAGE)
+
+ assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.VISIBLE)
+ }
+
+ @Test
+ fun seekBarChangesToEnabledAfterBind_seekBarChangesToVisible() {
+ useRealConstraintSets()
+
+ val state = mediaData.copy(semanticActions = MediaButton())
+ player.attachPlayer(viewHolder)
+ player.bindPlayer(state, PACKAGE)
+
+ getEnabledChangeListener().onEnabledChanged(enabled = true)
+
+ assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.VISIBLE)
+ }
+
+ @Test
+ fun seekBarChangesToDisabledAfterBind_noActions_seekBarChangesToGone() {
+ useRealConstraintSets()
val state = mediaData.copy(semanticActions = MediaButton())
player.attachPlayer(viewHolder)
+ getEnabledChangeListener().onEnabledChanged(enabled = true)
player.bindPlayer(state, PACKAGE)
- verify(expandedSet).setVisibility(R.id.media_progress_bar, ConstraintSet.INVISIBLE)
+ getEnabledChangeListener().onEnabledChanged(enabled = false)
+
+ assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.GONE)
+ }
+
+ @Test
+ fun seekBarChangesToDisabledAfterBind_hasActions_seekBarChangesToInvisible() {
+ useRealConstraintSets()
+
+ val icon = context.getDrawable(android.R.drawable.ic_media_play)
+ val semanticActions = MediaButton(
+ nextOrCustom = MediaAction(icon, Runnable {}, "next", null)
+ )
+ val state = mediaData.copy(semanticActions = semanticActions)
+
+ player.attachPlayer(viewHolder)
+ getEnabledChangeListener().onEnabledChanged(enabled = true)
+ player.bindPlayer(state, PACKAGE)
+
+ getEnabledChangeListener().onEnabledChanged(enabled = false)
+
+ assertThat(expandedSet.getVisibility(seekBar.id)).isEqualTo(ConstraintSet.INVISIBLE)
}
@Test
@@ -1317,4 +1380,24 @@
private fun getScrubbingChangeListener(): SeekBarViewModel.ScrubbingChangeListener =
withArgCaptor { verify(seekBarViewModel).setScrubbingChangeListener(capture()) }
+
+ private fun getEnabledChangeListener(): SeekBarViewModel.EnabledChangeListener =
+ withArgCaptor { verify(seekBarViewModel).setEnabledChangeListener(capture()) }
+
+ /**
+ * Update our test to use real ConstraintSets instead of mocks.
+ *
+ * Some item visibilities, such as the seekbar visibility, are dependent on other action's
+ * visibilities. If we use mocks for the ConstraintSets, then action visibility changes are
+ * just thrown away instead of being saved for reference later. This method sets us up to use
+ * ConstraintSets so that we do save visibility changes.
+ *
+ * TODO(b/229740380): Can/should we use real expanded and collapsed sets for all tests?
+ */
+ private fun useRealConstraintSets() {
+ expandedSet = ConstraintSet()
+ collapsedSet = ConstraintSet()
+ whenever(mediaViewController.expandedLayout).thenReturn(expandedSet)
+ whenever(mediaViewController.collapsedLayout).thenReturn(collapsedSet)
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
index b7d5ba1..604e1f3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaViewControllerTest.kt
@@ -12,6 +12,8 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
/**
* Tests for {@link MediaViewController}.
@@ -20,16 +22,25 @@
@RunWith(AndroidTestingRunner::class)
@TestableLooper.RunWithLooper
class MediaViewControllerTest : SysuiTestCase() {
+ @Mock
+ private lateinit var logger: MediaViewLogger
+
private val configurationController =
com.android.systemui.statusbar.phone.ConfigurationControllerImpl(context)
private val mediaHostStatesManager = MediaHostStatesManager()
- private val mediaViewController =
- MediaViewController(context, configurationController, mediaHostStatesManager)
+ private lateinit var mediaViewController: MediaViewController
private val mediaHostStateHolder = MediaHost.MediaHostStateHolder()
private var transitionLayout = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
@Before
fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ mediaViewController = MediaViewController(
+ context,
+ configurationController,
+ mediaHostStatesManager,
+ logger
+ )
mediaViewController.attach(transitionLayout, MediaViewController.TYPE.PLAYER)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
index 4a740f6..f5b006d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTest.java
@@ -205,9 +205,10 @@
when(mNavigationBarView.getAccessibilityButton()).thenReturn(mAccessibilityButton);
when(mNavigationBarView.getImeSwitchButton()).thenReturn(mImeSwitchButton);
when(mNavigationBarView.getBackButton()).thenReturn(mBackButton);
+ when(mNavigationBarView.getBarTransitions()).thenReturn(mNavigationBarTransitions);
when(mNavigationBarView.getRotationButtonController())
.thenReturn(mRotationButtonController);
- when(mNavigationBarTransitions.getLightTransitionsController())
+ when(mNavigationBarView.getLightTransitionsController())
.thenReturn(mLightBarTransitionsController);
when(mStatusBarKeyguardViewManager.isNavBarVisible()).thenReturn(true);
setupSysuiDependency();
@@ -458,7 +459,6 @@
mInputMethodManager,
mDeadZone,
mDeviceConfigProxyFake,
- mNavigationBarTransitions,
Optional.of(mock(BackAnimation.class))));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
index 084eca8..6a2a78b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarTransitionsTest.java
@@ -21,6 +21,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
@@ -36,8 +37,8 @@
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.recents.OverviewProxyService;
+import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.phone.BarTransitions;
-import com.android.systemui.statusbar.phone.LightBarTransitionsController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import org.junit.Before;
@@ -52,10 +53,6 @@
public class NavigationBarTransitionsTest extends SysuiTestCase {
@Mock
- LightBarTransitionsController.Factory mLightBarTransitionsFactory;
- @Mock
- LightBarTransitionsController mLightBarTransitions;
- @Mock
EdgeBackGestureHandler.Factory mEdgeBackGestureHandlerFactory;
@Mock
EdgeBackGestureHandler mEdgeBackGestureHandler;
@@ -79,11 +76,10 @@
.when(mDependency.injectMockDependency(NavigationModeController.class))
.getCurrentUserContext();
- when(mLightBarTransitionsFactory.create(any())).thenReturn(mLightBarTransitions);
NavigationBarView navBar = spy(new NavigationBarView(mContext, null));
when(navBar.getCurrentView()).thenReturn(navBar);
when(navBar.findViewById(anyInt())).thenReturn(navBar);
- mTransitions = new NavigationBarTransitions(navBar, mLightBarTransitionsFactory);
+ mTransitions = new NavigationBarTransitions(navBar, mock(CommandQueue.class));
}
@Test
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 97dd323..36c40a1 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -577,12 +577,14 @@
mPackageWatchdog.onPackageFailure(r.getPackageListWithVersionCode(),
PackageWatchdog.FAILURE_REASON_APP_CRASH);
- mService.mProcessList.noteAppKill(r, (crashInfo != null
- && "Native crash".equals(crashInfo.exceptionClassName))
- ? ApplicationExitInfo.REASON_CRASH_NATIVE
- : ApplicationExitInfo.REASON_CRASH,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- "crash");
+ synchronized (mService) {
+ mService.mProcessList.noteAppKill(r, (crashInfo != null
+ && "Native crash".equals(crashInfo.exceptionClassName))
+ ? ApplicationExitInfo.REASON_CRASH_NATIVE
+ : ApplicationExitInfo.REASON_CRASH,
+ ApplicationExitInfo.SUBREASON_UNKNOWN,
+ "crash");
+ }
}
final int relaunchReason = r != null
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 54e83ec..4bba686 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -46,6 +46,7 @@
import com.android.internal.display.BrightnessSynchronizer;
import com.android.internal.os.BackgroundThread;
import com.android.server.EventLogTags;
+import com.android.server.display.DisplayPowerController.BrightnessEvent;
import java.io.PrintWriter;
@@ -147,6 +148,9 @@
// The currently accepted nominal ambient light level.
private float mAmbientLux;
+ // The last ambient lux value prior to passing the darkening or brightening threshold.
+ private float mPreThresholdLux;
+
// True if mAmbientLux holds a valid value.
private boolean mAmbientLuxValid;
@@ -154,6 +158,9 @@
private float mAmbientBrighteningThreshold;
private float mAmbientDarkeningThreshold;
+ // The last brightness value prior to passing the darkening or brightening threshold.
+ private float mPreThresholdBrightness;
+
// The screen brightness threshold at which to brighten or darken the screen.
private float mScreenBrighteningThreshold;
private float mScreenDarkeningThreshold;
@@ -325,6 +332,21 @@
}
public float getAutomaticScreenBrightness() {
+ return getAutomaticScreenBrightness(null);
+ }
+
+ float getAutomaticScreenBrightness(BrightnessEvent brightnessEvent) {
+ if (brightnessEvent != null) {
+ brightnessEvent.lux =
+ mAmbientLuxValid ? mAmbientLux : PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ brightnessEvent.preThresholdLux = mPreThresholdLux;
+ brightnessEvent.preThresholdBrightness = mPreThresholdBrightness;
+ brightnessEvent.recommendedBrightness = mScreenAutoBrightness;
+ brightnessEvent.flags |= (!mAmbientLuxValid ? BrightnessEvent.FLAG_INVALID_LUX : 0)
+ | (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE
+ ? BrightnessEvent.FLAG_DOZE_SCALE : 0);
+ }
+
if (!mAmbientLuxValid) {
return PowerManager.BRIGHTNESS_INVALID_FLOAT;
}
@@ -506,6 +528,8 @@
pw.println(" mCurrentLightSensorRate=" + mCurrentLightSensorRate);
pw.println(" mAmbientLux=" + mAmbientLux);
pw.println(" mAmbientLuxValid=" + mAmbientLuxValid);
+ pw.println(" mPreThesholdLux=" + mPreThresholdLux);
+ pw.println(" mPreThesholdBrightness=" + mPreThresholdBrightness);
pw.println(" mAmbientBrighteningThreshold=" + mAmbientBrighteningThreshold);
pw.println(" mAmbientDarkeningThreshold=" + mAmbientDarkeningThreshold);
pw.println(" mScreenBrighteningThreshold=" + mScreenBrighteningThreshold);
@@ -574,7 +598,11 @@
} else if (mLightSensorEnabled) {
mLightSensorEnabled = false;
mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
+ if (!mAmbientLuxValid) {
+ mPreThresholdLux = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ }
mScreenAutoBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ mPreThresholdBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
mRecentLightSamples = 0;
mAmbientLightRingBuffer.clear();
mCurrentLightSensorRate = -1;
@@ -790,6 +818,7 @@
|| (slowAmbientLux <= mAmbientDarkeningThreshold
&& fastAmbientLux <= mAmbientDarkeningThreshold
&& nextDarkenTransition <= time)) {
+ mPreThresholdLux = mAmbientLux;
setAmbientLux(fastAmbientLux);
if (mLoggingEnabled) {
Slog.d(TAG, "updateAmbientLux: "
@@ -834,11 +863,11 @@
// If screenAutoBrightness is set, we should have screen{Brightening,Darkening}Threshold,
// in which case we ignore the new screen brightness if it doesn't differ enough from the
// previous one.
- if (!Float.isNaN(mScreenAutoBrightness)
- && !isManuallySet
+ boolean withinThreshold = !Float.isNaN(mScreenAutoBrightness)
&& newScreenAutoBrightness > mScreenDarkeningThreshold
- && newScreenAutoBrightness < mScreenBrighteningThreshold
- && currentBrightnessWithinAllowedRange) {
+ && newScreenAutoBrightness < mScreenBrighteningThreshold;
+
+ if (withinThreshold && !isManuallySet && currentBrightnessWithinAllowedRange) {
if (mLoggingEnabled) {
Slog.d(TAG, "ignoring newScreenAutoBrightness: "
+ mScreenDarkeningThreshold + " < " + newScreenAutoBrightness
@@ -853,6 +882,9 @@
+ "mScreenAutoBrightness=" + mScreenAutoBrightness + ", "
+ "newScreenAutoBrightness=" + newScreenAutoBrightness);
}
+ if (!withinThreshold) {
+ mPreThresholdBrightness = mScreenAutoBrightness;
+ }
mScreenAutoBrightness = newScreenAutoBrightness;
mScreenBrighteningThreshold = clampScreenBrightness(
mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 67268e2..698f41f 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -216,9 +216,6 @@
private final float mScreenBrightnessDefault;
- // Previously logged screen brightness. Used for autobrightness event dumpsys.
- private float mPreviousScreenBrightness = Float.NaN;
-
// The minimum allowed brightness while in VR.
private final float mScreenBrightnessForVrRangeMinimum;
@@ -394,8 +391,11 @@
private final Runnable mOnBrightnessChangeRunnable;
- // Used for keeping record in dumpsys for when and to which brightness auto adaptions were made.
- private RingBuffer<AutobrightnessEvent> mAutobrightnessEventRingBuffer;
+ private final BrightnessEvent mLastBrightnessEvent;
+ private final BrightnessEvent mTempBrightnessEvent;
+
+ // Keeps a record of brightness changes for dumpsys.
+ private RingBuffer<BrightnessEvent> mBrightnessEventRingBuffer;
// A record of state for skipping brightness ramps.
private int mSkipRampState = RAMP_STATE_SKIP_NONE;
@@ -455,6 +455,8 @@
// PowerManager.BRIGHTNESS_INVALID_FLOAT when there's no temporary adjustment set.
private float mTemporaryAutoBrightnessAdjustment;
+ private boolean mIsRbcActive;
+
// Animators.
private ObjectAnimator mColorFadeOnAnimator;
private ObjectAnimator mColorFadeOffAnimator;
@@ -481,6 +483,8 @@
mUniqueDisplayId = logicalDisplay.getPrimaryDisplayDeviceLocked().getUniqueId();
mDisplayStatsId = mUniqueDisplayId.hashCode();
mHandler = new DisplayControllerHandler(handler.getLooper());
+ mLastBrightnessEvent = new BrightnessEvent(mDisplayId);
+ mTempBrightnessEvent = new BrightnessEvent(mDisplayId);
if (mDisplayId == Display.DEFAULT_DISPLAY) {
mBatteryStats = BatteryStatsService.getService();
@@ -634,8 +638,8 @@
for (int i = 0; i < mNitsRange.length; i++) {
adjustedNits[i] = mCdsi.getReduceBrightColorsAdjustedBrightnessNits(mNitsRange[i]);
}
- mAutomaticBrightnessController.recalculateSplines(mCdsi.isReduceBrightColorsActivated(),
- adjustedNits);
+ mIsRbcActive = mCdsi.isReduceBrightColorsActivated();
+ mAutomaticBrightnessController.recalculateSplines(mIsRbcActive, adjustedNits);
// If rbc is turned on, off or there is a change in strength, we want to reset the short
@@ -991,8 +995,8 @@
mDisplayDeviceConfig.getAmbientHorizonShort(),
mDisplayDeviceConfig.getAmbientHorizonLong());
- mAutobrightnessEventRingBuffer =
- new RingBuffer<>(AutobrightnessEvent.class, RINGBUFFER_MAX);
+ mBrightnessEventRingBuffer =
+ new RingBuffer<>(BrightnessEvent.class, RINGBUFFER_MAX);
} else {
mUseSoftwareAutoBrightnessConfig = false;
}
@@ -1088,6 +1092,7 @@
boolean mustInitialize = false;
int brightnessAdjustmentFlags = 0;
mBrightnessReasonTemp.set(null);
+ mTempBrightnessEvent.reset();
synchronized (mLock) {
if (mStopped) {
return;
@@ -1314,7 +1319,8 @@
if (Float.isNaN(brightnessState)) {
float newAutoBrightnessAdjustment = autoBrightnessAdjustment;
if (autoBrightnessEnabled) {
- brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness();
+ brightnessState = mAutomaticBrightnessController.getAutomaticScreenBrightness(
+ mTempBrightnessEvent);
newAutoBrightnessAdjustment =
mAutomaticBrightnessController.getAutomaticScreenBrightnessAdjustment();
}
@@ -1376,6 +1382,7 @@
// we broadcast this change through setting.
final float unthrottledBrightnessState = brightnessState;
if (mBrightnessThrottler.isThrottled()) {
+ mTempBrightnessEvent.thermalMax = mBrightnessThrottler.getBrightnessCap();
brightnessState = Math.min(brightnessState, mBrightnessThrottler.getBrightnessCap());
mBrightnessReasonTemp.addModifier(BrightnessReason.MODIFIER_THROTTLED);
if (!mAppliedThrottling) {
@@ -1567,13 +1574,35 @@
Slog.v(TAG, "Brightness [" + brightnessState + "] manual adjustment.");
}
- // Add any automatic changes to autobrightness ringbuffer for dumpsys.
- if (mBrightnessReason.reason == BrightnessReason.REASON_AUTOMATIC
- && !BrightnessSynchronizer.floatEquals(
- mPreviousScreenBrightness, brightnessState)) {
- mPreviousScreenBrightness = brightnessState;
- mAutobrightnessEventRingBuffer.append(new AutobrightnessEvent(
- System.currentTimeMillis(), brightnessState));
+
+ // Log brightness events when a detail of significance has changed. Generally this is the
+ // brightness itself changing, but also includes data like HBM cap, thermal throttling
+ // brightness cap, RBC state, etc.
+ mTempBrightnessEvent.time = System.currentTimeMillis();
+ mTempBrightnessEvent.brightness = brightnessState;
+ mTempBrightnessEvent.reason.set(mBrightnessReason);
+ mTempBrightnessEvent.hbmMax = mHbmController.getCurrentBrightnessMax();
+ mTempBrightnessEvent.hbmMode = mHbmController.getHighBrightnessMode();
+ mTempBrightnessEvent.flags |= (mIsRbcActive ? BrightnessEvent.FLAG_RBC : 0);
+ // Temporary is what we use during slider interactions. We avoid logging those so that
+ // we don't spam logcat when the slider is being used.
+ boolean tempToTempTransition =
+ mTempBrightnessEvent.reason.reason == BrightnessReason.REASON_TEMPORARY
+ && mLastBrightnessEvent.reason.reason == BrightnessReason.REASON_TEMPORARY;
+ if ((!mTempBrightnessEvent.equalsMainData(mLastBrightnessEvent) && !tempToTempTransition)
+ || brightnessAdjustmentFlags != 0) {
+ mLastBrightnessEvent.copyFrom(mTempBrightnessEvent);
+ BrightnessEvent newEvent = new BrightnessEvent(mTempBrightnessEvent);
+
+ // Adjustment flags (and user-set flag) only get added after the equality checks since
+ // they are transient.
+ newEvent.adjustmentFlags = brightnessAdjustmentFlags;
+ newEvent.flags |= (userSetBrightnessChanged ? BrightnessEvent.FLAG_USER_SET : 0);
+ Slog.i(TAG, newEvent.toString(/* includeTime= */ false));
+
+ if (mBrightnessEventRingBuffer != null) {
+ mBrightnessEventRingBuffer.append(newEvent);
+ }
}
// Update display white-balance.
@@ -2482,6 +2511,7 @@
pw.println(" mPendingScreenOff=" + mPendingScreenOff);
pw.println(" mReportedToPolicy="
+ reportedToPolicyToString(mReportedScreenStateToPolicy));
+ pw.println(" mIsRbcActive=" + mIsRbcActive);
if (mScreenBrightnessRampAnimator != null) {
pw.println(" mScreenBrightnessRampAnimator.isAnimating()="
@@ -2503,7 +2533,7 @@
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.dump(pw);
- dumpAutobrightnessEvents(pw);
+ dumpBrightnessEvents(pw);
}
if (mHbmController != null) {
@@ -2560,16 +2590,16 @@
}
}
- private void dumpAutobrightnessEvents(PrintWriter pw) {
- int size = mAutobrightnessEventRingBuffer.size();
+ private void dumpBrightnessEvents(PrintWriter pw) {
+ int size = mBrightnessEventRingBuffer.size();
if (size < 1) {
pw.println("No Automatic Brightness Adjustments");
return;
}
pw.println("Automatic Brightness Adjustments Last " + size + " Events: ");
- AutobrightnessEvent[] eventArray = mAutobrightnessEventRingBuffer.toArray();
- for (int i = 0; i < mAutobrightnessEventRingBuffer.size(); i++) {
+ BrightnessEvent[] eventArray = mBrightnessEventRingBuffer.toArray();
+ for (int i = 0; i < mBrightnessEventRingBuffer.size(); i++) {
pw.println(" " + eventArray[i].toString());
}
}
@@ -2646,18 +2676,115 @@
}
}
- private static class AutobrightnessEvent {
- final long mTime;
- final float mBrightness;
+ class BrightnessEvent {
+ static final int FLAG_RBC = 0x1;
+ static final int FLAG_INVALID_LUX = 0x2;
+ static final int FLAG_DOZE_SCALE = 0x3;
+ static final int FLAG_USER_SET = 0x4;
- AutobrightnessEvent(long time, float brightness) {
- mTime = time;
- mBrightness = brightness;
+ public final BrightnessReason reason = new BrightnessReason();
+
+ public int displayId;
+ public float lux;
+ public float preThresholdLux;
+ public long time;
+ public float brightness;
+ public float recommendedBrightness;
+ public float preThresholdBrightness;
+ public float hbmMax;
+ public float thermalMax;
+ public int hbmMode;
+ public int flags;
+ public int adjustmentFlags;
+
+ BrightnessEvent(BrightnessEvent that) {
+ copyFrom(that);
+ }
+
+ BrightnessEvent(int displayId) {
+ this.displayId = displayId;
+ reset();
+ }
+
+ void copyFrom(BrightnessEvent that) {
+ displayId = that.displayId;
+ time = that.time;
+ lux = that.lux;
+ preThresholdLux = that.preThresholdLux;
+ brightness = that.brightness;
+ recommendedBrightness = that.recommendedBrightness;
+ preThresholdBrightness = that.preThresholdBrightness;
+ hbmMax = that.hbmMax;
+ thermalMax = that.thermalMax;
+ flags = that.flags;
+ hbmMode = that.hbmMode;
+ reason.set(that.reason);
+ adjustmentFlags = that.adjustmentFlags;
+ }
+
+ void reset() {
+ time = SystemClock.uptimeMillis();
+ brightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ recommendedBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ lux = 0;
+ preThresholdLux = 0;
+ preThresholdBrightness = PowerManager.BRIGHTNESS_INVALID_FLOAT;
+ hbmMax = PowerManager.BRIGHTNESS_MAX;
+ thermalMax = PowerManager.BRIGHTNESS_MAX;
+ flags = 0;
+ hbmMode = BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF;
+ reason.set(null);
+ adjustmentFlags = 0;
+ }
+
+ boolean equalsMainData(BrightnessEvent that) {
+ // This equals comparison purposefully ignores time since it is regularly changing and
+ // we don't want to log a brightness event just because the time changed.
+ return displayId == that.displayId
+ && Float.floatToRawIntBits(brightness)
+ == Float.floatToRawIntBits(that.brightness)
+ && Float.floatToRawIntBits(recommendedBrightness)
+ == Float.floatToRawIntBits(that.recommendedBrightness)
+ && Float.floatToRawIntBits(preThresholdBrightness)
+ == Float.floatToRawIntBits(that.preThresholdBrightness)
+ && Float.floatToRawIntBits(lux) == Float.floatToRawIntBits(that.lux)
+ && Float.floatToRawIntBits(preThresholdLux)
+ == Float.floatToRawIntBits(that.preThresholdLux)
+ && Float.floatToRawIntBits(hbmMax) == Float.floatToRawIntBits(that.hbmMax)
+ && hbmMode == that.hbmMode
+ && Float.floatToRawIntBits(thermalMax)
+ == Float.floatToRawIntBits(that.thermalMax)
+ && flags == that.flags
+ && adjustmentFlags == that.adjustmentFlags
+ && reason.equals(that.reason);
+ }
+
+ public String toString(boolean includeTime) {
+ return (includeTime ? TimeUtils.formatForLogging(time) + " - " : "")
+ + "BrightnessEvent: "
+ + "disp=" + displayId
+ + ", brt=" + brightness + ((flags & FLAG_USER_SET) != 0 ? "(user_set)" : "")
+ + ", rcmdBrt=" + recommendedBrightness
+ + ", preBrt=" + preThresholdBrightness
+ + ", lux=" + lux
+ + ", preLux=" + preThresholdLux
+ + ", hbmMax=" + hbmMax
+ + ", hbmMode=" + BrightnessInfo.hbmToString(hbmMode)
+ + ", thrmMax=" + thermalMax
+ + ", flags=" + flagsToString()
+ + ", reason=" + reason.toString(adjustmentFlags);
}
@Override
public String toString() {
- return TimeUtils.formatForLogging(mTime) + " - Brightness: " + mBrightness;
+ return toString(/* includeTime */ true);
+ }
+
+ private String flagsToString() {
+ return ((flags & FLAG_USER_SET) != 0 ? "user_set " : "")
+ + ((flags & FLAG_RBC) != 0 ? "rbc " : "")
+ + ((flags & FLAG_INVALID_LUX) != 0 ? "invalid_lux " : "")
+ + ((flags & FLAG_DOZE_SCALE) != 0 ? "doze_scale " : "");
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 0de523c..c4ff4ac 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -313,6 +313,7 @@
mSupportsStylusHw);
mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
mService.reRequestCurrentClientSessionLocked();
+ mService.performOnCreateInlineSuggestionsRequestLocked();
}
// reset Handwriting event receiver.
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 3c31405..bcebcb4 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -286,6 +286,30 @@
@NonNull
private final Set<String> mNonPreemptibleInputMethods;
+ private static final class CreateInlineSuggestionsRequest {
+ @NonNull final InlineSuggestionsRequestInfo mRequestInfo;
+ @NonNull final IInlineSuggestionsRequestCallback mCallback;
+ @NonNull final String mPackageName;
+
+ CreateInlineSuggestionsRequest(
+ @NonNull InlineSuggestionsRequestInfo requestInfo,
+ @NonNull IInlineSuggestionsRequestCallback callback,
+ @NonNull String packageName) {
+ mRequestInfo = requestInfo;
+ mCallback = callback;
+ mPackageName = packageName;
+ }
+ }
+
+ /**
+ * If a request to create inline autofill suggestions comes in while the IME is unbound
+ * due to {@link #mPreventImeStartupUnlessTextEditor}, this is where it is stored, so
+ * that it may be fulfilled once the IME rebinds.
+ */
+ @GuardedBy("ImfLock.class")
+ @Nullable
+ private CreateInlineSuggestionsRequest mPendingInlineSuggestionsRequest;
+
@UserIdInt
private int mLastSwitchUserId;
@@ -2137,16 +2161,24 @@
private void onCreateInlineSuggestionsRequestLocked(@UserIdInt int userId,
InlineSuggestionsRequestInfo requestInfo, IInlineSuggestionsRequestCallback callback,
boolean touchExplorationEnabled) {
+ clearPendingInlineSuggestionsRequestLocked();
final InputMethodInfo imi = mMethodMap.get(getSelectedMethodIdLocked());
try {
- IInputMethodInvoker curMethod = getCurMethodLocked();
- if (userId == mSettings.getCurrentUserId() && curMethod != null
+ if (userId == mSettings.getCurrentUserId()
&& imi != null && isInlineSuggestionsEnabled(imi, touchExplorationEnabled)) {
- final IInlineSuggestionsRequestCallback callbackImpl =
- new InlineSuggestionsRequestCallbackDecorator(callback,
- imi.getPackageName(), mCurTokenDisplayId, getCurTokenLocked(),
- this);
- curMethod.onCreateInlineSuggestionsRequest(requestInfo, callbackImpl);
+ mPendingInlineSuggestionsRequest = new CreateInlineSuggestionsRequest(
+ requestInfo, callback, imi.getPackageName());
+ if (getCurMethodLocked() != null) {
+ // In the normal case when the IME is connected, we can make the request here.
+ performOnCreateInlineSuggestionsRequestLocked();
+ } else {
+ // Otherwise, the next time the IME connection is established,
+ // InputMethodBindingController.mMainConnection#onServiceConnected() will call
+ // into #performOnCreateInlineSuggestionsRequestLocked() to make the request.
+ if (DEBUG) {
+ Slog.d(TAG, "IME not connected. Delaying inline suggestions request.");
+ }
+ }
} else {
callback.onInlineSuggestionsUnsupported();
}
@@ -2155,6 +2187,34 @@
}
}
+ @GuardedBy("ImfLock.class")
+ void performOnCreateInlineSuggestionsRequestLocked() {
+ if (mPendingInlineSuggestionsRequest == null) {
+ return;
+ }
+ IInputMethodInvoker curMethod = getCurMethodLocked();
+ if (DEBUG) {
+ Slog.d(TAG, "Performing onCreateInlineSuggestionsRequest. mCurMethod = " + curMethod);
+ }
+ if (curMethod != null) {
+ final IInlineSuggestionsRequestCallback callback =
+ new InlineSuggestionsRequestCallbackDecorator(
+ mPendingInlineSuggestionsRequest.mCallback,
+ mPendingInlineSuggestionsRequest.mPackageName,
+ mCurTokenDisplayId, getCurTokenLocked(), this);
+ curMethod.onCreateInlineSuggestionsRequest(
+ mPendingInlineSuggestionsRequest.mRequestInfo, callback);
+ } else {
+ Slog.w(TAG, "No IME connected! Abandoning inline suggestions creation request.");
+ }
+ clearPendingInlineSuggestionsRequestLocked();
+ }
+
+ @GuardedBy("ImfLock.class")
+ private void clearPendingInlineSuggestionsRequestLocked() {
+ mPendingInlineSuggestionsRequest = null;
+ }
+
private static boolean isInlineSuggestionsEnabled(InputMethodInfo imi,
boolean touchExplorationEnabled) {
return imi.isInlineSuggestionsEnabled()
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index de8e06a..111621d 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -1058,31 +1058,35 @@
}
int msgVersion = 0;
- int callbacksCount = mCallbacksList.beginBroadcast();
- if (DEBUG_LOG_ENABLED) {
- Log.v(TAG, "Sending message " + msgType + " version " + msgVersion + " from hubHandle "
- + contextHubHandle + ", appInstance " + appInstance + ", callBackCount "
- + callbacksCount);
- }
-
- if (callbacksCount < 1) {
+ // Synchronize access to mCallbacksList to prevent more than one outstanding broadcast as
+ // that will cause a crash.
+ synchronized (mCallbacksList) {
+ int callbacksCount = mCallbacksList.beginBroadcast();
if (DEBUG_LOG_ENABLED) {
- Log.v(TAG, "No message callbacks registered.");
+ Log.v(TAG, "Sending message " + msgType + " version " + msgVersion
+ + " from hubHandle " + contextHubHandle + ", appInstance " + appInstance
+ + ", callBackCount " + callbacksCount);
}
- return 0;
- }
- ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
- for (int i = 0; i < callbacksCount; ++i) {
- IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
- try {
- callback.onMessageReceipt(contextHubHandle, appInstance, msg);
- } catch (RemoteException e) {
- Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
- continue;
+ if (callbacksCount < 1) {
+ if (DEBUG_LOG_ENABLED) {
+ Log.v(TAG, "No message callbacks registered.");
+ }
+ return 0;
}
+
+ ContextHubMessage msg = new ContextHubMessage(msgType, msgVersion, data);
+ for (int i = 0; i < callbacksCount; ++i) {
+ IContextHubCallback callback = mCallbacksList.getBroadcastItem(i);
+ try {
+ callback.onMessageReceipt(contextHubHandle, appInstance, msg);
+ } catch (RemoteException e) {
+ Log.i(TAG, "Exception (" + e + ") calling remote callback (" + callback + ").");
+ continue;
+ }
+ }
+ mCallbacksList.finishBroadcast();
}
- mCallbacksList.finishBroadcast();
return 0;
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index daa7f29..09d3a0d 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -176,7 +176,7 @@
* This flag specifies whether VoLTE availability is based on provisioning. By default this is
* false.
* Used for UCE to determine if EAB provisioning checks should be based on provisioning.
- * @deprecated Use {@link Ims#KEY_MMTEL_REQUIRES_PROVISIONING_BUNDLE} instead.
+ * @deprecated Use {@link Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL} instead.
*/
@Deprecated
public static final String
diff --git a/telephony/java/android/telephony/ims/ImsRcsManager.java b/telephony/java/android/telephony/ims/ImsRcsManager.java
index 3415868..e00ea0e 100644
--- a/telephony/java/android/telephony/ims/ImsRcsManager.java
+++ b/telephony/java/android/telephony/ims/ImsRcsManager.java
@@ -18,6 +18,7 @@
import android.Manifest;
import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresFeature;
import android.annotation.RequiresPermission;
@@ -43,6 +44,8 @@
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ITelephony;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
@@ -87,6 +90,46 @@
"android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
/**
+ * This carrier supports User Capability Exchange as, defined by the framework using a
+ * presence server. If set, the RcsFeature should support capability exchange. If not set, this
+ * RcsFeature should not publish capabilities or service capability requests.
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
+ CAPABILITY_TYPE_NONE,
+ CAPABILITY_TYPE_OPTIONS_UCE,
+ CAPABILITY_TYPE_PRESENCE_UCE
+ })
+ public @interface RcsImsCapabilityFlag {}
+
+ /**
+ * Undefined capability type for initialization
+ */
+ public static final int CAPABILITY_TYPE_NONE = 0;
+
+ /**
+ * This carrier supports User Capability Exchange using SIP OPTIONS as defined by the
+ * framework. If set, the RcsFeature should support capability exchange using SIP OPTIONS.
+ * If not set, this RcsFeature should not service capability requests.
+ */
+ public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
+
+ /**
+ * This carrier supports User Capability Exchange using a presence server as defined by the
+ * framework. If set, the RcsFeature should support capability exchange using a presence
+ * server. If not set, this RcsFeature should not publish capabilities or service capability
+ * requests using presence.
+ */
+ public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
+
+ /**
+ * This is used to check the upper range of RCS capability
+ * @hide
+ */
+ public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_PRESENCE_UCE + 1;
+
+ /**
* An application can use {@link #addOnAvailabilityChangedListener} to register a
* {@link OnAvailabilityChangedListener}, which will notify the user when the RCS feature
* availability status updates from the ImsService.
@@ -104,7 +147,7 @@
*
* @param capabilities The new availability of the capabilities.
*/
- void onAvailabilityChanged(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities);
+ void onAvailabilityChanged(@RcsImsCapabilityFlag int capabilities);
}
/**
@@ -486,7 +529,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+ public boolean isCapable(@RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
if (imsRcsController == null) {
@@ -522,7 +565,7 @@
*/
@SystemApi
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public boolean isAvailable(@RcsUceAdapter.RcsImsCapabilityFlag int capability,
+ public boolean isAvailable(@RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech)
throws ImsException {
IImsRcsController imsRcsController = getIImsRcsController();
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 677c1a9..2833489 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -38,7 +38,6 @@
import android.telephony.ims.aidl.IImsConfigCallback;
import android.telephony.ims.aidl.IRcsConfigCallback;
import android.telephony.ims.feature.MmTelFeature;
-import android.telephony.ims.feature.RcsFeature;
import android.telephony.ims.stub.ImsConfigImplBase;
import android.telephony.ims.stub.ImsRegistrationImplBase;
@@ -970,7 +969,7 @@
/**
* Callback for IMS provisioning feature changes.
*/
- public static class FeatureProvisioningCallback {
+ public abstract static class FeatureProvisioningCallback {
private static class CallbackBinder extends IFeatureProvisioningCallback.Stub {
@@ -1024,12 +1023,10 @@
* specified, or {@code false} if the capability is not provisioned for the technology
* specified.
*/
- public void onFeatureProvisioningChanged(
+ public abstract void onFeatureProvisioningChanged(
@MmTelFeature.MmTelCapabilities.MmTelCapability int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int tech,
- boolean isProvisioned) {
- // Base Implementation
- }
+ boolean isProvisioned);
/**
* The IMS RCS provisioning has changed for a specific capability and IMS
@@ -1041,12 +1038,10 @@
* specified, or {@code false} if the capability is not provisioned for the technology
* specified.
*/
- public void onRcsFeatureProvisioningChanged(
- @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ public abstract void onRcsFeatureProvisioningChanged(
+ @ImsRcsManager.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int tech,
- boolean isProvisioned) {
- // Base Implementation
- }
+ boolean isProvisioned);
/**@hide*/
public final IFeatureProvisioningCallback getBinder() {
@@ -1505,7 +1500,7 @@
* Get the provisioning status for the IMS RCS capability specified.
*
* If provisioning is not required for the queried
- * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method will always return
+ * {@link ImsRcsManager.RcsImsCapabilityFlag} this method will always return
* {@code true}.
*
* @see CarrierConfigManager.Ims#KEY_CARRIER_RCS_PROVISIONING_REQUIRED_BOOL
@@ -1522,7 +1517,7 @@
@WorkerThread
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public boolean getRcsProvisioningStatusForCapability(
- @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability) {
+ @ImsRcsManager.RcsImsCapabilityFlag int capability) {
try {
return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability,
ImsRegistrationImplBase.REGISTRATION_TECH_LTE);
@@ -1535,7 +1530,7 @@
* Get the provisioning status for the IMS RCS capability specified.
*
* If provisioning is not required for the queried
- * {@link RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag} this method
+ * {@link ImsRcsManager.RcsImsCapabilityFlag} this method
* will always return {@code true}.
*
* <p> Requires Permission:
@@ -1553,7 +1548,7 @@
@WorkerThread
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public boolean getRcsProvisioningStatusForCapability(
- @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @ImsRcsManager.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int tech) {
try {
return getITelephony().getRcsProvisioningStatusForCapability(mSubId, capability, tech);
@@ -1590,7 +1585,7 @@
@WorkerThread
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRcsProvisioningStatusForCapability(
- @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @ImsRcsManager.RcsImsCapabilityFlag int capability,
boolean isProvisioned) {
try {
getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability,
@@ -1622,7 +1617,7 @@
@WorkerThread
@RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
public void setRcsProvisioningStatusForCapability(
- @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @ImsRcsManager.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int tech, boolean isProvisioned) {
try {
getITelephony().setRcsProvisioningStatusForCapability(mSubId, capability,
@@ -1676,7 +1671,7 @@
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
public boolean isRcsProvisioningRequiredForCapability(
- @RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag int capability,
+ @ImsRcsManager.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int tech) {
try {
return getITelephony().isRcsProvisioningRequiredForCapability(mSubId, capability, tech);
diff --git a/telephony/java/android/telephony/ims/RcsUceAdapter.java b/telephony/java/android/telephony/ims/RcsUceAdapter.java
index 154bb11..91dc38f 100644
--- a/telephony/java/android/telephony/ims/RcsUceAdapter.java
+++ b/telephony/java/android/telephony/ims/RcsUceAdapter.java
@@ -55,20 +55,28 @@
* This carrier supports User Capability Exchange as, defined by the framework using
* SIP OPTIONS. If set, the RcsFeature should support capability exchange. If not set, this
* RcsFeature should not publish capabilities or service capability requests.
+ * @deprecated Use {@link ImsRcsManager#CAPABILITY_TYPE_OPTIONS_UCE} instead.
* @hide
*/
+ @Deprecated
public static final int CAPABILITY_TYPE_OPTIONS_UCE = 1 << 0;
/**
* This carrier supports User Capability Exchange as, defined by the framework using a
* presence server. If set, the RcsFeature should support capability exchange. If not set, this
* RcsFeature should not publish capabilities or service capability requests.
+ * @deprecated Use {@link ImsRcsManager#CAPABILITY_TYPE_PRESENCE_UCE} instead.
* @hide
*/
+ @Deprecated
@SystemApi
public static final int CAPABILITY_TYPE_PRESENCE_UCE = 1 << 1;
- /**@hide*/
+ /**
+ * @deprecated Use {@link ImsRcsManager.RcsImsCapabilityFlag} instead.
+ * @hide
+ */
+ @Deprecated
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "CAPABILITY_TYPE_", value = {
CAPABILITY_TYPE_OPTIONS_UCE,
diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
index ad2e9e1..fb0e659 100644
--- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java
@@ -396,7 +396,7 @@
/**
* Undefined capability type for initialization
* This is used to check the upper range of MmTel capability
- * {@hide}
+ * @hide
*/
public static final int CAPABILITY_TYPE_NONE = 0;
@@ -427,7 +427,7 @@
/**
* This is used to check the upper range of MmTel capability
- * {@hide}
+ * @hide
*/
public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_CALL_COMPOSER + 1;
@@ -738,7 +738,7 @@
* Enabling/Disabling a capability here indicates that the capability should be registered or
* deregistered (depending on the capability change) and become available or unavailable to
* the framework.
- * * @hide
+ * @hide
*/
@Override
@SystemApi
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 70e4ef1..843827b 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -24,7 +24,7 @@
import android.content.Context;
import android.net.Uri;
import android.os.RemoteException;
-import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.ImsRcsManager;
import android.telephony.ims.aidl.CapabilityExchangeAidlWrapper;
import android.telephony.ims.aidl.ICapabilityExchangeEventListener;
import android.telephony.ims.aidl.IImsCapabilityCallback;
@@ -59,7 +59,9 @@
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
* this class and provide implementations of the RcsFeature methods that they support.
+ * @hide
*/
+@SystemApi
public class RcsFeature extends ImsFeature {
private static final String LOG_TAG = "RcsFeature";
@@ -184,18 +186,22 @@
* Contains the capabilities defined and supported by a {@link RcsFeature} in the
* form of a bitmask. The capabilities that are used in the RcsFeature are
* defined as:
- * {RcsUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
- * {RcsUceAdapter.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
+ * {@link ImsRcsManager.RcsImsCapabilityFlag#CAPABILITY_TYPE_OPTIONS_UCE}
+ * {@link ImsRcsManager.RcsImsCapabilityFlag#CAPABILITY_TYPE_PRESENCE_UCE}
*
* The enabled capabilities of this RcsFeature will be set by the framework
- * using {#changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
+ * using {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)}.
* After the capabilities have been set, the RcsFeature may then perform the necessary bring up
* of the capability and notify the capability status as true using
- * {#notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
+ * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. This will signal to the
* framework that the capability is available for usage.
*/
public static class RcsImsCapabilities extends Capabilities {
- /** @hide*/
+
+ /**
+ * Use {@link ImsRcsManager.RcsImsCapabilityFlag} instead in case used for public API
+ * @hide
+ */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "CAPABILITY_TYPE_", flag = true, value = {
CAPABILITY_TYPE_NONE,
@@ -226,7 +232,7 @@
/**
* This is used to check the upper range of RCS capability
- * {@hide}
+ * @hide
*/
public static final int CAPABILITY_TYPE_MAX = CAPABILITY_TYPE_PRESENCE_UCE + 1;
@@ -234,10 +240,8 @@
* Create a new {@link RcsImsCapabilities} instance with the provided capabilities.
* @param capabilities The capabilities that are supported for RCS in the form of a
* bitfield.
- * @hide
*/
- @SystemApi
- public RcsImsCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+ public RcsImsCapabilities(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
super(capabilities);
}
@@ -249,30 +253,18 @@
super(capabilities.getMask());
}
- /**
- * @hide
- */
@Override
- @SystemApi
- public void addCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+ public void addCapabilities(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
super.addCapabilities(capabilities);
}
- /**
- * @hide
- */
@Override
- @SystemApi
- public void removeCapabilities(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+ public void removeCapabilities(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
super.removeCapabilities(capabilities);
}
- /**
- * @hide
- */
@Override
- @SystemApi
- public boolean isCapable(@RcsUceAdapter.RcsImsCapabilityFlag int capabilities) {
+ public boolean isCapable(@ImsRcsManager.RcsImsCapabilityFlag int capabilities) {
return super.isCapable(capabilities);
}
}
@@ -288,9 +280,7 @@
* Method stubs called from the framework will be called asynchronously. To specify the
* {@link Executor} that the methods stubs will be called, use
* {@link RcsFeature#RcsFeature(Executor)} instead.
- * @hide
*/
- @SystemApi
public RcsFeature() {
super();
// Run on the Binder threads that call them.
@@ -302,9 +292,7 @@
* framework.
* @param executor The executor for the framework to use when executing the methods overridden
* by the implementation of RcsFeature.
- * @hide
*/
- @SystemApi
public RcsFeature(@NonNull Executor executor) {
super();
if (executor == null) {
@@ -335,10 +323,8 @@
* requests. To change the status of the capabilities
* {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)} should be called.
* @return A copy of the current RcsFeature capability status.
- * @hide
*/
@Override
- @SystemApi
public @NonNull final RcsImsCapabilities queryCapabilityStatus() {
return new RcsImsCapabilities(super.queryCapabilityStatus());
}
@@ -348,9 +334,7 @@
* this signals to the framework that the capability has been initialized and is ready.
* Call {@link #queryCapabilityStatus()} to return the current capability status.
* @param capabilities The current capability status of the RcsFeature.
- * @hide
*/
- @SystemApi
public final void notifyCapabilitiesStatusChanged(@NonNull RcsImsCapabilities capabilities) {
if (capabilities == null) {
throw new IllegalArgumentException("RcsImsCapabilities must be non-null!");
@@ -367,11 +351,9 @@
* @param capability The capability that we are querying the configuration for.
* @param radioTech The radio technology type that we are querying.
* @return true if the capability is enabled, false otherwise.
- * @hide
*/
- @SystemApi
public boolean queryCapabilityConfiguration(
- @RcsUceAdapter.RcsImsCapabilityFlag int capability,
+ @ImsRcsManager.RcsImsCapabilityFlag int capability,
@ImsRegistrationImplBase.ImsRegistrationTech int radioTech) {
// Base Implementation - Override to provide functionality
return false;
@@ -392,10 +374,8 @@
* be called for each capability change that resulted in an error.
* @param request The request to change the capability.
* @param callback To notify the framework that the result of the capability changes.
- * @hide
*/
@Override
- @SystemApi
public void changeEnabledCapabilities(@NonNull CapabilityChangeRequest request,
@NonNull CapabilityCallbackProxy callback) {
// Base Implementation - Override to provide functionality
@@ -415,9 +395,7 @@
* event to the framework.
* @return An instance of {@link RcsCapabilityExchangeImplBase} that implements capability
* exchange if it is supported by the device.
- * @hide
*/
- @SystemApi
public @NonNull RcsCapabilityExchangeImplBase createCapabilityExchangeImpl(
@NonNull CapabilityExchangeEventListener listener) {
// Base Implementation, override to implement functionality
@@ -427,28 +405,20 @@
/**
* Remove the given CapabilityExchangeImplBase instance.
* @param capExchangeImpl The {@link RcsCapabilityExchangeImplBase} instance to be destroyed.
- * @hide
*/
- @SystemApi
public void destroyCapabilityExchangeImpl(
@NonNull RcsCapabilityExchangeImplBase capExchangeImpl) {
// Override to implement the process of destroying RcsCapabilityExchangeImplBase instance.
}
- /**{@inheritDoc}
- * @hide
- */
+ /**{@inheritDoc}*/
@Override
- @SystemApi
public void onFeatureRemoved() {
}
- /**{@inheritDoc}
- * @hide
- */
+ /**{@inheritDoc}*/
@Override
- @SystemApi
public void onFeatureReady() {
}
diff --git a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
index ac5565b..593f080 100644
--- a/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
+++ b/telephony/java/android/telephony/ims/stub/ImsRegistrationImplBase.java
@@ -93,7 +93,7 @@
/**
* This is used to check the upper range of registration tech
- * {@hide}
+ * @hide
*/
public static final int REGISTRATION_TECH_MAX = REGISTRATION_TECH_NR + 1;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 75f1337..7f309e1 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -102,28 +102,59 @@
}
}
-fun FlickerTestParameter.navBarLayerRotatesAndScales() {
+/**
+ * Asserts that the [FlickerComponentName.NAV_BAR] layer is at the correct position at the start
+ * of the SF trace
+ */
+fun FlickerTestParameter.navBarLayerPositionStart() {
assertLayersStart {
val display = this.entry.displays.minByOrNull { it.id }
- ?: throw RuntimeException("There is no display!")
- this.visibleRegion(FlickerComponentName.NAV_BAR)
- .coversExactly(WindowUtils.getNavigationBarPosition(display))
- }
- assertLayersEnd {
- val display = this.entry.displays.minByOrNull { it.id }
- ?: throw RuntimeException("There is no display!")
+ ?: throw RuntimeException("There is no display!")
this.visibleRegion(FlickerComponentName.NAV_BAR)
.coversExactly(WindowUtils.getNavigationBarPosition(display))
}
}
-fun FlickerTestParameter.statusBarLayerRotatesScales() {
+/**
+ * Asserts that the [FlickerComponentName.NAV_BAR] layer is at the correct position at the end
+ * of the SF trace
+ */
+fun FlickerTestParameter.navBarLayerPositionEnd() {
+ assertLayersEnd {
+ val display = this.entry.displays.minByOrNull { it.id }
+ ?: throw RuntimeException("There is no display!")
+ this.visibleRegion(FlickerComponentName.NAV_BAR)
+ .coversExactly(WindowUtils.getNavigationBarPosition(display))
+ }
+}
+
+/**
+ * Asserts that the [FlickerComponentName.NAV_BAR] layer is at the correct position at the start
+ * and end of the SF trace
+ */
+fun FlickerTestParameter.navBarLayerRotatesAndScales() {
+ navBarLayerPositionStart()
+ navBarLayerPositionEnd()
+}
+
+/**
+ * Asserts that the [FlickerComponentName.STATUS_BAR] layer is at the correct position at the start
+ * of the SF trace
+ */
+fun FlickerTestParameter.statusBarLayerPositionStart() {
assertLayersStart {
val display = this.entry.displays.minByOrNull { it.id }
?: throw RuntimeException("There is no display!")
this.visibleRegion(FlickerComponentName.STATUS_BAR)
.coversExactly(WindowUtils.getStatusBarPosition(display))
}
+}
+
+/**
+ * Asserts that the [FlickerComponentName.STATUS_BAR] layer is at the correct position at the end
+ * of the SF trace
+ */
+fun FlickerTestParameter.statusBarLayerPositionEnd() {
assertLayersEnd {
val display = this.entry.displays.minByOrNull { it.id }
?: throw RuntimeException("There is no display!")
@@ -133,6 +164,15 @@
}
/**
+ * Asserts that the [FlickerComponentName.STATUS_BAR] layer is at the correct position at the start
+ * and end of the SF trace
+ */
+fun FlickerTestParameter.statusBarLayerRotatesScales() {
+ statusBarLayerPositionStart()
+ statusBarLayerPositionEnd()
+}
+
+/**
* Asserts that:
* [originalLayer] is visible at the start of the trace
* [originalLayer] becomes invisible during the trace and (in the same entry) [newLayer]
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
index d1319ac..20a2e22 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppBackButtonTest.kt
@@ -98,6 +98,12 @@
super.statusBarLayerRotatesScales()
}
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 229762973)
+ @Test
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
+ super.visibleLayersShownMoreThanOneConsecutiveEntry()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
index f5fb106..d00fd7d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppHomeButtonTest.kt
@@ -101,11 +101,10 @@
}
/** {@inheritDoc} */
- @Presubmit
+ @FlakyTest(bugId = 229762973)
@Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
+ override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
companion object {
/**
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
index 535612a..93b987e 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/ImeAppAutoFocusHelper.kt
@@ -41,6 +41,16 @@
waitIMEShown(device, wmHelper)
}
+ override fun launchViaIntent(
+ wmHelper: WindowManagerStateHelper,
+ expectedWindowName: String,
+ action: String?,
+ stringExtras: Map<String, String>
+ ) {
+ super.launchViaIntent(wmHelper, expectedWindowName, action, stringExtras)
+ waitIMEShown(uiDevice, wmHelper)
+ }
+
override fun open() {
val expectedPackage = if (rotation.isRotated()) {
imePackageName
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
index 8daf4ca..774b85b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationCold.kt
@@ -18,12 +18,14 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
import org.junit.FixMethodOrder
+import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.MethodSorters
import org.junit.runners.Parameterized
@@ -31,6 +33,8 @@
/**
* Test cold launching an app from a notification from the lock screen.
*
+ * This test assumes the device doesn't have AOD enabled
+ *
* To run this test: `atest FlickerTests:OpenAppFromLockNotificationCold`
*/
@RequiresDevice
@@ -65,6 +69,11 @@
}
}
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 229735718)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
index 8eb182a..53ee57b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWarm.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -33,6 +34,8 @@
/**
* Test warm launching an app from a notification from the lock screen.
*
+ * This test assumes the device doesn't have AOD enabled
+ *
* To run this test: `atest FlickerTests:OpenAppFromLockNotificationWarm`
*/
@RequiresDevice
@@ -97,6 +100,11 @@
}
}
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 229735718)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 28a914b..bc637f8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -18,6 +18,7 @@
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.RequiresDevice
+import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.FlickerTestParameterFactory
@@ -103,6 +104,11 @@
}
}
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 229735718)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
companion object {
/**
* Creates the test configurations.
@@ -113,7 +119,7 @@
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
- return com.android.server.wm.flicker.FlickerTestParameterFactory.getInstance()
+ return FlickerTestParameterFactory.getInstance()
.getConfigNonRotationTests(repetitions = 3)
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
index f47e272..fe80162 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockTransition.kt
@@ -20,6 +20,7 @@
import androidx.test.filters.FlakyTest
import com.android.server.wm.flicker.FlickerTestParameter
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.navBarLayerPositionEnd
import com.android.server.wm.traces.common.FlickerComponentName
import org.junit.Test
@@ -99,4 +100,27 @@
@FlakyTest(bugId = 203538234)
@Test
override fun appWindowBecomesVisible() = super.appWindowBecomesVisible()
+
+ /**
+ * Checks the position of the navigation bar at the start and end of the transition
+ *
+ * Differently from the normal usage of this assertion, check only the final state of the
+ * transition because the display is off at the start and the NavBar is never visible
+ */
+ @Presubmit
+ @Test
+ override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
+
+ /**
+ * Checks that the status bar layer is visible at the end of the trace
+ *
+ * It is not possible to check at the start because the screen is off
+ */
+ @Presubmit
+ @Test
+ override fun statusBarLayerIsVisible() {
+ testSpec.assertLayersEnd {
+ this.isVisible(FlickerComponentName.STATUS_BAR)
+ }
+ }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
index ee018ec..5022dd8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationCold.kt
@@ -32,6 +32,8 @@
/**
* Test cold launching an app from a notification.
*
+ * This test assumes the device doesn't have AOD enabled
+ *
* To run this test: `atest FlickerTests:OpenAppFromNotificationCold`
*/
@RequiresDevice
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
index 74f1fd7..af9eaa5 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromNotificationWarm.kt
@@ -40,6 +40,8 @@
/**
* Test cold launching an app from a notification.
*
+ * This test assumes the device doesn't have AOD enabled
+ *
* To run this test: `atest FlickerTests:OpenAppFromNotificationWarm`
*/
@RequiresDevice
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 6e33f66..18f077f 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -26,9 +26,11 @@
import com.android.server.wm.flicker.LAUNCHER_COMPONENT
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.isShellTransitionsEnabled
import com.android.server.wm.flicker.helpers.reopenAppFromOverview
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.traces.common.WindowManagerConditionsFactory
+import org.junit.Assume
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -132,6 +134,26 @@
@Test
override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart()
+ /** {@inheritDoc} */
+ @FlakyTest(bugId = 229735718)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ Assume.assumeFalse(isShellTransitionsEnabled)
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
+ @FlakyTest(bugId = 229738092)
+ @Test
+ fun appWindowReplacesLauncherAsTopWindow_ShellTransit() {
+ Assume.assumeTrue(isShellTransitionsEnabled)
+ super.appWindowReplacesLauncherAsTopWindow()
+ }
+
companion object {
/**
* Creates the test configurations.
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index f357177..55eb3c3 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Postsubmit
import androidx.test.filters.FlakyTest
import android.platform.test.annotations.Presubmit
import android.platform.test.annotations.RequiresDevice
@@ -27,6 +28,7 @@
import com.android.server.wm.flicker.annotation.Group1
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerPositionEnd
import com.android.server.wm.traces.common.FlickerComponentName
import org.junit.FixMethodOrder
import org.junit.Test
@@ -37,6 +39,8 @@
/**
* Test launching an app while the device is locked
*
+ * This test assumes the device doesn't have AOD enabled
+ *
* To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
*
* Actions:
@@ -103,8 +107,7 @@
/**
* Checks that the status bar layer is visible at the end of the trace
*
- * It is not possible to check at the start because the animation is working differently
- * in devices with and without blur (b/202936526)
+ * It is not possible to check at the start because the screen is off
*/
@Presubmit
@Test
@@ -115,7 +118,7 @@
}
/** {@inheritDoc} */
- @FlakyTest(bugId = 202936526)
+ @FlakyTest(bugId = 206753786)
@Test
override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
@@ -131,10 +134,15 @@
}
}
- /** {@inheritDoc} */
- @FlakyTest
+ /**
+ * Checks the position of the navigation bar at the start and end of the transition
+ *
+ * Differently from the normal usage of this assertion, check only the final state of the
+ * transition because the display is off at the start and the NavBar is never visible
+ */
+ @Postsubmit
@Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+ override fun navBarLayerRotatesAndScales() = testSpec.navBarLayerPositionEnd()
/** {@inheritDoc} */
@FlakyTest
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index 48f6aeb..97528c0 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -130,6 +130,10 @@
@Test
override fun appWindowBecomesVisible() = super.appWindowBecomesVisible_warmStart()
+ @FlakyTest(bugId = 229735718)
+ @Test
+ override fun entireScreenCovered() = super.entireScreenCovered()
+
companion object {
/**
* Creates the test configurations.