Merge changes from topic "fix-b-188932434-common-types-2"
* changes:
Move common audio AIDL types to audio.media.audio.common
MediaFormat: Add more audio MIME types
Add android.media.audio.common.AidlConversion class
diff --git a/Android.bp b/Android.bp
index c156774..b8c060d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -346,6 +346,8 @@
"modules-utils-preconditions",
"modules-utils-os",
"framework-permission-aidl-java",
+ "spatializer-aidl-java",
+ "audiopolicy-types-aidl-java",
],
}
diff --git a/OWNERS b/OWNERS
index 03cfac9..ab5bd18 100644
--- a/OWNERS
+++ b/OWNERS
@@ -23,6 +23,9 @@
# via https://android.git.corp.google.com/All-Projects/+/refs/meta/config/rules.pl.
per-file */api/*current.txt = *
+# Test mapping changes can be made by anyone
+per-file */TEST_MAPPING = *
+
# Support bulk translation updates
per-file */res*/values*/*.xml = byi@google.com, delphij@google.com
diff --git a/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java b/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java
new file mode 100644
index 0000000..f3d7390
--- /dev/null
+++ b/apct-tests/perftests/core/src/android/os/LongArrayMultiStateCounterPerfTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
+
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.internal.os.LongArrayMultiStateCounter;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@LargeTest
+public class LongArrayMultiStateCounterPerfTest {
+
+ @Rule
+ public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
+
+ /**
+ * A complete line-for-line reimplementation of
+ * {@link }com.android.internal.os.CpuTimeInFreqMultiStateCounter}, only in Java instead of
+ * native.
+ */
+ private static class TestLongArrayMultiStateCounter {
+ private final int mStateCount;
+ private final int mArrayLength;
+ private int mCurrentState;
+ private long mLastStateChangeTimestampMs;
+ private long mLastUpdateTimestampMs;
+
+ private static class State {
+ private long mTimeInStateSinceUpdate;
+ private long[] mCounter;
+ }
+
+ private final State[] mStates;
+ private final long[] mLastTimeInFreq;
+ private final long[] mDelta;
+
+ TestLongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
+ long timestampMs) {
+ mStateCount = stateCount;
+ mArrayLength = arrayLength;
+ mCurrentState = initialState;
+ mLastStateChangeTimestampMs = timestampMs;
+ mLastUpdateTimestampMs = timestampMs;
+ mStates = new State[stateCount];
+ for (int i = 0; i < mStateCount; i++) {
+ mStates[i] = new State();
+ mStates[i].mCounter = new long[mArrayLength];
+ }
+ mLastTimeInFreq = new long[mArrayLength];
+ mDelta = new long[mArrayLength];
+ }
+
+ public void setState(int state, long timestampMs) {
+ if (timestampMs >= mLastStateChangeTimestampMs) {
+ mStates[mCurrentState].mTimeInStateSinceUpdate +=
+ timestampMs - mLastStateChangeTimestampMs;
+ } else {
+ for (int i = 0; i < mStateCount; i++) {
+ mStates[i].mTimeInStateSinceUpdate = 0;
+ }
+ }
+ mCurrentState = state;
+ mLastStateChangeTimestampMs = timestampMs;
+ }
+
+ public void updateValue(long[] timeInFreq, long timestampMs) {
+ setState(mCurrentState, timestampMs);
+
+ if (timestampMs > mLastUpdateTimestampMs) {
+ if (delta(mLastTimeInFreq, timeInFreq, mDelta)) {
+ long timeSinceUpdate = timestampMs - mLastUpdateTimestampMs;
+ for (int i = 0; i < mStateCount; i++) {
+ long timeInState = mStates[i].mTimeInStateSinceUpdate;
+ if (timeInState > 0) {
+ add(mStates[i].mCounter, mDelta, timeInState, timeSinceUpdate);
+ mStates[i].mTimeInStateSinceUpdate = 0;
+ }
+ }
+ } else {
+ throw new RuntimeException();
+ }
+ } else if (timestampMs < mLastUpdateTimestampMs) {
+ throw new RuntimeException();
+ }
+ System.arraycopy(timeInFreq, 0, mLastTimeInFreq, 0, mArrayLength);
+ mLastUpdateTimestampMs = timestampMs;
+ }
+
+ private boolean delta(long[] timeInFreq1, long[] timeInFreq2, long[] delta) {
+ if (delta.length != mArrayLength) {
+ throw new RuntimeException();
+ }
+
+ boolean is_delta_valid = true;
+ for (int i = 0; i < mStateCount; i++) {
+ if (timeInFreq2[i] >= timeInFreq1[i]) {
+ delta[i] = timeInFreq2[i] - timeInFreq1[i];
+ } else {
+ delta[i] = 0;
+ is_delta_valid = false;
+ }
+ }
+
+ return is_delta_valid;
+ }
+
+ private void add(long[] counter, long[] delta, long numerator, long denominator) {
+ if (numerator != denominator) {
+ for (int i = 0; i < mArrayLength; i++) {
+ counter[i] += delta[i] * numerator / denominator;
+ }
+ } else {
+ for (int i = 0; i < mArrayLength; i++) {
+ counter[i] += delta[i];
+ }
+ }
+ }
+ }
+
+ @Test
+ public void javaImplementation() {
+ TestLongArrayMultiStateCounter counter =
+ new TestLongArrayMultiStateCounter(2, 4, 0, 1000);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ long time = 1000;
+ long[] timeInFreq = {100, 200, 300, 400};
+ while (state.keepRunning()) {
+ counter.setState(1, time);
+ counter.setState(0, time + 1000);
+ counter.updateValue(timeInFreq, time + 2000);
+ time += 10000;
+ }
+ }
+
+ @Test
+ public void nativeImplementation() {
+ LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
+ final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ long time = 1000;
+ LongArrayMultiStateCounter.LongArrayContainer timeInFreq =
+ new LongArrayMultiStateCounter.LongArrayContainer(4);
+ timeInFreq.setValues(new long[]{100, 200, 300, 400});
+ while (state.keepRunning()) {
+ counter.setState(1, time);
+ counter.setState(0, time + 1000);
+ counter.updateValues(timeInFreq, time + 2000);
+ time += 10000;
+ }
+ }
+}
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 7c81f09..90a5d49 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -1339,7 +1339,7 @@
mTimeCheckThread->run("BootAnimation::TimeCheckThread", PRIORITY_NORMAL);
}
- if (mAnimation != nullptr && mAnimation->dynamicColoringEnabled) {
+ if (mAnimation->dynamicColoringEnabled) {
initDynamicColors();
}
diff --git a/core/api/current.txt b/core/api/current.txt
index dc62931..2f01265 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -2013,6 +2013,9 @@
public static final class R.id {
ctor public R.id();
field public static final int accessibilityActionContextClick = 16908348; // 0x102003c
+ field public static final int accessibilityActionDragCancel;
+ field public static final int accessibilityActionDragDrop;
+ field public static final int accessibilityActionDragStart;
field public static final int accessibilityActionHideTooltip = 16908357; // 0x1020045
field public static final int accessibilityActionImeEnter = 16908372; // 0x1020054
field public static final int accessibilityActionMoveWindow = 16908354; // 0x1020042
@@ -10681,6 +10684,8 @@
field public static final String PERFORMANCE_HINT_SERVICE = "performance_hint";
field public static final String POWER_SERVICE = "power";
field public static final String PRINT_SERVICE = "print";
+ field public static final int RECEIVER_EXPORTED = 2; // 0x2
+ field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
field public static final String RESTRICTIONS_SERVICE = "restrictions";
field public static final String ROLE_SERVICE = "role";
@@ -50712,6 +50717,9 @@
method public void setPackageName(CharSequence);
method public void writeToParcel(android.os.Parcel, int);
field public static final int CONTENT_CHANGE_TYPE_CONTENT_DESCRIPTION = 4; // 0x4
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 512; // 0x200
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 256; // 0x100
+ field public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 128; // 0x80
field public static final int CONTENT_CHANGE_TYPE_PANE_APPEARED = 16; // 0x10
field public static final int CONTENT_CHANGE_TYPE_PANE_DISAPPEARED = 32; // 0x20
field public static final int CONTENT_CHANGE_TYPE_PANE_TITLE = 8; // 0x8
@@ -51010,6 +51018,9 @@
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_COPY;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_CUT;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DISMISS;
+ field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_CANCEL;
+ field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_DROP;
+ field @NonNull public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_DRAG_START;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_EXPAND;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_FOCUS;
field public static final android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction ACTION_HIDE_TOOLTIP;
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 96476a5..4f03b4f 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -8411,7 +8411,7 @@
* @hide
*/
public final boolean isVisibleForAutofill() {
- return mStopped;
+ return !mStopped;
}
/**
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 8cf1f80..4e4c2219 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -236,14 +236,14 @@
void addCrossProfileIntentFilter(in ComponentName admin, in IntentFilter filter, int flags);
void clearCrossProfileIntentFilters(in ComponentName admin);
- boolean setPermittedAccessibilityServices(in ComponentName admin,in List packageList);
- List getPermittedAccessibilityServices(in ComponentName admin);
- List getPermittedAccessibilityServicesForUser(int userId);
+ boolean setPermittedAccessibilityServices(in ComponentName admin,in List<String> packageList);
+ List<String> getPermittedAccessibilityServices(in ComponentName admin);
+ List<String> getPermittedAccessibilityServicesForUser(int userId);
boolean isAccessibilityServicePermittedByAdmin(in ComponentName admin, String packageName, int userId);
- boolean setPermittedInputMethods(in ComponentName admin,in List packageList, boolean parent);
- List getPermittedInputMethods(in ComponentName admin, boolean parent);
- List getPermittedInputMethodsForCurrentUser();
+ boolean setPermittedInputMethods(in ComponentName admin,in List<String> packageList, boolean parent);
+ List<String> getPermittedInputMethods(in ComponentName admin, boolean parent);
+ List<String> getPermittedInputMethodsForCurrentUser();
boolean isInputMethodPermittedByAdmin(in ComponentName admin, String packageName, int userId, boolean parent);
boolean setPermittedCrossProfileNotificationListeners(in ComponentName admin, in List<String> packageList);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index ad1163f..f5a0c43 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -534,8 +534,8 @@
| Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE;
/** @hide */
- @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
- RECEIVER_VISIBLE_TO_INSTANT_APPS
+ @IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
+ RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
})
@Retention(RetentionPolicy.SOURCE)
public @interface RegisterReceiverFlags {}
@@ -546,6 +546,18 @@
public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x1;
/**
+ * Flag for {@link #registerReceiver}: The receiver can receive broadcasts from other Apps.
+ * Has the same behavior as marking a statically registered receiver with "exported=true"
+ */
+ public static final int RECEIVER_EXPORTED = 0x2;
+
+ /**
+ * Flag for {@link #registerReceiver}: The receiver cannot receive broadcasts from other Apps.
+ * Has the same behavior as marking a statically registered receiver with "exported=false"
+ */
+ public static final int RECEIVER_NOT_EXPORTED = 0x4;
+
+ /**
* Returns an AssetManager instance for the application's package.
* <p>
* <strong>Note:</strong> Implementations of this method should return
@@ -2989,8 +3001,12 @@
*
* @param receiver The BroadcastReceiver to handle the broadcast.
* @param filter Selects the Intent broadcasts to be received.
- * @param flags Additional options for the receiver. May be 0 or
- * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
+ * @param flags Additional options for the receiver. As of
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+ * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+ * for protected broadcasts, and may additionally specify
+ * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
+ * specified.
*
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
@@ -3062,8 +3078,12 @@
* no permission is required.
* @param scheduler Handler identifying the thread that will receive
* the Intent. If null, the main thread of the process will be used.
- * @param flags Additional options for the receiver. May be 0 or
- * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
+ * @param flags Additional options for the receiver. As of
+ * {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
+ * {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
+ * for protected broadcasts, and may additionally specify
+ * {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
+ * specified.
*
* @return The first sticky intent found that matches <var>filter</var>,
* or null if there are none.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 3253246..546abf8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -30,6 +30,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.app.ActivityThread;
import android.app.AppGlobals;
import android.bluetooth.BluetoothDevice;
import android.compat.annotation.UnsupportedAppUsage;
@@ -8281,7 +8282,10 @@
* needed.
*/
public @Nullable String resolveTypeIfNeeded(@NonNull ContentResolver resolver) {
- if (mComponent != null) {
+ // Match logic in PackageManagerService#applyEnforceIntentFilterMatching(...)
+ if (mComponent != null && (Process.myUid() == Process.ROOT_UID
+ || Process.myUid() == Process.SYSTEM_UID
+ || mComponent.getPackageName().equals(ActivityThread.currentPackageName()))) {
return mType;
}
return resolveType(resolver);
diff --git a/core/java/android/content/om/IOverlayManager.aidl b/core/java/android/content/om/IOverlayManager.aidl
index e319d2c..a0f3d7a 100644
--- a/core/java/android/content/om/IOverlayManager.aidl
+++ b/core/java/android/content/om/IOverlayManager.aidl
@@ -40,7 +40,7 @@
* requested user, an empty map is returned.
*/
@UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
- Map getAllOverlays(in int userId);
+ Map<String, List<OverlayInfo>> getAllOverlays(in int userId);
/**
* Returns information about all overlays for the given target package for
@@ -52,7 +52,7 @@
* @return A list of OverlayInfo objects; if no overlays exist for the
* requested package, an empty list is returned.
*/
- List getOverlayInfosForTarget(in String targetPackageName, in int userId);
+ List<OverlayInfo> getOverlayInfosForTarget(in String targetPackageName, in int userId);
/**
* Returns information about the overlay with the given package name for the
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 5a89708..76e9fcb 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -343,7 +343,7 @@
}
public boolean isDemo() {
- return UserManager.isUserTypeDemo(userType);
+ return UserManager.isUserTypeDemo(userType) || (flags & FLAG_DEMO) != 0;
}
public boolean isFull() {
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 45bdb11..c1d5a28 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -1051,9 +1051,8 @@
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CONVERSATIONS,
isPriorityCategoryEnabled(Policy.PRIORITY_CATEGORY_CONVERSATIONS, defaultPolicy))) {
priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
- conversationSenders = getNotificationPolicySenders(
- zenPolicy.getPriorityConversationSenders(),
- conversationSenders);
+ conversationSenders = getConversationSendersWithDefault(
+ zenPolicy.getPriorityConversationSenders(), conversationSenders);
}
if (zenPolicy.isCategoryAllowed(ZenPolicy.PRIORITY_CATEGORY_CALLS,
@@ -1166,6 +1165,17 @@
}
}
+ private int getConversationSendersWithDefault(@ZenPolicy.ConversationSenders int senders,
+ int defaultPolicySender) {
+ switch (senders) {
+ case ZenPolicy.CONVERSATION_SENDERS_ANYONE:
+ case ZenPolicy.CONVERSATION_SENDERS_IMPORTANT:
+ case ZenPolicy.CONVERSATION_SENDERS_NONE:
+ return senders;
+ default:
+ return defaultPolicySender;
+ }
+ }
/**
* Maps NotificationManager.Policy senders type to ZenPolicy.PeopleType
@@ -1216,7 +1226,8 @@
}
priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
- priorityConversationSenders = allowConversationsFrom;
+ priorityConversationSenders = getConversationSendersWithDefault(
+ allowConversationsFrom, priorityConversationSenders);
return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
suppressedVisualEffects, areChannelsBypassingDnd
diff --git a/core/java/android/view/InputWindowHandle.java b/core/java/android/view/InputWindowHandle.java
index 4816d2c..2b579d0 100644
--- a/core/java/android/view/InputWindowHandle.java
+++ b/core/java/android/view/InputWindowHandle.java
@@ -47,6 +47,11 @@
*/
@Nullable
private IBinder windowToken;
+ /**
+ * Used to cache IWindow from the windowToken so we don't need to convert every time getWindow
+ * is called.
+ */
+ private IWindow window;
// The window name.
public String name;
@@ -145,7 +150,7 @@
.append(", visible=").append(visible)
.append(", scaleFactor=").append(scaleFactor)
.append(", transform=").append(transform)
- .append(", windowToken=").append(getWindow())
+ .append(", windowToken=").append(windowToken)
.toString();
}
@@ -180,9 +185,14 @@
public void setWindowToken(IWindow iwindow) {
windowToken = iwindow.asBinder();
+ window = iwindow;
}
public IWindow getWindow() {
- return IWindow.Stub.asInterface(windowToken);
+ if (window != null) {
+ return window;
+ }
+ window = IWindow.Stub.asInterface(windowToken);
+ return window;
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 47546848..eb6bc58 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -320,6 +320,19 @@
int TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE = 27;
/**
+ * A window in a new task fragment is being opened.
+ * @hide
+ */
+ int TRANSIT_OLD_TASK_FRAGMENT_OPEN = 28;
+
+ /**
+ * A window in the top-most activity of task fragment is being closed to reveal the activity
+ * below.
+ * @hide
+ */
+ int TRANSIT_OLD_TASK_FRAGMENT_CLOSE = 29;
+
+ /**
* @hide
*/
@IntDef(prefix = { "TRANSIT_OLD_" }, value = {
@@ -344,7 +357,9 @@
TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN,
TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE,
TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE,
- TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE
+ TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE,
+ TRANSIT_OLD_TASK_FRAGMENT_OPEN,
+ TRANSIT_OLD_TASK_FRAGMENT_CLOSE
})
@Retention(RetentionPolicy.SOURCE)
@interface TransitionOldType {}
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index 40da86a..ff6f8ac 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -613,6 +613,36 @@
public static final int CONTENT_CHANGE_TYPE_STATE_DESCRIPTION = 0x00000040;
/**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * A drag has started while accessibility is enabled. This is either via an
+ * AccessibilityAction, or via touch events. This is sent from the source that initiated the
+ * drag.
+ *
+ * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START
+ */
+ public static final int CONTENT_CHANGE_TYPE_DRAG_STARTED = 0x00000080;
+
+ /**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * A drag in with accessibility enabled has ended. This means the content has been
+ * successfully dropped. This is sent from the target that accepted the dragged content.
+ *
+ * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_DROP
+ */
+ public static final int CONTENT_CHANGE_TYPE_DRAG_DROPPED = 0x00000100;
+
+ /**
+ * Change type for {@link #TYPE_WINDOW_CONTENT_CHANGED} event:
+ * A drag in with accessibility enabled has ended. This means the content has been
+ * unsuccessfully dropped, the user has canceled the action via an AccessibilityAction, or
+ * no drop has been detected within a timeout and the drag was automatically cancelled. This is
+ * sent from the source that initiated the drag.
+ *
+ * @see AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_CANCEL
+ */
+ public static final int CONTENT_CHANGE_TYPE_DRAG_CANCELLED = 0x0000200;
+
+ /**
* Change type for {@link #TYPE_WINDOWS_CHANGED} event:
* The window was added.
*/
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 085eb81..587a270 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -27,6 +27,7 @@
import android.annotation.Nullable;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ClipData;
import android.graphics.Rect;
import android.graphics.Region;
import android.os.Build;
@@ -4353,6 +4354,14 @@
case R.id.accessibilityActionImeEnter:
return "ACTION_IME_ENTER";
default:
+ // TODO(197520937): Use finalized constants in switch
+ if (action == R.id.accessibilityActionDragStart) {
+ return "ACTION_DRAG";
+ } else if (action == R.id.accessibilityActionDragCancel) {
+ return "ACTION_CANCEL_DRAG";
+ } else if (action == R.id.accessibilityActionDragDrop) {
+ return "ACTION_DROP";
+ }
return "ACTION_UNKNOWN";
}
}
@@ -4995,6 +5004,46 @@
@NonNull public static final AccessibilityAction ACTION_IME_ENTER =
new AccessibilityAction(R.id.accessibilityActionImeEnter);
+ /**
+ * Action to start a drag.
+ * <p>
+ * This action initiates a drag & drop within the system. The source's dragged content is
+ * prepared before the drag begins. In View, this action should prepare the arguments to
+ * {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)} and then
+ * call {@link View#startDragAndDrop(ClipData, View.DragShadowBuilder, Object, int)}. The
+ * equivalent should be performed for other UI toolkits.
+ * </p>
+ *
+ * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_STARTED
+ */
+ @NonNull public static final AccessibilityAction ACTION_DRAG_START =
+ new AccessibilityAction(R.id.accessibilityActionDragStart);
+
+ /**
+ * Action to trigger a drop of the content being dragged.
+ * <p>
+ * This action is added to potential drop targets if the source started a drag with
+ * {@link #ACTION_DRAG_START}. In View, these targets are Views that accepted
+ * {@link android.view.DragEvent#ACTION_DRAG_STARTED} and have an
+ * {@link View.OnDragListener}.
+ * </p>
+ *
+ * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_DROPPED
+ */
+ @NonNull public static final AccessibilityAction ACTION_DRAG_DROP =
+ new AccessibilityAction(R.id.accessibilityActionDragDrop);
+
+ /**
+ * Action to cancel a drag.
+ * <p>
+ * This action is added to the source that started a drag with {@link #ACTION_DRAG_START}.
+ * </p>
+ *
+ * @see AccessibilityEvent#CONTENT_CHANGE_TYPE_DRAG_CANCELLED
+ */
+ @NonNull public static final AccessibilityAction ACTION_DRAG_CANCEL =
+ new AccessibilityAction(R.id.accessibilityActionDragCancel);
+
private final int mActionId;
private final CharSequence mLabel;
diff --git a/core/java/android/view/autofill/AutofillClientController.java b/core/java/android/view/autofill/AutofillClientController.java
index 7056444..c47f6f7 100644
--- a/core/java/android/view/autofill/AutofillClientController.java
+++ b/core/java/android/view/autofill/AutofillClientController.java
@@ -324,7 +324,7 @@
@Override
public boolean autofillClientIsVisibleForAutofill() {
- return !mActivity.isVisibleForAutofill();
+ return mActivity.isVisibleForAutofill();
}
@Override
diff --git a/core/java/com/android/ims/internal/uce/common/CapInfo.java b/core/java/com/android/ims/internal/uce/common/CapInfo.java
index bca647a..f5c4b1f 100644
--- a/core/java/com/android/ims/internal/uce/common/CapInfo.java
+++ b/core/java/com/android/ims/internal/uce/common/CapInfo.java
@@ -20,6 +20,10 @@
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.Bundle;
+
+import java.util.Map;
+import java.util.HashMap;
/** Class for capability discovery information.
* @hide */
@@ -88,6 +92,95 @@
/** Time used to compute when to query again. */
private long mCapTimestamp = 0;
+ private Map<String, String> mCapInfoMap = new HashMap<String, String>();
+
+ /** IM session feature tag key. */
+ public static final String INSTANT_MSG =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\"";
+ /** File transfer feature tag key. */
+ public static final String FILE_TRANSFER =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.ft\"";
+ /** File transfer Thumbnail feature tag key. */
+ public static final String FILE_TRANSFER_THUMBNAIL =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftthumb\"";
+ /** File transfer Store and forward feature tag key. */
+ public static final String FILE_TRANSFER_SNF =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.ftstandfw\"";
+ /** File transfer HTTP feature tag key. */
+ public static final String FILE_TRANSFER_HTTP =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fthttp\"";
+ /** Image sharing feature tag key. */
+ public static final String IMAGE_SHARE =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-is\"";
+ /** Video sharing during a CS call feature tag key-- IR-74. */
+ public static final String VIDEO_SHARE_DURING_CS = "+g.3gpp.cs-voice";
+ /** Video sharing outside of voice call feature tag key-- IR-84. */
+ public static final String VIDEO_SHARE =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-vs\"";
+ /** Social presence feature tag key. */
+ public static final String SOCIAL_PRESENCE =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.sp\"";
+ /** Presence discovery feature tag key. */
+ public static final String CAPDISC_VIA_PRESENCE =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.dp\"";
+ /** IP voice call feature tag key (IR-92/IR-58). */
+ public static final String IP_VOICE =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\"";
+ /** IP video call feature tag key (IR-92/IR-58). */
+ public static final String IP_VIDEO =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.mmtel\";video";
+ /** IP Geo location Pull using File Transfer feature tag key. */
+ public static final String GEOPULL_FT =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopullft\"";
+ /** IP Geo location Pull feature tag key. */
+ public static final String GEOPULL =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopull\"";
+ /** IP Geo location Push feature tag key. */
+ public static final String GEOPUSH =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.geopush\"";
+ /** Standalone messaging feature tag key. */
+ public static final String STANDALONE_MSG =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg;" +
+ "urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\"";
+ /** Full Store and Forward Group Chat information feature tag key. */
+ public static final String FULL_SNF_GROUPCHAT =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.fullsfgroupchat\"";
+ /** RCS IP Voice call feature tag key. */
+ public static final String RCS_IP_VOICE_CALL =
+ "+g.gsma.rcs.ipcall";
+ /** RCS IP Video call feature tag key. */
+ public static final String RCS_IP_VIDEO_CALL =
+ "+g.gsma.rcs.ipvideocall";
+ /** RCS IP Video only call feature tag key. */
+ public static final String RCS_IP_VIDEO_ONLY_CALL =
+ "+g.gsma.rcs.ipvideoonlycall";
+ /** IP Geo location Push using SMS feature tag key. */
+ public static final String GEOSMS =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.geosms\"";
+ /** RCS call composer feature tag key. */
+ public static final String CALLCOMPOSER =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.callcomposer\"";
+ /** RCS post-call feature tag key. */
+ public static final String POSTCALL =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.callunanswered\"";
+ /** Shared map feature tag key. */
+ public static final String SHAREDMAP =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.sharedmap\"";
+ /** Shared Sketch feature tag key. */
+ public static final String SHAREDSKETCH =
+ "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gppservice.ims.icsi.gsma.sharedsketch\"";
+ /** Chatbot communication feature tag key. */
+ public static final String CHATBOT =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gppapplication.ims.iari.rcs.chatbot\"";
+ /** Chatbot role feature tag key. */
+ public static final String CHATBOTROLE = "+g.gsma.rcs.isbot";
+ /** Standalone Chatbot communication feature tag key. */
+ public static final String STANDALONE_CHATBOT =
+ "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcs.chatbot.sa\"";
+ /** MMtel based call composer feature tag key. */
+ public static final String MMTEL_CALLCOMPOSER = "+g.gsma.callcomposer";
+
+
/**
* Constructor for the CapInfo class.
@@ -99,6 +192,7 @@
/**
* Checks whether IM is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isImSupported() {
@@ -107,6 +201,7 @@
/**
* Sets IM as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setImSupported(boolean imSupported) {
@@ -115,6 +210,7 @@
/**
* Checks whether FT Thumbnail is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isFtThumbSupported() {
@@ -123,16 +219,16 @@
/**
* Sets FT thumbnail as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setFtThumbSupported(boolean ftThumbSupported) {
this.mFtThumbSupported = ftThumbSupported;
}
-
-
/**
* Checks whether FT Store and Forward is supported
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isFtSnFSupported() {
@@ -141,6 +237,7 @@
/**
* Sets FT Store and Forward as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setFtSnFSupported(boolean ftSnFSupported) {
@@ -149,6 +246,7 @@
/**
* Checks whether File transfer HTTP is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isFtHttpSupported() {
@@ -157,6 +255,7 @@
/**
* Sets File transfer HTTP as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setFtHttpSupported(boolean ftHttpSupported) {
@@ -165,6 +264,7 @@
/**
* Checks whether FT is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isFtSupported() {
@@ -173,6 +273,7 @@
/**
* Sets FT as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setFtSupported(boolean ftSupported) {
@@ -181,6 +282,7 @@
/**
* Checks whether IS is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isIsSupported() {
@@ -189,6 +291,7 @@
/**
* Sets IS as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setIsSupported(boolean isSupported) {
@@ -197,6 +300,7 @@
/**
* Checks whether video sharing is supported during a CS call.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isVsDuringCSSupported() {
@@ -204,8 +308,9 @@
}
/**
- * Sets video sharing as supported or not supported during a CS
- * call.
+ * Sets video sharing as supported or not supported during a CS
+ * call.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setVsDuringCSSupported(boolean vsDuringCSSupported) {
@@ -213,8 +318,9 @@
}
/**
- * Checks whether video sharing outside a voice call is
- * supported.
+ * Checks whether video sharing outside a voice call is
+ * supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isVsSupported() {
@@ -223,6 +329,7 @@
/**
* Sets video sharing as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setVsSupported(boolean vsSupported) {
@@ -231,6 +338,7 @@
/**
* Checks whether social presence is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isSpSupported() {
@@ -239,6 +347,7 @@
/**
* Sets social presence as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setSpSupported(boolean spSupported) {
@@ -248,6 +357,7 @@
/**
* Checks whether capability discovery via presence is
* supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isCdViaPresenceSupported() {
@@ -257,6 +367,7 @@
/**
* Sets capability discovery via presence as supported or not
* supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setCdViaPresenceSupported(boolean cdViaPresenceSupported) {
@@ -265,6 +376,7 @@
/**
* Checks whether IP voice call is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isIpVoiceSupported() {
@@ -273,6 +385,7 @@
/**
* Sets IP voice call as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setIpVoiceSupported(boolean ipVoiceSupported) {
@@ -281,6 +394,7 @@
/**
* Checks whether IP video call is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isIpVideoSupported() {
@@ -289,6 +403,7 @@
/**
* Sets IP video call as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setIpVideoSupported(boolean ipVideoSupported) {
@@ -298,6 +413,7 @@
/**
* Checks whether Geo location Pull using File Transfer is
* supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isGeoPullFtSupported() {
@@ -307,6 +423,7 @@
/**
* Sets Geo location Pull using File Transfer as supported or
* not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setGeoPullFtSupported(boolean geoPullFtSupported) {
@@ -315,6 +432,7 @@
/**
* Checks whether Geo Pull is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isGeoPullSupported() {
@@ -323,6 +441,7 @@
/**
* Sets Geo Pull as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setGeoPullSupported(boolean geoPullSupported) {
@@ -331,6 +450,7 @@
/**
* Checks whether Geo Push is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isGeoPushSupported() {
@@ -339,6 +459,7 @@
/**
* Sets Geo Push as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setGeoPushSupported(boolean geoPushSupported) {
@@ -347,6 +468,7 @@
/**
* Checks whether short messaging is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isSmSupported() {
@@ -355,6 +477,7 @@
/**
* Sets short messaging as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setSmSupported(boolean smSupported) {
@@ -363,22 +486,32 @@
/**
* Checks whether store/forward and group chat are supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isFullSnFGroupChatSupported() {
return mFullSnFGroupChatSupported;
}
+ /**
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isRcsIpVoiceCallSupported() {
return mRcsIpVoiceCallSupported;
}
+ /**
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isRcsIpVideoCallSupported() {
return mRcsIpVideoCallSupported;
}
+ /**
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isRcsIpVideoOnlyCallSupported() {
return mRcsIpVideoOnlyCallSupported;
@@ -386,20 +519,32 @@
/**
* Sets store/forward and group chat supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setFullSnFGroupChatSupported(boolean fullSnFGroupChatSupported) {
this.mFullSnFGroupChatSupported = fullSnFGroupChatSupported;
}
+ /**
+ * @deprecated Use {@link #addCapability(String, String)} instead.
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setRcsIpVoiceCallSupported(boolean rcsIpVoiceCallSupported) {
this.mRcsIpVoiceCallSupported = rcsIpVoiceCallSupported;
}
+
+ /**
+ * @deprecated Use {@link #addCapability(String, String)} instead.
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setRcsIpVideoCallSupported(boolean rcsIpVideoCallSupported) {
this.mRcsIpVideoCallSupported = rcsIpVideoCallSupported;
}
+
+ /**
+ * @deprecated Use {@link #addCapability(String, String)} instead.
+ */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void setRcsIpVideoOnlyCallSupported(boolean rcsIpVideoOnlyCallSupported) {
this.mRcsIpVideoOnlyCallSupported = rcsIpVideoOnlyCallSupported;
@@ -407,6 +552,7 @@
/**
* Checks whether Geo Push via SMS is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isGeoSmsSupported() {
return mGeoSmsSupported;
@@ -414,6 +560,7 @@
/**
* Sets Geolocation Push via SMS as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setGeoSmsSupported(boolean geoSmsSupported) {
this.mGeoSmsSupported = geoSmsSupported;
@@ -421,6 +568,7 @@
/**
* Checks whether RCS call composer is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isCallComposerSupported() {
return mCallComposerSupported;
@@ -428,6 +576,7 @@
/**
* Sets call composer as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setCallComposerSupported(boolean callComposerSupported) {
this.mCallComposerSupported = callComposerSupported;
@@ -435,6 +584,7 @@
/**
* Checks whether post call is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isPostCallSupported(){
return mPostCallSupported;
@@ -442,13 +592,15 @@
/**
* Sets post call as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
- public void setPostCallSupported(boolean postCallSupported) {
- this.mPostCallSupported = postCallSupported;
- }
+ public void setPostCallSupported(boolean postCallSupported) {
+ this.mPostCallSupported = postCallSupported;
+ }
/**
* Checks whether shared map is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isSharedMapSupported() {
return mSharedMapSupported;
@@ -456,6 +608,7 @@
/**
* Sets shared map as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setSharedMapSupported(boolean sharedMapSupported) {
this.mSharedMapSupported = sharedMapSupported;
@@ -463,6 +616,7 @@
/**
* Checks whether shared sketch is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isSharedSketchSupported() {
return mSharedSketchSupported;
@@ -470,6 +624,7 @@
/**
* Sets shared sketch as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setSharedSketchSupported(boolean sharedSketchSupported) {
this.mSharedSketchSupported = sharedSketchSupported;
@@ -477,6 +632,7 @@
/**
* Checks whether chatbot communication is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isChatbotSupported() {
return mChatbotSupported;
@@ -484,6 +640,7 @@
/**
* Sets chatbot communication as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setChatbotSupported(boolean chatbotSupported) {
this.mChatbotSupported = chatbotSupported;
@@ -491,6 +648,7 @@
/**
* Checks whether chatbot role is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isChatbotRoleSupported() {
return mChatbotRoleSupported;
@@ -498,6 +656,7 @@
/**
* Sets chatbot role as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setChatbotRoleSupported(boolean chatbotRoleSupported) {
this.mChatbotRoleSupported = chatbotRoleSupported;
@@ -505,6 +664,7 @@
/**
* Checks whether standalone chatbot communication is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isSmChatbotSupported() {
return mSmChatbotSupported;
@@ -512,6 +672,7 @@
/**
* Sets standalone chatbot communication as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setSmChatbotSupported(boolean smChatbotSupported) {
this.mSmChatbotSupported = smChatbotSupported;
@@ -519,6 +680,7 @@
/**
* Checks whether Mmtel based call composer is supported.
+ * @deprecated Use {@link #isCapabilitySupported(String)} instead.
*/
public boolean isMmtelCallComposerSupported() {
return mMmtelCallComposerSupported;
@@ -526,6 +688,7 @@
/**
* Sets Mmtel based call composer as supported or not supported.
+ * @deprecated Use {@link #addCapability(String, String)} instead.
*/
public void setMmtelCallComposerSupported(boolean mmtelCallComposerSupported) {
this.mMmtelCallComposerSupported = mmtelCallComposerSupported;
@@ -555,6 +718,84 @@
this.mCapTimestamp = capTimestamp;
}
+ /**
+ * Adds the feature tag string with supported versions to
+ * the mCapInfoMap.
+ * Map<String featureType, String versions>
+ * Versions format:
+ * "+g.gsma.rcs.botversion=\"#=1" -> Version 1 supported
+ * "+g.gsma.rcs.botversion=\"#=1,#=2\"" -> Versions 1 and 2 are supported
+ *
+ * Example #1: Add standard feature tag with one version support
+ * addCapability(CapInfo.STANDALONE_CHATBOT, "+g.gsma.rcs.botversion=\"#=1");
+ * The above example indicates standalone chatbot feature tag is supported
+ * in version 1.
+ *
+ * Example #2: Add standard feature tag with multiple version support
+ * addCapability(CapInfo.CHATBOT, "+g.gsma.rcs.botversion=\"#=1,#=2\"");
+ * The above example indicates session based chatbot feature tag is supported
+ * in versions 1 and 2.
+ *
+ * Example #3: Add standard feature tag with no version support
+ * addCapability(CapInfo.INSTANT_MSG, "");
+ * The above example indicates im feature tag does not have version support.
+ *
+ * Example #4: Add custom/extension feature tag with no version support
+ * addCapability("+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.custom_im\"",
+ * "");
+ * Call setNewFeatureTag(int presenceServiceHdl, String featureTag,
+ * in PresServiceInfo serviceInfo, int userData) API
+ * in IPresenceService.aidl before calling addCapability() API
+ */
+ public void addCapability(String featureTagName, String versions) {
+ this.mCapInfoMap.put(featureTagName, versions);
+ }
+
+ /**
+ * Returns String of versions of the feature tag passed.
+ * Returns "" if versioning support is not present for the feature tag passed.
+ * Returns null if feature tag is not present.
+ *
+ * Example # 1:
+ * getCapabilityVersions(CapInfo.STANDALONE_CHATBOT);
+ * The above returns String in this format "+g.gsma.rcs.botversion=\"#=1,#=2\"",
+ * indicating more than one versions are supported for standalone chatbot feature tag
+ *
+ * Example # 2:
+ * getCapabilityVersions(CapInfo.INSTANT_MSG);
+ * The above returns empty String in this format "",
+ * indicating versions support is not present for im feature tag
+ *
+ * Example #3:
+ * getCapabilityVersions(
+ * "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.custom_im\");
+ * The above returns String "",
+ * indicating version supported is not present for the custom feature tag passed.
+ */
+ public String getCapabilityVersions(String featureTagName) {
+ return mCapInfoMap.get(featureTagName);
+ }
+
+ /** Removes the entry of the feature tag passed, from the Map. */
+ public void removeCapability(String featureTagName) {
+ this.mCapInfoMap.remove(featureTagName);
+ }
+
+ /** Sets Map of feature tag string and string of supported versions. */
+ public void setCapInfoMap(Map<String, String> capInfoMap) {
+ this.mCapInfoMap = capInfoMap;
+ }
+
+ /** Gets Map of feature tag string and string of supported versions. */
+ public Map<String, String> getCapInfoMap() {
+ return mCapInfoMap;
+ }
+
+ /** Checks whether the featureTag is supported or not. */
+ public boolean isCapabilitySupported(String featureTag) {
+ return mCapInfoMap.containsKey(featureTag);
+ }
+
public int describeContents() {
// TODO Auto-generated method stub
return 0;
@@ -594,6 +835,12 @@
dest.writeInt(mRcsIpVideoOnlyCallSupported ? 1 : 0);
dest.writeStringArray(mExts);
dest.writeLong(mCapTimestamp);
+
+ Bundle capInfoBundle = new Bundle();
+ for (Map.Entry<String, String> entry : mCapInfoMap.entrySet()) {
+ capInfoBundle.putString(entry.getKey(), entry.getValue());
+ }
+ dest.writeBundle(capInfoBundle);
}
public static final Parcelable.Creator<CapInfo> CREATOR = new Parcelable.Creator<CapInfo>() {
@@ -646,5 +893,10 @@
mExts = source.createStringArray();
mCapTimestamp = source.readLong();
+
+ Bundle capInfoBundle = source.readBundle();
+ for (String key: capInfoBundle.keySet()) {
+ mCapInfoMap.put(key, capInfoBundle.getString(key));
+ }
}
}
diff --git a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
index acea0f0..3242081 100644
--- a/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
+++ b/core/java/com/android/ims/internal/uce/options/OptionsSipResponse.java
@@ -30,6 +30,7 @@
private int mSipResponseCode = 0;
private int mRetryAfter = 0;
private String mReasonPhrase = "";
+ private String mReasonHeader = "";
/**
* Gets the Options command ID.
@@ -117,6 +118,22 @@
}
/**
+ * Gets the reason header associated with the SIP response code.
+ * @hide
+ */
+ public String getReasonHeader() {
+ return mReasonHeader;
+ }
+
+ /**
+ * Sets the SIP response code reason phrase.
+ * @hide
+ */
+ public void setReasonHeader(String reasonHeader) {
+ this.mReasonHeader = reasonHeader;
+ }
+
+ /**
* Constructor for the OptionsSipResponse class.
* @hide
*/
@@ -138,6 +155,7 @@
dest.writeString(mReasonPhrase);
dest.writeParcelable(mCmdId, flags);
dest.writeInt(mRetryAfter);
+ dest.writeString(mReasonHeader);
}
/** @hide */
@@ -164,5 +182,6 @@
mReasonPhrase = source.readString();
mCmdId = source.readParcelable(OptionsCmdId.class.getClassLoader());
mRetryAfter = source.readInt();
+ mReasonHeader = source.readString();
}
}
diff --git a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
index 9549152..5e394ef 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresSipResponse.java
@@ -29,6 +29,7 @@
private int mSipResponseCode = 0;
private int mRetryAfter = 0;
private String mReasonPhrase = "";
+ private String mReasonHeader = "";
/**
* Gets the Presence command ID.
@@ -123,6 +124,23 @@
}
/**
+ * Gets the reason header associated with the SIP response
+ * code.
+ * @hide
+ */
+ public String getReasonHeader() {
+ return mReasonHeader;
+ }
+
+ /**
+ * Sets the SIP response code reason header.
+ * @hide
+ */
+ public void setReasonHeader(String reasonHeader) {
+ this.mReasonHeader = reasonHeader;
+ }
+
+ /**
* Constructor for the PresSipResponse class.
* @hide
*/
@@ -141,6 +159,7 @@
dest.writeString(mReasonPhrase);
dest.writeParcelable(mCmdId, flags);
dest.writeInt(mRetryAfter);
+ dest.writeString(mReasonHeader);
}
/** @hide */
@@ -168,5 +187,6 @@
mReasonPhrase = source.readString();
mCmdId = source.readParcelable(PresCmdId.class.getClassLoader());
mRetryAfter = source.readInt();
+ mReasonHeader = source.readString();
}
}
\ No newline at end of file
diff --git a/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
index 34a7b1e..ce3d568 100644
--- a/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
+++ b/core/java/com/android/ims/internal/uce/presence/PresTupleInfo.java
@@ -27,6 +27,7 @@
private String mFeatureTag = "";
private String mContactUri = "";
private String mTimestamp = "";
+ private String mVersion = "";
/**
@@ -80,6 +81,22 @@
}
/**
+ * Gets the version.
+ * @hide
+ */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Sets the version.
+ * @hide
+ */
+ public void setVersion(String version) {
+ this.mVersion = version;
+ }
+
+ /**
* Constructor for the PresTupleInfo class.
* @hide
*/
@@ -96,6 +113,7 @@
dest.writeString(mFeatureTag);
dest.writeString(mContactUri);
dest.writeString(mTimestamp);
+ dest.writeString(mVersion);
}
/** @hide */
@@ -121,5 +139,6 @@
mFeatureTag = source.readString();
mContactUri = source.readString();
mTimestamp = source.readString();
+ mVersion = source.readString();
}
}
\ No newline at end of file
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 02cd8db..35d25ca 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -458,56 +458,19 @@
private class ChooserHandler extends Handler {
private static final int CHOOSER_TARGET_SERVICE_RESULT = 1;
- private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT = 2;
- private static final int CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT = 3;
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT = 4;
private static final int SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED = 5;
private static final int LIST_VIEW_UPDATE_MESSAGE = 6;
- private static final int WATCHDOG_TIMEOUT_MAX_MILLIS = 1000;
- private static final int WATCHDOG_TIMEOUT_MIN_MILLIS = 300;
-
- private boolean mMinTimeoutPassed = false;
private boolean mReceivedDirectShareTargets = false;
private void removeAllMessages() {
removeMessages(LIST_VIEW_UPDATE_MESSAGE);
- removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT);
- removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT);
removeMessages(CHOOSER_TARGET_SERVICE_RESULT);
removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT);
removeMessages(SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED);
}
- private void restartServiceRequestTimer() {
- mMinTimeoutPassed = false;
- removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT);
- removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT);
-
- if (DEBUG) {
- Log.d(TAG, "queryTargets setting watchdog timer for "
- + WATCHDOG_TIMEOUT_MAX_MILLIS + "ms");
- }
-
- sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT,
- WATCHDOG_TIMEOUT_MIN_MILLIS);
- sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT,
- WATCHDOG_TIMEOUT_MAX_MILLIS);
- }
-
- private void maybeStopServiceRequestTimer() {
- // Set a minimum timeout threshold, to ensure both apis, sharing shortcuts
- // and older-style direct share services, have had time to load, otherwise
- // just checking mServiceConnections could force us to end prematurely
- if (mMinTimeoutPassed && mServiceConnections.isEmpty() && mReceivedDirectShareTargets) {
- logDirectShareTargetReceived(
- MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_CHOOSER_SERVICE);
- sendVoiceChoicesIfNeeded();
- mChooserMultiProfilePagerAdapter.getActiveListAdapter()
- .completeServiceTargetLoading();
- }
- }
-
@Override
public void handleMessage(Message msg) {
if (mChooserMultiProfilePagerAdapter.getActiveListAdapter() == null || isDestroyed()) {
@@ -532,7 +495,7 @@
if (adapterForUserHandle != null) {
adapterForUserHandle.addServiceResults(sri.originalTarget,
sri.resultTargets, TARGET_TYPE_CHOOSER_TARGET,
- /* directShareShortcutInfoCache */ null, mServiceConnections);
+ /* directShareShortcutInfoCache */ null);
if (!sri.resultTargets.isEmpty() && sri.originalTarget != null) {
mChooserTargetComponentNameCache.put(
sri.resultTargets.get(0).getComponentName(),
@@ -543,21 +506,6 @@
unbindService(sri.connection);
sri.connection.destroy();
mServiceConnections.remove(sri.connection);
- maybeStopServiceRequestTimer();
- break;
-
- case CHOOSER_TARGET_SERVICE_WATCHDOG_MIN_TIMEOUT:
- mMinTimeoutPassed = true;
- maybeStopServiceRequestTimer();
- break;
-
- case CHOOSER_TARGET_SERVICE_WATCHDOG_MAX_TIMEOUT:
- mMinTimeoutPassed = true;
- if (!mServiceConnections.isEmpty()) {
- getChooserActivityLogger().logSharesheetDirectLoadTimeout();
- }
- unbindRemainingServices();
- maybeStopServiceRequestTimer();
break;
case LIST_VIEW_UPDATE_MESSAGE:
@@ -580,20 +528,19 @@
if (adapterForUserHandle != null) {
adapterForUserHandle.addServiceResults(
resultInfo.originalTarget, resultInfo.resultTargets, msg.arg1,
- mDirectShareShortcutInfoCache, mServiceConnections);
+ mDirectShareShortcutInfoCache);
}
}
break;
case SHORTCUT_MANAGER_SHARE_TARGET_RESULT_COMPLETED:
- mReceivedDirectShareTargets = true;
-
logDirectShareTargetReceived(
MetricsEvent.ACTION_DIRECT_SHARE_TARGETS_LOADED_SHORTCUT_MANAGER);
sendVoiceChoicesIfNeeded();
getChooserActivityLogger().logSharesheetDirectLoadComplete();
- maybeStopServiceRequestTimer();
+ mChooserMultiProfilePagerAdapter.getActiveListAdapter()
+ .completeServiceTargetLoading();
break;
default:
@@ -1702,7 +1649,7 @@
/* origTarget */ null,
Lists.newArrayList(mCallerChooserTargets),
TARGET_TYPE_DEFAULT,
- /* directShareShortcutInfoCache */ null, mServiceConnections);
+ /* directShareShortcutInfoCache */ null);
}
}
@@ -2028,8 +1975,6 @@
break;
}
}
-
- mChooserHandler.restartServiceRequestTimer();
}
private IntentFilter getTargetIntentFilter() {
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index 87737ca..07c4050 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -491,9 +491,7 @@
*/
public void addServiceResults(DisplayResolveInfo origTarget, List<ChooserTarget> targets,
@ChooserActivity.ShareTargetType int targetType,
- Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos,
- List<ChooserActivity.ChooserTargetServiceConnection>
- pendingChooserTargetServiceConnections) {
+ Map<ChooserTarget, ShortcutInfo> directShareToShortcutInfos) {
if (DEBUG) {
Log.d(TAG, "addServiceResults " + origTarget.getResolvedComponentName() + ", "
+ targets.size()
diff --git a/core/java/com/android/internal/app/TEST_MAPPING b/core/java/com/android/internal/app/TEST_MAPPING
index 8bd7912..08e1d57 100644
--- a/core/java/com/android/internal/app/TEST_MAPPING
+++ b/core/java/com/android/internal/app/TEST_MAPPING
@@ -3,17 +3,14 @@
{
"name": "CtsSuspendAppsTestCases",
"file_patterns": ["(/|^)SuspendedAppActivity\\.java"]
- }
- ],
- "postsubmit": [
+ },
{
"name": "FrameworksCoreTests",
"options": [
{
"include-filter": "com.android.internal.app."
},
-
- // Many tests failing - do not enable for continuous execution
+ // Exclude currently failing tests from presubmit
{
"exclude-filter": "com.android.internal.app.IntentForwarderActivityTest"
},
diff --git a/core/java/com/android/internal/os/LongArrayMultiStateCounter.java b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
new file mode 100644
index 0000000..1a3b29d
--- /dev/null
+++ b/core/java/com/android/internal/os/LongArrayMultiStateCounter.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2021 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.internal.os;
+
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+/**
+ * Performs per-state counting of multi-element values over time. The class' behavior is illustrated
+ * by this example:
+ * <pre>
+ * // At 0 ms, the state of the tracked object is 0
+ * counter.setState(0, 0);
+ *
+ * // At 1000 ms, the state changes to 1
+ * counter.setState(1, 1000);
+ *
+ * // At 3000 ms, the tracked values are updated to {100, 200}
+ * arrayContainer.setValues(new long[]{{30, 300}};
+ * counter.updateValues(arrayContainer, 3000);
+ *
+ * // The values are distributed between states 0 and 1 according to the time
+ * // spent in those respective states. In this specific case, 1000 and 2000 ms.
+ * counter.getValues(arrayContainer, 0);
+ * // arrayContainer now has values {10, 100}
+ * counter.getValues(arrayContainer, 1);
+ * // arrayContainer now has values {20, 200}
+ * </pre>
+ *
+ * The tracked values are expected to increase monotonically.
+ *
+ * @hide
+ */
+public class LongArrayMultiStateCounter {
+
+ /**
+ * Container for a native equivalent of a long[].
+ */
+ public static class LongArrayContainer {
+ private static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ LongArrayContainer.class.getClassLoader(), native_getReleaseFunc());
+
+ private final long mNativeObject;
+ private final int mLength;
+
+ public LongArrayContainer(int length) {
+ mLength = length;
+ mNativeObject = native_init(length);
+ sRegistry.registerNativeAllocation(this, mNativeObject);
+ }
+
+ /**
+ * Copies the supplied values into the underlying native array.
+ */
+ public void setValues(long[] array) {
+ if (array.length != mLength) {
+ throw new IllegalArgumentException(
+ "Invalid array length: " + mLength + ", expected: " + mLength);
+ }
+ native_setValues(mNativeObject, array);
+ }
+
+ /**
+ * Copies the underlying native array values to the supplied array.
+ */
+ public void getValues(long[] array) {
+ if (array.length != mLength) {
+ throw new IllegalArgumentException(
+ "Invalid array length: " + mLength + ", expected: " + mLength);
+ }
+ native_getValues(mNativeObject, array);
+ }
+
+ @CriticalNative
+ private static native long native_init(int length);
+
+ @CriticalNative
+ private static native long native_getReleaseFunc();
+
+ @FastNative
+ private native void native_setValues(long nativeObject, long[] array);
+
+ @FastNative
+ private native void native_getValues(long nativeObject, long[] array);
+ }
+
+ private static final NativeAllocationRegistry sRegistry =
+ NativeAllocationRegistry.createMalloced(
+ LongArrayMultiStateCounter.class.getClassLoader(), native_getReleaseFunc());
+
+ private final int mStateCount;
+ private final int mLength;
+ private final long mNativeObject;
+
+ public LongArrayMultiStateCounter(int stateCount, int arrayLength, int initialState,
+ long timestampMs) {
+ mStateCount = stateCount;
+ mLength = arrayLength;
+ mNativeObject = native_init(stateCount, arrayLength, initialState, timestampMs);
+ sRegistry.registerNativeAllocation(this, mNativeObject);
+ }
+
+ /**
+ * Sets the current state to the supplied value.
+ */
+ public void setState(int state, long timestampMs) {
+ if (state < 0 || state >= mStateCount) {
+ throw new IllegalArgumentException(
+ "State: " + state + ", outside the range: [0-" + mStateCount + "]");
+ }
+ native_setState(mNativeObject, state, timestampMs);
+ }
+
+ /**
+ * Sets the new values. The delta between the previously set values and these values
+ * is distributed among the state according to the time the object spent in those states
+ * since the previous call to updateValues.
+ */
+ public void updateValues(LongArrayContainer longArrayContainer, long timestampMs) {
+ if (longArrayContainer.mLength != mLength) {
+ throw new IllegalArgumentException(
+ "Invalid array length: " + longArrayContainer.mLength + ", expected: "
+ + mLength);
+ }
+ native_updateValues(mNativeObject, longArrayContainer.mNativeObject, timestampMs);
+ }
+
+ /**
+ * Populates longArrayContainer with the accumulated counts for the specified state.
+ */
+ public void getCounts(LongArrayContainer longArrayContainer, int state) {
+ if (state < 0 || state >= mStateCount) {
+ throw new IllegalArgumentException(
+ "State: " + state + ", outside the range: [0-" + mStateCount + "]");
+ }
+ native_getCounts(mNativeObject, longArrayContainer.mNativeObject, state);
+ }
+
+ @Override
+ public String toString() {
+ return native_toString(mNativeObject);
+ }
+
+ @CriticalNative
+ private static native long native_init(int stateCount, int arrayLength, int initialState,
+ long timestampMs);
+
+ @CriticalNative
+ private static native long native_getReleaseFunc();
+
+ @CriticalNative
+ private static native void native_setState(long nativeObject, int state, long timestampMs);
+
+ @CriticalNative
+ private static native void native_updateValues(long nativeObject,
+ long longArrayContainerNativeObject, long timestampMs);
+
+ @CriticalNative
+ private static native void native_getCounts(long nativeObject,
+ long longArrayContainerNativeObject, int state);
+
+ @FastNative
+ private native String native_toString(long nativeObject);
+}
diff --git a/core/java/com/android/internal/os/SystemServicePowerCalculator.java b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
index b4a2b63..c527c06 100644
--- a/core/java/com/android/internal/os/SystemServicePowerCalculator.java
+++ b/core/java/com/android/internal/os/SystemServicePowerCalculator.java
@@ -175,8 +175,11 @@
final double systemUidModeledPowerMah = mCpuPowerCalculator.calculateUidModeledPowerMah(
systemUid, BatteryStats.STATS_SINCE_CHARGED);
- return uCtoMah(consumptionUC) * systemServiceModeledPowerMah
- / systemUidModeledPowerMah;
+ if (systemUidModeledPowerMah > 0) {
+ return uCtoMah(consumptionUC) * systemServiceModeledPowerMah / systemUidModeledPowerMah;
+ } else {
+ return 0;
+ }
}
private double calculatePowerUsingPowerProfile(BatteryStats batteryStats) {
diff --git a/core/java/com/android/internal/util/OWNERS b/core/java/com/android/internal/util/OWNERS
index 5b68159..100a605d 100644
--- a/core/java/com/android/internal/util/OWNERS
+++ b/core/java/com/android/internal/util/OWNERS
@@ -1,6 +1,7 @@
per-file AsyncChannel* = lorenzo@google.com, satk@google.com, etancohen@google.com
per-file MessageUtils*, Protocol*, RingBuffer*, TokenBucket* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
per-file Protocol* = etancohen@google.com, lorenzo@google.com
per-file State* = jchalard@google.com, lorenzo@google.com, satk@google.com
per-file DataClass* = eugenesusla@google.com
\ No newline at end of file
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 4f76aad..21a327c 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -217,6 +217,7 @@
"com_android_internal_os_KernelCpuUidBpfMapReader.cpp",
"com_android_internal_os_KernelSingleProcessCpuThreadReader.cpp",
"com_android_internal_os_KernelSingleUidTimeReader.cpp",
+ "com_android_internal_os_LongArrayMultiStateCounter.cpp",
"com_android_internal_os_Zygote.cpp",
"com_android_internal_os_ZygoteCommandBuffer.cpp",
"com_android_internal_os_ZygoteInit.cpp",
@@ -245,9 +246,12 @@
"android.media.audio.common.types-V1-cpp",
"audioclient-types-aidl-cpp",
"audioflinger-aidl-cpp",
+ "audiopolicy-types-aidl-cpp",
+ "spatializer-aidl-cpp",
"av-types-aidl-cpp",
"android.hardware.camera.device@3.2",
"libandroidicu",
+ "libbattery",
"libbpf_android",
"libnetdbpf",
"libnetdutils",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 09d5cb1..91179c2 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -204,6 +204,7 @@
extern int register_com_android_internal_os_KernelCpuUidBpfMapReader(JNIEnv *env);
extern int register_com_android_internal_os_KernelSingleProcessCpuThreadReader(JNIEnv* env);
extern int register_com_android_internal_os_KernelSingleUidTimeReader(JNIEnv *env);
+extern int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv* env);
extern int register_com_android_internal_os_Zygote(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteCommandBuffer(JNIEnv *env);
extern int register_com_android_internal_os_ZygoteInit(JNIEnv *env);
@@ -1586,6 +1587,7 @@
REG_JNI(register_com_android_internal_content_om_OverlayConfig),
REG_JNI(register_com_android_internal_net_NetworkUtilsInternal),
REG_JNI(register_com_android_internal_os_ClassLoaderFactory),
+ REG_JNI(register_com_android_internal_os_LongArrayMultiStateCounter),
REG_JNI(register_com_android_internal_os_Zygote),
REG_JNI(register_com_android_internal_os_ZygoteCommandBuffer),
REG_JNI(register_com_android_internal_os_ZygoteInit),
diff --git a/core/jni/android_media_AudioDeviceAttributes.cpp b/core/jni/android_media_AudioDeviceAttributes.cpp
index 2a16dce..6879a60 100644
--- a/core/jni/android_media_AudioDeviceAttributes.cpp
+++ b/core/jni/android_media_AudioDeviceAttributes.cpp
@@ -24,6 +24,11 @@
static jclass gAudioDeviceAttributesClass;
static jmethodID gAudioDeviceAttributesCstor;
+static struct {
+ jfieldID mAddress;
+ jfieldID mNativeType;
+ // other fields unused by JNI
+} gAudioDeviceAttributesFields;
namespace android {
@@ -33,12 +38,25 @@
jint jNativeType = (jint)devTypeAddr->mType;
ScopedLocalRef<jstring> jAddress(env, env->NewStringUTF(devTypeAddr->getAddress()));
- *jAudioDeviceAttributes = env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor,
- jNativeType, jAddress.get());
+ *jAudioDeviceAttributes =
+ env->NewObject(gAudioDeviceAttributesClass, gAudioDeviceAttributesCstor,
+ jNativeType, jAddress.get());
return jStatus;
}
+jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr,
+ const jobject jAudioDeviceAttributes) {
+ devTypeAddr->mType = (audio_devices_t)env->GetIntField(jAudioDeviceAttributes,
+ gAudioDeviceAttributesFields.mNativeType);
+
+ jstring jAddress = (jstring)env->GetObjectField(jAudioDeviceAttributes,
+ gAudioDeviceAttributesFields.mAddress);
+ devTypeAddr->setAddress(ScopedUtfChars(env, jAddress).c_str());
+
+ return AUDIO_JAVA_SUCCESS;
+}
+
} // namespace android
int register_android_media_AudioDeviceAttributes(JNIEnv *env) {
@@ -48,5 +66,10 @@
gAudioDeviceAttributesCstor =
GetMethodIDOrDie(env, audioDeviceTypeAddressClass, "<init>", "(ILjava/lang/String;)V");
+ gAudioDeviceAttributesFields.mNativeType =
+ GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mNativeType", "I");
+ gAudioDeviceAttributesFields.mAddress =
+ GetFieldIDOrDie(env, gAudioDeviceAttributesClass, "mAddress", "Ljava/lang/String;");
+
return 0;
}
diff --git a/core/jni/android_media_AudioDeviceAttributes.h b/core/jni/android_media_AudioDeviceAttributes.h
index b49d9ba..4a1f40d 100644
--- a/core/jni/android_media_AudioDeviceAttributes.h
+++ b/core/jni/android_media_AudioDeviceAttributes.h
@@ -28,6 +28,9 @@
extern jint createAudioDeviceAttributesFromNative(JNIEnv *env, jobject *jAudioDeviceAttributes,
const AudioDeviceTypeAddr *devTypeAddr);
+
+extern jint createAudioDeviceTypeAddrFromJava(JNIEnv *env, AudioDeviceTypeAddr *devTypeAddr,
+ const jobject jAudioDeviceAttributes);
} // namespace android
#endif
\ No newline at end of file
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 8a1f1a0..268871b 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -27,6 +27,8 @@
#include "core_jni_helpers.h"
#include <android/media/AudioVibratorInfo.h>
+#include <android/media/INativeSpatializerCallback.h>
+#include <android/media/ISpatializer.h>
#include <audiomanager/AudioManager.h>
#include <media/AudioContainers.h>
#include <media/AudioPolicy.h>
@@ -2025,6 +2027,18 @@
AudioSystem::setRoutingCallback(android_media_AudioSystem_routing_callback);
}
+void javaAudioFormatToNativeAudioConfig(JNIEnv *env, audio_config_t *nConfig,
+ const jobject jFormat, bool isInput) {
+ *nConfig = AUDIO_CONFIG_INITIALIZER;
+ nConfig->format = audioFormatToNative(env->GetIntField(jFormat, gAudioFormatFields.mEncoding));
+ nConfig->sample_rate = env->GetIntField(jFormat, gAudioFormatFields.mSampleRate);
+ jint jChannelMask = env->GetIntField(jFormat, gAudioFormatFields.mChannelMask);
+ if (isInput) {
+ nConfig->channel_mask = inChannelMaskToNative(jChannelMask);
+ } else {
+ nConfig->channel_mask = outChannelMaskToNative(jChannelMask);
+ }
+}
static jint convertAudioMixToNative(JNIEnv *env,
AudioMix *nAudioMix,
@@ -2045,13 +2059,7 @@
nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
jobject jFormat = env->GetObjectField(jAudioMix, gAudioMixFields.mFormat);
- nAudioMix->mFormat = AUDIO_CONFIG_INITIALIZER;
- nAudioMix->mFormat.sample_rate = env->GetIntField(jFormat,
- gAudioFormatFields.mSampleRate);
- nAudioMix->mFormat.channel_mask = outChannelMaskToNative(env->GetIntField(jFormat,
- gAudioFormatFields.mChannelMask));
- nAudioMix->mFormat.format = audioFormatToNative(env->GetIntField(jFormat,
- gAudioFormatFields.mEncoding));
+ javaAudioFormatToNativeAudioConfig(env, &nAudioMix->mFormat, jFormat, false /*isInput*/);
env->DeleteLocalRef(jFormat);
jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
@@ -2714,6 +2722,58 @@
return (jint)check_AudioSystem_Command(AudioSystem::setVibratorInfos(vibratorInfos));
}
+static jobject android_media_AudioSystem_getSpatializer(JNIEnv *env, jobject thiz,
+ jobject jISpatializerCallback) {
+ sp<media::INativeSpatializerCallback> nISpatializerCallback
+ = interface_cast<media::INativeSpatializerCallback>(
+ ibinderForJavaObject(env, jISpatializerCallback));
+ sp<media::ISpatializer> nSpatializer;
+ status_t status = AudioSystem::getSpatializer(nISpatializerCallback,
+ &nSpatializer);
+ if (status != NO_ERROR) {
+ return nullptr;
+ }
+ return javaObjectForIBinder(env, IInterface::asBinder(nSpatializer));
+}
+
+static jboolean android_media_AudioSystem_canBeSpatialized(JNIEnv *env, jobject thiz,
+ jobject jaa, jobject jFormat,
+ jobjectArray jDeviceArray) {
+ JNIAudioAttributeHelper::UniqueAaPtr paa = JNIAudioAttributeHelper::makeUnique();
+ jint jStatus = JNIAudioAttributeHelper::nativeFromJava(env, jaa, paa.get());
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return false;
+ }
+
+ AudioDeviceTypeAddrVector nDevices;
+
+ const size_t numDevices = env->GetArrayLength(jDeviceArray);
+ for (size_t i = 0; i < numDevices; ++i) {
+ AudioDeviceTypeAddr device;
+ jobject jDevice = env->GetObjectArrayElement(jDeviceArray, i);
+ if (jDevice == nullptr) {
+ return false;
+ }
+ jStatus = createAudioDeviceTypeAddrFromJava(env, &device, jDevice);
+ if (jStatus != (jint)AUDIO_JAVA_SUCCESS) {
+ return false;
+ }
+ nDevices.push_back(device);
+ }
+
+ audio_config_t nConfig;
+ javaAudioFormatToNativeAudioConfig(env, &nConfig, jFormat, false /*isInput*/);
+
+ bool canBeSpatialized;
+ status_t status =
+ AudioSystem::canBeSpatialized(paa.get(), &nConfig, nDevices, &canBeSpatialized);
+ if (status != NO_ERROR) {
+ ALOGW("%s native returned error %d", __func__, status);
+ return false;
+ }
+ return canBeSpatialized;
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gMethods[] =
@@ -2850,7 +2910,15 @@
(void *)android_media_AudioSystem_removeUserIdDeviceAffinities},
{"setCurrentImeUid", "(I)I", (void *)android_media_AudioSystem_setCurrentImeUid},
{"setVibratorInfos", "(Ljava/util/List;)I",
- (void *)android_media_AudioSystem_setVibratorInfos}};
+ (void *)android_media_AudioSystem_setVibratorInfos},
+ {"nativeGetSpatializer",
+ "(Landroid/media/INativeSpatializerCallback;)Landroid/os/IBinder;",
+ (void *)android_media_AudioSystem_getSpatializer},
+ {"canBeSpatialized",
+ "(Landroid/media/AudioAttributes;Landroid/media/AudioFormat;"
+ "[Landroid/media/AudioDeviceAttributes;)Z",
+ (void *)android_media_AudioSystem_canBeSpatialized}};
+
static const JNINativeMethod gEventHandlerMethods[] = {
{"native_setup",
diff --git a/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
new file mode 100644
index 0000000..953902a
--- /dev/null
+++ b/core/jni/com_android_internal_os_LongArrayMultiStateCounter.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <cstring>
+#include "LongArrayMultiStateCounter.h"
+#include "core_jni_helpers.h"
+
+namespace android {
+
+static jlong native_init(jint stateCount, jint arrayLength, jint initialState, jlong timestamp) {
+ battery::LongArrayMultiStateCounter *counter =
+ new battery::LongArrayMultiStateCounter(stateCount, initialState,
+ std::vector<uint64_t>(arrayLength), timestamp);
+ return reinterpret_cast<jlong>(counter);
+}
+
+static void native_dispose(void *nativePtr) {
+ battery::LongArrayMultiStateCounter *counter =
+ reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+ delete counter;
+}
+
+static jlong native_getReleaseFunc() {
+ return reinterpret_cast<jlong>(native_dispose);
+}
+
+static void native_setState(jlong nativePtr, jint state, jlong timestamp) {
+ battery::LongArrayMultiStateCounter *counter =
+ reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+ counter->setState(state, timestamp);
+}
+
+static void native_updateValues(jlong nativePtr, jlong longArrayContainerNativePtr,
+ jlong timestamp) {
+ battery::LongArrayMultiStateCounter *counter =
+ reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+ std::vector<uint64_t> *vector =
+ reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
+
+ counter->updateValue(*vector, timestamp);
+}
+
+static void native_getCounts(jlong nativePtr, jlong longArrayContainerNativePtr, jint state) {
+ battery::LongArrayMultiStateCounter *counter =
+ reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+ std::vector<uint64_t> *vector =
+ reinterpret_cast<std::vector<uint64_t> *>(longArrayContainerNativePtr);
+
+ *vector = counter->getCount(state);
+}
+
+static jobject native_toString(JNIEnv *env, jlong nativePtr, jobject self) {
+ battery::LongArrayMultiStateCounter *counter =
+ reinterpret_cast<battery::LongArrayMultiStateCounter *>(nativePtr);
+ return env->NewStringUTF(counter->toString().c_str());
+}
+
+static jlong native_init_LongArrayContainer(jint length) {
+ return reinterpret_cast<jlong>(new std::vector<uint64_t>(length));
+}
+
+static const JNINativeMethod g_LongArrayMultiStateCounter_methods[] = {
+ // @CriticalNative
+ {"native_init", "(IIIJ)J", (void *)native_init},
+ // @CriticalNative
+ {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc},
+ // @CriticalNative
+ {"native_setState", "(JIJ)V", (void *)native_setState},
+ // @CriticalNative
+ {"native_updateValues", "(JJJ)V", (void *)native_updateValues},
+ // @CriticalNative
+ {"native_getCounts", "(JJI)V", (void *)native_getCounts},
+ // @FastNative
+ {"native_toString", "(J)Ljava/lang/String;", (void *)native_toString},
+};
+
+/////////////////////// LongArrayMultiStateCounter.LongArrayContainer ////////////////////////
+
+static void native_dispose_LongArrayContainer(jlong nativePtr) {
+ std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+ delete vector;
+}
+
+static jlong native_getReleaseFunc_LongArrayContainer() {
+ return reinterpret_cast<jlong>(native_dispose_LongArrayContainer);
+}
+
+static void native_setValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
+ jlongArray jarray) {
+ std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+ ScopedLongArrayRO scopedArray(env, jarray);
+ const uint64_t *array = reinterpret_cast<const uint64_t *>(scopedArray.get());
+ uint8_t size = scopedArray.size();
+
+ // Boundary checks are performed in the Java layer
+ std::copy(array, array + size, vector->data());
+}
+
+static void native_getValues_LongArrayContainer(JNIEnv *env, jobject self, jlong nativePtr,
+ jlongArray jarray) {
+ std::vector<uint64_t> *vector = reinterpret_cast<std::vector<uint64_t> *>(nativePtr);
+ ScopedLongArrayRW scopedArray(env, jarray);
+
+ // Boundary checks are performed in the Java layer
+ std::copy(vector->data(), vector->data() + vector->size(), scopedArray.get());
+}
+
+static const JNINativeMethod g_LongArrayContainer_methods[] = {
+ // @CriticalNative
+ {"native_init", "(I)J", (void *)native_init_LongArrayContainer},
+ // @CriticalNative
+ {"native_getReleaseFunc", "()J", (void *)native_getReleaseFunc_LongArrayContainer},
+ // @FastNative
+ {"native_setValues", "(J[J)V", (void *)native_setValues_LongArrayContainer},
+ // @FastNative
+ {"native_getValues", "(J[J)V", (void *)native_getValues_LongArrayContainer},
+};
+
+int register_com_android_internal_os_LongArrayMultiStateCounter(JNIEnv *env) {
+ // 0 represents success, thus "|" and not "&"
+ return RegisterMethodsOrDie(env, "com/android/internal/os/LongArrayMultiStateCounter",
+ g_LongArrayMultiStateCounter_methods,
+ NELEM(g_LongArrayMultiStateCounter_methods)) |
+ RegisterMethodsOrDie(env,
+ "com/android/internal/os/LongArrayMultiStateCounter"
+ "$LongArrayContainer",
+ g_LongArrayContainer_methods, NELEM(g_LongArrayContainer_methods));
+}
+
+} // namespace android
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index c4838b8..84f82fd 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -254,6 +254,15 @@
<!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_IME_ENTER}. -->
<item type="id" name="accessibilityActionImeEnter" />
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_START}. -->
+ <item type="id" name="accessibilityActionDragStart" />
+
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_DROP}. -->
+ <item type="id" name="accessibilityActionDragDrop" />
+
+ <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_DRAG_CANCEL}. -->
+ <item type="id" name="accessibilityActionDragCancel" />
+
<!-- View tag for remote views to store the index of the next child when adding nested remote views dynamically. -->
<item type="id" name="remote_views_next_child" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fd03d72..a20477c 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3224,6 +3224,9 @@
</staging-public-group>
<staging-public-group type="id" first-id="0x01fe0000">
+ <public name="accessibilityActionDragStart" />
+ <public name="accessibilityActionDragDrop" />
+ <public name="accessibilityActionDragCancel" />
</staging-public-group>
<staging-public-group type="style" first-id="0x01fd0000">
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 6e34a33..b5ab282 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -269,7 +269,7 @@
onView(withId(R.id.content_preview_thumbnail)).check(matches(isDisplayed()));
}
- @Test
+ @Test @Ignore
public void twoOptionsAndUserSelectsOne() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -298,7 +298,7 @@
assertThat(chosen[0], is(toChoose));
}
- @Test
+ @Test @Ignore
public void fourOptionsStackedIntoOneTarget() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
@@ -351,7 +351,7 @@
}
}
- @Test
+ @Test @Ignore
public void updateChooserCountsAndModelAfterUserSelection() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -424,7 +424,7 @@
assertThat(activity.isFinishing(), is(true));
}
- @Test
+ @Test @Ignore
public void hasOtherProfileOneOption() throws Exception {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -461,7 +461,7 @@
assertThat(chosen[0], is(toChoose));
}
- @Test
+ @Test @Ignore
public void hasOtherProfileTwoOptionsAndUserSelectsOne() throws Exception {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -500,7 +500,7 @@
assertThat(chosen[0], is(toChoose));
}
- @Test
+ @Test @Ignore
public void hasLastChosenActivityAndOtherProfile() throws Exception {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -564,7 +564,7 @@
assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK);
}
- @Test
+ @Test @Ignore
public void copyTextToClipboardLogging() throws Exception {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -595,7 +595,7 @@
}
- @Test
+ @Test @Ignore
public void testNearbyShareLogging() throws Exception {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -643,7 +643,7 @@
- @Test
+ @Test @Ignore
public void testEditImageLogs() throws Exception {
Intent sendIntent = createSendImageIntent(
Uri.parse("android.resource://com.android.frameworks.coretests/"
@@ -1129,7 +1129,7 @@
}
// This test is too long and too slow and should not be taken as an example for future tests.
- @Test
+ @Test @Ignore
public void testDirectTargetSelectionLogging() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -1162,8 +1162,7 @@
/* resolveInfoPresentationGetter */ null),
serviceTargets,
TARGET_TYPE_CHOOSER_TARGET,
- directShareToShortcutInfos,
- List.of())
+ directShareToShortcutInfos)
);
// Thread.sleep shouldn't be a thing in an integration test but it's
@@ -1200,7 +1199,7 @@
}
// This test is too long and too slow and should not be taken as an example for future tests.
- @Test
+ @Test @Ignore
public void testDirectTargetLoggingWithRankedAppTarget() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -1234,8 +1233,7 @@
/* resolveInfoPresentationGetter */ null),
serviceTargets,
TARGET_TYPE_CHOOSER_TARGET,
- directShareToShortcutInfos,
- List.of())
+ directShareToShortcutInfos)
);
// Thread.sleep shouldn't be a thing in an integration test but it's
// necessary here because of the way the code is structured
@@ -1266,7 +1264,7 @@
.getAllValues().get(2).getTaggedData(MetricsEvent.FIELD_RANKED_POSITION), is(0));
}
- @Test
+ @Test @Ignore
public void testShortcutTargetWithApplyAppLimits() throws InterruptedException {
// Set up resources
sOverrides.resources = Mockito.spy(
@@ -1305,8 +1303,7 @@
/* resolveInfoPresentationGetter */ null),
serviceTargets,
TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
- directShareToShortcutInfos,
- List.of())
+ directShareToShortcutInfos)
);
// Thread.sleep shouldn't be a thing in an integration test but it's
// necessary here because of the way the code is structured
@@ -1323,7 +1320,7 @@
activity.getAdapter().getItem(0).getDisplayLabel(), is("testTitle0"));
}
- @Test
+ @Test @Ignore
public void testShortcutTargetWithoutApplyAppLimits() throws InterruptedException {
DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SYSTEMUI,
SystemUiDeviceConfigFlags.APPLY_SHARING_APP_LIMITS_IN_SYSUI,
@@ -1366,8 +1363,7 @@
/* resolveInfoPresentationGetter */ null),
serviceTargets,
TARGET_TYPE_SHORTCUTS_FROM_PREDICTION_SERVICE,
- directShareToShortcutInfos,
- List.of())
+ directShareToShortcutInfos)
);
// Thread.sleep shouldn't be a thing in an integration test but it's
// necessary here because of the way the code is structured
@@ -1387,13 +1383,13 @@
}
// This test is too long and too slow and should not be taken as an example for future tests.
- @Test
+ @Test @Ignore
public void testDirectTargetLoggingWithAppTargetNotRankedPortrait()
throws InterruptedException {
testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_PORTRAIT, 4);
}
- @Test
+ @Test @Ignore
public void testDirectTargetLoggingWithAppTargetNotRankedLandscape()
throws InterruptedException {
testDirectTargetLoggingWithAppTargetNotRanked(Configuration.ORIENTATION_LANDSCAPE, 8);
@@ -1442,8 +1438,7 @@
/* resolveInfoPresentationGetter */ null),
serviceTargets,
TARGET_TYPE_CHOOSER_TARGET,
- directShareToShortcutInfos,
- List.of())
+ directShareToShortcutInfos)
);
// Thread.sleep shouldn't be a thing in an integration test but it's
// necessary here because of the way the code is structured
@@ -1554,7 +1549,7 @@
assertThat(activity.getWorkListAdapter().getCount(), is(workProfileTargets));
}
- @Test
+ @Test @Ignore
public void testWorkTab_selectingWorkTabAppOpensAppInWorkProfile() throws InterruptedException {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
@@ -1719,7 +1714,7 @@
.check(matches(isDisplayed()));
}
- @Test
+ @Test @Ignore
public void testAppTargetLogging() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1775,7 +1770,7 @@
.SharesheetTargetSelectedEvent.SHARESHEET_APP_TARGET_SELECTED.getId()));
}
- @Test
+ @Test @Ignore
public void testDirectTargetLogging() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -1806,8 +1801,7 @@
/* resolveInfoPresentationGetter */ null),
serviceTargets,
TARGET_TYPE_CHOOSER_TARGET,
- directShareToShortcutInfos,
- null)
+ directShareToShortcutInfos)
);
// Thread.sleep shouldn't be a thing in an integration test but it's
// necessary here because of the way the code is structured
@@ -1856,7 +1850,7 @@
.SharesheetTargetSelectedEvent.SHARESHEET_SERVICE_TARGET_SELECTED.getId()));
}
- @Test
+ @Test @Ignore
public void testEmptyDirectRowLogging() throws InterruptedException {
Intent sendIntent = createSendTextIntent();
// We need app targets for direct targets to get displayed
@@ -1907,7 +1901,7 @@
.SharesheetStandardEvent.SHARESHEET_EMPTY_DIRECT_SHARE_ROW.getId()));
}
- @Test
+ @Test @Ignore
public void testCopyTextToClipboardLogging() throws Exception {
Intent sendIntent = createSendTextIntent();
List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
@@ -1953,7 +1947,7 @@
.SharesheetTargetSelectedEvent.SHARESHEET_COPY_TARGET_SELECTED.getId()));
}
- @Test
+ @Test @Ignore
public void testSwitchProfileLogging() throws InterruptedException {
// enable the work tab feature flag
ResolverActivity.ENABLE_TABBED_VIEW = true;
diff --git a/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
new file mode 100644
index 0000000..26296f1
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/os/LongArrayMultiStateCounterTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2021 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.internal.os;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class LongArrayMultiStateCounterTest {
+
+ @Test
+ public void setStateAndUpdateValue() {
+ LongArrayMultiStateCounter.LongArrayContainer longArrayContainer =
+ new LongArrayMultiStateCounter.LongArrayContainer(4);
+ LongArrayMultiStateCounter counter = new LongArrayMultiStateCounter(2, 4, 0, 1000);
+ counter.setState(1, 2000);
+ counter.setState(0, 4000);
+ longArrayContainer.setValues(new long[]{100, 200, 300, 400});
+ counter.updateValues(longArrayContainer, 9000);
+ counter.getCounts(longArrayContainer, 0);
+
+ long[] result = new long[4];
+ longArrayContainer.getValues(result);
+ assertThat(result).isEqualTo(new long[]{75, 150, 225, 300});
+
+ counter.getCounts(longArrayContainer, 1);
+ longArrayContainer.getValues(result);
+ assertThat(result).isEqualTo(new long[]{25, 50, 75, 100});
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/OWNERS b/core/tests/coretests/src/com/android/internal/util/OWNERS
new file mode 100644
index 0000000..d832745
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/util/OWNERS
@@ -0,0 +1,2 @@
+per-file *Notification* = file:/services/core/java/com/android/server/notification/OWNERS
+per-file *ContrastColor* = file:/services/core/java/com/android/server/notification/OWNERS
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index f3cfcf1..67358c4 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -579,7 +579,7 @@
//
// Note: mNamespace == KeyProperties.NAMESPACE_APPLICATION implies that the target domain
// is Domain.APP and Domain.SELINUX is the target domain otherwise.
- if (alias != descriptor.alias
+ if (!alias.equals(descriptor.alias)
|| descriptor.domain != targetDomain
|| (descriptor.domain == Domain.SELINUX && descriptor.nspace != targetNamespace)) {
throw new KeyStoreException("Can only replace keys with same alias: " + alias
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index c32dddf..3b9bcd3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -93,6 +93,7 @@
private final Rect mDividerBounds = new Rect();
private final Rect mBounds1 = new Rect();
private final Rect mBounds2 = new Rect();
+ private final Rect mTmpBounds = new Rect();
private final SplitLayoutHandler mSplitLayoutHandler;
private final SplitWindowManager mSplitWindowManager;
private final DisplayImeController mDisplayImeController;
@@ -188,9 +189,10 @@
final int rotation = configuration.windowConfiguration.getRotation();
final Rect rootBounds = configuration.windowConfiguration.getBounds();
if (rotation != mRotation || !mRootBounds.equals(rootBounds)) {
+ mTmpBounds.set(mRootBounds);
mRootBounds.set(rootBounds);
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
- resetDividerPosition();
+ initDividerPosition(mTmpBounds);
affectsLayout = true;
}
@@ -202,6 +204,19 @@
return affectsLayout;
}
+ private void initDividerPosition(Rect oldBounds) {
+ final float snapRatio = (float) mDividePosition
+ / (float) (isLandscape(oldBounds) ? oldBounds.width() : oldBounds.height());
+ // Estimate position by previous ratio.
+ final float length =
+ (float) (isLandscape() ? mRootBounds.width() : mRootBounds.height());
+ final int estimatePosition = (int) (length * snapRatio);
+ // Init divider position by estimated position using current bounds snap algorithm.
+ mDividePosition = mDividerSnapAlgorithm.calculateNonDismissingSnapTarget(
+ estimatePosition).position;
+ updateBounds(mDividePosition);
+ }
+
/** Updates recording bounds of divider window and both of the splits. */
private void updateBounds(int position) {
mDividerBounds.set(mRootBounds);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 5bd6891..60c9e1c 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -18,6 +18,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.bluetooth.BluetoothCodecConfig;
@@ -2000,6 +2001,46 @@
*/
public static native int setVibratorInfos(@NonNull List<Vibrator> vibrators);
+ /**
+ * @hide
+ * If a spatializer effect is present on the platform, this will return an
+ * ISpatializer interface to control this feature.
+ * If no spatializer is present, a null interface is returned.
+ * The INativeSpatializerCallback passed must not be null.
+ * Only one ISpatializer interface can exist at a given time. The native audio policy
+ * service will reject the request if an interface was already acquired and previous owner
+ * did not die or call ISpatializer.release().
+ * @param callback the callback to receive state updates if the ISpatializer
+ * interface is acquired.
+ * @return the ISpatializer interface made available to control the
+ * platform spatializer
+ */
+ @Nullable
+ public static ISpatializer getSpatializer(INativeSpatializerCallback callback) {
+ return ISpatializer.Stub.asInterface(nativeGetSpatializer(callback));
+ }
+ private static native IBinder nativeGetSpatializer(INativeSpatializerCallback callback);
+
+ /**
+ * @hide
+ * Queries if some kind of spatialization will be performed if the audio playback context
+ * described by the provided arguments is present.
+ * The context is made of:
+ * - The audio attributes describing the playback use case.
+ * - The audio configuration describing the audio format, channels, sampling rate ...
+ * - The devices describing the sink audio device selected for playback.
+ * All arguments are optional and only the specified arguments are used to match against
+ * supported criteria. For instance, supplying no argument will tell if spatialization is
+ * supported or not in general.
+ * @param attributes audio attributes describing the playback use case
+ * @param format audio configuration describing the audio format, channels, sampling rate...
+ * @param devices the sink audio device selected for playback
+ * @return true if spatialization is enabled for this context, false otherwise.
+ */
+ public static native boolean canBeSpatialized(AudioAttributes attributes,
+ AudioFormat format,
+ AudioDeviceAttributes[] devices);
+
// Items shared with audio service
/**
diff --git a/media/java/android/media/PlayerBase.java b/media/java/android/media/PlayerBase.java
index 86ed50b..72ee00f 100644
--- a/media/java/android/media/PlayerBase.java
+++ b/media/java/android/media/PlayerBase.java
@@ -102,6 +102,13 @@
mState = AudioPlaybackConfiguration.PLAYER_STATE_IDLE;
};
+ /** @hide */
+ public int getPlayerIId() {
+ synchronized (mLock) {
+ return mPlayerIId;
+ }
+ }
+
/**
* Call from derived class when instantiation / initialization is successful
*/
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
index 6016aaf..28c6166 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_clock_switch.xml
@@ -68,16 +68,6 @@
lockScreenWeight="400"
/>
</FrameLayout>
- <FrameLayout
- android:id="@+id/keyguard_smartspace_container"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/below_clock_padding_start"
- android:paddingEnd="@dimen/below_clock_padding_end"
- android:layout_alignParentStart="true"
- android:layout_below="@id/lockscreen_clock_view"
- />
- <!-- either keyguard_status_area or keyguard_smartspace_container is visible -->
<include layout="@layout/keyguard_status_area"
android:id="@+id/keyguard_status_area"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 2b5076b..a2b4ac122 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -91,18 +91,6 @@
android:layout_height="match_parent"
android:visibility="gone"/>
- <FrameLayout
- android:id="@+id/split_shade_smartspace_container"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:paddingStart="@dimen/notification_side_paddings"
- android:paddingEnd="@dimen/notification_side_paddings"
- systemui:layout_constraintStart_toStartOf="@id/qs_edge_guideline"
- systemui:layout_constraintEnd_toEndOf="parent"
- systemui:layout_constraintTop_toTopOf="parent"
- android:visibility="gone">
- </FrameLayout>
-
<include layout="@layout/dock_info_overlay"/>
<FrameLayout
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index f1288e3..d9a5670 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -62,8 +62,7 @@
<com.android.systemui.statusbar.LightRevealScrim
android:id="@+id/light_reveal_scrim"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:visibility="gone" />
+ android:layout_height="match_parent" />
<include layout="@layout/status_bar_expanded"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
index 0b78ddb..382e895 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitchController.java
@@ -17,13 +17,13 @@
package com.android.keyguard;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static com.android.keyguard.KeyguardClockSwitch.LARGE;
import android.app.WallpaperManager;
import android.text.TextUtils;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
@@ -93,7 +93,8 @@
private final ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
- private ViewGroup mSmartspaceContainer;
+ // If set, will replace keyguard_status_area
+ private View mSmartspaceView;
private final KeyguardUnlockAnimationController mKeyguardUnlockAnimationController;
private SmartspaceTransitionController mSmartspaceTransitionController;
@@ -147,8 +148,6 @@
mClockFrame = mView.findViewById(R.id.lockscreen_clock_view);
mLargeClockFrame = mView.findViewById(R.id.lockscreen_clock_view_large);
- mSmartspaceContainer = mView.findViewById(R.id.keyguard_smartspace_container);
- mSmartspaceController.setKeyguardStatusContainer(mSmartspaceContainer);
mClockViewController =
new AnimatableClockController(
@@ -190,25 +189,35 @@
}
updateAodIcons();
- if (mSmartspaceController.isSmartspaceEnabled()) {
- // "Enabled" doesn't mean smartspace is displayed here - inside mSmartspaceContainer -
- // it might be a part of another view when in split shade. But it means that it CAN be
- // displayed here, so we want to hide keyguard_status_area and set views relations
- // accordingly.
+ if (mSmartspaceController.isEnabled()) {
+ mSmartspaceView = mSmartspaceController.buildAndConnectView(mView);
View ksa = mView.findViewById(R.id.keyguard_status_area);
- // we show either keyguard_status_area or smartspace, so when smartspace can be visible,
- // keyguard_status_area should be hidden
+ int ksaIndex = mView.indexOfChild(ksa);
ksa.setVisibility(View.GONE);
+ // Place smartspace view below normal clock...
+ RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
+ MATCH_PARENT, WRAP_CONTENT);
+ lp.addRule(RelativeLayout.BELOW, R.id.lockscreen_clock_view);
+
+ mView.addView(mSmartspaceView, ksaIndex, lp);
+ int startPadding = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.below_clock_padding_start);
+ int endPadding = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.below_clock_padding_end);
+ mSmartspaceView.setPaddingRelative(startPadding, 0, endPadding, 0);
+
updateClockLayout();
- View nic = mView.findViewById(R.id.left_aligned_notification_icon_container);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
- lp.addRule(RelativeLayout.BELOW, mSmartspaceContainer.getId());
+ View nic = mView.findViewById(
+ R.id.left_aligned_notification_icon_container);
+ lp = (RelativeLayout.LayoutParams) nic.getLayoutParams();
+ lp.addRule(RelativeLayout.BELOW, mSmartspaceView.getId());
nic.setLayoutParams(lp);
- mView.setSmartspaceView(mSmartspaceContainer);
- mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceContainer);
+
+ mView.setSmartspaceView(mSmartspaceView);
+ mSmartspaceTransitionController.setLockscreenSmartspace(mSmartspaceView);
}
}
@@ -231,7 +240,10 @@
// instance of this class. In order to fix this, we need to modify the plugin so that
// (a) we get a new view each time and (b) we can properly clean up an old view by making
// it unregister itself as a plugin listener.
- mSmartspaceContainer.removeAllViews();
+ if (mSmartspaceView != null) {
+ mView.removeView(mSmartspaceView);
+ mSmartspaceView = null;
+ }
}
/**
@@ -244,7 +256,7 @@
}
private void updateClockLayout() {
- if (mSmartspaceController.isSmartspaceEnabled()) {
+ if (mSmartspaceController.isEnabled()) {
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(MATCH_PARENT,
MATCH_PARENT);
lp.topMargin = getContext().getResources().getDimensionPixelSize(
@@ -309,8 +321,8 @@
PropertyAnimator.setProperty(mLargeClockFrame, AnimatableProperty.SCALE_Y,
scale, props, animate);
- if (mSmartspaceContainer != null) {
- PropertyAnimator.setProperty(mSmartspaceContainer, AnimatableProperty.TRANSLATION_X,
+ if (mSmartspaceView != null) {
+ PropertyAnimator.setProperty(mSmartspaceView, AnimatableProperty.TRANSLATION_X,
x, props, animate);
// If we're unlocking with the SmartSpace shared element transition, let the controller
@@ -328,8 +340,8 @@
public void setChildrenAlphaExcludingSmartspace(float alpha) {
final Set<View> excludedViews = new HashSet<>();
- if (mSmartspaceContainer != null) {
- excludedViews.add(mSmartspaceContainer);
+ if (mSmartspaceView != null) {
+ excludedViews.add(mSmartspaceView);
}
setChildrenAlphaExcluding(alpha, excludedViews);
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
index 867f117..1804ad4 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusViewController.java
@@ -80,7 +80,7 @@
mKeyguardStateController = keyguardStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
keyguardStateController, dozeParameters, unlockedScreenOffAnimationController,
- /* animateYPos= */ true);
+ /* animateYPos= */ true, /* visibleOnCommunal= */ false);
mKeyguardUnlockAnimationController = keyguardUnlockAnimationController;
mSmartspaceTransitionController = smartspaceTransitionController;
}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index a71b4f4..56fdb89 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -43,6 +43,7 @@
private final KeyguardStateController mKeyguardStateController;
private final DozeParameters mDozeParameters;
private final UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+ private final boolean mVisibleOnCommunal;
private boolean mAnimateYPos;
private boolean mKeyguardViewVisibilityAnimating;
private boolean mLastOccludedState = false;
@@ -53,13 +54,15 @@
KeyguardStateController keyguardStateController,
DozeParameters dozeParameters,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
- boolean animateYPos) {
+ boolean animateYPos,
+ boolean visibleOnCommunal) {
mView = view;
mCommunalStateController = communalStateController;
mKeyguardStateController = keyguardStateController;
mDozeParameters = dozeParameters;
mUnlockedScreenOffAnimationController = unlockedScreenOffAnimationController;
mAnimateYPos = animateYPos;
+ mVisibleOnCommunal = visibleOnCommunal;
}
public boolean isVisibilityAnimating() {
@@ -79,7 +82,7 @@
mKeyguardViewVisibilityAnimating = false;
// If the communal view is showing, hide immediately
- if (mCommunalStateController.getCommunalViewShowing()) {
+ if (!mVisibleOnCommunal && mCommunalStateController.getCommunalViewShowing()) {
mView.setVisibility(View.GONE);
mView.setAlpha(1f);
return;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index b5378cd..c323bf7 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -706,15 +706,21 @@
return mCoreLayoutParams;
}
+
private void onOrientationChanged() {
// When the configuration changes it's almost always necessary to destroy and re-create
// the overlay's window to pass it the new LayoutParams.
// Hiding the overlay will destroy its window. It's safe to hide the overlay regardless
// of whether it is already hidden.
+ final boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
hideUdfpsOverlay();
+
// If the overlay needs to be shown, this will re-create and show the overlay with the
// updated LayoutParams. Otherwise, the overlay will remain hidden.
updateOverlay();
+ if (wasShowingAltAuth) {
+ mKeyguardViewManager.showGenericBouncer(true);
+ }
}
private void showUdfpsOverlay(@NonNull ServerRequest request) {
@@ -785,6 +791,7 @@
mLockscreenShadeTransitionController,
mConfigurationController,
mSystemClock,
+ mKeyguardStateController,
this
);
case IUdfpsOverlayController.REASON_AUTH_BP:
@@ -820,10 +827,14 @@
Log.v(TAG, "hideUdfpsOverlay | removing window");
// Reset the controller back to its starting state.
onFingerUp();
+ boolean wasShowingAltAuth = mKeyguardViewManager.isShowingAlternateAuth();
mWindowManager.removeView(mView);
mView.setOnTouchListener(null);
mView.setOnHoverListener(null);
mView.setAnimationViewController(null);
+ if (wasShowingAltAuth) {
+ mKeyguardViewManager.resetAlternateAuth(true);
+ }
mAccessibilityManager.removeTouchExplorationStateChangeListener(
mTouchExplorationStateChangeListener);
mView = null;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index b81b547..4d9675c 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -34,6 +34,7 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.SystemClock;
@@ -53,6 +54,7 @@
@NonNull private final LockscreenShadeTransitionController mLockScreenShadeTransitionController;
@NonNull private final ConfigurationController mConfigurationController;
@NonNull private final SystemClock mSystemClock;
+ @NonNull private final KeyguardStateController mKeyguardStateController;
@NonNull private final UdfpsController mUdfpsController;
private boolean mShowingUdfpsBouncer;
@@ -63,6 +65,8 @@
private float mTransitionToFullShadeProgress;
private float mLastDozeAmount;
private long mLastUdfpsBouncerShowTime = -1;
+ private float mStatusBarExpansion;
+ private boolean mLaunchTransitionFadingAway;
/**
* hidden amount of pin/pattern/password bouncer
@@ -84,6 +88,7 @@
@NonNull LockscreenShadeTransitionController transitionController,
@NonNull ConfigurationController configurationController,
@NonNull SystemClock systemClock,
+ @NonNull KeyguardStateController keyguardStateController,
@NonNull UdfpsController udfpsController) {
super(view, statusBarStateController, statusBarOptional, dumpManager);
mKeyguardViewManager = statusBarKeyguardViewManager;
@@ -93,6 +98,7 @@
mLockScreenShadeTransitionController = transitionController;
mConfigurationController = configurationController;
mSystemClock = systemClock;
+ mKeyguardStateController = keyguardStateController;
mUdfpsController = udfpsController;
}
@@ -102,6 +108,12 @@
}
@Override
+ public void onInit() {
+ super.onInit();
+ mKeyguardViewManager.setAlternateAuthInterceptor(mAlternateAuthInterceptor);
+ }
+
+ @Override
protected void onViewAttached() {
super.onViewAttached();
final float dozeAmount = mStatusBarStateController.getDozeAmount();
@@ -111,11 +123,16 @@
mUdfpsRequested = false;
+ mLaunchTransitionFadingAway = mKeyguardStateController.isLaunchTransitionFadingAway();
+ mKeyguardStateController.addCallback(mKeyguardStateControllerCallback);
mStatusBarState = mStatusBarStateController.getState();
mQsExpanded = mKeyguardViewManager.isQsExpanded();
mInputBouncerHiddenAmount = KeyguardBouncer.EXPANSION_HIDDEN;
mIsBouncerVisible = mKeyguardViewManager.bouncerIsOrWillBeShowing();
mConfigurationController.addCallback(mConfigurationListener);
+ mStatusBarOptional.ifPresent(
+ statusBar -> statusBar.addExpansionChangedListener(
+ mStatusBarExpansionChangedListener));
updateAlpha();
updatePauseAuth();
@@ -128,10 +145,14 @@
super.onViewDetached();
mFaceDetectRunning = false;
+ mKeyguardStateController.removeCallback(mKeyguardStateControllerCallback);
mStatusBarStateController.removeCallback(mStateListener);
mKeyguardViewManager.removeAlternateAuthInterceptor(mAlternateAuthInterceptor);
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
mConfigurationController.removeCallback(mConfigurationListener);
+ mStatusBarOptional.ifPresent(
+ statusBar -> statusBar.removeExpansionChangedListener(
+ mStatusBarExpansionChangedListener));
if (mLockScreenShadeTransitionController.getUdfpsKeyguardViewController() == this) {
mLockScreenShadeTransitionController.setUdfpsKeyguardViewController(null);
}
@@ -146,9 +167,11 @@
pw.println("mQsExpanded=" + mQsExpanded);
pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
+ pw.println("mStatusBarExpansion=" + mStatusBarExpansion);
pw.println("mAlpha=" + mView.getAlpha());
pw.println("mUdfpsRequested=" + mUdfpsRequested);
pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
+ pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
}
/**
@@ -198,6 +221,10 @@
return false;
}
+ if (mLaunchTransitionFadingAway) {
+ return true;
+ }
+
if (mStatusBarState != KEYGUARD) {
return true;
}
@@ -255,10 +282,13 @@
}
private void updateAlpha() {
- // fade icon on transition to showing bouncer
+ // fade icon on transitions to showing the status bar, but if mUdfpsRequested, then
+ // the keyguard is occluded by some application - so instead use the input bouncer
+ // hidden amount to determine the fade
+ float expansion = mUdfpsRequested ? mInputBouncerHiddenAmount : mStatusBarExpansion;
int alpha = mShowingUdfpsBouncer ? 255
: (int) MathUtils.constrain(
- MathUtils.map(.5f, .9f, 0f, 255f, mInputBouncerHiddenAmount),
+ MathUtils.map(.5f, .9f, 0f, 255f, expansion),
0f, 255f);
alpha *= (1.0f - mTransitionToFullShadeProgress);
mView.setUnpausedAlpha(alpha);
@@ -374,4 +404,23 @@
mView.updateColor();
}
};
+
+ private final StatusBar.ExpansionChangedListener mStatusBarExpansionChangedListener =
+ new StatusBar.ExpansionChangedListener() {
+ @Override
+ public void onExpansionChanged(float expansion, boolean expanded) {
+ mStatusBarExpansion = expansion;
+ updateAlpha();
+ }
+ };
+
+ private final KeyguardStateController.Callback mKeyguardStateControllerCallback =
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onLaunchTransitionFadingAwayChanged() {
+ mLaunchTransitionFadingAway =
+ mKeyguardStateController.isLaunchTransitionFadingAway();
+ updatePauseAuth();
+ }
+ };
}
diff --git a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
index 320c2ea..1680e42 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/CommunalHostViewController.java
@@ -24,8 +24,11 @@
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.KeyguardVisibilityHelper;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.ViewController;
@@ -70,6 +73,8 @@
private static final int SHOW_COMMUNAL_VIEW_INVALID_STATES =
STATE_DOZING | STATE_BOUNCER_SHOWING | STATE_KEYGUARD_OCCLUDED;
+ private final KeyguardVisibilityHelper mKeyguardVisibilityHelper;
+
private ViewController<? extends View> mCommunalViewController;
private KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
@@ -123,6 +128,8 @@
CommunalStateController communalStateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
KeyguardStateController keyguardStateController,
+ DozeParameters dozeParameters,
+ UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
StatusBarStateController statusBarStateController, CommunalHostView view) {
super(view);
mCommunalStateController = communalStateController;
@@ -130,6 +137,21 @@
mMainExecutor = mainExecutor;
mKeyguardStateController = keyguardStateController;
mStatusBarStateController = statusBarStateController;
+ mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
+ keyguardStateController, dozeParameters, unlockedScreenOffAnimationController,
+ /* animateYPos= */ false, /* visibleOnCommunal= */ true);
+ }
+
+ /**
+ * Set the visibility of the keyguard status view based on some new state.
+ */
+ public void setKeyguardStatusViewVisibility(
+ int statusBarState,
+ boolean keyguardFadingAway,
+ boolean goingToFullShade,
+ int oldStatusBarState) {
+ mKeyguardVisibilityHelper.setViewVisibility(
+ statusBarState, keyguardFadingAway, goingToFullShade, oldStatusBarState);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index b2db86f..55e6154 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -456,13 +456,24 @@
public void updateListening() {
if (!mConfigured || mSensor == null) return;
- if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)
- && !mRegistered) {
- mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
- if (DEBUG) Log.d(TAG, "requestTriggerSensor " + mRegistered);
+ if (mRequested && !mDisabled && (enabledBySetting() || mIgnoresSetting)) {
+ if (!mRegistered) {
+ mRegistered = mSensorManager.requestTriggerSensor(this, mSensor);
+ if (DEBUG) {
+ Log.d(TAG, "requestTriggerSensor[" + mSensor
+ + "] " + mRegistered);
+ }
+ } else {
+ if (DEBUG) {
+ Log.d(TAG, "requestTriggerSensor[" + mSensor
+ + "] already registered");
+ }
+ }
} else if (mRegistered) {
final boolean rt = mSensorManager.cancelTriggerSensor(this, mSensor);
- if (DEBUG) Log.d(TAG, "cancelTriggerSensor " + rt);
+ if (DEBUG) {
+ Log.d(TAG, "cancelTriggerSensor[" + mSensor + "] " + rt);
+ }
mRegistered = false;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/DreamHelper.java b/packages/SystemUI/src/com/android/systemui/idle/DreamHelper.java
new file mode 100644
index 0000000..fba1067
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/idle/DreamHelper.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.idle;
+
+import android.content.Context;
+import android.service.dreams.Sandman;
+
+import javax.inject.Inject;
+
+/**
+ * A helper class to the idle mode for requests related to the
+ * {@link DreamService}.
+ */
+public class DreamHelper {
+ @Inject
+ protected DreamHelper() {
+ }
+
+ /**
+ * Requests the system to start dreaming.
+ *
+ * @param context The context within which the dream request is sent.
+ */
+ public void startDreaming(Context context) {
+ Sandman.startDreamByUserRequest(context);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
index 38af02b..97d32c3 100644
--- a/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/idle/IdleHostViewController.java
@@ -31,7 +31,6 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.SystemClock;
-import android.service.dreams.Sandman;
import android.util.Log;
import android.view.Choreographer;
import android.view.View;
@@ -63,41 +62,41 @@
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@Retention(RetentionPolicy.RUNTIME)
- @IntDef({STATE_IDLE_MODE_ENABLED, STATE_DOZING, STATE_KEYGUARD_SHOWING, STATE_IDLING})
+ @IntDef({STATE_IDLE_MODE_ENABLED, STATE_KEYGUARD_SHOWING, STATE_DOZING, STATE_DREAMING,
+ STATE_LOW_LIGHT, STATE_IDLING, STATE_SHOULD_START_IDLING})
public @interface State {}
// Set at construction to indicate idle mode is available.
private static final int STATE_IDLE_MODE_ENABLED = 1 << 0;
- // Set when the device has entered a system level dream.
- private static final int STATE_DOZING = 1 << 1;
+ // Set when keyguard is present, even below a dream or AOD. AKA the device is locked.
+ private static final int STATE_KEYGUARD_SHOWING = 1 << 1;
- // Set when the keyguard is showing.
- private static final int STATE_KEYGUARD_SHOWING = 1 << 2;
+ // Set when the device has entered a dozing / low power state.
+ private static final int STATE_DOZING = 1 << 2;
- // Set when input monitoring has established the device is now idling.
- private static final int STATE_IDLING = 1 << 3;
+ // Set when the device has entered a dreaming state, which includes dozing.
+ private static final int STATE_DREAMING = 1 << 3;
// Set when the device is in a low light environment.
private static final int STATE_LOW_LIGHT = 1 << 4;
- // The state the controller must be in to start recognizing idleness (lack of input
- // interaction).
- private static final int CONDITIONS_IDLE_MONITORING =
- STATE_IDLE_MODE_ENABLED | STATE_KEYGUARD_SHOWING;
+ // Set when the device is idling, which is either dozing or dreaming.
+ private static final int STATE_IDLING = 1 << 5;
- // The state the controller must be in before entering idle mode.
- private static final int CONDITIONS_IDLING = CONDITIONS_IDLE_MONITORING | STATE_IDLING;
-
- // The state the controller must be in to start listening for low light signals.
- private static final int CONDITIONS_LOW_LIGHT_MONITORING =
- STATE_IDLE_MODE_ENABLED | STATE_KEYGUARD_SHOWING;
+ // Set when the controller decides that the device should start idling (either dozing or
+ // dreaming).
+ private static final int STATE_SHOULD_START_IDLING = 1 << 6;
// The aggregate current state.
private int mState;
private boolean mIdleModeActive;
private boolean mLowLightModeActive;
private boolean mIsMonitoringLowLight;
+ private boolean mIsMonitoringDream;
+
+ // Whether in a state waiting for dozing to complete before starting dreaming.
+ private boolean mDozeToDreamLock = false;
private final Context mContext;
@@ -134,15 +133,21 @@
// Choreographer to use for monitoring input.
private final Choreographer mChoreographer;
+ // Helper class for DreamService related requests.
+ private final DreamHelper mDreamHelper;
+
// Monitor for tracking touches for activity.
private InputMonitorCompat mInputMonitor;
- // Delayed callback for enabling idle mode.
+ // Intent filter for receiving dream broadcasts.
+ private IntentFilter mDreamIntentFilter;
+
+ // Delayed callback for starting idling.
private final Runnable mEnableIdlingCallback = () -> {
if (DEBUG) {
- Log.d(TAG, "enabling idle");
+ Log.d(TAG, "time out, should start idling");
}
- setState(STATE_IDLING, true);
+ setState(STATE_SHOULD_START_IDLING, true);
};
private final KeyguardStateController.Callback mKeyguardCallback =
@@ -161,11 +166,13 @@
}
};
- private final BroadcastReceiver mDreamEndedReceiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mDreamStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
- setState(STATE_IDLING, false);
+ if (Intent.ACTION_DREAMING_STARTED.equals(intent.getAction())) {
+ setState(STATE_DREAMING, true);
+ } else if (Intent.ACTION_DREAMING_STOPPED.equals(intent.getAction())) {
+ setState(STATE_DREAMING, false);
}
}
};
@@ -185,7 +192,8 @@
@Named(IDLE_VIEW) Provider<View> idleViewProvider,
Choreographer choreographer,
KeyguardStateController keyguardStateController,
- StatusBarStateController statusBarStateController) {
+ StatusBarStateController statusBarStateController,
+ DreamHelper dreamHelper) {
super(view);
mContext = context;
mBroadcastDispatcher = broadcastDispatcher;
@@ -196,6 +204,7 @@
mStatusBarStateController = statusBarStateController;
mLooper = looper;
mChoreographer = choreographer;
+ mDreamHelper = dreamHelper;
mState = STATE_KEYGUARD_SHOWING;
@@ -226,6 +235,20 @@
}
private void setState(@State int state, boolean active) {
+ // If waiting for dozing to stop, ignore any state update until dozing is stopped.
+ if (mDozeToDreamLock) {
+ if (state == STATE_DOZING && !active) {
+ if (DEBUG) {
+ Log.d(TAG, "dozing stopped, now start dreaming");
+ }
+
+ mDozeToDreamLock = false;
+ enableIdleMode(true);
+ }
+
+ return;
+ }
+
final int oldState = mState;
if (active) {
@@ -234,27 +257,81 @@
mState &= ~state;
}
- // If we have entered doze or no longer match the preconditions for idling, remove idling.
- if ((mState & STATE_DOZING) == STATE_DOZING
- || (mState & CONDITIONS_IDLE_MONITORING) != CONDITIONS_IDLE_MONITORING) {
- mState &= ~STATE_IDLING;
- }
-
if (oldState == mState) {
return;
}
- if (DEBUG) {
- Log.d(TAG, "state changed from " + oldState + " to " + mState);
+ // Updates STATE_IDLING.
+ final boolean isIdling = getState(STATE_DOZING) || getState(STATE_DREAMING);
+ if (isIdling) {
+ mState |= STATE_IDLING;
+ } else {
+ mState &= ~STATE_IDLING;
}
- enableIdleMonitoring(mState == CONDITIONS_IDLE_MONITORING);
- enableIdleMode(mState == CONDITIONS_IDLING);
- // Loose matching. Doesn't need to be the exact state to monitor low light, but only
- // the specified states need to match.
- enableLowLightMonitoring(
- (mState & CONDITIONS_LOW_LIGHT_MONITORING) == CONDITIONS_LOW_LIGHT_MONITORING);
- enableLowLightMode((mState & STATE_LOW_LIGHT) == STATE_LOW_LIGHT);
+ // Updates STATE_SHOULD_START_IDLING.
+ final boolean stoppedIdling = stoppedIdling(oldState);
+ if (stoppedIdling) {
+ mState &= ~STATE_SHOULD_START_IDLING;
+ } else if (shouldStartIdling(oldState)) {
+ mState |= STATE_SHOULD_START_IDLING;
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "set " + getStateName(state) + " to " + active);
+ logCurrentState();
+ }
+
+ final boolean wasLowLight = getState(STATE_LOW_LIGHT, oldState);
+ final boolean isLowLight = getState(STATE_LOW_LIGHT);
+ final boolean wasIdling = getState(STATE_IDLING, oldState);
+
+ // When the device is idling and no longer in low light, wake up from dozing, wait till
+ // done, and start dreaming.
+ if (wasLowLight && !isLowLight && wasIdling && isIdling) {
+ if (DEBUG) {
+ Log.d(TAG, "idling and no longer in low light, stop dozing");
+ }
+
+ mDozeToDreamLock = true;
+
+ enableLowLightMode(false);
+ return;
+ }
+
+ final boolean inCommunalMode = getState(STATE_IDLE_MODE_ENABLED)
+ && getState(STATE_KEYGUARD_SHOWING);
+
+ enableDreamMonitoring(inCommunalMode);
+ enableLowLightMonitoring(inCommunalMode);
+ enableIdleMonitoring(inCommunalMode && !getState(STATE_IDLING));
+ enableIdleMode(inCommunalMode && !getState(STATE_LOW_LIGHT)
+ && getState(STATE_SHOULD_START_IDLING));
+ enableLowLightMode(inCommunalMode && !stoppedIdling && getState(STATE_LOW_LIGHT));
+ }
+
+ private void enableDreamMonitoring(boolean enable) {
+ if (mIsMonitoringDream == enable) {
+ return;
+ }
+
+ mIsMonitoringDream = enable;
+
+ if (DEBUG) {
+ Log.d(TAG, (enable ? "enable" : "disable") + " dream monitoring");
+ }
+
+ if (mDreamIntentFilter == null) {
+ mDreamIntentFilter = new IntentFilter();
+ mDreamIntentFilter.addAction(Intent.ACTION_DREAMING_STARTED);
+ mDreamIntentFilter.addAction(Intent.ACTION_DREAMING_STOPPED);
+ }
+
+ if (enable) {
+ mBroadcastDispatcher.registerReceiver(mDreamStateReceiver, mDreamIntentFilter);
+ } else {
+ mBroadcastDispatcher.unregisterReceiver(mDreamStateReceiver);
+ }
}
private void enableIdleMonitoring(boolean enable) {
@@ -302,22 +379,14 @@
}
if (DEBUG) {
- Log.d(TAG, "enable idle mode:" + enable);
+ Log.d(TAG, (enable ? "enable" : "disable") + " idle mode");
}
mIdleModeActive = enable;
if (mIdleModeActive) {
- // Track when the dream ends to cancel any timeouts.
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_DREAMING_STOPPED);
- mBroadcastDispatcher.registerReceiver(mDreamEndedReceiver, filter);
-
// Start dream.
- Sandman.startDreamByUserRequest(mContext);
- } else {
- // Stop tracking dream end.
- mBroadcastDispatcher.unregisterReceiver(mDreamEndedReceiver);
+ mDreamHelper.startDreaming(mContext);
}
}
@@ -329,11 +398,11 @@
mIsMonitoringLowLight = enable;
if (mIsMonitoringLowLight) {
- if (DEBUG) Log.d(TAG, "Enabling low light monitoring.");
+ if (DEBUG) Log.d(TAG, "enable low light monitoring");
mSensorManager.registerListener(this /*listener*/, mSensor,
SensorManager.SENSOR_DELAY_NORMAL);
} else {
- if (DEBUG) Log.d(TAG, "Disabling low light monitoring.");
+ if (DEBUG) Log.d(TAG, "disable low light monitoring");
mSensorManager.unregisterListener(this);
}
}
@@ -346,13 +415,13 @@
mLowLightModeActive = enable;
if (mLowLightModeActive) {
- if (DEBUG) Log.d(TAG, "Entering low light, start dozing.");
+ if (DEBUG) Log.d(TAG, "enter low light, start dozing");
mPowerManager.goToSleep(
SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
} else {
- if (DEBUG) Log.d(TAG, "Exiting low light, stop dozing.");
+ if (DEBUG) Log.d(TAG, "exit low light, stop dozing");
mPowerManager.wakeUp(SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_APPLICATION, "Exit low light condition");
}
@@ -381,8 +450,12 @@
return;
}
- final boolean isLowLight = event.values[0] < 10;
- setState(STATE_LOW_LIGHT, isLowLight);
+ final boolean shouldBeLowLight = event.values[0] < 10;
+ final boolean isLowLight = getState(STATE_LOW_LIGHT);
+
+ if (shouldBeLowLight != isLowLight) {
+ setState(STATE_LOW_LIGHT, shouldBeLowLight);
+ }
}
@Override
@@ -391,4 +464,62 @@
Log.d(TAG, "onAccuracyChanged accuracy=" + accuracy);
}
}
+
+ // Returns whether the device just stopped idling by comparing the previous state with the
+ // current one.
+ private boolean stoppedIdling(int oldState) {
+ // The device stopped idling if it's no longer dreaming or dozing.
+ return !getState(STATE_DOZING) && !getState(STATE_DREAMING)
+ && (getState(STATE_DOZING, oldState) || getState(STATE_DREAMING, oldState));
+ }
+
+ private boolean shouldStartIdling(int oldState) {
+ // Should start idling immediately if the device went in low light environment.
+ return !getState(STATE_LOW_LIGHT, oldState) && getState(STATE_LOW_LIGHT);
+ }
+
+ private String getStateName(@State int state) {
+ switch (state) {
+ case STATE_IDLE_MODE_ENABLED:
+ return "STATE_IDLE_MODE_ENABLED";
+ case STATE_KEYGUARD_SHOWING:
+ return "STATE_KEYGUARD_SHOWING";
+ case STATE_DOZING:
+ return "STATE_DOZING";
+ case STATE_DREAMING:
+ return "STATE_DREAMING";
+ case STATE_LOW_LIGHT:
+ return "STATE_LOW_LIGHT";
+ case STATE_IDLING:
+ return "STATE_IDLING";
+ case STATE_SHOULD_START_IDLING:
+ return "STATE_SHOULD_START_IDLING";
+ default:
+ return "STATE_UNKNOWN";
+ }
+ }
+
+ private boolean getState(@State int state) {
+ return getState(state, mState);
+ }
+
+ private boolean getState(@State int state, int oldState) {
+ return (oldState & state) == state;
+ }
+
+ private String getStateLog(@State int state) {
+ return getStateName(state) + " = " + getState(state);
+ }
+
+ private void logCurrentState() {
+ Log.d(TAG, "current state: {\n"
+ + "\t" + getStateLog(STATE_IDLE_MODE_ENABLED) + "\n"
+ + "\t" + getStateLog(STATE_KEYGUARD_SHOWING) + "\n"
+ + "\t" + getStateLog(STATE_DOZING) + "\n"
+ + "\t" + getStateLog(STATE_DREAMING) + "\n"
+ + "\t" + getStateLog(STATE_LOW_LIGHT) + "\n"
+ + "\t" + getStateLog(STATE_IDLING) + "\n"
+ + "\t" + getStateLog(STATE_SHOULD_START_IDLING) + "\n"
+ + "}");
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
index 89786ee..a617850 100644
--- a/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/NotificationPlayer.java
@@ -139,7 +139,7 @@
+ " with ducking", e);
}
player.start();
- if (DEBUG) { Log.d(mTag, "player.start"); }
+ if (DEBUG) { Log.d(mTag, "player.start piid:" + player.getPlayerIId()); }
} catch (Exception e) {
if (player != null) {
player.release();
@@ -155,7 +155,13 @@
mPlayer = player;
}
if (mp != null) {
- if (DEBUG) { Log.d(mTag, "mPlayer.release"); }
+ if (DEBUG) {
+ Log.d(mTag, "mPlayer.pause+release piid:" + player.getPlayerIId());
+ }
+ mp.pause();
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ie) { }
mp.release();
}
this.notify();
@@ -244,6 +250,10 @@
try {
mp.stop();
} catch (Exception e) { }
+ if (DEBUG) {
+ Log.i(mTag, "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to notif cancelled");
+ }
mp.release();
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
@@ -284,7 +294,7 @@
public void onCompletion(MediaPlayer mp) {
synchronized(mQueueAudioFocusLock) {
if (mAudioManagerWithAudioFocus != null) {
- if (DEBUG) Log.d(mTag, "onCompletion() abandonning AudioFocus");
+ if (DEBUG) Log.d(mTag, "onCompletion() abandoning AudioFocus");
mAudioManagerWithAudioFocus.abandonAudioFocus(null);
mAudioManagerWithAudioFocus = null;
} else {
@@ -310,6 +320,10 @@
}
}
if (mp != null) {
+ if (DEBUG) {
+ Log.i("NotificationPlayer", "About to release MediaPlayer piid:"
+ + mp.getPlayerIId() + " due to onCompletion");
+ }
mp.release();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 658be72..a5fc5ab 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -428,19 +428,6 @@
}
};
- private final BroadcastReceiver mDebugAnyPackageChangedReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- final String[] stringArrayExtra = intent.getStringArrayExtra(
- Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
- Log.e("b/188806432", intent.toString()
- + (stringArrayExtra != null
- ? ", EXTRA_CHANGED_COMPONENT_NAME_LIST: " + String.join(", ",
- stringArrayExtra)
- : ""));
- }
- };
-
private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -581,13 +568,6 @@
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
- // b/188806432
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addDataScheme("package");
- filter.addDataSchemeSpecificPart("", PatternMatcher.PATTERN_PREFIX);
- mContext.registerReceiver(mDebugAnyPackageChangedReceiver, filter);
-
// Listen for status bar state changes
statusBarWinController.registerCallback(mStatusBarWindowCallback);
mScreenshotHelper = new ScreenshotHelper(context);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
index 51dbd85..03d8e7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LightRevealScrim.kt
@@ -12,8 +12,10 @@
import android.graphics.RadialGradient
import android.graphics.Shader
import android.util.AttributeSet
+import android.util.MathUtils.lerp
import android.view.View
import com.android.systemui.animation.Interpolators
+import com.android.systemui.statusbar.LightRevealEffect.Companion.getPercentPastThreshold
import java.util.function.Consumer
/**
@@ -63,12 +65,12 @@
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
val ovalWidthIncreaseAmount =
- LightRevealEffect.getPercentPastThreshold(interpolatedAmount, WIDEN_OVAL_THRESHOLD)
+ getPercentPastThreshold(interpolatedAmount, WIDEN_OVAL_THRESHOLD)
val initialWidthMultiplier = (1f - OVAL_INITIAL_WIDTH_PERCENT) / 2f
with(scrim) {
- revealGradientEndColorAlpha = 1f - LightRevealEffect.getPercentPastThreshold(
+ revealGradientEndColorAlpha = 1f - getPercentPastThreshold(
amount, FADE_END_COLOR_OUT_THRESHOLD)
setRevealGradientBounds(
scrim.width * initialWidthMultiplier +
@@ -90,26 +92,49 @@
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
val interpolatedAmount = INTERPOLATOR.getInterpolation(amount)
- // TODO(b/193801466): add alpha reveal in the beginning as well
+ scrim.startColorAlpha =
+ getPercentPastThreshold(1 - interpolatedAmount,
+ threshold = 1 - START_COLOR_REVEAL_PERCENTAGE)
+
scrim.revealGradientEndColorAlpha =
- 1f - LightRevealEffect.getPercentPastThreshold(interpolatedAmount, threshold = 0.6f)
+ 1f - getPercentPastThreshold(interpolatedAmount,
+ threshold = REVEAL_GRADIENT_END_COLOR_ALPHA_START_PERCENTAGE)
+
+ // Start changing gradient bounds later to avoid harsh gradient in the beginning
+ val gradientBoundsAmount = lerp(GRADIENT_START_BOUNDS_PERCENTAGE, 1.0f, interpolatedAmount)
if (isVertical) {
scrim.setRevealGradientBounds(
- left = scrim.width / 2 - (scrim.width / 2) * interpolatedAmount,
+ left = scrim.width / 2 - (scrim.width / 2) * gradientBoundsAmount,
top = 0f,
- right = scrim.width / 2 + (scrim.width / 2) * interpolatedAmount,
+ right = scrim.width / 2 + (scrim.width / 2) * gradientBoundsAmount,
bottom = scrim.height.toFloat()
)
} else {
scrim.setRevealGradientBounds(
left = 0f,
- top = scrim.height / 2 - (scrim.height / 2) * interpolatedAmount,
+ top = scrim.height / 2 - (scrim.height / 2) * gradientBoundsAmount,
right = scrim.width.toFloat(),
- bottom = scrim.height / 2 + (scrim.height / 2) * interpolatedAmount
+ bottom = scrim.height / 2 + (scrim.height / 2) * gradientBoundsAmount
)
}
}
+
+ private companion object {
+ // From which percentage we should start the gradient reveal width
+ // E.g. if 0 - starts with 0px width, 0.3f - starts with 30% width
+ private const val GRADIENT_START_BOUNDS_PERCENTAGE = 0.3f
+
+ // When to start changing alpha color of the gradient scrim
+ // E.g. if 0.6f - starts fading the gradient away at 60% and becomes completely
+ // transparent at 100%
+ private const val REVEAL_GRADIENT_END_COLOR_ALPHA_START_PERCENTAGE = 0.6f
+
+ // When to finish displaying start color fill that reveals the content
+ // E.g. if 0.3f - the content won't be visible at 0% and it will gradually
+ // reduce the alpha until 30% (at this point the color fill is invisible)
+ private const val START_COLOR_REVEAL_PERCENTAGE = 0.3f
+ }
}
class CircleReveal(
@@ -125,7 +150,7 @@
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
// reveal amount updates already have an interpolator, so we intentionally use the
// non-interpolated amount
- val fadeAmount = LightRevealEffect.getPercentPastThreshold(amount, 0.5f)
+ val fadeAmount = getPercentPastThreshold(amount, 0.5f)
val radius = startRadius + ((endRadius - startRadius) * amount)
scrim.revealGradientEndColorAlpha = 1f - fadeAmount
scrim.setRevealGradientBounds(
@@ -153,8 +178,7 @@
override fun setRevealAmountOnScrim(amount: Float, scrim: LightRevealScrim) {
val interpolatedAmount = Interpolators.FAST_OUT_SLOW_IN_REVERSE.getInterpolation(amount)
- val fadeAmount =
- LightRevealEffect.getPercentPastThreshold(interpolatedAmount, 0.5f)
+ val fadeAmount = getPercentPastThreshold(interpolatedAmount, 0.5f)
with(scrim) {
revealGradientEndColorAlpha = 1f - fadeAmount
@@ -216,6 +240,23 @@
var revealGradientWidth: Float = 0f
var revealGradientHeight: Float = 0f
+ /**
+ * Alpha of the fill that can be used in the beginning of the animation to hide the content.
+ * Normally the gradient bounds are animated from small size so the content is not visible,
+ * but if the start gradient bounds allow to see some content this could be used to make the
+ * reveal smoother. It can help to add fade in effect in the beginning of the animation.
+ * The color of the fill is determined by [revealGradientEndColor].
+ *
+ * 0 - no fill and content is visible, 1 - the content is covered with the start color
+ */
+ var startColorAlpha = 0f
+ set(value) {
+ if (field != value) {
+ field = value
+ invalidate()
+ }
+ }
+
var revealGradientEndColor: Int = Color.BLACK
set(value) {
if (field != value) {
@@ -309,6 +350,10 @@
return
}
+ if (startColorAlpha > 0f) {
+ canvas.drawColor(updateColorAlpha(revealGradientEndColor, startColorAlpha))
+ }
+
with(shaderGradientMatrix) {
setScale(revealGradientWidth, revealGradientHeight, 0f, 0f)
postTranslate(revealGradientCenter.x, revealGradientCenter.y)
@@ -322,11 +367,15 @@
private fun setPaintColorFilter() {
gradientPaint.colorFilter = PorterDuffColorFilter(
- Color.argb(
- (revealGradientEndColorAlpha * 255).toInt(),
- Color.red(revealGradientEndColor),
- Color.green(revealGradientEndColor),
- Color.blue(revealGradientEndColor)),
- PorterDuff.Mode.MULTIPLY)
+ updateColorAlpha(revealGradientEndColor, revealGradientEndColorAlpha),
+ PorterDuff.Mode.MULTIPLY)
}
+
+ private fun updateColorAlpha(color: Int, alpha: Float): Int =
+ Color.argb(
+ (alpha * 255).toInt(),
+ Color.red(color),
+ Color.green(color),
+ Color.blue(color)
+ )
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
index fdbe728..f2060b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceController.kt
@@ -31,8 +31,6 @@
import android.os.UserHandle
import android.provider.Settings
import android.view.View
-import android.view.View.GONE
-import android.view.View.VISIBLE
import android.view.ViewGroup
import com.android.settingslib.Utils
import com.android.systemui.R
@@ -46,21 +44,14 @@
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.settings.UserTracker
import com.android.systemui.flags.FeatureFlags
-import com.android.systemui.statusbar.StatusBarState
-import com.android.systemui.statusbar.notification.AnimatableProperty
-import com.android.systemui.statusbar.notification.PropertyAnimator
-import com.android.systemui.statusbar.notification.stack.AnimationProperties
-import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.policy.ConfigurationController
import com.android.systemui.util.concurrency.Execution
import com.android.systemui.util.settings.SecureSettings
+import java.lang.RuntimeException
import java.util.Optional
import java.util.concurrent.Executor
import javax.inject.Inject
-private val ANIMATION_PROPERTIES = AnimationProperties()
- .setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD.toLong())
-
/**
* Controller for managing the smartspace view on the lockscreen
*/
@@ -81,15 +72,10 @@
@Main private val handler: Handler,
optionalPlugin: Optional<BcSmartspaceDataPlugin>
) {
-
- var splitShadeContainer: ViewGroup? = null
- private var singlePaneContainer: ViewGroup? = null
-
private var session: SmartspaceSession? = null
private val plugin: BcSmartspaceDataPlugin? = optionalPlugin.orElse(null)
private lateinit var smartspaceView: SmartspaceView
- // smartspace casted to View
lateinit var view: View
private set
@@ -97,60 +83,12 @@
private var showSensitiveContentForManagedUser = false
private var managedUserHandle: UserHandle? = null
- private var isAod = false
- private var isSplitShade = false
-
- fun isSmartspaceEnabled(): Boolean {
+ fun isEnabled(): Boolean {
execution.assertIsMainThread()
return featureFlags.isSmartspaceEnabled && plugin != null
}
- fun setKeyguardStatusContainer(container: ViewGroup) {
- singlePaneContainer = container
- // reattach smartspace if necessary as this might be a new container
- updateSmartSpaceContainer()
- }
-
- fun onSplitShadeChanged(splitShade: Boolean) {
- isSplitShade = splitShade
- updateSmartSpaceContainer()
- }
-
- private fun updateSmartSpaceContainer() {
- if (!isSmartspaceEnabled()) return
- // in AOD we always want to show smartspace on the left i.e. in singlePaneContainer
- if (isSplitShade && !isAod) {
- switchContainerVisibility(
- newParent = splitShadeContainer,
- oldParent = singlePaneContainer)
- } else {
- switchContainerVisibility(
- newParent = singlePaneContainer,
- oldParent = splitShadeContainer)
- }
- requestSmartspaceUpdate()
- }
-
- private fun switchContainerVisibility(newParent: ViewGroup?, oldParent: ViewGroup?) {
- // it might be the case that smartspace was already attached and we just needed to update
- // visibility, e.g. going from lockscreen -> unlocked -> lockscreen
- if (newParent?.childCount == 0) {
- oldParent?.removeAllViews()
- newParent.addView(buildAndConnectView(newParent))
- }
- oldParent?.visibility = GONE
- newParent?.visibility = VISIBLE
- }
-
- fun setSplitShadeSmartspaceAlpha(alpha: Float) {
- // the other container's alpha is modified as a part of keyguard status view, so we don't
- // have to do that here
- if (splitShadeContainer?.visibility == VISIBLE) {
- splitShadeContainer?.alpha = alpha
- }
- }
-
/**
* Constructs the smartspace view and connects it to the smartspace service. Subsequent calls
* are idempotent until [disconnect] is called.
@@ -158,7 +96,7 @@
fun buildAndConnectView(parent: ViewGroup): View {
execution.assertIsMainThread()
- if (!isSmartspaceEnabled()) {
+ if (!isEnabled()) {
throw RuntimeException("Cannot build view when not enabled")
}
@@ -244,6 +182,7 @@
userTracker.removeCallback(userTrackerCallback)
contentResolver.unregisterContentObserver(settingsObserver)
configurationController.removeCallback(configChangeListener)
+ statusBarStateController.removeCallback(statusBarStateListener)
session = null
plugin?.onTargetsAvailable(emptyList())
@@ -259,13 +198,6 @@
plugin?.unregisterListener(listener)
}
- fun shiftSplitShadeSmartspace(y: Int, animate: Boolean) {
- if (splitShadeContainer?.visibility == VISIBLE) {
- PropertyAnimator.setProperty(splitShadeContainer, AnimatableProperty.Y, y.toFloat(),
- ANIMATION_PROPERTIES, animate)
- }
- }
-
private val sessionListener = SmartspaceSession.OnTargetsAvailableListener { targets ->
execution.assertIsMainThread()
val filteredTargets = targets.filter(::filterSmartspaceTarget)
@@ -301,23 +233,6 @@
execution.assertIsMainThread()
smartspaceView.setDozeAmount(eased)
}
-
- override fun onDozingChanged(isDozing: Boolean) {
- isAod = isDozing
- updateSmartSpaceContainer()
- }
-
- override fun onStateChanged(newState: Int) {
- if (newState == StatusBarState.KEYGUARD) {
- if (isSmartspaceEnabled()) {
- updateSmartSpaceContainer()
- }
- } else {
- splitShadeContainer?.visibility = GONE
- singlePaneContainer?.visibility = GONE
- disconnect()
- }
- }
}
private fun filterSmartspaceTarget(t: SmartspaceTarget): Boolean {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
index a0ef1b6..e26fa04 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilder.java
@@ -28,8 +28,6 @@
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_SORTING;
import static com.android.systemui.statusbar.notification.collection.listbuilder.PipelineState.STATE_TRANSFORMING;
-import static java.util.Objects.requireNonNull;
-
import android.annotation.MainThread;
import android.annotation.Nullable;
import android.util.ArrayMap;
@@ -344,14 +342,8 @@
mPipelineState.incrementTo(STATE_GROUP_STABILIZING);
stabilizeGroupingNotifs(mNotifList);
- // Step 5: Sort
- // Assign each top-level entry a section, then sort the list by section and then within
- // section by our list of custom comparators
- dispatchOnBeforeSort(mReadOnlyNotifList);
- mPipelineState.incrementTo(STATE_SORTING);
- sortList();
- // Step 6: Filter out entries after pre-group filtering, grouping, promoting and sorting
+ // Step 5: Filter out entries after pre-group filtering, grouping and promoting
// Now filters can see grouping information to determine whether to filter or not.
dispatchOnBeforeFinalizeFilter(mReadOnlyNotifList);
mPipelineState.incrementTo(STATE_FINALIZE_FILTERING);
@@ -359,6 +351,13 @@
applyNewNotifList();
pruneIncompleteGroups(mNotifList);
+ // Step 6: Sort
+ // Assign each top-level entry a section, then sort the list by section and then within
+ // section by our list of custom comparators
+ dispatchOnBeforeSort(mReadOnlyNotifList);
+ mPipelineState.incrementTo(STATE_SORTING);
+ sortList();
+
// Step 7: Lock in our group structure and log anything that's changed since the last run
mPipelineState.incrementTo(STATE_FINALIZING);
logChanges();
@@ -837,8 +836,8 @@
private final Comparator<ListEntry> mTopLevelComparator = (o1, o2) -> {
int cmp = Integer.compare(
- requireNonNull(o1.getSection()).getIndex(),
- requireNonNull(o2.getSection()).getIndex());
+ o1.getSectionIndex(),
+ o2.getSectionIndex());
if (cmp == 0) {
for (int i = 0; i < mNotifComparators.size(); i++) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
index 798bfe7..027ac0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/listbuilder/PipelineState.java
@@ -82,8 +82,8 @@
public static final int STATE_GROUPING = 4;
public static final int STATE_TRANSFORMING = 5;
public static final int STATE_GROUP_STABILIZING = 6;
- public static final int STATE_SORTING = 7;
- public static final int STATE_FINALIZE_FILTERING = 8;
+ public static final int STATE_FINALIZE_FILTERING = 7;
+ public static final int STATE_SORTING = 8;
public static final int STATE_FINALIZING = 9;
@IntDef(prefix = { "STATE_" }, value = {
@@ -94,8 +94,8 @@
STATE_GROUPING,
STATE_TRANSFORMING,
STATE_GROUP_STABILIZING,
- STATE_SORTING,
STATE_FINALIZE_FILTERING,
+ STATE_SORTING,
STATE_FINALIZING,
})
@Retention(RetentionPolicy.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index c1a63e9..ef1d75e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -53,6 +53,9 @@
notifList.firstOrNull()?.section?.headerController?.let {
children.add(NodeSpecImpl(this, it))
}
+ notifList.firstOrNull()?.let {
+ children.add(buildNotifNode(it, this))
+ }
notifList.asSequence().zipWithNext().forEach { (prev, entry) ->
// Insert new header if the section has changed between two entries
entry.section.takeIf { it != prev.section }?.headerController?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 19c2585..f77c052 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -33,11 +33,23 @@
*/
public class KeyguardClockPositionAlgorithm {
/**
+ * How much the clock height influences the shade position.
+ * 0 means nothing, 1 means move the shade up by the height of the clock
+ * 0.5f means move the shade up by half of the size of the clock.
+ */
+ private static float CLOCK_HEIGHT_WEIGHT = 0.7f;
+
+ /**
* Margin between the bottom of the status view and the notification shade.
*/
private int mStatusViewBottomMargin;
/**
+ * Height of the parent view - display size in px.
+ */
+ private int mHeight;
+
+ /**
* Height of {@link KeyguardStatusView}.
*/
private int mKeyguardStatusHeight;
@@ -56,6 +68,21 @@
private int mUserSwitchPreferredY;
/**
+ * Whether or not there is a custom clock face on keyguard.
+ */
+ private boolean mHasCustomClock;
+
+ /**
+ * Whether or not the NSSL contains any visible notifications.
+ */
+ private boolean mHasVisibleNotifs;
+
+ /**
+ * Height of notification stack: Sum of height of each notification.
+ */
+ private int mNotificationStackHeight;
+
+ /**
* Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
* avatar.
*/
@@ -121,7 +148,6 @@
private int mUnlockedStackScrollerPadding;
private boolean mIsSplitShade;
- private int mSplitShadeSmartspaceHeight;
/**
* Refreshes the dimension values.
@@ -144,25 +170,28 @@
* Sets up algorithm values.
*/
public void setup(int keyguardStatusBarHeaderHeight, int maxShadeBottom,
- float panelExpansion,
- int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY, float dark,
+ int notificationStackHeight, float panelExpansion, int parentHeight,
+ int keyguardStatusHeight, int userSwitchHeight, int userSwitchPreferredY,
+ boolean hasCustomClock, boolean hasVisibleNotifs, float dark,
float overStrechAmount, boolean bypassEnabled, int unlockedStackScrollerPadding,
- float qsExpansion, int cutoutTopInset, int splitShadeSmartspaceHeight,
- boolean isSplitShade) {
+ float qsExpansion, int cutoutTopInset, boolean isSplitShade) {
mMinTopMargin = keyguardStatusBarHeaderHeight + Math.max(mContainerTopPadding,
userSwitchHeight);
mMaxShadeBottom = maxShadeBottom;
+ mNotificationStackHeight = notificationStackHeight;
mPanelExpansion = panelExpansion;
+ mHeight = parentHeight;
mKeyguardStatusHeight = keyguardStatusHeight + mStatusViewBottomMargin;
mUserSwitchHeight = userSwitchHeight;
mUserSwitchPreferredY = userSwitchPreferredY;
+ mHasCustomClock = hasCustomClock;
+ mHasVisibleNotifs = hasVisibleNotifs;
mDarkAmount = dark;
mOverStretchAmount = overStrechAmount;
mBypassEnabled = bypassEnabled;
mUnlockedStackScrollerPadding = unlockedStackScrollerPadding;
mQsExpansion = qsExpansion;
mCutoutTopInset = cutoutTopInset;
- mSplitShadeSmartspaceHeight = splitShadeSmartspaceHeight;
mIsSplitShade = isSplitShade;
}
@@ -184,7 +213,7 @@
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
- return clockYPosition + mSplitShadeSmartspaceHeight;
+ return clockYPosition;
} else {
return clockYPosition + mKeyguardStatusHeight;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index ef3dced..3e604ec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -205,6 +205,14 @@
mView.setTopClipping(notificationPanelTop - mView.getTop());
}
+ /**
+ * Updates the {@link KeyguardStatusBarView} state based on the provided values.
+ */
+ public void updateViewState(float alpha, int visibility) {
+ mView.setAlpha(alpha);
+ mView.setVisibility(visibility);
+ }
+
/** */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusBarView:");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index c71842b..b5eb90e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -117,7 +117,6 @@
import com.android.systemui.doze.DozeLog;
import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
import com.android.systemui.fragments.FragmentService;
-import com.android.systemui.idle.IdleHostView;
import com.android.systemui.idle.IdleHostViewController;
import com.android.systemui.idle.dagger.IdleViewComponent;
import com.android.systemui.media.KeyguardMediaController;
@@ -148,7 +147,6 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.AnimatableProperty;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
@@ -241,7 +239,6 @@
private final HeightListener mHeightListener = new HeightListener();
private final ConfigurationListener mConfigurationListener = new ConfigurationListener();
private final SettingsChangeObserver mSettingsChangeObserver;
- private final LockscreenSmartspaceController mLockscreenSmartspaceController;
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
@@ -376,8 +373,6 @@
private IdleHostViewController mIdleHostViewController;
private LockIconViewController mLockIconViewController;
private NotificationsQuickSettingsContainer mNotificationContainerParent;
- private FrameLayout mSplitShadeSmartspaceContainer;
-
private boolean mAnimateNextPositionUpdate;
private float mQuickQsOffsetHeight;
private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
@@ -808,7 +803,6 @@
@Main Executor uiExecutor,
SecureSettings secureSettings,
SplitShadeHeaderController splitShadeHeaderController,
- LockscreenSmartspaceController lockscreenSmartspaceController,
UnlockedScreenOffAnimationController unlockedScreenOffAnimationController,
LockscreenGestureLogger lockscreenGestureLogger,
NotificationRemoteInputManager remoteInputManager,
@@ -852,7 +846,6 @@
mQSDetailDisplayer = qsDetailDisplayer;
mFragmentService = fragmentService;
mSettingsChangeObserver = new SettingsChangeObserver(handler);
- mLockscreenSmartspaceController = lockscreenSmartspaceController;
mShouldUseSplitNotificationShade =
Utils.shouldUseSplitNotificationShade(mResources);
mView.setWillNotDraw(!DEBUG);
@@ -949,9 +942,6 @@
mKeyguardStatusBar = mView.findViewById(R.id.keyguard_header);
mBigClockContainer = mView.findViewById(R.id.big_clock_container);
mCommunalView = mView.findViewById(R.id.communal_host);
- mSplitShadeSmartspaceContainer = mView.findViewById(R.id.split_shade_smartspace_container);
- mLockscreenSmartspaceController.setSplitShadeContainer(mSplitShadeSmartspaceContainer);
- mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
UserAvatarView userAvatarView = null;
KeyguardUserSwitcherView keyguardUserSwitcherView = null;
@@ -971,12 +961,16 @@
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
+ IdleViewComponent idleViewComponent = mIdleViewComponentFactory
+ .build(mView.findViewById(R.id.idle_host_view));
+ mIdleHostViewController = idleViewComponent.getIdleHostViewController();
+ mIdleHostViewController.init();
+
updateViewControllers(
mView.findViewById(R.id.keyguard_status_view),
userAvatarView,
keyguardUserSwitcherView,
- mCommunalView,
- mView.findViewById(R.id.idle_host_view));
+ mCommunalView);
mNotificationContainerParent = mView.findViewById(R.id.notification_container_parent);
NotificationStackScrollLayout stackScrollLayout = mView.findViewById(
R.id.notification_stack_scroller);
@@ -1068,18 +1062,13 @@
private void updateViewControllers(KeyguardStatusView keyguardStatusView,
UserAvatarView userAvatarView,
KeyguardUserSwitcherView keyguardUserSwitcherView,
- CommunalHostView communalView,
- IdleHostView idleHostView) {
+ CommunalHostView communalView) {
// Re-associate the KeyguardStatusViewController
KeyguardStatusViewComponent statusViewComponent =
mKeyguardStatusViewComponentFactory.build(keyguardStatusView);
mKeyguardStatusViewController = statusViewComponent.getKeyguardStatusViewController();
mKeyguardStatusViewController.init();
- IdleViewComponent idleViewComponent = mIdleViewComponentFactory.build(idleHostView);
- mIdleHostViewController = idleViewComponent.getIdleHostViewController();
- mIdleHostViewController.init();
-
if (communalView != null) {
CommunalViewComponent communalViewComponent =
mCommunalViewComponentFactory.build(communalView);
@@ -1174,7 +1163,7 @@
mNotificationContainerParent.setSplitShadeEnabled(mShouldUseSplitNotificationShade);
updateKeyguardStatusViewAlignment(/* animate= */false);
- mLockscreenSmartspaceController.onSplitShadeChanged(mShouldUseSplitNotificationShade);
+
mKeyguardMediaController.refreshMediaPosition();
}
@@ -1251,8 +1240,7 @@
mBigClockContainer.removeAllViews();
updateViewControllers(mView.findViewById(R.id.keyguard_status_view), userAvatarView,
- keyguardUserSwitcherView, mCommunalView,
- mView.findViewById(R.id.idle_host_view));
+ keyguardUserSwitcherView, mCommunalView);
// Update keyguard bottom area
int index = mView.indexOfChild(mKeyguardBottomArea);
@@ -1441,15 +1429,16 @@
? 1.0f : mInterpolatedDarkAmount;
mClockPositionAlgorithm.setup(mStatusBarHeaderHeightKeyguard,
totalHeight - bottomPadding,
+ mNotificationStackScrollLayoutController.getIntrinsicContentHeight(),
expandedFraction,
+ totalHeight,
mKeyguardStatusViewController.getLockscreenHeight(),
userIconHeight,
- userSwitcherPreferredY,
- darkamount, mOverStretchAmount,
+ userSwitcherPreferredY, hasCustomClock(),
+ hasVisibleNotifications, darkamount, mOverStretchAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
computeQsExpansionFraction(),
mDisplayTopInset,
- mSplitShadeSmartspaceContainer.getHeight(),
mShouldUseSplitNotificationShade);
mClockPositionAlgorithm.run(mClockPositionResult);
boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
@@ -1469,9 +1458,6 @@
mClockPositionResult.userSwitchY,
animateClock);
}
- // no need to translate in X axis - horizontal position is determined by constraints
- mLockscreenSmartspaceController
- .shiftSplitShadeSmartspace(mClockPositionResult.clockY, animateClock);
updateNotificationTranslucency();
updateClock();
}
@@ -1647,7 +1633,6 @@
if (mKeyguardUserSwitcherController != null) {
mKeyguardUserSwitcherController.setAlpha(alpha);
}
- mLockscreenSmartspaceController.setSplitShadeSmartspaceAlpha(alpha);
}
public void animateToFullShade(long delay) {
@@ -3840,7 +3825,6 @@
public void dozeTimeTick() {
mKeyguardBottomArea.dozeTimeTick();
mKeyguardStatusViewController.dozeTimeTick();
- mLockscreenSmartspaceController.requestSmartspaceUpdate();
if (mInterpolatedDarkAmount > 0) {
positionClockAndNotifications();
}
@@ -4583,6 +4567,15 @@
keyguardFadingAway,
goingToFullShade,
mBarState);
+
+ if (mCommunalViewController != null) {
+ mCommunalViewController.setKeyguardStatusViewVisibility(
+ statusBarState,
+ keyguardFadingAway,
+ goingToFullShade,
+ mBarState);
+ }
+
setKeyguardBottomAreaVisibility(statusBarState, goingToFullShade);
mBarState = statusBarState;
@@ -4606,8 +4599,9 @@
}
}
} else {
- mKeyguardStatusBar.setAlpha(1f);
- mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
+ mKeyguardStatusBarViewController.updateViewState(
+ /* alpha= */ 1f,
+ keyguardShowing ? View.VISIBLE : View.INVISIBLE);
if (keyguardShowing && oldState != mBarState) {
if (mQs != null) {
mQs.hideImmediately();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index e3319e5..87d4543 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -402,7 +402,7 @@
if (mKeyguardUpdateMonitor.needsSlowUnlockTransition() && mState == ScrimState.UNLOCKED) {
mAnimationDelay = StatusBar.FADE_KEYGUARD_START_DELAY;
scheduleUpdate();
- } else if ((oldState == ScrimState.AOD // leaving doze
+ } else if (((oldState == ScrimState.AOD || oldState == ScrimState.PULSING) // leaving doze
&& (!mDozeParameters.getAlwaysOn() || mState == ScrimState.UNLOCKED))
|| (mState == ScrimState.AOD && !mDozeParameters.getDisplayNeedsBlanking())) {
// Scheduling a frame isn't enough when:
@@ -696,7 +696,8 @@
}
if (mUnOcclusionAnimationRunning && mState == ScrimState.KEYGUARD) {
// We're unoccluding the keyguard and don't want to have a bright flash.
- mNotificationsAlpha = 0f;
+ mNotificationsAlpha = KEYGUARD_SCRIM_ALPHA;
+ mNotificationsTint = ScrimState.KEYGUARD.getNotifTint();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index e33c9f8..850b986 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -229,7 +229,8 @@
? mKeyguardFadingAwayDuration
: StatusBar.FADE_KEYGUARD_DURATION;
- mAnimateChange = !mLaunchingAffordanceWithPreview;
+ boolean fromAod = previousState == AOD || previousState == PULSING;
+ mAnimateChange = !mLaunchingAffordanceWithPreview && !fromAod;
mFrontTint = Color.TRANSPARENT;
mBehindTint = Color.BLACK;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index be01308..f07f619 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1028,7 +1028,7 @@
mNotificationShadeWindowViewController,
mNotificationPanelViewController,
mAmbientIndicationContainer);
- mDozeParameters.addCallback(this::updateLightRevealScrimVisibility);
+ updateLightRevealScrimVisibility();
mConfigurationController.addCallback(mConfigurationListener);
@@ -1135,6 +1135,10 @@
mStatusBarView.setPanel(mNotificationPanelViewController);
mStatusBarView.setScrimController(mScrimController);
mStatusBarView.setExpansionChangedListeners(mExpansionChangedListeners);
+ for (ExpansionChangedListener listener : mExpansionChangedListeners) {
+ sendInitialExpansionAmount(listener);
+ }
+
mPhoneStatusBarViewController =
new PhoneStatusBarViewController(mStatusBarView, mCommandQueue);
mPhoneStatusBarViewController.init();
@@ -4161,6 +4165,14 @@
public void addExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
mExpansionChangedListeners.add(listener);
+ sendInitialExpansionAmount(listener);
+ }
+
+ private void sendInitialExpansionAmount(ExpansionChangedListener expansionChangedListener) {
+ if (mStatusBarView != null) {
+ expansionChangedListener.onExpansionChanged(mStatusBarView.getExpansionFraction(),
+ mStatusBarView.isExpanded());
+ }
}
public void removeExpansionChangedListener(@NonNull ExpansionChangedListener listener) {
@@ -4174,12 +4186,6 @@
}
mLightRevealScrim.setAlpha(mScrimController.getState().getMaxLightRevealScrimAlpha());
- if (mFeatureFlags.useNewLockscreenAnimations()
- && (mDozeParameters.getAlwaysOn() || mDozeParameters.isQuickPickupEnabled())) {
- mLightRevealScrim.setVisibility(View.VISIBLE);
- } else {
- mLightRevealScrim.setVisibility(View.GONE);
- }
}
private final KeyguardUpdateMonitorCallback mUpdateCallback =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 119eff6..4316ccf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -308,8 +308,10 @@
* Sets a new alt auth interceptor.
*/
public void setAlternateAuthInterceptor(@NonNull AlternateAuthInterceptor authInterceptor) {
- mAlternateAuthInterceptor = authInterceptor;
- resetAlternateAuth(false);
+ if (!Objects.equals(mAlternateAuthInterceptor, authInterceptor)) {
+ mAlternateAuthInterceptor = authInterceptor;
+ resetAlternateAuth(false);
+ }
}
private void registerListeners() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
index dd38f98..a29b72c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardQsUserSwitchController.java
@@ -137,7 +137,8 @@
mStatusBarStateController = statusBarStateController;
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
keyguardStateController, dozeParameters,
- unlockedScreenOffAnimationController, /* animateYPos= */ false);
+ unlockedScreenOffAnimationController, /* animateYPos= */ false,
+ /* visibleOnCommunal= */ false);
mUserDetailAdapter = new KeyguardUserDetailAdapter(context, userDetailViewAdapterProvider);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
index 742b1ab..7bf1601 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateController.java
@@ -251,5 +251,11 @@
* {@link KeyguardStateController#isFaceAuthEnabled()}.
*/
default void onFaceAuthEnabledChanged() {}
+
+ /**
+ * Triggered when the notification panel is starting or has finished
+ * fading away on transition to an app.
+ */
+ default void onLaunchTransitionFadingAwayChanged() {}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index 64750bd..f787ecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -343,6 +343,7 @@
@Override
public void setLaunchTransitionFadingAway(boolean fadingAway) {
mLaunchTransitionFadingAway = fadingAway;
+ new ArrayList<>(mCallbacks).forEach(Callback::onLaunchTransitionFadingAwayChanged);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 3240ad2..c4b5961 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -176,7 +176,8 @@
mUserSwitcherController, this);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mView, communalStateController,
keyguardStateController, dozeParameters,
- unlockedScreenOffAnimationController, /* animateYPos= */ false);
+ unlockedScreenOffAnimationController, /* animateYPos= */ false,
+ /* visibleOnCommunal= */ false);
mBackground = new KeyguardUserSwitcherScrim(context);
}
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
index ce65733..06b0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchControllerTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -28,7 +29,6 @@
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
@@ -104,8 +104,6 @@
private AnimatableClockView mLargeClockView;
@Mock
private FrameLayout mLargeClockFrame;
- @Mock
- private ViewGroup mSmartspaceContainer;
private final View mFakeSmartspaceView = new View(mContext);
@@ -125,8 +123,6 @@
when(mView.findViewById(R.id.animatable_clock_view)).thenReturn(mClockView);
when(mView.findViewById(R.id.animatable_clock_view_large)).thenReturn(mLargeClockView);
when(mView.findViewById(R.id.lockscreen_clock_view_large)).thenReturn(mLargeClockFrame);
- when(mView.findViewById(R.id.keyguard_smartspace_container))
- .thenReturn(mSmartspaceContainer);
when(mClockView.getContext()).thenReturn(getContext());
when(mLargeClockView.getContext()).thenReturn(getContext());
@@ -214,7 +210,7 @@
@Test
public void testSmartspaceEnabledRemovesKeyguardStatusArea() {
- when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
+ when(mSmartspaceController.isEnabled()).thenReturn(true);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mController.init();
@@ -223,7 +219,7 @@
@Test
public void testSmartspaceDisabledShowsKeyguardStatusArea() {
- when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(false);
+ when(mSmartspaceController.isEnabled()).thenReturn(false);
mController.init();
assertEquals(View.VISIBLE, mStatusArea.getVisibility());
@@ -231,16 +227,17 @@
@Test
public void testDetachRemovesSmartspaceView() {
- when(mSmartspaceController.isSmartspaceEnabled()).thenReturn(true);
+ when(mSmartspaceController.isEnabled()).thenReturn(true);
when(mSmartspaceController.buildAndConnectView(any())).thenReturn(mFakeSmartspaceView);
mController.init();
+ verify(mView).addView(eq(mFakeSmartspaceView), anyInt(), any());
ArgumentCaptor<View.OnAttachStateChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(View.OnAttachStateChangeListener.class);
verify(mView).addOnAttachStateChangeListener(listenerArgumentCaptor.capture());
listenerArgumentCaptor.getValue().onViewDetachedFromWindow(mView);
- verify(mSmartspaceContainer).removeAllViews();
+ verify(mView).removeView(mFakeSmartspaceView);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
index 548b655..1efcbd6 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardVisibilityHelperTest.java
@@ -56,7 +56,7 @@
when(mTargetView.animate()).thenReturn(mViewPropertyAnimator);
mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
mCommunalStateController, mKeyguardStateController, mDozeParameters,
- mUnlockedScreenOffAnimationController, false);
+ mUnlockedScreenOffAnimationController, false, false);
}
@Test
@@ -74,4 +74,19 @@
false, StatusBarState.KEYGUARD);
verify(mTargetView).setVisibility(View.VISIBLE);
}
+
+ @Test
+ public void testVisibleOnCommunal() {
+ when(mCommunalStateController.getCommunalViewShowing()).thenReturn(true);
+ when(mKeyguardStateController.isOccluded()).thenReturn(false);
+
+ // Verify that helpers constructed with visibility on communal are not hidden when communal
+ // is present.
+ mKeyguardVisibilityHelper = new KeyguardVisibilityHelper(mTargetView,
+ mCommunalStateController, mKeyguardStateController, mDozeParameters,
+ mUnlockedScreenOffAnimationController, false, true);
+ mKeyguardVisibilityHelper.setViewVisibility(StatusBarState.KEYGUARD, false,
+ false, StatusBarState.KEYGUARD);
+ verify(mTargetView).setVisibility(View.VISIBLE);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index 5901080..ae009bc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -417,6 +417,21 @@
}
@Test
+ public void hideUdfpsOverlay_resetsAltAuthBouncerWhenShowing() throws RemoteException {
+ // GIVEN overlay was showing and the udfps bouncer is showing
+ mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
+ IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
+ when(mStatusBarKeyguardViewManager.isShowingAlternateAuth()).thenReturn(true);
+
+ // WHEN the overlay is hidden
+ mOverlayController.hideUdfpsOverlay(TEST_UDFPS_SENSOR_ID);
+ mFgExecutor.runAllReady();
+
+ // THEN the udfps bouncer is reset
+ verify(mStatusBarKeyguardViewManager).resetAlternateAuth(eq(true));
+ }
+
+ @Test
public void testSubscribesToOrientationChangesWhenShowingOverlay() throws Exception {
mOverlayController.showUdfpsOverlay(TEST_UDFPS_SENSOR_ID,
IUdfpsOverlayController.REASON_AUTH_FPM_KEYGUARD, mUdfpsOverlayControllerCallback);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index 17730d9..decec63 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -23,6 +23,8 @@
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -33,7 +35,6 @@
import androidx.test.filters.SmallTest;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.keyguard.KeyguardViewMediator;
@@ -43,6 +44,7 @@
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.DelayableExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -55,6 +57,7 @@
import org.mockito.MockitoAnnotations;
import java.util.Optional;
+import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -80,6 +83,8 @@
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Mock
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
private KeyguardViewMediator mKeyguardViewMediator;
@Mock
private ConfigurationController mConfigurationController;
@@ -94,14 +99,15 @@
private StatusBarStateController.StateListener mStatusBarStateListener;
@Captor private ArgumentCaptor<StatusBar.ExpansionChangedListener> mExpansionListenerCaptor;
- private StatusBar.ExpansionChangedListener mExpansionListener;
+ private List<StatusBar.ExpansionChangedListener> mExpansionListeners;
@Captor private ArgumentCaptor<StatusBarKeyguardViewManager.AlternateAuthInterceptor>
mAltAuthInterceptorCaptor;
private StatusBarKeyguardViewManager.AlternateAuthInterceptor mAltAuthInterceptor;
- @Captor private ArgumentCaptor<KeyguardUpdateMonitorCallback> mUpdateMonitorCallbackCaptor;
- private KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback;
+ @Captor private ArgumentCaptor<KeyguardStateController.Callback>
+ mKeyguardStateControllerCallbackCaptor;
+ private KeyguardStateController.Callback mKeyguardStateControllerCallback;
@Before
public void setUp() {
@@ -121,13 +127,14 @@
mLockscreenShadeTransitionController,
mConfigurationController,
mSystemClock,
+ mKeyguardStateController,
mUdfpsController);
}
@Test
public void testRegistersExpansionChangedListenerOnAttached() {
mController.onViewAttached();
- captureExpansionListener();
+ captureExpansionListeners();
}
@Test
@@ -156,11 +163,15 @@
public void testListenersUnregisteredOnDetached() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
mController.onViewDetached();
verify(mStatusBarStateController).removeCallback(mStatusBarStateListener);
- verify(mStatusBar).removeExpansionChangedListener(mExpansionListener);
+ for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+ verify(mStatusBar).removeExpansionChangedListener(listener);
+ }
+ verify(mKeyguardStateController).removeCallback(mKeyguardStateControllerCallback);
}
@Test
@@ -179,7 +190,6 @@
public void testShouldPauseAuthBouncerShowing() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -190,7 +200,6 @@
public void testShouldNotPauseAuthOnKeyguard() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -198,10 +207,25 @@
}
@Test
+ public void testShouldPauseAuthIsLaunchTransitionFadingAway() {
+ // GIVEN view is attached and we're on the keyguard (see testShouldNotPauseAuthOnKeyguard)
+ mController.onViewAttached();
+ captureStatusBarStateListeners();
+ sendStatusBarStateChanged(StatusBarState.KEYGUARD);
+
+ // WHEN isLaunchTransitionFadingAway=true
+ captureKeyguardStateControllerCallback();
+ when(mKeyguardStateController.isLaunchTransitionFadingAway()).thenReturn(true);
+ mKeyguardStateControllerCallback.onLaunchTransitionFadingAwayChanged();
+
+ // THEN pause auth
+ assertTrue(mController.shouldPauseAuth());
+ }
+
+ @Test
public void testShouldPauseAuthOnShadeLocked() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
sendStatusBarStateChanged(StatusBarState.SHADE_LOCKED);
@@ -212,7 +236,6 @@
public void testShouldPauseAuthOnShade() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
// WHEN not on keyguard yet (shade = home)
sendStatusBarStateChanged(StatusBarState.SHADE);
@@ -225,7 +248,6 @@
public void testShouldPauseAuthAnimatingScreenOffFromShade() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
// WHEN transitioning from home/shade => keyguard + animating screen off
mStatusBarStateListener.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD);
@@ -239,7 +261,6 @@
public void testDoNotPauseAuthAnimatingScreenOffFromLS() {
mController.onViewAttached();
captureStatusBarStateListeners();
- captureExpansionListener();
// WHEN animating screen off transition from LS => AOD
sendStatusBarStateChanged(StatusBarState.KEYGUARD);
@@ -333,6 +354,21 @@
verify(mStatusBarKeyguardViewManager).resetAlternateAuth(anyBoolean());
}
+ @Test
+ public void testFadeInWithStatusBarExpansion() {
+ // GIVEN view is attached
+ mController.onViewAttached();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
+ reset(mView);
+
+ // WHEN status bar expansion is 0
+ updateStatusBarExpansion(0, true);
+
+ // THEN alpha is 0
+ verify(mView).setUnpausedAlpha(0);
+ }
+
private void sendStatusBarStateChanged(int statusBarState) {
mStatusBarStateListener.onStateChanged(statusBarState);
}
@@ -342,9 +378,18 @@
mStatusBarStateListener = mStateListenerCaptor.getValue();
}
- private void captureExpansionListener() {
- verify(mStatusBar).addExpansionChangedListener(mExpansionListenerCaptor.capture());
- mExpansionListener = mExpansionListenerCaptor.getValue();
+ private void captureExpansionListeners() {
+ verify(mStatusBar, times(2))
+ .addExpansionChangedListener(mExpansionListenerCaptor.capture());
+ // first (index=0) is from super class, UdfpsAnimationViewController.
+ // second (index=1) is from UdfpsKeyguardViewController
+ mExpansionListeners = mExpansionListenerCaptor.getAllValues();
+ }
+
+ private void updateStatusBarExpansion(float expansion, boolean expanded) {
+ for (StatusBar.ExpansionChangedListener listener : mExpansionListeners) {
+ listener.onExpansionChanged(expansion, expanded);
+ }
}
private void captureAltAuthInterceptor() {
@@ -353,8 +398,11 @@
mAltAuthInterceptor = mAltAuthInterceptorCaptor.getValue();
}
- private void captureKeyguardUpdateMonitorCallback() {
- verify(mKeyguardUpdateMonitor).registerCallback(mUpdateMonitorCallbackCaptor.capture());
- mKeyguardUpdateMonitorCallback = mUpdateMonitorCallbackCaptor.getValue();
+
+
+ private void captureKeyguardStateControllerCallback() {
+ verify(mKeyguardStateController).addCallback(
+ mKeyguardStateControllerCallbackCaptor.capture());
+ mKeyguardStateControllerCallback = mKeyguardStateControllerCallbackCaptor.getValue();
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
index 9906379..9c6c044 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/communal/CommunalHostViewControllerTest.java
@@ -29,6 +29,8 @@
import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.DozeParameters;
+import com.android.systemui.statusbar.phone.UnlockedScreenOffAnimationController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
@@ -61,6 +63,12 @@
@Mock
private CommunalHostView mCommunalView;
+ @Mock
+ private DozeParameters mDozeParameters;
+
+ @Mock
+ private UnlockedScreenOffAnimationController mUnlockedScreenOffAnimationController;
+
private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());
private CommunalHostViewController mController;
@@ -76,8 +84,8 @@
when(mCommunalView.isAttachedToWindow()).thenReturn(true);
mController = new CommunalHostViewController(mFakeExecutor, mCommunalStateController,
- mKeyguardUpdateMonitor, mKeyguardStateController, mStatusBarStateController,
- mCommunalView);
+ mKeyguardUpdateMonitor, mKeyguardStateController, mDozeParameters,
+ mUnlockedScreenOffAnimationController, mStatusBarStateController, mCommunalView);
mController.init();
mFakeExecutor.runAllReady();
Mockito.clearInvocations(mCommunalView);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
index 0c94f09..5c4c27c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSensorsTest.java
@@ -88,7 +88,7 @@
private FakeSettings mFakeSettings = new FakeSettings();
private SensorManagerPlugin.SensorEventListener mWakeLockScreenListener;
private TestableLooper mTestableLooper;
- private DozeSensors mDozeSensors;
+ private TestableDozeSensors mDozeSensors;
private TriggerSensor mSensorTap;
@Before
@@ -170,6 +170,94 @@
assertTrue(mSensorTap.mRequested);
}
+ @Test
+ public void testDozeSensorSetListening() {
+ // GIVEN doze sensors enabled
+ when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+ // GIVEN a trigger sensor
+ Sensor mockSensor = mock(Sensor.class);
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ mockSensor,
+ /* settingEnabled */ true,
+ /* requiresTouchScreen */ true);
+ when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+ .thenReturn(true);
+
+ // WHEN we want to listen for the trigger sensor
+ triggerSensor.setListening(true);
+
+ // THEN the sensor is registered
+ assertTrue(triggerSensor.mRegistered);
+ }
+
+ @Test
+ public void testDozeSensorSettingDisabled() {
+ // GIVEN doze sensors enabled
+ when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+ // GIVEN a trigger sensor
+ Sensor mockSensor = mock(Sensor.class);
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ mockSensor,
+ /* settingEnabled*/ false,
+ /* requiresTouchScreen */ true);
+ when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+ .thenReturn(true);
+
+ // WHEN setListening is called
+ triggerSensor.setListening(true);
+
+ // THEN the sensor is not registered
+ assertFalse(triggerSensor.mRegistered);
+ }
+
+ @Test
+ public void testDozeSensorIgnoreSetting() {
+ // GIVEN doze sensors enabled
+ when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+ // GIVEN a trigger sensor that's
+ Sensor mockSensor = mock(Sensor.class);
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ mockSensor,
+ /* settingEnabled*/ false,
+ /* requiresTouchScreen */ true);
+ when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+ .thenReturn(true);
+
+ // GIVEN sensor is listening
+ triggerSensor.setListening(true);
+
+ // WHEN ignoreSetting is called
+ triggerSensor.ignoreSetting(true);
+
+ // THEN the sensor is registered
+ assertTrue(triggerSensor.mRegistered);
+ }
+
+ @Test
+ public void testUpdateListeningAfterAlreadyRegistered() {
+ // GIVEN doze sensors enabled
+ when(mAmbientDisplayConfiguration.enabled(anyInt())).thenReturn(true);
+
+ // GIVEN a trigger sensor
+ Sensor mockSensor = mock(Sensor.class);
+ TriggerSensor triggerSensor = mDozeSensors.createDozeSensor(
+ mockSensor,
+ /* settingEnabled*/ true,
+ /* requiresTouchScreen */ true);
+ when(mSensorManager.requestTriggerSensor(eq(triggerSensor), eq(mockSensor)))
+ .thenReturn(true);
+
+ // WHEN setListening is called AND updateListening is called
+ triggerSensor.setListening(true);
+ triggerSensor.updateListening();
+
+ // THEN the sensor is still registered
+ assertTrue(triggerSensor.mRegistered);
+ }
+
private class TestableDozeSensors extends DozeSensors {
TestableDozeSensors() {
@@ -187,5 +275,17 @@
}
mSensors = new TriggerSensor[] {mTriggerSensor, mSensorTap};
}
+
+ public TriggerSensor createDozeSensor(Sensor sensor, boolean settingEnabled,
+ boolean requiresTouchScreen) {
+ return new TriggerSensor(/* sensor */ sensor,
+ /* setting name */ "test_setting",
+ /* settingDefault */ settingEnabled,
+ /* configured */ true,
+ /* pulseReason*/ 0,
+ /* reportsTouchCoordinate*/ false,
+ requiresTouchScreen,
+ mDozeLog);
+ }
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/idle/IdleHostViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/idle/IdleHostViewControllerTest.java
new file mode 100644
index 0000000..664072f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/idle/IdleHostViewControllerTest.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2021 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.idle;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.BroadcastReceiver;
+import android.content.Intent;
+import android.content.res.Resources;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.os.Looper;
+import android.os.PowerManager;
+import android.testing.AndroidTestingRunner;
+import android.view.Choreographer;
+import android.view.View;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.broadcast.BroadcastDispatcher;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.InputMonitorCompat;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
+import com.android.systemui.util.concurrency.DelayableExecutor;
+import com.android.systemui.util.sensors.AsyncSensorManager;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.time.Instant;
+
+import javax.inject.Provider;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+public class IdleHostViewControllerTest extends SysuiTestCase {
+ @Mock private BroadcastDispatcher mBroadcastDispatcher;
+ @Mock private PowerManager mPowerManager;
+ @Mock private AsyncSensorManager mSensorManager;
+ @Mock private IdleHostView mIdleHostView;
+ @Mock private InputMonitorFactory mInputMonitorFactory;
+ @Mock private DelayableExecutor mDelayableExecutor;
+ @Mock private Resources mResources;
+ @Mock private Looper mLooper;
+ @Mock private Provider<View> mViewProvider;
+ @Mock private Choreographer mChoreographer;
+ @Mock private KeyguardStateController mKeyguardStateController;
+ @Mock private StatusBarStateController mStatusBarStateController;
+ @Mock private Sensor mSensor;
+ @Mock private DreamHelper mDreamHelper;
+ @Mock private InputMonitorCompat mInputMonitor;
+
+ private final long mTimestamp = Instant.now().toEpochMilli();
+ private KeyguardStateController.Callback mKeyguardStateCallback;
+ private StatusBarStateController.StateListener mStatusBarStateListener;
+ private IdleHostViewController mController;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(mResources.getBoolean(R.bool.config_enableIdleMode)).thenReturn(true);
+ when(mStatusBarStateController.isDozing()).thenReturn(false);
+ when(mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT)).thenReturn(mSensor);
+ when(mInputMonitorFactory.getInputMonitor("IdleHostViewController"))
+ .thenReturn(mInputMonitor);
+
+ mController = new IdleHostViewController(mContext,
+ mBroadcastDispatcher, mPowerManager, mSensorManager, mIdleHostView,
+ mInputMonitorFactory, mDelayableExecutor, mResources, mLooper, mViewProvider,
+ mChoreographer, mKeyguardStateController, mStatusBarStateController, mDreamHelper);
+ mController.init();
+ mController.onViewAttached();
+
+ // Captures keyguard state controller callback.
+ ArgumentCaptor<KeyguardStateController.Callback> keyguardStateCallbackCaptor =
+ ArgumentCaptor.forClass(KeyguardStateController.Callback.class);
+ verify(mKeyguardStateController).addCallback(keyguardStateCallbackCaptor.capture());
+ mKeyguardStateCallback = keyguardStateCallbackCaptor.getValue();
+
+ // Captures status bar state listener.
+ ArgumentCaptor<StatusBarStateController.StateListener> statusBarStateListenerCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+ verify(mStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture());
+ mStatusBarStateListener = statusBarStateListenerCaptor.getValue();
+ }
+
+ @Test
+ public void testTimeoutToIdleMode() {
+ // Keyguard showing.
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ mKeyguardStateCallback.onKeyguardShowingChanged();
+
+ // Regular ambient lighting.
+ final SensorEvent sensorEvent = new SensorEvent(mSensor, 3, mTimestamp,
+ new float[]{90});
+ mController.onSensorChanged(sensorEvent);
+
+ // Times out.
+ ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
+ verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
+ callbackCapture.getValue().run();
+
+ // Verifies start dreaming (idle mode).
+ verify(mDreamHelper).startDreaming(any());
+ }
+
+ @Test
+ public void testTimeoutToLowLightMode() {
+ // Keyguard showing.
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ mKeyguardStateCallback.onKeyguardShowingChanged();
+
+ // Captures dream broadcast receiver;
+ ArgumentCaptor<BroadcastReceiver> dreamBroadcastReceiverCaptor =
+ ArgumentCaptor.forClass(BroadcastReceiver.class);
+ verify(mBroadcastDispatcher)
+ .registerReceiver(dreamBroadcastReceiverCaptor.capture(), any());
+ final BroadcastReceiver dreamBroadcastReceiver = dreamBroadcastReceiverCaptor.getValue();
+
+ // Low ambient lighting.
+ final SensorEvent sensorEvent = new SensorEvent(mSensor, 3, mTimestamp,
+ new float[]{5});
+ mController.onSensorChanged(sensorEvent);
+
+ // Verifies it goes to sleep because of low light.
+ verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+
+ mStatusBarStateListener.onDozingChanged(true /*isDozing*/);
+ dreamBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STARTED));
+
+ // User wakes up the device.
+ mStatusBarStateListener.onDozingChanged(false /*isDozing*/);
+ dreamBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_DREAMING_STOPPED));
+
+ // Clears power manager invocations to make sure the below dozing was triggered by the
+ // timeout.
+ clearInvocations(mPowerManager);
+
+ // Times out.
+ ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
+ verify(mDelayableExecutor, atLeastOnce()).executeDelayed(callbackCapture.capture(),
+ anyLong());
+ callbackCapture.getValue().run();
+
+ // Verifies go to sleep (low light mode).
+ verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+ }
+
+ @Test
+ public void testTransitionBetweenIdleAndLowLightMode() {
+ // Regular ambient lighting.
+ final SensorEvent sensorEventRegularLight = new SensorEvent(mSensor, 3, mTimestamp,
+ new float[]{90});
+ mController.onSensorChanged(sensorEventRegularLight);
+
+ // Keyguard showing.
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ mKeyguardStateCallback.onKeyguardShowingChanged();
+
+ // Times out.
+ ArgumentCaptor<Runnable> callbackCapture = ArgumentCaptor.forClass(Runnable.class);
+ verify(mDelayableExecutor).executeDelayed(callbackCapture.capture(), anyLong());
+ callbackCapture.getValue().run();
+
+ // Verifies in idle mode (dreaming).
+ verify(mDreamHelper).startDreaming(any());
+ clearInvocations(mDreamHelper);
+
+ // Ambient lighting becomes dim.
+ final SensorEvent sensorEventLowLight = new SensorEvent(mSensor, 3, mTimestamp,
+ new float[]{5});
+ mController.onSensorChanged(sensorEventLowLight);
+
+ // Verifies in low light mode (dozing).
+ verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+
+ // Ambient lighting becomes bright again.
+ mController.onSensorChanged(sensorEventRegularLight);
+
+ // Verifies in idle mode (dreaming).
+ verify(mDreamHelper).startDreaming(any());
+ }
+
+ @Test
+ public void testStartDozingWhenLowLight() {
+ // Regular ambient lighting.
+ final SensorEvent sensorEventRegularLight = new SensorEvent(mSensor, 3, mTimestamp,
+ new float[]{90});
+ mController.onSensorChanged(sensorEventRegularLight);
+
+ // Keyguard showing.
+ when(mKeyguardStateController.isShowing()).thenReturn(true);
+ mKeyguardStateCallback.onKeyguardShowingChanged();
+
+ // Verifies it doesn't go to sleep yet.
+ verify(mPowerManager, never()).goToSleep(anyLong(), anyInt(), anyInt());
+
+ // Ambient lighting becomes dim.
+ final SensorEvent sensorEventLowLight = new SensorEvent(mSensor, 3, mTimestamp,
+ new float[]{5});
+ mController.onSensorChanged(sensorEventLowLight);
+
+ // Verifies it goes to sleep.
+ verify(mPowerManager).goToSleep(anyLong(), anyInt(), anyInt());
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
index 756e984..a2bb0af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/lockscreen/LockscreenSmartspaceControllerTest.kt
@@ -389,6 +389,7 @@
verify(userTracker).removeCallback(userListener)
verify(contentResolver).unregisterContentObserver(settingsObserver)
verify(configurationController).removeCallback(configChangeListener)
+ verify(statusBarStateController).removeCallback(statusBarStateListener)
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
index 2ce22a6..3378003 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/ShadeListBuilderTest.java
@@ -802,13 +802,13 @@
.onBeforeTransformGroups(anyList());
inOrder.verify(promoter, atLeastOnce())
.shouldPromoteToTopLevel(any(NotificationEntry.class));
+ inOrder.verify(mOnBeforeFinalizeFilterListener).onBeforeFinalizeFilter(anyList());
+ inOrder.verify(preRenderFilter, atLeastOnce())
+ .shouldFilterOut(any(NotificationEntry.class), anyLong());
inOrder.verify(mOnBeforeSortListener).onBeforeSort(anyList());
inOrder.verify(section, atLeastOnce()).isInSection(any(ListEntry.class));
inOrder.verify(comparator, atLeastOnce())
.compare(any(ListEntry.class), any(ListEntry.class));
- inOrder.verify(mOnBeforeFinalizeFilterListener).onBeforeFinalizeFilter(anyList());
- inOrder.verify(preRenderFilter, atLeastOnce())
- .shouldFilterOut(any(NotificationEntry.class), anyLong());
inOrder.verify(mOnBeforeRenderListListener).onBeforeRenderList(anyList());
inOrder.verify(mOnRenderListListener).onRenderList(anyList());
}
@@ -1045,12 +1045,32 @@
// because group changes aren't allowed by the stability manager
verifyBuiltList(
notif(0),
+ notif(2),
group(
summary(3),
child(4),
child(5)
- ),
- notif(2)
+ )
+ );
+ }
+
+ @Test
+ public void testBrokenGroupNotificationOrdering() {
+ // GIVEN two group children with different sections & without a summary yet
+
+ addGroupChild(0, PACKAGE_2, GROUP_1);
+ addNotif(1, PACKAGE_1);
+ addGroupChild(2, PACKAGE_2, GROUP_1);
+ addGroupChild(3, PACKAGE_2, GROUP_1);
+
+ dispatchBuild();
+
+ // THEN all notifications are not grouped and posted in order by index
+ verifyBuiltList(
+ notif(0),
+ notif(1),
+ notif(2),
+ notif(3)
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 2e76bd7..690b841 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -38,27 +38,35 @@
private static final float ZERO_DRAG = 0.f;
private static final float OPAQUE = 1.f;
private static final float TRANSPARENT = 0.f;
+ private static final boolean HAS_CUSTOM_CLOCK = false;
+ private static final boolean HAS_VISIBLE_NOTIFS = false;
private KeyguardClockPositionAlgorithm mClockPositionAlgorithm;
private KeyguardClockPositionAlgorithm.Result mClockPosition;
+ private int mNotificationStackHeight;
private float mPanelExpansion;
private int mKeyguardStatusHeight;
private float mDark;
+ private boolean mHasCustomClock;
+ private boolean mHasVisibleNotifs;
private float mQsExpansion;
- private int mCutoutTopInsetPx = 0;
- private int mSplitShadeSmartspaceHeightPx = 0;
+ private int mCutoutTopInset = 0; // in pixels
private boolean mIsSplitShade = false;
@Before
public void setUp() {
mClockPositionAlgorithm = new KeyguardClockPositionAlgorithm();
mClockPosition = new KeyguardClockPositionAlgorithm.Result();
+
+ mHasCustomClock = HAS_CUSTOM_CLOCK;
+ mHasVisibleNotifs = HAS_VISIBLE_NOTIFS;
}
@Test
public void clockPositionTopOfScreenOnAOD() {
- // GIVEN on AOD and clock has 0 height
+ // GIVEN on AOD and both stack scroll and clock have 0 height
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -71,10 +79,11 @@
@Test
public void clockPositionBelowCutout() {
- // GIVEN on AOD and clock has 0 height
+ // GIVEN on AOD and both stack scroll and clock have 0 height
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
- mCutoutTopInsetPx = 300;
+ mCutoutTopInset = 300;
// WHEN the clock position algorithm is run
positionClock();
// THEN the clock Y position is below the cutout
@@ -88,6 +97,7 @@
public void clockPositionAdjustsForKeyguardStatusOnAOD() {
// GIVEN on AOD with a clock of height 100
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = 100;
// WHEN the clock position algorithm is run
positionClock();
@@ -102,6 +112,7 @@
public void clockPositionLargeClockOnAOD() {
// GIVEN on AOD with a full screen clock
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -114,8 +125,9 @@
@Test
public void clockPositionTopOfScreenOnLockScreen() {
- // GIVEN on lock screen with clock of 0 height
+ // GIVEN on lock screen with stack scroll and clock of 0 height
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -126,9 +138,24 @@
}
@Test
+ public void clockPositionWithStackScrollExpandOnLockScreen() {
+ // GIVEN on lock screen with stack scroll of height 500
+ givenLockScreen();
+ mNotificationStackHeight = 500;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ // WHEN the clock position algorithm is run
+ positionClock();
+ // THEN the clock Y position stays to the top
+ assertThat(mClockPosition.clockY).isEqualTo(0);
+ // AND the clock is positioned on the left.
+ assertThat(mClockPosition.clockX).isEqualTo(0);
+ }
+
+ @Test
public void clockPositionWithPartialDragOnLockScreen() {
// GIVEN dragging up on lock screen
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
mPanelExpansion = 0.5f;
// WHEN the clock position algorithm is run
@@ -144,6 +171,7 @@
public void clockPositionWithFullDragOnLockScreen() {
// GIVEN the lock screen is dragged up
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
mPanelExpansion = 0.f;
// WHEN the clock position algorithm is run
@@ -156,6 +184,7 @@
public void largeClockOnLockScreenIsTransparent() {
// GIVEN on lock screen with a full screen clock
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the clock position algorithm is run
positionClock();
@@ -165,8 +194,9 @@
@Test
public void notifPositionTopOfScreenOnAOD() {
- // GIVEN on AOD and clock has 0 height
+ // GIVEN on AOD and both stack scroll and clock have 0 height
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -178,6 +208,7 @@
public void notifPositionIndependentOfKeyguardStatusHeightOnAOD() {
// GIVEN on AOD and clock has a nonzero height
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = 100;
// WHEN the position algorithm is run
positionClock();
@@ -189,6 +220,7 @@
public void notifPositionWithLargeClockOnAOD() {
// GIVEN on AOD and clock has a nonzero height
givenAOD();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -198,8 +230,9 @@
@Test
public void notifPositionMiddleOfScreenOnLockScreen() {
- // GIVEN on lock screen and clock has 0 height
+ // GIVEN on lock screen and both stack scroll and clock have 0 height
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -208,21 +241,47 @@
}
@Test
+ public void notifPositionAdjustsForStackHeightOnLockScreen() {
+ // GIVEN on lock screen and stack scroller has a nonzero height
+ givenLockScreen();
+ mNotificationStackHeight = 500;
+ mKeyguardStatusHeight = EMPTY_HEIGHT;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notif padding adjusts for keyguard status height
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(0);
+ }
+
+ @Test
public void notifPositionAdjustsForClockHeightOnLockScreen() {
// GIVEN on lock screen and stack scroller has a nonzero height
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = 200;
// WHEN the position algorithm is run
positionClock();
+ // THEN the notif padding adjusts for both clock and notif stack.
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
+ }
+ @Test
+ public void notifPositionAdjustsForStackHeightAndClockHeightOnLockScreen() {
+ // GIVEN on lock screen and stack scroller has a nonzero height
+ givenLockScreen();
+ mNotificationStackHeight = 500;
+ mKeyguardStatusHeight = 200;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notifs are placed below the statusview
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
}
@Test
public void notifPositionAlignedWithClockInSplitShadeMode() {
+ // GIVEN on lock screen and split shade mode
givenLockScreen();
mIsSplitShade = true;
- mKeyguardStatusHeight = 200;
+ mHasCustomClock = true;
// WHEN the position algorithm is run
positionClock();
// THEN the notif padding DOESN'T adjust for keyguard status height.
@@ -230,20 +289,10 @@
}
@Test
- public void notifPositionAdjustedBySmartspaceHeightInSplitShadeMode() {
- givenLockScreen();
- mSplitShadeSmartspaceHeightPx = 200;
- mIsSplitShade = true;
- // WHEN the position algorithm is run
- positionClock();
-
- assertThat(mClockPosition.stackScrollerPadding).isEqualTo(200);
- }
-
- @Test
public void notifPositionWithLargeClockOnLockScreen() {
// GIVEN on lock screen and clock has a nonzero height
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
// WHEN the position algorithm is run
positionClock();
@@ -255,6 +304,7 @@
public void notifPositionWithFullDragOnLockScreen() {
// GIVEN the lock screen is dragged up
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = EMPTY_HEIGHT;
mPanelExpansion = 0.f;
// WHEN the clock position algorithm is run
@@ -267,18 +317,19 @@
public void notifPositionWithLargeClockFullDragOnLockScreen() {
// GIVEN the lock screen is dragged up and a full screen clock
givenLockScreen();
+ mNotificationStackHeight = EMPTY_HEIGHT;
mKeyguardStatusHeight = SCREEN_HEIGHT;
mPanelExpansion = 0.f;
// WHEN the clock position algorithm is run
positionClock();
-
+ // THEN the notif padding is zero.
assertThat(mClockPosition.stackScrollerPadding).isEqualTo(
(int) (mKeyguardStatusHeight * .667f));
}
@Test
public void clockHiddenWhenQsIsExpanded() {
- // GIVEN on the lock screen with visible notifications
+ // GIVEN on the lock screen with a custom clock and visible notifications
givenLockScreen();
mQsExpansion = 1;
// WHEN the clock position algorithm is run
@@ -298,12 +349,12 @@
}
private void positionClock() {
- mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT,
- mPanelExpansion, mKeyguardStatusHeight,
+ mClockPositionAlgorithm.setup(EMPTY_MARGIN, SCREEN_HEIGHT, mNotificationStackHeight,
+ mPanelExpansion, SCREEN_HEIGHT, mKeyguardStatusHeight,
0 /* userSwitchHeight */, 0 /* userSwitchPreferredY */,
- mDark, ZERO_DRAG, false /* bypassEnabled */,
+ mHasCustomClock, mHasVisibleNotifs, mDark, ZERO_DRAG, false /* bypassEnabled */,
0 /* unlockedStackScrollerPadding */, mQsExpansion,
- mCutoutTopInsetPx, mSplitShadeSmartspaceHeightPx, mIsSplitShade);
+ mCutoutTopInset, mIsSplitShade);
mClockPositionAlgorithm.run(mClockPosition);
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index 85e17ba..d92816e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -25,6 +25,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.LayoutInflater;
+import android.view.View;
import androidx.test.filters.SmallTest;
@@ -162,4 +163,18 @@
assertThat(mKeyguardStatusBarView.getClipBounds().top).isEqualTo(0);
}
+
+ @Test
+ public void updateViewState_alphaAndVisibilityGiven_viewUpdated() {
+ // Verify the initial values so we know the method triggers changes.
+ assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(1f);
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+
+ float newAlpha = 0.5f;
+ int newVisibility = View.INVISIBLE;
+ mController.updateViewState(newAlpha, newVisibility);
+
+ assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(newAlpha);
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(newVisibility);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index e9d698f..7338fad 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -63,7 +63,6 @@
import android.view.ViewStub;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
-import android.widget.FrameLayout;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.constraintlayout.widget.ConstraintSet;
@@ -121,7 +120,6 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
-import com.android.systemui.statusbar.lockscreen.LockscreenSmartspaceController;
import com.android.systemui.statusbar.notification.ConversationNotificationManager;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -344,10 +342,6 @@
@Mock
private ControlsComponent mControlsComponent;
@Mock
- private LockscreenSmartspaceController mLockscreenSmartspaceController;
- @Mock
- private FrameLayout mSplitShadeSmartspaceContainer;
- @Mock
private LockscreenGestureLogger mLockscreenGestureLogger;
private SysuiStatusBarStateController mStatusBarStateController;
@@ -399,8 +393,6 @@
when(mView.findViewById(R.id.qs_frame)).thenReturn(mQsFrame);
when(mView.findViewById(R.id.keyguard_status_view))
.thenReturn(mock(KeyguardStatusView.class));
- when(mView.findViewById(R.id.split_shade_smartspace_container))
- .thenReturn(mSplitShadeSmartspaceContainer);
mNotificationContainerParent = new NotificationsQuickSettingsContainer(getContext(), null);
mNotificationContainerParent.addView(newViewWithId(R.id.qs_frame));
mNotificationContainerParent.addView(newViewWithId(R.id.notification_stack_scroller));
@@ -514,7 +506,6 @@
new FakeExecutor(new FakeSystemClock()),
mSecureSettings,
mSplitShadeHeaderController,
- mLockscreenSmartspaceController,
mUnlockedScreenOffAnimationController,
mLockscreenGestureLogger,
mNotificationRemoteInputManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 1953903..9b8e259 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -16,10 +16,13 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.phone.ScrimController.KEYGUARD_SCRIM_ALPHA;
import static com.android.systemui.statusbar.phone.ScrimController.OPAQUE;
import static com.android.systemui.statusbar.phone.ScrimController.SEMI_TRANSPARENT;
import static com.android.systemui.statusbar.phone.ScrimController.TRANSPARENT;
+import static com.google.common.truth.Truth.assertThat;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyFloat;
@@ -741,9 +744,9 @@
}
@Test
- public void transitionToUnlockedFromAod() {
- // Simulate unlock with fingerprint
- mScrimController.transitionTo(ScrimState.AOD);
+ public void transitionToUnlockedFromOff() {
+ // Simulate unlock with fingerprint without AOD
+ mScrimController.transitionTo(ScrimState.OFF);
mScrimController.setPanelExpansion(0f);
finishAnimationsImmediately();
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -769,6 +772,28 @@
}
@Test
+ public void transitionToUnlockedFromAod() {
+ // Simulate unlock with fingerprint
+ mScrimController.transitionTo(ScrimState.AOD);
+ mScrimController.setPanelExpansion(0f);
+ finishAnimationsImmediately();
+ mScrimController.transitionTo(ScrimState.UNLOCKED);
+
+ finishAnimationsImmediately();
+
+ // All scrims should be transparent at the end of fade transition.
+ assertScrimAlpha(Map.of(
+ mScrimInFront, TRANSPARENT,
+ mScrimBehind, TRANSPARENT));
+
+ // Make sure at the very end of the animation, we're reset to transparent
+ assertScrimTinted(Map.of(
+ mScrimInFront, false,
+ mScrimBehind, true
+ ));
+ }
+
+ @Test
public void scrimBlanksBeforeLeavingAod() {
// Simulate unlock with fingerprint
mScrimController.transitionTo(ScrimState.AOD);
@@ -1082,6 +1107,26 @@
}
@Test
+ public void testDoesntAnimate_whenUnlocking() {
+ // LightRevealScrim will animate the transition, we should only hide the keyguard scrims.
+ ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ ScrimState.UNLOCKED.prepare(ScrimState.PULSING);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
+
+ ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ ScrimState.UNLOCKED.prepare(ScrimState.AOD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isFalse();
+
+ // LightRevealScrim doesn't animate when AOD is disabled. We need to use the legacy anim.
+ ScrimState.UNLOCKED.prepare(ScrimState.KEYGUARD);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ ScrimState.UNLOCKED.prepare(ScrimState.OFF);
+ assertThat(ScrimState.UNLOCKED.getAnimateChange()).isTrue();
+ }
+
+ @Test
public void testScrimsVisible_whenShadeVisible_clippingQs() {
mScrimController.setClipsQsScrim(true);
mScrimController.transitionTo(ScrimState.UNLOCKED);
@@ -1143,8 +1188,10 @@
mScrimController.transitionTo(ScrimState.KEYGUARD);
mScrimController.setUnocclusionAnimationRunning(true);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.0f, /* expansion */ 0.0f);
- assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.0f, /* expansion */ 1.0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
+ /* expansion */ 0.0f);
+ assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ KEYGUARD_SCRIM_ALPHA,
+ /* expansion */ 1.0f);
// Verify normal behavior after
mScrimController.setUnocclusionAnimationRunning(false);
diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java
index e390ae28..6529b11 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -479,6 +479,35 @@
@AppIdInt int recipientAppId, int visibleUid,
boolean direct);
+ /**
+ * Grants implicit access based on an interaction between two apps. This grants access to the
+ * from one application to the other's package metadata.
+ * <p>
+ * When an application explicitly tries to interact with another application [via an
+ * activity, service or provider that is either declared in the caller's
+ * manifest via the {@code <queries>} tag or has been exposed via the target apps manifest using
+ * the {@code visibleToInstantApp} attribute], the target application must be able to see
+ * metadata about the calling app. If the calling application uses an implicit intent [ie
+ * action VIEW, category BROWSABLE], it remains hidden from the launched app.
+ * <p>
+ * If an interaction is not explicit, the {@code direct} argument should be set to false as
+ * visibility should not be granted in some cases. This method handles that logic.
+ * <p>
+ * @param userId the user
+ * @param intent the intent that triggered the grant
+ * @param recipientAppId The app ID of the application that is being given access to {@code
+ * visibleUid}
+ * @param visibleUid The uid of the application that is becoming accessible to {@code
+ * recipientAppId}
+ * @param direct true if the access is being made due to direct interaction between visibleUid
+ * and recipientAppId.
+ * @param retainOnUpdate true if the implicit access is retained across package update.
+ */
+ public abstract void grantImplicitAccess(
+ @UserIdInt int userId, Intent intent,
+ @AppIdInt int recipientAppId, int visibleUid,
+ boolean direct, boolean retainOnUpdate);
+
public abstract boolean isInstantAppInstallerComponent(ComponentName component);
/**
* Prunes instant apps and state associated with uninstalled
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b202c23..18cc154 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -194,6 +194,9 @@
import android.app.usage.UsageStatsManagerInternal;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetManagerInternal;
+import android.compat.Compatibility;
+import android.compat.annotation.ChangeId;
+import android.compat.annotation.EnabledSince;
import android.content.AttributionSource;
import android.content.AutofillOptions;
import android.content.BroadcastReceiver;
@@ -544,6 +547,16 @@
static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
/**
+ * It is now required for apps to explicitly set either
+ * {@link android.content.Context#RECEIVER_EXPORTED} or
+ * {@link android.content.Context#RECEIVER_NOT_EXPORTED} when registering a receiver for an
+ * unprotected broadcast in code.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
+ private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
+
+ /**
* The maximum number of bytes that {@link #setProcessStateSummary} accepts.
*
* @see {@link android.app.ActivityManager#setProcessStateSummary(byte[])}
@@ -12416,6 +12429,11 @@
ProcessRecord callerApp = null;
final boolean visibleToInstantApps
= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
+ // Dynamic receivers are exported by default for versions prior to T
+ final boolean exported =
+ ((flags & Context.RECEIVER_EXPORTED) != 0
+ || (!Compatibility.isChangeEnabled(161145287)));
+
int callingUid;
int callingPid;
boolean instantApp;
@@ -12452,8 +12470,10 @@
noAction.add(null);
actions = noAction.iterator();
}
+ boolean onlyProtectedBroadcasts = actions.hasNext();
- // Collect stickies of users
+ // Collect stickies of users and check if broadcast is only registered for protected
+ // broadcasts
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
while (actions.hasNext()) {
String action = actions.next();
@@ -12469,6 +12489,31 @@
}
}
}
+ if (onlyProtectedBroadcasts) {
+ try {
+ onlyProtectedBroadcasts &=
+ AppGlobals.getPackageManager().isProtectedBroadcast(action);
+ } catch (RemoteException e) {
+ onlyProtectedBroadcasts = false;
+ Slog.w(TAG, "Remote exception", e);
+ }
+ }
+ }
+
+ // If the change is enabled, but neither exported or not exported is set, we need to log
+ // an error so the consumer can know to explicitly set the value for their flag
+ if (!onlyProtectedBroadcasts && (Compatibility.isChangeEnabled(161145287)
+ && (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED))
+ == 0)) {
+ Slog.e(TAG,
+ callerPackage + ": Targeting T+ (version " + Build.VERSION_CODES.TIRAMISU
+ + " and above) requires that one of RECEIVER_EXPORTED or "
+ + "RECEIVER_NOT_EXPORTED be specified when registering a receiver");
+ } else if (((flags & Context.RECEIVER_EXPORTED) != 0) && (
+ (flags & Context.RECEIVER_NOT_EXPORTED) != 0)) {
+ throw new IllegalArgumentException(
+ "Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED"
+ + "flag");
}
}
@@ -12557,7 +12602,8 @@
+ " callerPackage is " + callerPackage);
}
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
- receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);
+ receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
+ exported);
if (rl.containsFilter(filter)) {
Slog.w(TAG, "Receiver with filter " + filter
+ " already registered for pid " + rl.pid
diff --git a/services/core/java/com/android/server/am/BroadcastFilter.java b/services/core/java/com/android/server/am/BroadcastFilter.java
index 50e06c3..8e38f0a 100644
--- a/services/core/java/com/android/server/am/BroadcastFilter.java
+++ b/services/core/java/com/android/server/am/BroadcastFilter.java
@@ -34,10 +34,12 @@
final int owningUserId;
final boolean instantApp;
final boolean visibleToInstantApp;
+ final boolean exported;
BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
String _packageName, String _featureId, String _receiverId, String _requiredPermission,
- int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp) {
+ int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp,
+ boolean _exported) {
super(_filter);
receiverList = _receiverList;
packageName = _packageName;
@@ -48,6 +50,7 @@
owningUserId = _userId;
instantApp = _instantApp;
visibleToInstantApp = _visibleToInstantApp;
+ exported = _exported;
}
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 503b3a9..32d93ab 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -775,6 +775,22 @@
skip = true;
}
+ // Ensure that broadcasts are only sent to other apps if they are explicitly marked as
+ // exported, or are System level broadcasts
+ if (!skip && !filter.exported && Process.SYSTEM_UID != r.callingUid
+ && filter.receiverList.uid != r.callingUid) {
+
+ Slog.w(TAG, "Exported Denial: sending "
+ + r.intent.toString()
+ + ", action: " + r.intent.getAction()
+ + " from " + r.callerPackage
+ + " (uid=" + r.callingUid + ")"
+ + " due to receiver " + filter.receiverList.app
+ + " (uid " + filter.receiverList.uid + ")"
+ + " not specifying RECEIVER_EXPORTED");
+ // skip = true;
+ }
+
if (skip) {
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 43fd7ba..bd7baab 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2825,8 +2825,9 @@
if (uid == android.os.Process.SYSTEM_UID) {
uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
}
- if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid,
- callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+ // validate calling package and app op
+ if (!checkNoteAppOp(
+ STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage, attributionTag)) {
return;
}
@@ -3536,8 +3537,8 @@
if (uid == android.os.Process.SYSTEM_UID) {
uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
}
- if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid,
- callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+ if (!checkNoteAppOp(
+ STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage, attributionTag)) {
return;
}
@@ -3956,8 +3957,8 @@
uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
}
// If OP_AUDIO_MASTER_VOLUME is set, disallow unmuting.
- if (!mute && mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid,
- callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+ if (!mute && !checkNoteAppOp(
+ AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage, attributionTag)) {
return;
}
if (userId != UserHandle.getCallingUserId() &&
@@ -4090,8 +4091,8 @@
? MediaMetrics.Value.MUTE : MediaMetrics.Value.UNMUTE);
// If OP_MUTE_MICROPHONE is set, disallow unmuting.
- if (!on && mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid,
- callingPackage, attributionTag, null) != AppOpsManager.MODE_ALLOWED) {
+ if (!on && !checkNoteAppOp(
+ AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage, attributionTag)) {
mmi.set(MediaMetrics.Property.EARLY_RETURN, "disallow unmuting").record();
return;
}
@@ -10574,4 +10575,32 @@
}
mFullVolumeDevices.remove(audioSystemDeviceOut);
}
+
+ //====================
+ // Helper functions for app ops
+ //====================
+ /**
+ * Validates, and notes an app op for a given uid and package name.
+ * Validation comes from exception catching: a security exception indicates the package
+ * doesn't exist, an IAE indicates the uid and package don't match. The code only checks
+ * if exception was thrown for robustness to code changes in op validation
+ * @param op the app op to check
+ * @param uid the uid of the caller
+ * @param packageName the package to check
+ * @return true if the origin of the call is valid (no uid / package mismatch) and the caller
+ * is allowed to perform the operation
+ */
+ private boolean checkNoteAppOp(int op, int uid, String packageName, String attributionTag) {
+ try {
+ if (mAppOps.noteOp(op, uid, packageName, attributionTag, null)
+ != AppOpsManager.MODE_ALLOWED) {
+ return false;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error noting op:" + op + " on uid:" + uid + " for package:"
+ + packageName, e);
+ return false;
+ }
+ return true;
+ }
}
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 86c9ca9..48eea89 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -230,8 +230,6 @@
info.rotation = mOverrideDisplayInfo.rotation;
info.displayCutout = mOverrideDisplayInfo.displayCutout;
info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
- info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
- info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
info.shouldConstrainMetricsForLauncher =
mOverrideDisplayInfo.shouldConstrainMetricsForLauncher;
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 56b77b5..15e671c 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -97,6 +97,13 @@
private final SparseSetArray<Integer> mImplicitlyQueryable = new SparseSetArray<>();
/**
+ * This contains a list of app UIDs that are implicitly queryable because another app explicitly
+ * interacted with it, but could keep across package updates. For example, if application A
+ * grants persistable uri permission to application B; regardless of any manifest entries.
+ */
+ private final SparseSetArray<Integer> mRetainedImplicitlyQueryable = new SparseSetArray<>();
+
+ /**
* A mapping from the set of App IDs that query other App IDs via package name to the
* list of packages that they can see.
*/
@@ -256,6 +263,7 @@
*/
private AppsFilter(AppsFilter orig) {
Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable);
+ Snapshots.copy(mRetainedImplicitlyQueryable, orig.mRetainedImplicitlyQueryable);
Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage);
Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent);
Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary);
@@ -633,15 +641,19 @@
*
* @param recipientUid the uid gaining visibility of the {@code visibleUid}.
* @param visibleUid the uid becoming visible to the {@recipientUid}
+ * @param retainOnUpdate if the implicit access retained across package updates.
* @return {@code true} if implicit access was not already granted.
*/
- public boolean grantImplicitAccess(int recipientUid, int visibleUid) {
+ public boolean grantImplicitAccess(int recipientUid, int visibleUid, boolean retainOnUpdate) {
if (recipientUid == visibleUid) {
return false;
}
- final boolean changed = mImplicitlyQueryable.add(recipientUid, visibleUid);
+ final boolean changed = retainOnUpdate
+ ? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid)
+ : mImplicitlyQueryable.add(recipientUid, visibleUid);
if (changed && DEBUG_LOGGING) {
- Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid);
+ Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: "
+ + recipientUid + " -> " + visibleUid);
}
synchronized (mCacheLock) {
if (mShouldFilterCache != null) {
@@ -677,7 +689,7 @@
try {
if (isReplace) {
// let's first remove any prior rules for this package
- removePackage(newPkgSetting);
+ removePackage(newPkgSetting, true /*isReplace*/);
}
mStateProvider.runWithState((settings, users) -> {
ArraySet<String> additionalChangedPackages =
@@ -1078,8 +1090,9 @@
* Removes a package for consideration when filtering visibility between apps.
*
* @param setting the setting of the package being removed.
+ * @param isReplace if the package is being replaced.
*/
- public void removePackage(PackageSetting setting) {
+ public void removePackage(PackageSetting setting, boolean isReplace) {
mStateProvider.runWithState((settings, users) -> {
final int userCount = users.length;
for (int u = 0; u < userCount; u++) {
@@ -1089,6 +1102,16 @@
for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) {
mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid);
}
+
+ if (isReplace) {
+ continue;
+ }
+
+ mRetainedImplicitlyQueryable.remove(removingUid);
+ for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) {
+ mRetainedImplicitlyQueryable.remove(
+ mRetainedImplicitlyQueryable.keyAt(i), removingUid);
+ }
}
if (!mQueriesViaComponentRequireRecompute) {
@@ -1414,6 +1437,24 @@
try {
if (DEBUG_TRACING) {
+ Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mRetainedImplicitlyQueryable");
+ }
+ final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
+ if (mRetainedImplicitlyQueryable.contains(callingUid, targetUid)) {
+ if (DEBUG_LOGGING) {
+ log(callingSetting, targetPkgSetting,
+ "retained implicitly queryable for user");
+ }
+ return false;
+ }
+ } finally {
+ if (DEBUG_TRACING) {
+ Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+ }
+ }
+
+ try {
+ if (DEBUG_TRACING) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
}
final String targetName = targetPkg.getPackageName();
@@ -1550,6 +1591,9 @@
dumpQueriesMap(pw,
filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
mImplicitlyQueryable, " ", expandPackages);
+ dumpQueriesMap(pw,
+ filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
+ mRetainedImplicitlyQueryable, " ", expandPackages);
}
pw.println(" queryable via uses-library:");
dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 114dec6..3cd41d3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -18051,7 +18051,8 @@
synchronized (mLock) {
mDomainVerificationManager.clearPackage(deletedPs.name);
mSettings.getKeySetManagerService().removeAppKeySetDataLPw(packageName);
- mAppsFilter.removePackage(getPackageSetting(packageName));
+ mAppsFilter.removePackage(getPackageSetting(packageName),
+ false /* isReplace */);
removedAppId = mSettings.removePackageLPw(packageName);
if (outInfo != null) {
outInfo.mRemovedAppId = removedAppId;
@@ -23787,6 +23788,13 @@
@Override
public void grantImplicitAccess(int userId, Intent intent,
int recipientAppId, int visibleUid, boolean direct) {
+ grantImplicitAccess(userId, intent, recipientAppId, visibleUid, direct,
+ false /* retainOnUpdate */);
+ }
+
+ @Override
+ public void grantImplicitAccess(int userId, Intent intent,
+ int recipientAppId, int visibleUid, boolean direct, boolean retainOnUpdate) {
synchronized (mLock) {
final AndroidPackage visiblePackage = getPackage(visibleUid);
final int recipientUid = UserHandle.getUid(userId, recipientAppId);
@@ -23807,7 +23815,8 @@
accessGranted = mInstantAppRegistry.grantInstantAccessLPw(userId, intent,
recipientAppId, UserHandle.getAppId(visibleUid) /*instantAppId*/);
} else {
- accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid);
+ accessGranted = mAppsFilter.grantImplicitAccess(recipientUid, visibleUid,
+ retainOnUpdate);
}
if (accessGranted) {
ApplicationPackageManager.invalidateGetPackagesForUidCache();
@@ -24747,7 +24756,7 @@
}
int visibleUid = providerInfo.applicationInfo.uid;
mPmInternal.grantImplicitAccess(userId, null /*Intent*/, UserHandle.getAppId(recipientUid),
- visibleUid, false);
+ visibleUid, false /*direct*/);
}
boolean canHaveOatDir(String packageName) {
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index b1b46af..11aed8d 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -497,13 +497,10 @@
if (permissionTree.getUid() == UserHandle.getAppId(callingUid)) {
return permissionTree;
}
- throw new SecurityException("Calling uid " + callingUid
- + " is not allowed to add to permission tree "
- + permissionTree.getName() + " owned by uid "
- + permissionTree.getUid());
}
}
- throw new SecurityException("No permission tree found for " + permissionName);
+ throw new SecurityException("Calling uid " + callingUid
+ + " is not allowed to add to or remove from the permission tree");
}
@Nullable
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index fd1995d..b17257a 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -706,10 +706,10 @@
sourcePkg, targetPkg, targetUid, grantUri);
perm.initPersistedModes(modeFlags, createdTime);
mPmInternal.grantImplicitAccess(
- targetUserId, null,
+ targetUserId, null /* intent */,
UserHandle.getAppId(targetUid),
pi.applicationInfo.uid,
- false /* direct */);
+ false /* direct */, true /* retainOnUpdate */);
}
} else {
Slog.w(TAG, "Persisted grant for " + uri + " had source " + sourcePkg
@@ -773,8 +773,9 @@
perm = findOrCreateUriPermissionLocked(pi.packageName, targetPkg, targetUid, grantUri);
}
perm.grantModes(modeFlags, owner);
- mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null,
- UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
+ mPmInternal.grantImplicitAccess(UserHandle.getUserId(targetUid), null /*intent*/,
+ UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/,
+ (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0);
}
/** Like grantUriPermissionUnchecked, but takes an Intent. */
@@ -1187,7 +1188,7 @@
// provider supports granting permissions
mPmInternal.grantImplicitAccess(
UserHandle.getUserId(targetUid), null,
- UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false);
+ UserHandle.getAppId(targetUid), pi.applicationInfo.uid, false /*direct*/);
return -1;
}
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 94e6ca2..2b57179 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -670,6 +670,7 @@
if (magnifying) {
switch (transition) {
case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN:
+ case WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN:
case WindowManager.TRANSIT_OLD_TASK_OPEN:
case WindowManager.TRANSIT_OLD_TASK_TO_FRONT:
case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN:
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index ce1592d..c715c39 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -59,6 +59,8 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
import static com.android.server.am.MemoryStatUtil.MemoryStat;
import static com.android.server.am.MemoryStatUtil.readMemoryStatFromFilesystem;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_METRICS;
@@ -89,6 +91,7 @@
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
+import android.util.SparseArray;
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
@@ -157,6 +160,9 @@
private final ArrayList<TransitionInfo> mTransitionInfoList = new ArrayList<>();
/** Map : Last launched activity => {@link TransitionInfo} */
private final ArrayMap<ActivityRecord, TransitionInfo> mLastTransitionInfo = new ArrayMap<>();
+ /** SparseArray : Package UID => {@link PackageCompatStateInfo} */
+ private final SparseArray<PackageCompatStateInfo> mPackageUidToCompatStateInfo =
+ new SparseArray<>(0);
private ArtManagerInternal mArtManagerInternal;
private final StringBuilder mStringBuilder = new StringBuilder();
@@ -452,6 +458,15 @@
}
}
+ /** Information about the App Compat state logging associated with a package UID . */
+ private static final class PackageCompatStateInfo {
+ /** All activities that have a visible state. */
+ final ArrayList<ActivityRecord> mVisibleActivities = new ArrayList<>();
+ /** The last logged state. */
+ int mLastLoggedState = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+ @Nullable ActivityRecord mLastLoggedActivity;
+ }
+
ActivityMetricsLogger(ActivityTaskSupervisor supervisor, Looper looper) {
mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
mSupervisor = supervisor;
@@ -703,6 +718,7 @@
// Always calculate the delay because the caller may need to know the individual drawn time.
info.mWindowsDrawnDelayMs = info.calculateDelay(timestampNs);
info.removePendingDrawActivity(r);
+ info.updatePendingDraw(false /* keepInitializing */);
final TransitionInfoSnapshot infoSnapshot = new TransitionInfoSnapshot(info);
if (info.mLoggedTransitionStarting && info.allDrawn()) {
done(false /* abort */, info, "notifyWindowsDrawn - all windows drawn", timestampNs);
@@ -774,6 +790,21 @@
/** Makes sure that the reference to the removed activity is cleared. */
void notifyActivityRemoved(@NonNull ActivityRecord r) {
mLastTransitionInfo.remove(r);
+
+ final int packageUid = r.info.applicationInfo.uid;
+ final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
+ if (compatStateInfo == null) {
+ return;
+ }
+
+ compatStateInfo.mVisibleActivities.remove(r);
+ if (compatStateInfo.mLastLoggedActivity == r) {
+ compatStateInfo.mLastLoggedActivity = null;
+ }
+ if (compatStateInfo.mVisibleActivities.isEmpty()) {
+ // No need to keep the entry if there are no visible activities.
+ mPackageUidToCompatStateInfo.remove(packageUid);
+ }
}
/**
@@ -1270,6 +1301,115 @@
memoryStat.swapInBytes);
}
+ /**
+ * Logs the current App Compat state of the given {@link ActivityRecord} with its package
+ * UID, if all of the following hold:
+ * <ul>
+ * <li>The current state is different than the last logged state for the package UID of the
+ * activity.
+ * <li>If the current state is NOT_VISIBLE, there is a previously logged state for the
+ * package UID and there are no other visible activities with the same package UID.
+ * <li>The last logged activity with the same package UID is either {@code activity} or the
+ * last logged state is NOT_VISIBLE or NOT_LETTERBOXED.
+ * </ul>
+ *
+ * <p>If the current state is NOT_VISIBLE and the previous state which was logged by {@code
+ * activity} wasn't, looks for the first visible activity with the same package UID that has
+ * a letterboxed state, or a non-letterboxed state if there isn't one, and logs that state.
+ *
+ * <p>This method assumes that the caller is wrapping the call with a synchronized block so
+ * that there won't be a race condition between two activities with the same package.
+ */
+ void logAppCompatState(@NonNull ActivityRecord activity) {
+ final int packageUid = activity.info.applicationInfo.uid;
+ final int state = activity.getAppCompatState();
+
+ if (!mPackageUidToCompatStateInfo.contains(packageUid)) {
+ mPackageUidToCompatStateInfo.put(packageUid, new PackageCompatStateInfo());
+ }
+ final PackageCompatStateInfo compatStateInfo = mPackageUidToCompatStateInfo.get(packageUid);
+ final int lastLoggedState = compatStateInfo.mLastLoggedState;
+ final ActivityRecord lastLoggedActivity = compatStateInfo.mLastLoggedActivity;
+
+ final boolean isVisible = state != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+ final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
+ if (isVisible && !visibleActivities.contains(activity)) {
+ visibleActivities.add(activity);
+ } else if (!isVisible) {
+ visibleActivities.remove(activity);
+ if (visibleActivities.isEmpty()) {
+ // No need to keep the entry if there are no visible activities.
+ mPackageUidToCompatStateInfo.remove(packageUid);
+ }
+ }
+
+ if (state == lastLoggedState) {
+ // We don’t want to log the same state twice or log DEFAULT_NOT_VISIBLE before any
+ // visible state was logged.
+ return;
+ }
+
+ if (!isVisible && !visibleActivities.isEmpty()) {
+ // There is another visible activity for this package UID.
+ if (activity == lastLoggedActivity) {
+ // Make sure a new visible state is logged if needed.
+ findAppCompatStateToLog(compatStateInfo, packageUid);
+ }
+ return;
+ }
+
+ if (activity != lastLoggedActivity
+ && lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE
+ && lastLoggedState != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED) {
+ // Another visible activity for this package UID has logged a letterboxed state.
+ return;
+ }
+
+ logAppCompatStateInternal(activity, state, packageUid, compatStateInfo);
+ }
+
+ /**
+ * Looks for the first visible activity in {@code compatStateInfo} that has a letterboxed
+ * state, or a non-letterboxed state if there isn't one, and logs that state for the given
+ * {@code packageUid}.
+ */
+ private void findAppCompatStateToLog(PackageCompatStateInfo compatStateInfo, int packageUid) {
+ final ArrayList<ActivityRecord> visibleActivities = compatStateInfo.mVisibleActivities;
+
+ ActivityRecord activityToLog = null;
+ int stateToLog = APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+ for (int i = 0; i < visibleActivities.size(); i++) {
+ ActivityRecord activity = visibleActivities.get(i);
+ int state = activity.getAppCompatState();
+ if (state == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
+ // This shouldn't happen.
+ Slog.w(TAG, "Visible activity with NOT_VISIBLE App Compat state for package UID: "
+ + packageUid);
+ continue;
+ }
+ if (stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE || (
+ stateToLog == APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED
+ && state != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED)) {
+ activityToLog = activity;
+ stateToLog = state;
+ }
+ }
+ if (activityToLog != null && stateToLog != APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE) {
+ logAppCompatStateInternal(activityToLog, stateToLog, packageUid, compatStateInfo);
+ }
+ }
+
+ private void logAppCompatStateInternal(@NonNull ActivityRecord activity, int state,
+ int packageUid, PackageCompatStateInfo compatStateInfo) {
+ compatStateInfo.mLastLoggedState = state;
+ compatStateInfo.mLastLoggedActivity = activity;
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPAT_STATE_CHANGED, packageUid, state);
+
+ if (DEBUG_METRICS) {
+ Slog.i(TAG, String.format("APP_COMPAT_STATE_CHANGED(%s, %s)", packageUid, state));
+ }
+ }
+
private ArtManagerInternal getArtManagerInternal() {
if (mArtManagerInternal == null) {
// Note that this may be null.
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 3625c7a..cf6a38f 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -127,6 +127,11 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STATES;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SWITCH;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityRecord.State.DESTROYED;
@@ -3935,7 +3940,9 @@
if (tStartingWindow != null && fromActivity.mStartingSurface != null) {
// In this case, the starting icon has already been displayed, so start
// letting windows get shown immediately without any more transitions.
- getDisplayContent().mSkipAppTransitionAnimation = true;
+ if (fromActivity.mVisible) {
+ mDisplayContent.mSkipAppTransitionAnimation = true;
+ }
ProtoLog.v(WM_DEBUG_STARTING_WINDOW, "Moving existing starting %s"
+ " from %s to %s", tStartingWindow, fromActivity, this);
@@ -4690,6 +4697,7 @@
ActivityTaskManagerService.LAYOUT_REASON_VISIBILITY_CHANGED);
mTaskSupervisor.getActivityMetricsLogger().notifyVisibilityChanged(this);
mTaskSupervisor.mAppVisibilitiesChangedSinceLastPause = true;
+ logAppCompatState();
}
@VisibleForTesting
@@ -7438,6 +7446,8 @@
}
resolvedConfig.windowConfiguration.setMaxBounds(mTmpBounds);
}
+
+ logAppCompatState();
}
/**
@@ -7447,18 +7457,55 @@
* LetterboxUiController#shouldShowLetterboxUi} for more context.
*/
boolean areBoundsLetterboxed() {
+ return getAppCompatState(/* ignoreVisibility= */ true)
+ != APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+ }
+
+ /**
+ * Logs the current App Compat state via {@link ActivityMetricsLogger#logAppCompatState}.
+ */
+ private void logAppCompatState() {
+ mTaskSupervisor.getActivityMetricsLogger().logAppCompatState(this);
+ }
+
+ /**
+ * Returns the current App Compat state of this activity.
+ *
+ * <p>The App Compat state indicates whether the activity is visible and letterboxed, and if so
+ * what is the reason for letterboxing. The state is used for logging the time spent in
+ * letterbox (sliced by the reason) vs non-letterbox per app.
+ */
+ int getAppCompatState() {
+ return getAppCompatState(/* ignoreVisibility= */ false);
+ }
+
+ /**
+ * Same as {@link #getAppCompatState()} except when {@code ignoreVisibility} the visibility
+ * of the activity is ignored.
+ *
+ * @param ignoreVisibility whether to ignore the visibility of the activity and not return
+ * NOT_VISIBLE if {@code mVisibleRequested} is false.
+ */
+ private int getAppCompatState(boolean ignoreVisibility) {
+ if (!ignoreVisibility && !mVisibleRequested) {
+ return APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
+ }
if (mInSizeCompatModeForBounds) {
- return true;
+ return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
}
// Letterbox for fixed orientation. This check returns true only when an activity is
// letterboxed for fixed orientation. Aspect ratio restrictions are also applied if
// present. But this doesn't return true when the activity is letterboxed only because
// of aspect ratio restrictions.
if (isLetterboxedForFixedOrientationAndAspectRatio()) {
- return true;
+ return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
}
// Letterbox for limited aspect ratio.
- return mIsAspectRatioApplied;
+ if (mIsAspectRatioApplied) {
+ return APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
+ }
+
+ return APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
}
/**
@@ -9220,6 +9267,11 @@
super.finishSync(outMergedTransaction, cancel);
}
+ @Override
+ boolean canBeAnimationTarget() {
+ return true;
+ }
+
static class Builder {
private final ActivityTaskManagerService mAtmService;
private WindowProcessController mCallerApp;
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index f6757f5..af538272 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -1798,7 +1798,7 @@
mRootWindowContainer.startPowerModeLaunchIfNeeded(
false /* forceSend */, mStartActivity);
- final boolean isTaskSwitch = startedTask != prevTopTask;
+ final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
mTargetRootTask.startActivityLocked(mStartActivity,
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
isTaskSwitch, mOptions, sourceRecord);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 174b396..6aea848 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -40,6 +40,8 @@
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
@@ -1005,6 +1007,21 @@
animAttr = enter
? WindowAnimation_launchTaskBehindSourceAnimation
: WindowAnimation_launchTaskBehindTargetAnimation;
+ break;
+ // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
+ // need new TaskFragment transition.
+ case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
+ animAttr = enter
+ ? WindowAnimation_activityOpenEnterAnimation
+ : WindowAnimation_activityOpenExitAnimation;
+ break;
+ // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
+ // need new TaskFragment transition.
+ case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
+ animAttr = enter
+ ? WindowAnimation_activityCloseEnterAnimation
+ : WindowAnimation_activityCloseExitAnimation;
+ break;
}
a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null;
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
@@ -1315,6 +1332,12 @@
case TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE: {
return "TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE";
}
+ case TRANSIT_OLD_TASK_FRAGMENT_OPEN: {
+ return "TRANSIT_OLD_TASK_FRAGMENT_OPEN";
+ }
+ case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: {
+ return "TRANSIT_OLD_TASK_FRAGMENT_CLOSE";
+ }
default: {
return "<UNKNOWN: " + transition + ">";
}
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index d6b0086..6745c69 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -39,6 +39,8 @@
import static android.view.WindowManager.TRANSIT_OLD_NONE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
@@ -68,6 +70,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.os.Trace;
import android.util.ArrayMap;
@@ -86,6 +89,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.function.Predicate;
@@ -102,6 +107,20 @@
private RemoteAnimationDefinition mRemoteAnimationDefinition = null;
private static final int KEYGUARD_GOING_AWAY_ANIMATION_DURATION = 400;
+ private static final int TYPE_NONE = 0;
+ private static final int TYPE_ACTIVITY = 1;
+ private static final int TYPE_TASK_FRAGMENT = 2;
+ private static final int TYPE_TASK = 3;
+
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_NONE,
+ TYPE_ACTIVITY,
+ TYPE_TASK_FRAGMENT,
+ TYPE_TASK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface TransitContainerType {}
+
private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>();
AppTransitionController(WindowManagerService service, DisplayContent displayContent) {
@@ -387,33 +406,38 @@
openingApps, closingApps, true /* visible */);
final ArraySet<WindowContainer> closingWcs = getAnimationTargets(
openingApps, closingApps, false /* visible */);
- final boolean isActivityOpening = !openingWcs.isEmpty()
- && openingWcs.valueAt(0).asActivityRecord() != null;
- final boolean isActivityClosing = !closingWcs.isEmpty()
- && closingWcs.valueAt(0).asActivityRecord() != null;
- final boolean isTaskOpening = !openingWcs.isEmpty() && !isActivityOpening;
- final boolean isTaskClosing = !closingWcs.isEmpty() && !isActivityClosing;
-
- if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && isTaskOpening) {
+ final WindowContainer<?> openingContainer = !openingWcs.isEmpty()
+ ? openingWcs.valueAt(0) : null;
+ final WindowContainer<?> closingContainer = !closingWcs.isEmpty()
+ ? closingWcs.valueAt(0) : null;
+ @TransitContainerType int openingType = getTransitContainerType(openingContainer);
+ @TransitContainerType int closingType = getTransitContainerType(closingContainer);
+ if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && openingType == TYPE_TASK) {
return TRANSIT_OLD_TASK_TO_FRONT;
}
- if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && isTaskClosing) {
+ if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && closingType == TYPE_TASK) {
return TRANSIT_OLD_TASK_TO_BACK;
}
if (appTransition.containsTransitRequest(TRANSIT_OPEN)) {
- if (isTaskOpening) {
+ if (openingType == TYPE_TASK) {
return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0
? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN;
}
- if (isActivityOpening) {
+ if (openingType == TYPE_ACTIVITY) {
return TRANSIT_OLD_ACTIVITY_OPEN;
}
+ if (openingType == TYPE_TASK_FRAGMENT) {
+ return TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+ }
}
if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) {
- if (isTaskClosing) {
+ if (closingType == TYPE_TASK) {
return TRANSIT_OLD_TASK_CLOSE;
}
- if (isActivityClosing) {
+ if (closingType == TYPE_TASK_FRAGMENT) {
+ return TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+ }
+ if (closingType == TYPE_ACTIVITY) {
for (int i = closingApps.size() - 1; i >= 0; i--) {
if (closingApps.valueAt(i).visibleIgnoringKeyguard) {
return TRANSIT_OLD_ACTIVITY_CLOSE;
@@ -430,6 +454,23 @@
return TRANSIT_OLD_NONE;
}
+ @TransitContainerType
+ private static int getTransitContainerType(@Nullable WindowContainer<?> container) {
+ if (container == null) {
+ return TYPE_NONE;
+ }
+ if (container.asTask() != null) {
+ return TYPE_TASK;
+ }
+ if (container.asTaskFragment() != null) {
+ return TYPE_TASK_FRAGMENT;
+ }
+ if (container.asActivityRecord() != null) {
+ return TYPE_ACTIVITY;
+ }
+ return TYPE_NONE;
+ }
+
private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) {
final WindowState mainWindow = activity != null ? activity.findMainWindow() : null;
return mainWindow != null ? mainWindow.mAttrs : null;
@@ -633,6 +674,7 @@
boolean canPromote = true;
if (parent == null || !parent.canCreateRemoteAnimationTarget()
+ || !parent.canBeAnimationTarget()
// We cannot promote the animation on Task's parent when the task is in
// clearing task in case the animating get stuck when performing the opening
// task that behind it.
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 1a429f8..6b57ede 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -396,6 +396,7 @@
RemoteAnimationTarget mTarget;
final WindowContainer mWindowContainer;
final Rect mStartBounds;
+ private @RemoteAnimationTarget.Mode int mMode = RemoteAnimationTarget.MODE_CHANGING;
RemoteAnimationRecord(WindowContainer windowContainer, Point endPos, Rect localBounds,
Rect endBounds, Rect startBounds) {
@@ -428,18 +429,12 @@
return mTarget;
}
+ void setMode(@RemoteAnimationTarget.Mode int mode) {
+ mMode = mode;
+ }
+
int getMode() {
- final DisplayContent dc = mWindowContainer.getDisplayContent();
- final ActivityRecord topActivity = mWindowContainer.getTopMostActivity();
- // Note that opening/closing transitions are per-activity while changing transitions
- // are per-task.
- if (dc.mOpeningApps.contains(topActivity)) {
- return RemoteAnimationTarget.MODE_OPENING;
- } else if (dc.mChangingContainers.contains(mWindowContainer)) {
- return RemoteAnimationTarget.MODE_CHANGING;
- } else {
- return RemoteAnimationTarget.MODE_CLOSING;
- }
+ return mMode;
}
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 6e4792bd..5363c9b 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -324,6 +324,7 @@
// Reset the adjacent TaskFragment if its adjacent TaskFragment is also this TaskFragment.
if (mAdjacentTaskFragment != null && mAdjacentTaskFragment.mAdjacentTaskFragment == this) {
mAdjacentTaskFragment.mAdjacentTaskFragment = null;
+ mAdjacentTaskFragment.mDelayLastActivityRemoval = false;
}
mAdjacentTaskFragment = null;
mDelayLastActivityRemoval = false;
@@ -1616,7 +1617,12 @@
@Override
RemoteAnimationTarget createRemoteAnimationTarget(
RemoteAnimationController.RemoteAnimationRecord record) {
- final ActivityRecord activity = getTopMostActivity();
+ final ActivityRecord activity = record.getMode() == RemoteAnimationTarget.MODE_OPENING
+ // There may be a trampoline activity without window on top of the existing task
+ // which is moving to front. Exclude the finishing activity so the window of next
+ // activity can be chosen to create the animation target.
+ ? getTopNonFinishingActivity()
+ : getTopMostActivity();
return activity != null ? activity.createRemoteAnimationTarget(record) : null;
}
@@ -2149,6 +2155,11 @@
sendTaskFragmentVanished();
}
+ @Override
+ boolean canBeAnimationTarget() {
+ return true;
+ }
+
boolean dump(String prefix, FileDescriptor fd, PrintWriter pw, boolean dumpAll,
boolean dumpClient, String dumpPackage, final boolean needSep, Runnable header) {
boolean printed = false;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index c48e9d1..b6c8e13 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -2689,6 +2689,11 @@
final RemoteAnimationController.RemoteAnimationRecord adapters =
controller.createRemoteAnimationRecord(this, mTmpPoint, localBounds,
screenBounds, (isChanging ? mSurfaceFreezer.mFreezeBounds : null));
+ if (!isChanging) {
+ adapters.setMode(enter
+ ? RemoteAnimationTarget.MODE_OPENING
+ : RemoteAnimationTarget.MODE_CLOSING);
+ }
resultAdapters = new Pair<>(adapters.mAdapter, adapters.mThumbnailAdapter);
} else if (isChanging) {
final float durationScale = mWmService.getTransitionAnimationScaleLocked();
@@ -2842,6 +2847,14 @@
return false;
}
+ /**
+ * {@code true} to indicate that this container can be a candidate of
+ * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) animation
+ * target}. */
+ boolean canBeAnimationTarget() {
+ return false;
+ }
+
boolean okToDisplay() {
final DisplayContent dc = getDisplayContent();
return dc != null && dc.okToDisplay();
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b98debc..a9ddd35 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -10110,7 +10110,7 @@
}
@Override
- public boolean setPermittedAccessibilityServices(ComponentName who, List packageList) {
+ public boolean setPermittedAccessibilityServices(ComponentName who, List<String> packageList) {
if (!mHasFeature) {
return false;
}
@@ -10162,7 +10162,7 @@
}
@Override
- public List getPermittedAccessibilityServices(ComponentName who) {
+ public List<String> getPermittedAccessibilityServices(ComponentName who) {
if (!mHasFeature) {
return null;
}
@@ -10177,7 +10177,7 @@
}
@Override
- public List getPermittedAccessibilityServicesForUser(int userId) {
+ public List<String> getPermittedAccessibilityServicesForUser(int userId) {
if (!mHasFeature) {
return null;
}
@@ -10263,7 +10263,7 @@
}
@Override
- public boolean setPermittedInputMethods(ComponentName who, List packageList,
+ public boolean setPermittedInputMethods(ComponentName who, List<String> packageList,
boolean calledOnParentInstance) {
if (!mHasFeature) {
return false;
@@ -10327,7 +10327,8 @@
}
@Override
- public List getPermittedInputMethods(ComponentName who, boolean calledOnParentInstance) {
+ public List<String> getPermittedInputMethods(ComponentName who,
+ boolean calledOnParentInstance) {
if (!mHasFeature) {
return null;
}
@@ -10348,7 +10349,7 @@
}
@Override
- public List getPermittedInputMethodsForCurrentUser() {
+ public List<String> getPermittedInputMethodsForCurrentUser() {
final CallerIdentity caller = getCallerIdentity();
Preconditions.checkCallAuthorization(canManageUsers(caller));
diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
index be942d6..9bc20a7 100644
--- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java
@@ -829,7 +829,7 @@
assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting,
actorSetting, SYSTEM_USER));
- appsFilter.removePackage(targetSetting);
+ appsFilter.removePackage(targetSetting, false /* isReplace */);
// Actor loses visibility to the overlay via removal of the target
assertTrue(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting,
@@ -1074,7 +1074,8 @@
watcher.verifyNoChangeReported("getVisibility");
// provider read
- appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+ appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId,
+ false /* retainOnUpdate */);
watcher.verifyChangeReported("grantImplicitAccess");
// ensure implicit access is included in the filter
@@ -1143,7 +1144,8 @@
watcher.verifyNoChangeReported("get");
// provider read
- appsFilter.grantImplicitAccess(hasProviderAppId, queriesProviderAppId);
+ appsFilter.grantImplicitAccess(
+ hasProviderAppId, queriesProviderAppId, false /* retainOnUpdate */);
watcher.verifyChangeReported("grantImplicitAccess");
// ensure implicit access is included in the filter
@@ -1154,7 +1156,7 @@
watcher.verifyNoChangeReported("get");
// remove a package
- appsFilter.removePackage(seesNothing);
+ appsFilter.removePackage(seesNothing, false /* isReplace */);
watcher.verifyChangeReported("removePackage");
}
diff --git a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
index 25b51da..e418d2f 100644
--- a/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/uri/UriGrantsManagerServiceTest.java
@@ -73,8 +73,8 @@
// we expect the following only during grant if a grant is expected
private void verifyNoVisibilityGrant() {
- verify(mContext.mPmInternal, never())
- .grantImplicitAccess(anyInt(), any(), anyInt(), anyInt(), anyBoolean());
+ verify(mContext.mPmInternal, never()).grantImplicitAccess(
+ anyInt(), any(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
}
@Before
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index 733d3f0..9dca235 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import static android.service.notification.ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
+
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertNull;
@@ -36,13 +38,10 @@
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.util.FastXmlSerializer;
import com.android.server.UiServiceTestCase;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlSerializer;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -81,10 +80,12 @@
ZenModeConfig config = getMutedAllConfig();
config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE;
+ // Explicitly allow conversations from priority senders to make sure that goes through
ZenPolicy zenPolicy = new ZenPolicy.Builder()
.allowAlarms(true)
.allowReminders(true)
.allowEvents(true)
+ .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
.showLights(false)
.showInAmbientDisplay(false)
.build();
@@ -93,11 +94,12 @@
int priorityCategories = originalPolicy.priorityCategories;
int priorityCallSenders = originalPolicy.priorityCallSenders;
int priorityMessageSenders = originalPolicy.priorityMessageSenders;
- int priorityConversationsSenders = originalPolicy.priorityConversationSenders;
+ int priorityConversationsSenders = CONVERSATION_SENDERS_IMPORTANT;
int suppressedVisualEffects = originalPolicy.suppressedVisualEffects;
priorityCategories |= Policy.PRIORITY_CATEGORY_ALARMS;
priorityCategories |= Policy.PRIORITY_CATEGORY_REMINDERS;
priorityCategories |= Policy.PRIORITY_CATEGORY_EVENTS;
+ priorityCategories |= Policy.PRIORITY_CATEGORY_CONVERSATIONS;
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT;
@@ -344,7 +346,7 @@
config.allowCallsFrom = ZenModeConfig.SOURCE_ANYONE;
config.allowMessagesFrom = ZenModeConfig.SOURCE_ANYONE;
config.allowConversations = true;
- config.allowConversationsFrom = ZenPolicy.CONVERSATION_SENDERS_IMPORTANT;
+ config.allowConversationsFrom = CONVERSATION_SENDERS_IMPORTANT;
config.suppressedVisualEffects = 0;
return config;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index 89a126b..0b91802 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -476,6 +476,16 @@
}
@Test
+ public void testConsecutiveLaunch() {
+ mTrampolineActivity.setState(ActivityRecord.State.INITIALIZING, "test");
+ onActivityLaunched(mTrampolineActivity);
+ mActivityMetricsLogger.notifyActivityLaunching(mTopActivity.intent,
+ mTrampolineActivity /* caller */, mTrampolineActivity.getUid());
+ notifyActivityLaunched(START_SUCCESS, mTopActivity);
+ transitToDrawnAndVerifyOnLaunchFinished(mTopActivity);
+ }
+
+ @Test
public void testConsecutiveLaunchNewTask() {
final IBinder launchCookie = mock(IBinder.class);
final WindowContainerToken launchRootTask = mock(WindowContainerToken.class);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index e717c34..9ad479a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -219,7 +219,7 @@
public void testNoCleanupMovingActivityInSameStack() {
final ActivityRecord activity = createActivityWith2LevelTask();
final Task rootTask = activity.getRootTask();
- final Task newTask = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask).build();
+ final Task newTask = createTaskInRootTask(rootTask, 0 /* userId */);
activity.reparent(newTask, 0, null /*reason*/);
verify(rootTask, times(0)).cleanUpActivityReferences(any());
}
@@ -2510,8 +2510,10 @@
@Test
public void testTransferStartingWindow() {
registerTestStartingWindowOrganizer();
- final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true).build();
- final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true).build();
+ final ActivityRecord activity1 = new ActivityBuilder(mAtm).setCreateTask(true)
+ .setVisible(false).build();
+ final ActivityRecord activity2 = new ActivityBuilder(mAtm).setCreateTask(true)
+ .setVisible(false).build();
activity1.addStartingWindow(mPackageName,
android.R.style.Theme, null, "Test", 0, 0, 0, 0, null, true, true, false, true,
false, false);
@@ -2520,6 +2522,7 @@
android.R.style.Theme, null, "Test", 0, 0, 0, 0, activity1,
true, true, false, true, false, false);
waitUntilHandlersIdle();
+ assertFalse(mDisplayContent.mSkipAppTransitionAnimation);
assertNoStartingWindow(activity1);
assertHasStartingWindow(activity2);
}
@@ -2627,6 +2630,7 @@
false /* newTask */, false /* isTaskSwitch */, null /* options */,
null /* sourceRecord */);
+ assertTrue(mDisplayContent.mSkipAppTransitionAnimation);
assertNull(middle.mStartingWindow);
assertHasStartingWindow(top);
assertTrue(top.isVisible());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 1b4d0a4..3e8a2e9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -478,7 +478,7 @@
final ActivityRecord splitSecondActivity =
new ActivityBuilder(mAtm).setCreateTask(true).build();
final ActivityRecord splitPrimaryActivity = new TaskBuilder(mSupervisor)
- .setParentTask(splitOrg.mPrimary)
+ .setParentTaskFragment(splitOrg.mPrimary)
.setCreateActivity(true)
.build()
.getTopMostActivity();
@@ -856,7 +856,7 @@
// Create another activity on top of the secondary display.
final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build();
+ final Task topTask = new TaskBuilder(mSupervisor).setParentTaskFragment(topStack).build();
new ActivityBuilder(mAtm).setTask(topTask).build();
doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger();
@@ -920,7 +920,7 @@
DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity");
final Task task = new TaskBuilder(mSupervisor)
.setComponent(componentName)
- .setParentTask(stack)
+ .setParentTaskFragment(stack)
.build();
return new ActivityBuilder(mAtm)
.setComponent(componentName)
@@ -1056,8 +1056,8 @@
final ActivityStarter starter = prepareStarter(0 /* flags */);
starter.mStartActivity = new ActivityBuilder(mAtm).build();
final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
- .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
- WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */))
+ .setParentTaskFragment(createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
+ ACTIVITY_TYPE_STANDARD))
.setUserId(10)
.build();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index 3a6aac9..11e3fd4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -375,7 +375,7 @@
final ArraySet<ActivityRecord> closing = new ArraySet<>();
closing.add(activity3);
- // Promote animation targets to TaskStack level. Invisible ActivityRecords don't affect
+ // Promote animation targets to root Task level. Invisible ActivityRecords don't affect
// promotion decision.
assertEquals(
new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}),
@@ -520,6 +520,128 @@
opening, closing, false /* visible */));
}
+ @Test
+ public void testGetAnimationTargets_openingClosingTaskFragment() {
+ // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible)
+ // +- [TaskFragment2] - [ActivityRecord2] (closing, visible)
+ final Task parentTask = createTask(mDisplayContent);
+ final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(parentTask,
+ false /* createEmbeddedTask */);
+ final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+ activity1.setVisible(false);
+ activity1.mVisibleRequested = true;
+
+ final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(parentTask,
+ false /* createEmbeddedTask */);
+ final ActivityRecord activity2 = taskFragment2.getTopMostActivity();
+ activity2.setVisible(true);
+ activity2.mVisibleRequested = false;
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity1);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+ closing.add(activity2);
+
+ // Promote animation targets up to TaskFragment level, not beyond.
+ assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, false /* visible */));
+ }
+
+ @Test
+ public void testGetAnimationTargets_openingClosingTaskFragmentWithEmbeddedTask() {
+ // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible)
+ // +- [TaskFragment2] - [ActivityRecord2] (closing, visible)
+ final Task parentTask = createTask(mDisplayContent);
+ final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(parentTask,
+ true /* createEmbeddedTask */);
+ final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+ activity1.setVisible(false);
+ activity1.mVisibleRequested = true;
+
+ final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(parentTask,
+ true /* createEmbeddedTask */);
+ final ActivityRecord activity2 = taskFragment2.getTopMostActivity();
+ activity2.setVisible(true);
+ activity2.mVisibleRequested = false;
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity1);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+ closing.add(activity2);
+
+ // Promote animation targets up to TaskFragment level, not beyond.
+ assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, false /* visible */));
+ }
+
+ @Test
+ public void testGetAnimationTargets_openingTheOnlyTaskFragmentInTask() {
+ // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (opening, invisible)
+ // +- [Task2] - [ActivityRecord2] (closing, visible)
+ final Task task1 = createTask(mDisplayContent);
+ final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task1,
+ false /* createEmbeddedTask */);
+ final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+ activity1.setVisible(false);
+ activity1.mVisibleRequested = true;
+
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
+ activity2.setVisible(true);
+ activity2.mVisibleRequested = false;
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity1);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+ closing.add(activity2);
+
+ // Promote animation targets up to leaf Task level because there's only one TaskFragment in
+ // the Task.
+ assertEquals(new ArraySet<>(new WindowContainer[]{task1}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, false /* visible */));
+ }
+
+ @Test
+ public void testGetAnimationTargets_closingTheOnlyTaskFragmentInTask() {
+ // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (closing, visible)
+ // +- [Task2] - [ActivityRecord2] (opening, invisible)
+ final Task task1 = createTask(mDisplayContent);
+ final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task1,
+ false /* createEmbeddedTask */);
+ final ActivityRecord activity1 = taskFragment1.getTopMostActivity();
+ activity1.setVisible(true);
+ activity1.mVisibleRequested = false;
+
+ final ActivityRecord activity2 = createActivityRecord(mDisplayContent);
+ activity2.setVisible(false);
+ activity2.mVisibleRequested = true;
+
+ final ArraySet<ActivityRecord> opening = new ArraySet<>();
+ opening.add(activity2);
+ final ArraySet<ActivityRecord> closing = new ArraySet<>();
+ closing.add(activity1);
+
+ // Promote animation targets up to leaf Task level because there's only one TaskFragment in
+ // the Task.
+ assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, true /* visible */));
+ assertEquals(new ArraySet<>(new WindowContainer[]{task1}),
+ AppTransitionController.getAnimationTargets(
+ opening, closing, false /* visible */));
+ }
+
static class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
@Override
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index c3279bf..67aac13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -23,6 +23,8 @@
import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_UNSET;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -40,6 +42,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.util.ArraySet;
import android.view.Display;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -147,6 +150,91 @@
}
@Test
+ public void testTaskFragmentOpeningTransition() {
+ final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+ false /* createEmbeddedTask */);
+ activity.setVisible(false);
+
+ mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
+ mDisplayContent.mOpeningApps.add(activity);
+ assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /* skipAppTransitionAnimation */));
+ }
+
+ @Test
+ public void testEmbeddedTaskOpeningTransition() {
+ final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+ true /* createEmbeddedTask */);
+ activity.setVisible(false);
+
+ mDisplayContent.prepareAppTransition(TRANSIT_OPEN);
+ mDisplayContent.mOpeningApps.add(activity);
+ assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /* skipAppTransitionAnimation */));
+ }
+
+ @Test
+ public void testTaskFragmentClosingTransition() {
+ final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+ false /* createEmbeddedTask */);
+ activity.setVisible(true);
+
+ mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+ mDisplayContent.mClosingApps.add(activity);
+ assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /* skipAppTransitionAnimation */));
+ }
+
+ @Test
+ public void testEmbeddedTaskClosingTransition() {
+ final ActivityRecord activity = createHierarchyForTaskFragmentTest(
+ true /* createEmbeddedTask */);
+ activity.setVisible(true);
+
+ mDisplayContent.prepareAppTransition(TRANSIT_CLOSE);
+ mDisplayContent.mClosingApps.add(activity);
+ assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE,
+ AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition,
+ mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps,
+ null /* wallpaperTarget */, null /* oldWallpaper */,
+ false /* skipAppTransitionAnimation */));
+ }
+
+ /**
+ * Creates a {@link Task} with two {@link TaskFragment TaskFragments}.
+ * The bottom TaskFragment is to prevent
+ * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) the animation
+ * target} to promote to Task or above.
+ *
+ * @param createEmbeddedTask {@code true} to create embedded Task for verified TaskFragment
+ * @return The Activity to be put in either opening or closing Activity
+ */
+ private ActivityRecord createHierarchyForTaskFragmentTest(boolean createEmbeddedTask) {
+ final Task parentTask = createTask(mDisplayContent);
+ final TaskFragment bottomTaskFragment = createTaskFragmentWithParentTask(parentTask,
+ false /* createEmbeddedTask */);
+ final ActivityRecord bottomActivity = bottomTaskFragment.getTopMostActivity();
+ bottomActivity.setOccludesParent(true);
+ bottomActivity.setVisible(true);
+
+ final TaskFragment verifiedTaskFragment = createTaskFragmentWithParentTask(parentTask,
+ createEmbeddedTask);
+ final ActivityRecord activity = verifiedTaskFragment.getTopMostActivity();
+ activity.setOccludesParent(true);
+
+ return activity;
+ }
+
+ @Test
public void testAppTransitionStateForMultiDisplay() {
// Create 2 displays & presume both display the state is ON for ready to display & animate.
final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 473d303..14dc33e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -2352,10 +2352,10 @@
ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task rootTask4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, ON_TOP);
- final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask1).build();
- final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask2).build();
- final Task task3 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask3).build();
- final Task task4 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask4).build();
+ final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask1).build();
+ final Task task2 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask2).build();
+ final Task task3 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask3).build();
+ final Task task4 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask4).build();
// Reordering root tasks while removing root tasks.
doAnswer(invocation -> {
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 7cb7c79d..8a6db2c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -117,7 +117,7 @@
Task rootTask = mTestDisplay.getDefaultTaskDisplayArea()
.createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true);
mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT)
- .setParentTask(rootTask).build();
+ .setParentTaskFragment(rootTask).build();
mTestTask.mUserId = TEST_USER_ID;
mTestTask.mLastNonFullscreenBounds = TEST_BOUNDS;
mTestTask.setHasBeenVisible(true);
@@ -353,7 +353,7 @@
final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor)
.setComponent(ALTERNATIVE_COMPONENT)
.setUserId(TEST_USER_ID)
- .setParentTask(stack)
+ .setParentTaskFragment(stack)
.build();
anotherTaskOfTheSameUser.setWindowingMode(WINDOWING_MODE_FREEFORM);
anotherTaskOfTheSameUser.setBounds(200, 300, 400, 500);
@@ -365,7 +365,7 @@
final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor)
.setComponent(TEST_COMPONENT)
.setUserId(ALTERNATIVE_USER_ID)
- .setParentTask(stack)
+ .setParentTaskFragment(stack)
.build();
anotherTaskOfDifferentUser.setWindowingMode(WINDOWING_MODE_FREEFORM);
anotherTaskOfDifferentUser.setBounds(300, 400, 500, 600);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
index 1b078b7..22e687a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java
@@ -331,7 +331,7 @@
// other task
Task task1 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
- .setParentTask(mTaskContainer.getRootHomeTask()).build();
+ .setParentTaskFragment(mTaskContainer.getRootHomeTask()).build();
Task task2 = createTaskBuilder(".Task1")
.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK)
.build();
@@ -471,8 +471,8 @@
final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build();
root.mCreatedByOrganizer = true;
// Add organized and non-organized child.
- final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build();
- final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build();
+ final Task child1 = createTaskBuilder(".Task1").setParentTaskFragment(root).build();
+ final Task child2 = createTaskBuilder(".Task2").setParentTaskFragment(root).build();
doReturn(true).when(child1).isOrganized();
doReturn(false).when(child2).isOrganized();
mRecentTasks.add(root);
@@ -508,7 +508,8 @@
// tasks because their intents are identical.
mRecentTasks.add(task1);
// Go home to trigger the removal of untracked tasks.
- mRecentTasks.add(createTaskBuilder(".Home").setParentTask(mTaskContainer.getRootHomeTask())
+ mRecentTasks.add(createTaskBuilder(".Home")
+ .setParentTaskFragment(mTaskContainer.getRootHomeTask())
.build());
triggerIdleToTrim();
@@ -675,7 +676,7 @@
public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() {
// Create some set of tasks, some of which are visible and some are not
Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
- .setParentTask(mTaskContainer.getRootHomeTask())
+ .setParentTaskFragment(mTaskContainer.getRootHomeTask())
.build();
homeTask.mUserSetupComplete = true;
mRecentTasks.add(homeTask);
@@ -696,7 +697,7 @@
t1.mUserSetupComplete = true;
mRecentTasks.add(t1);
Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask")
- .setParentTask(mTaskContainer.getRootHomeTask())
+ .setParentTaskFragment(mTaskContainer.getRootHomeTask())
.build();
homeTask.mUserSetupComplete = true;
mRecentTasks.add(homeTask);
@@ -949,10 +950,10 @@
// Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all
// the tasks belong in stacks above the home stack
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(aboveHomeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task3").setParentTask(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setParentTaskFragment(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task3").setParentTaskFragment(aboveHomeStack).build());
triggerTrimAndAssertNoTasksTrimmed();
}
@@ -970,11 +971,11 @@
// Add a number of tasks (beyond the max) but ensure that only the task in the stack behind
// the home stack is trimmed once a new task is added
final Task behindHomeTask = createTaskBuilder(".Task1")
- .setParentTask(behindHomeStack)
+ .setParentTaskFragment(behindHomeStack)
.build();
mRecentTasks.add(behindHomeTask);
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeStack).build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(aboveHomeStack).build());
triggerTrimAndAssertTrimmed(behindHomeTask);
}
@@ -990,10 +991,12 @@
// Add a number of tasks (beyond the max) on each display, ensure that the tasks are not
// removed
- mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeTask).build());
- mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayRootTask).build());
- mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayRootTask).build());
- mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeTask).build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeTask).build());
+ mRecentTasks.add(createTaskBuilder(".Task1").setParentTaskFragment(otherDisplayRootTask)
+ .build());
+ mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(otherDisplayRootTask)
+ .build());
+ mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTaskFragment(homeTask).build());
triggerTrimAndAssertNoTasksTrimmed();
}
@@ -1023,7 +1026,7 @@
Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build();
mRecentTasks.add(t1);
mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".HomeTask")
- .setParentTask(mTaskContainer.getRootHomeTask()).build());
+ .setParentTaskFragment(mTaskContainer.getRootHomeTask()).build());
Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build();
mRecentTasks.add(t2);
mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".PipTask")
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index b6cfa8e..89ae5ed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -51,6 +51,7 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.IRemoteAnimationFinishedCallback;
import android.view.IRemoteAnimationRunner;
@@ -274,6 +275,32 @@
}
@Test
+ public void testOpeningTaskWithTopFinishingActivity() {
+ final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "win");
+ final Task task = win.getTask();
+ final ActivityRecord topFinishing = new ActivityBuilder(mAtm).setTask(task).build();
+ // Now the task contains:
+ // - Activity[1] (top, finishing, no window)
+ // - Activity[0] (has window)
+ topFinishing.finishing = true;
+ spyOn(mDisplayContent.mAppTransition);
+ doReturn(mController).when(mDisplayContent.mAppTransition).getRemoteAnimationController();
+ task.applyAnimationUnchecked(null /* lp */, true /* enter */, TRANSIT_OLD_TASK_OPEN,
+ false /* isVoiceInteraction */, null /* sources */);
+ mController.goodToGo(TRANSIT_OLD_TASK_OPEN);
+ mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
+ final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
+ ArgumentCaptor.forClass(RemoteAnimationTarget[].class);
+ try {
+ verify(mMockRunner).onAnimationStart(eq(TRANSIT_OLD_TASK_OPEN),
+ appsCaptor.capture(), any(), any(), any());
+ } catch (RemoteException ignored) {
+ }
+ assertEquals(1, appsCaptor.getValue().length);
+ assertEquals(RemoteAnimationTarget.MODE_OPENING, appsCaptor.getValue()[0].mode);
+ }
+
+ @Test
public void testChangeToSmallerSize() throws Exception {
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
mDisplayContent.mChangingContainers.add(win.mActivityRecord);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
index 56d01cd..030733b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java
@@ -329,7 +329,7 @@
// Create primary splitscreen root task.
final Task primarySplitScreen = new TaskBuilder(mAtm.mTaskSupervisor)
- .setParentTask(organizer.mPrimary)
+ .setParentTaskFragment(organizer.mPrimary)
.setOnTop(true)
.build();
@@ -505,8 +505,8 @@
targetActivity);
final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME,
aliasActivity);
- final Task parentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
- final Task task = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(parentTask).build();
+ final Task parentTask = new TaskBuilder(mSupervisor).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(parentTask).build();
task.origActivity = alias;
task.realActivity = target;
new ActivityBuilder(mAtm).setComponent(target).setTask(task).setTargetActivity(
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 8d4acbb..f2eb709 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -168,7 +168,7 @@
@Test
public void testTaskLayerRank() {
final Task rootTask = new TaskBuilder(mSupervisor).build();
- final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
new ActivityBuilder(mAtm).setTask(task1).build().mVisibleRequested = true;
mWm.mRoot.rankTaskLayers();
@@ -523,7 +523,8 @@
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
ACTIVITY_TYPE_STANDARD, false /* onTop */);
- final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetRootTask).build();
+ final Task targetTask = new TaskBuilder(mSupervisor).setParentTaskFragment(targetRootTask)
+ .build();
// Create Recents on secondary display.
final TestDisplayContent secondDisplay = addNewDisplayContentAt(
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index c44c22f..cb85884 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -166,7 +166,7 @@
final Task task = new TaskBuilder(mAtm.mTaskSupervisor)
.setComponent(new ComponentName(mContext.getPackageName(), className))
.setTaskId(taskId)
- .setParentTask(stack)
+ .setParentTaskFragment(stack)
.build();
task.lastActiveTime = lastActiveTime;
final ActivityRecord activity = new ActivityBuilder(mAtm)
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 3bebf6b..6407c92 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -40,6 +40,11 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED;
+import static com.android.internal.util.FrameworkStatsLog.APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE;
import static com.android.server.wm.ActivityRecord.State.RESTARTING_PROCESS;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityRecord.State.STOPPED;
@@ -55,7 +60,9 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.same;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doCallRealMethod;
@@ -101,10 +108,14 @@
private Task mTask;
private ActivityRecord mActivity;
+ private ActivityMetricsLogger mActivityMetricsLogger;
private Properties mInitialConstrainDisplayApisFlags;
@Before
public void setUp() throws Exception {
+ mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
+ clearInvocations(mActivityMetricsLogger);
+ doReturn(mActivityMetricsLogger).when(mAtm.mTaskSupervisor).getActivityMetricsLogger();
mInitialConstrainDisplayApisFlags = DeviceConfig.getProperties(
NAMESPACE_CONSTRAIN_DISPLAY_APIS);
DeviceConfig.setProperties(
@@ -1939,13 +1950,19 @@
setUpDisplaySizeWithApp(1000, 2500);
assertFalse(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
prepareUnresizable(mActivity, /* maxAspect= */ 2, SCREEN_ORIENTATION_PORTRAIT);
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity,
+ APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
+
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
+ verifyLogAppCompatState(mActivity,
+ APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE);
rotateDisplay(mActivity.mDisplayContent, ROTATION_0);
// After returning to the original rotation, bounds are computed in
@@ -1955,6 +1972,18 @@
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity,
+ APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
+
+ // After setting the visibility of the activity to false, areBoundsLetterboxed() still
+ // returns true but the NOT_VISIBLE App Compat state is logged.
+ mActivity.setVisibility(false);
+ assertTrue(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_VISIBLE);
+ mActivity.setVisibility(true);
+ assertTrue(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity,
+ APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_ASPECT_RATIO);
}
@Test
@@ -1963,12 +1992,15 @@
mActivity.mDisplayContent.setIgnoreOrientationRequest(true /* ignoreOrientationRequest */);
assertFalse(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertTrue(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertFalse(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity,
+ APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_FIXED_ORIENTATION);
}
@Test
@@ -1978,12 +2010,15 @@
prepareUnresizable(mActivity, SCREEN_ORIENTATION_PORTRAIT);
assertFalse(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity, APP_COMPAT_STATE_CHANGED__STATE__NOT_LETTERBOXED);
rotateDisplay(mActivity.mDisplayContent, ROTATION_90);
assertFalse(mActivity.isLetterboxedForFixedOrientationAndAspectRatio());
assertTrue(mActivity.inSizeCompatMode());
assertTrue(mActivity.areBoundsLetterboxed());
+ verifyLogAppCompatState(mActivity,
+ APP_COMPAT_STATE_CHANGED__STATE__LETTERBOXED_FOR_SIZE_COMPAT_MODE);
}
/**
@@ -2197,6 +2232,11 @@
.isEqualTo(activity.getWindowConfiguration().getBounds());
}
+ private void verifyLogAppCompatState(ActivityRecord activity, int state) {
+ verify(mActivityMetricsLogger, atLeastOnce()).logAppCompatState(
+ argThat(r -> activity == r && r.getAppCompatState() == state));
+ }
+
static Configuration rotateDisplay(DisplayContent display, int rotation) {
final Configuration c = new Configuration();
display.getDisplayRotation().setRotation(rotation);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
index c45c18d..d68edba 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java
@@ -620,7 +620,7 @@
final Task pinnedRootTask = mRootWindowContainer.getDefaultTaskDisplayArea()
.createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP);
final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor)
- .setParentTask(pinnedRootTask).build();
+ .setParentTaskFragment(pinnedRootTask).build();
new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE)
.setTask(pinnedTask).build();
pinnedRootTask.moveToFront("movePinnedRootTaskToFront");
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 5e4c67c..e528a4a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -1716,7 +1716,7 @@
final Task rootTask = display.getDefaultTaskDisplayArea()
.createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true);
rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
- final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
// Just work around the unnecessary adjustments for bounds.
task.getWindowConfiguration().setBounds(bounds);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index 8074944..67e8c87 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -427,7 +427,7 @@
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM,
ACTIVITY_TYPE_STANDARD, true /* onTop */);
- Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
final Configuration parentConfig = rootTask.getConfiguration();
parentConfig.windowConfiguration.setBounds(parentBounds);
parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT;
@@ -757,7 +757,7 @@
DisplayInfo displayInfo = new DisplayInfo();
mAtm.mContext.getDisplay().getDisplayInfo(displayInfo);
final int displayHeight = displayInfo.logicalHeight;
- final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
final Configuration inOutConfig = new Configuration();
final Configuration parentConfig = new Configuration();
final int longSide = 1200;
@@ -1375,7 +1375,7 @@
TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea();
Task rootTask = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD,
true /* onTop */);
- Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build();
+ Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build();
final Configuration parentConfig = rootTask.getConfiguration();
parentConfig.windowConfiguration.setAppBounds(parentBounds);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 050fd80..e7ef6ae 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -56,6 +56,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
+import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN;
import static org.junit.Assert.assertEquals;
@@ -589,7 +590,7 @@
Task createTaskInRootTask(Task rootTask, int userId) {
final Task task = new TaskBuilder(rootTask.mTaskSupervisor)
.setUserId(userId)
- .setParentTask(rootTask)
+ .setParentTaskFragment(rootTask)
.build();
return task;
}
@@ -675,6 +676,26 @@
activity.mVisibleRequested = true;
}
+ /**
+ * Creates a {@link TaskFragment} and attach it to the {@code parentTask}.
+ *
+ * @param parentTask the {@link Task} this TaskFragment is going to be attached
+ * @param createEmbeddedTask Sets to {@code true} to create an embedded Task for this
+ * TaskFragment. Otherwise, create a {@link ActivityRecord}.
+ * @return the created TaskFragment
+ */
+ static TaskFragment createTaskFragmentWithParentTask(@NonNull Task parentTask,
+ boolean createEmbeddedTask) {
+ final TaskFragmentBuilder builder = new TaskFragmentBuilder(parentTask.mAtmService)
+ .setParentTask(parentTask);
+ if (createEmbeddedTask) {
+ builder.createEmbeddedTask();
+ } else {
+ builder.createActivityCount(1);
+ }
+ return builder.build();
+ }
+
/** Creates a {@link DisplayContent} that supports IME and adds it to the system. */
DisplayContent createNewDisplay() {
return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL);
@@ -1042,7 +1063,7 @@
// Apply the root activity info and intent
.setActivityInfo(aInfo)
.setIntent(intent)
- .setParentTask(mParentTask).build();
+ .setParentTaskFragment(mParentTask).build();
} else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateRootTask(
mParentTask.getWindowingMode(), mParentTask.getActivityType())) {
// The parent task can be the task root.
@@ -1101,6 +1122,64 @@
}
}
+ static class TaskFragmentBuilder {
+ private final ActivityTaskManagerService mAtm;
+ private Task mParentTask;
+ private boolean mCreateParentTask;
+ private boolean mCreateEmbeddedTask;
+ private int mCreateActivityCount = 0;
+
+ TaskFragmentBuilder(ActivityTaskManagerService service) {
+ mAtm = service;
+ }
+
+ TaskFragmentBuilder setCreateParentTask() {
+ mCreateParentTask = true;
+ return this;
+ }
+
+ TaskFragmentBuilder setParentTask(Task task) {
+ mParentTask = task;
+ return this;
+ }
+
+ /** Creates a child embedded Task and its Activity */
+ TaskFragmentBuilder createEmbeddedTask() {
+ mCreateEmbeddedTask = true;
+ return this;
+ }
+
+ TaskFragmentBuilder createActivityCount(int count) {
+ mCreateActivityCount = count;
+ return this;
+ }
+
+ TaskFragment build() {
+ SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
+
+ final TaskFragment taskFragment = new TaskFragment(mAtm, null /* fragmentToken */,
+ false /* createdByOrganizer */);
+ if (mParentTask == null && mCreateParentTask) {
+ mParentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
+ }
+ if (mParentTask != null) {
+ mParentTask.addChild(taskFragment, POSITION_TOP);
+ }
+ if (mCreateEmbeddedTask) {
+ new TaskBuilder(mAtm.mTaskSupervisor)
+ .setParentTaskFragment(taskFragment)
+ .setCreateActivity(true)
+ .build();
+ }
+ while (mCreateActivityCount > 0) {
+ final ActivityRecord activity = new ActivityBuilder(mAtm).build();
+ taskFragment.addChild(activity);
+ mCreateActivityCount--;
+ }
+ return taskFragment;
+ }
+ }
+
/**
* Builder for creating new tasks.
*/
@@ -1121,7 +1200,7 @@
private IVoiceInteractionSession mVoiceSession;
private boolean mCreateParentTask = false;
- private Task mParentTask;
+ private TaskFragment mParentTaskFragment;
private boolean mCreateActivity = false;
@@ -1205,8 +1284,8 @@
return this;
}
- TaskBuilder setParentTask(Task parentTask) {
- mParentTask = parentTask;
+ TaskBuilder setParentTaskFragment(TaskFragment parentTaskFragment) {
+ mParentTaskFragment = parentTaskFragment;
return this;
}
@@ -1219,12 +1298,13 @@
SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock);
// Create parent task.
- if (mParentTask == null && mCreateParentTask) {
- mParentTask = mTaskDisplayArea.createRootTask(
+ if (mParentTaskFragment == null && mCreateParentTask) {
+ mParentTaskFragment = mTaskDisplayArea.createRootTask(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
}
- if (mParentTask != null && !Mockito.mockingDetails(mParentTask).isSpy()) {
- spyOn(mParentTask);
+ if (mParentTaskFragment != null
+ && !Mockito.mockingDetails(mParentTaskFragment).isSpy()) {
+ spyOn(mParentTaskFragment);
}
// Create task.
@@ -1252,13 +1332,15 @@
.setOnTop(mOnTop)
.setVoiceSession(mVoiceSession);
final Task task;
- if (mParentTask == null) {
+ if (mParentTaskFragment == null) {
task = builder.setActivityType(mActivityType)
.setParent(mTaskDisplayArea)
.build();
} else {
- task = builder.setParent(mParentTask).build();
- mParentTask.moveToFront("build-task");
+ task = builder.setParent(mParentTaskFragment).build();
+ if (mParentTaskFragment.asTask() != null) {
+ mParentTaskFragment.asTask().moveToFront("build-task");
+ }
}
spyOn(task);
task.mUserId = mUserId;