summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java25
-rw-r--r--core/java/android/content/Context.java2
-rw-r--r--core/java/android/net/LocalSocket.java6
-rw-r--r--core/java/android/view/ViewRootImpl.java6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java37
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java2
-rw-r--r--libs/incident/libincident.map.txt20
-rw-r--r--media/TEST_MAPPING2
-rw-r--r--native/android/libandroid.map.txt8
-rw-r--r--packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml25
-rw-r--r--packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml30
-rw-r--r--packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml30
-rw-r--r--packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml37
-rw-r--r--packages/CredentialManager/res/values/colors.xml38
-rw-r--r--packages/CredentialManager/res/values/dimens.xml22
-rw-r--r--packages/CredentialManager/res/values/styles.xml38
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt77
-rw-r--r--packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt88
-rw-r--r--packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml2
-rw-r--r--packages/SystemUI/res/values/ids.xml2
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt22
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt111
-rw-r--r--packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt5
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt65
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt19
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java11
-rw-r--r--services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java8
-rw-r--r--services/core/java/com/android/server/os/BugreportManagerServiceImpl.java71
-rw-r--r--services/core/java/com/android/server/policy/PhoneWindowManager.java92
-rw-r--r--services/core/java/com/android/server/policy/WindowWakeUpPolicy.java176
-rw-r--r--services/credentials/java/com/android/server/credentials/CredentialManagerService.java4
-rw-r--r--services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java1
-rw-r--r--services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java6
-rw-r--r--services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java79
42 files changed, 893 insertions, 342 deletions
diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
index e5a06c9bd146..3c361d772d3d 100644
--- a/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
+++ b/apct-tests/perftests/core/src/android/graphics/perftests/CanvasPerfTest.java
@@ -16,12 +16,14 @@
package android.graphics.perftests;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Color;
+import android.graphics.ColorSpace;
import android.graphics.ImageDecoder;
import android.graphics.Paint;
import android.graphics.RecordingCanvas;
@@ -104,15 +106,36 @@ public class CanvasPerfTest {
}
@Test
- public void testCreateScaledBitmap() throws IOException {
+ public void testCreateScaledSrgbBitmap() throws IOException {
BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
final Context context = InstrumentationRegistry.getContext();
Bitmap source = ImageDecoder.decodeBitmap(
ImageDecoder.createSource(context.getResources(), R.drawable.fountain_night),
(decoder, info, source1) -> {
decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.SRGB));
});
source.setGainmap(null);
+ assertEquals(source.getColorSpace().getId(), ColorSpace.Named.SRGB.ordinal());
+
+ while (state.keepRunning()) {
+ Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true)
+ .recycle();
+ }
+ }
+
+ @Test
+ public void testCreateScaledP3Bitmap() throws IOException {
+ BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final Context context = InstrumentationRegistry.getContext();
+ Bitmap source = ImageDecoder.decodeBitmap(
+ ImageDecoder.createSource(context.getResources(), R.drawable.fountain_night),
+ (decoder, info, source1) -> {
+ decoder.setAllocator(ImageDecoder.ALLOCATOR_SOFTWARE);
+ decoder.setTargetColorSpace(ColorSpace.get(ColorSpace.Named.DISPLAY_P3));
+ });
+ source.setGainmap(null);
+ assertEquals(source.getColorSpace().getId(), ColorSpace.Named.DISPLAY_P3.ordinal());
while (state.keepRunning()) {
Bitmap.createScaledBitmap(source, source.getWidth() / 2, source.getHeight() / 2, true)
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index b75c64dcc3c1..fa76e3976a58 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3547,6 +3547,8 @@ public abstract class Context {
*
* @param receiver The BroadcastReceiver to unregister.
*
+ * @throws IllegalArgumentException if the {@code receiver} was not previously registered or
+ * already unregistered.
* @see #registerReceiver
*/
public abstract void unregisterReceiver(BroadcastReceiver receiver);
diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java
index b69410cf7d73..a86396cd7c8d 100644
--- a/core/java/android/net/LocalSocket.java
+++ b/core/java/android/net/LocalSocket.java
@@ -196,7 +196,8 @@ public class LocalSocket implements Closeable {
}
/**
- * Retrieves the input stream for this instance.
+ * Retrieves the input stream for this instance. Closing this stream is equivalent to closing
+ * the entire socket and its associated streams using {@link #close()}.
*
* @return input stream
* @throws IOException if socket has been closed or cannot be created.
@@ -207,7 +208,8 @@ public class LocalSocket implements Closeable {
}
/**
- * Retrieves the output stream for this instance.
+ * Retrieves the output stream for this instance. Closing this stream is equivalent to closing
+ * the entire socket and its associated streams using {@link #close()}.
*
* @return output stream
* @throws IOException if socket has been closed or cannot be created.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 1f81a6418962..fcdad6673fd0 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -11910,6 +11910,12 @@ public final class ViewRootImpl implements ViewParent,
if (syncBuffer) {
boolean result = mBlastBufferQueue.syncNextTransaction(transaction -> {
+ Runnable timeoutRunnable = () -> Log.e(mTag,
+ "Failed to submit the sync transaction after 4s. Likely to ANR "
+ + "soon");
+ mHandler.postDelayed(timeoutRunnable, 4L * Build.HW_TIMEOUT_MULTIPLIER);
+ transaction.addTransactionCommittedListener(mSimpleExecutor,
+ () -> mHandler.removeCallbacks(timeoutRunnable));
surfaceSyncGroup.addTransaction(transaction);
surfaceSyncGroup.markSyncReady();
});
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 662a5c47d633..a76bd269f31b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -95,7 +95,6 @@ public class BubblePositioner {
private int mMinimumFlyoutWidthLargeScreen;
private PointF mRestingStackPosition;
- private int[] mPaddings = new int[4];
private boolean mShowingInBubbleBar;
private final Point mBubbleBarPosition = new Point();
@@ -344,46 +343,44 @@ public class BubblePositioner {
final int pointerTotalHeight = getPointerSize();
final int expandedViewLargeScreenInsetFurthestEdge =
getExpandedViewLargeScreenInsetFurthestEdge(isOverflow);
+ int[] paddings = new int[4];
if (mDeviceConfig.isLargeScreen()) {
// Note:
// If we're in portrait OR if we're a small tablet, then the two insets values will
// be equal. If we're landscape and a large tablet, the two values will be different.
// [left, top, right, bottom]
- mPaddings[0] = onLeft
+ paddings[0] = onLeft
? mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight
: expandedViewLargeScreenInsetFurthestEdge;
- mPaddings[1] = 0;
- mPaddings[2] = onLeft
+ paddings[1] = 0;
+ paddings[2] = onLeft
? expandedViewLargeScreenInsetFurthestEdge
: mExpandedViewLargeScreenInsetClosestEdge - pointerTotalHeight;
// Overflow doesn't show manage button / get padding from it so add padding here
- mPaddings[3] = isOverflow ? mExpandedViewPadding : 0;
- return mPaddings;
+ paddings[3] = isOverflow ? mExpandedViewPadding : 0;
+ return paddings;
} else {
int leftPadding = mInsets.left + mExpandedViewPadding;
int rightPadding = mInsets.right + mExpandedViewPadding;
- final float expandedViewWidth = isOverflow
- ? mOverflowWidth
- : mExpandedViewLargeScreenWidth;
if (showBubblesVertically()) {
if (!onLeft) {
rightPadding += mBubbleSize - pointerTotalHeight;
leftPadding += isOverflow
- ? (mPositionRect.width() - rightPadding - expandedViewWidth)
+ ? (mPositionRect.width() - rightPadding - mOverflowWidth)
: 0;
} else {
leftPadding += mBubbleSize - pointerTotalHeight;
rightPadding += isOverflow
- ? (mPositionRect.width() - leftPadding - expandedViewWidth)
+ ? (mPositionRect.width() - leftPadding - mOverflowWidth)
: 0;
}
}
// [left, top, right, bottom]
- mPaddings[0] = leftPadding;
- mPaddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
- mPaddings[2] = rightPadding;
- mPaddings[3] = 0;
- return mPaddings;
+ paddings[0] = leftPadding;
+ paddings[1] = showBubblesVertically() ? 0 : mPointerMargin;
+ paddings[2] = rightPadding;
+ paddings[3] = 0;
+ return paddings;
}
}
@@ -395,7 +392,7 @@ public class BubblePositioner {
}
/** Gets the y position of the expanded view if it was top-aligned. */
- public float getExpandedViewYTopAligned() {
+ public int getExpandedViewYTopAligned() {
final int top = getAvailableRect().top;
if (showBubblesVertically()) {
return top - mPointerWidth + mExpandedViewPadding;
@@ -413,7 +410,7 @@ public class BubblePositioner {
return getExpandedViewHeightForLargeScreen();
}
// Subtract top insets because availableRect.height would account for that
- int expandedContainerY = (int) getExpandedViewYTopAligned() - getInsets().top;
+ int expandedContainerY = getExpandedViewYTopAligned() - getInsets().top;
int paddingTop = showBubblesVertically()
? 0
: mPointerHeight;
@@ -474,11 +471,11 @@ public class BubblePositioner {
public float getExpandedViewY(BubbleViewProvider bubble, float bubblePosition) {
boolean isOverflow = bubble == null || BubbleOverflow.KEY.equals(bubble.getKey());
float expandedViewHeight = getExpandedViewHeight(bubble);
- float topAlignment = getExpandedViewYTopAligned();
+ int topAlignment = getExpandedViewYTopAligned();
int manageButtonHeight =
isOverflow ? mExpandedViewPadding : mManageButtonHeightIncludingMargins;
- // On largescreen portrait bubbles are bottom aligned.
+ // On large screen portrait bubbles are bottom aligned.
if (areBubblesBottomAligned() && expandedViewHeight == MAX_HEIGHT) {
return mPositionRect.bottom - manageButtonHeight
- getExpandedViewHeightForLargeScreen() - mPointerWidth;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
index 02af2d06a1dd..7798aa753aa2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationController.java
@@ -420,7 +420,7 @@ public class ExpandedAnimationController
bubbleView.setTranslationY(y);
}
- final float expandedY = mPositioner.getExpandedViewYTopAligned();
+ final int expandedY = mPositioner.getExpandedViewYTopAligned();
final boolean draggedOutEnough =
y > expandedY + mBubbleSizePx || y < expandedY - mBubbleSizePx;
if (draggedOutEnough != mBubbleDraggedOutEnough) {
diff --git a/libs/incident/libincident.map.txt b/libs/incident/libincident.map.txt
index f75cceaf59fa..d8650e129742 100644
--- a/libs/incident/libincident.map.txt
+++ b/libs/incident/libincident.map.txt
@@ -1,15 +1,15 @@
LIBINCIDENT {
global:
- AIncidentReportArgs_init; # systemapi # introduced=30
- AIncidentReportArgs_clone; # systemapi # introduced=30
- AIncidentReportArgs_delete; # systemapi # introduced=30
- AIncidentReportArgs_setAll; # systemapi # introduced=30
- AIncidentReportArgs_setPrivacyPolicy; # systemapi # introduced=30
- AIncidentReportArgs_addSection; # systemapi # introduced=30
- AIncidentReportArgs_setReceiverPackage; # systemapi # introduced=30
- AIncidentReportArgs_setReceiverClass; # systemapi # introduced=30
- AIncidentReportArgs_addHeader; # systemapi # introduced=30
- AIncidentReportArgs_takeReport; # systemapi # introduced=30
+ AIncidentReportArgs_init; # systemapi introduced=30
+ AIncidentReportArgs_clone; # systemapi introduced=30
+ AIncidentReportArgs_delete; # systemapi introduced=30
+ AIncidentReportArgs_setAll; # systemapi introduced=30
+ AIncidentReportArgs_setPrivacyPolicy; # systemapi introduced=30
+ AIncidentReportArgs_addSection; # systemapi introduced=30
+ AIncidentReportArgs_setReceiverPackage; # systemapi introduced=30
+ AIncidentReportArgs_setReceiverClass; # systemapi introduced=30
+ AIncidentReportArgs_addHeader; # systemapi introduced=30
+ AIncidentReportArgs_takeReport; # systemapi introduced=30
local:
*;
};
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index f8176a1dd052..8f5f1f6a4794 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -50,7 +50,7 @@
]
}
],
- "presubmit": [
+ "postsubmit": [
{
"file_patterns": [
"[^/]*(LoudnessCodec)[^/]*\\.java"
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 9f2a9ac4798d..960510879a4c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -1,9 +1,9 @@
LIBANDROID {
global:
- AActivityManager_addUidImportanceListener; # systemapi # introduced=31
- AActivityManager_removeUidImportanceListener; # systemapi # introduced=31
- AActivityManager_isUidActive; # systemapi # introduced=31
- AActivityManager_getUidImportance; # systemapi # introduced=31
+ AActivityManager_addUidImportanceListener; # systemapi introduced=31
+ AActivityManager_removeUidImportanceListener; # systemapi introduced=31
+ AActivityManager_isUidActive; # systemapi introduced=31
+ AActivityManager_getUidImportance; # systemapi introduced=31
AAssetDir_close;
AAssetDir_getNextFileName;
AAssetDir_rewind;
diff --git a/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml b/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
new file mode 100644
index 000000000000..9d16f32db932
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/autofill_light_selectable_item_background.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Copied from //frameworks/base/core/res/res/drawable/item_background_material.xml -->
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ android:color="@color/autofill_light_colorControlHighlight">
+ <item android:id="@android:id/mask">
+ <color android:color="@android:color/white"/>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
new file mode 100644
index 000000000000..2f0c83b6556a
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
+ android:color="@android:color/transparent">
+ <item
+ android:bottom="1dp"
+ android:shape="rectangle"
+ android:top="1dp">
+ <shape>
+ <corners android:radius="28dp" />
+ <solid android:color="@android:color/system_surface_container_high_light" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
new file mode 100644
index 000000000000..39f49caa7051
--- /dev/null
+++ b/packages/CredentialManager/res/drawable/fill_dialog_dynamic_list_item_one_dark.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" tools:ignore="NewApi"
+ android:color="@android:color/transparent">
+ <item
+ android:bottom="1dp"
+ android:shape="rectangle"
+ android:top="1dp">
+ <shape>
+ <corners android:radius="28dp" />
+ <solid android:color="@android:color/system_surface_container_high_dark" />
+ </shape>
+ </item>
+</ripple> \ No newline at end of file
diff --git a/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml b/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml
new file mode 100644
index 000000000000..e4e9f7ac85a9
--- /dev/null
+++ b/packages/CredentialManager/res/layout/autofill_dataset_left_with_item_tag_hint.xml
@@ -0,0 +1,37 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ style="@style/autofill.Dataset">
+ <ImageView
+ android:id="@android:id/icon1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:layout_alignParentStart="true"
+ android:background="@null"/>
+ <TextView
+ android:id="@android:id/text1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentTop="true"
+ android:layout_toEndOf="@android:id/icon1"
+ style="@style/autofill.TextAppearance"/>
+
+</RelativeLayout>
diff --git a/packages/CredentialManager/res/values/colors.xml b/packages/CredentialManager/res/values/colors.xml
new file mode 100644
index 000000000000..63b9f24d9033
--- /dev/null
+++ b/packages/CredentialManager/res/values/colors.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<!-- Color palette -->
+<resources>
+ <color name="autofill_light_colorPrimary">@color/primary_material_light</color>
+ <color name="autofill_light_colorAccent">@color/accent_material_light</color>
+ <color name="autofill_light_colorControlHighlight">@color/ripple_material_light</color>
+ <color name="autofill_light_colorButtonNormal">@color/button_material_light</color>
+
+ <!-- Text colors -->
+ <color name="autofill_light_textColorPrimary">@color/abc_primary_text_material_light</color>
+ <color name="autofill_light_textColorSecondary">@color/abc_secondary_text_material_light</color>
+ <color name="autofill_light_textColorHint">@color/abc_hint_foreground_material_light</color>
+ <color name="autofill_light_textColorHintInverse">@color/abc_hint_foreground_material_dark
+ </color>
+ <color name="autofill_light_textColorHighlight">@color/highlighted_text_material_light</color>
+ <color name="autofill_light_textColorLink">@color/autofill_light_colorAccent</color>
+
+ <!-- These colors are used for Remote Views. -->
+ <color name="background_dark_mode">#0E0C0B</color>
+ <color name="background">#F1F3F4</color>
+ <color name="text_primary_dark_mode">#DFDEDB</color>
+ <color name="text_primary">#202124</color>
+</resources> \ No newline at end of file
diff --git a/packages/CredentialManager/res/values/dimens.xml b/packages/CredentialManager/res/values/dimens.xml
new file mode 100644
index 000000000000..67003a330974
--- /dev/null
+++ b/packages/CredentialManager/res/values/dimens.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <dimen name="autofill_view_padding">16dp</dimen>
+ <dimen name="autofill_icon_size">16dp</dimen>
+</resources> \ No newline at end of file
diff --git a/packages/CredentialManager/res/values/styles.xml b/packages/CredentialManager/res/values/styles.xml
new file mode 100644
index 000000000000..4a5761acdd83
--- /dev/null
+++ b/packages/CredentialManager/res/values/styles.xml
@@ -0,0 +1,38 @@
+<!--
+ ~ Copyright (C) 2023 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<resources>
+ <style name="autofill.TextAppearance.Small" parent="@style/autofill.TextAppearance">
+ <item name="android:textSize">12sp</item>
+ </style>
+
+
+ <style name="autofill.Dataset" parent="">
+ <item name="android:background">@drawable/autofill_light_selectable_item_background</item>
+ </style>
+
+ <style name="autofill.TextAppearance" parent="">
+ <item name="android:textColor">@color/autofill_light_textColorPrimary</item>
+ <item name="android:textColorHint">@color/autofill_light_textColorHint</item>
+ <item name="android:textColorHighlight">@color/autofill_light_textColorHighlight</item>
+ <item name="android:textColorLink">@color/autofill_light_textColorLink</item>
+ <item name="android:textSize">14sp</item>
+ </style>
+
+ <style name="autofill.TextAppearance.Primary">
+ <item name="android:textColor">@color/autofill_light_textColorPrimary</item>
+ </style>
+</resources> \ No newline at end of file
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 20d2f09ced8f..0ff1c7fd8953 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -16,6 +16,7 @@
package com.android.credentialmanager.autofill
+import android.R
import android.app.assist.AssistStructure
import android.content.Context
import android.credentials.CredentialManager
@@ -41,18 +42,19 @@ import android.service.autofill.SaveRequest
import android.service.credentials.CredentialProviderService
import android.util.Log
import android.view.autofill.AutofillId
-import org.json.JSONException
import android.widget.inline.InlinePresentationSpec
import androidx.autofill.inline.v1.InlineSuggestionUi
import androidx.credentials.provider.CustomCredentialEntry
import androidx.credentials.provider.PasswordCredentialEntry
import androidx.credentials.provider.PublicKeyCredentialEntry
import com.android.credentialmanager.GetFlowUtils
-import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.common.ui.RemoteViewsFactory
import com.android.credentialmanager.getflow.ProviderDisplayInfo
-import com.android.credentialmanager.model.get.ProviderInfo
import com.android.credentialmanager.getflow.toProviderDisplayInfo
import com.android.credentialmanager.ktx.credentialEntry
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import com.android.credentialmanager.model.get.ProviderInfo
+import org.json.JSONException
import org.json.JSONObject
import java.util.concurrent.Executors
@@ -127,9 +129,11 @@ class CredentialAutofillService : AutofillService() {
is PasswordCredentialEntry -> {
entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
}
+
is PublicKeyCredentialEntry -> {
entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
}
+
is CustomCredentialEntry -> {
entryIconMap[entry.key + entry.subkey] = credentialEntry.icon
}
@@ -172,11 +176,11 @@ class CredentialAutofillService : AutofillService() {
}
private fun processProvidersForAutofillId(
- filLRequest: FillRequest,
- autofillId: AutofillId,
- providerList: List<ProviderInfo>,
- entryIconMap: Map<String, Icon>,
- fillResponseBuilder: FillResponse.Builder
+ filLRequest: FillRequest,
+ autofillId: AutofillId,
+ providerList: List<ProviderInfo>,
+ entryIconMap: Map<String, Icon>,
+ fillResponseBuilder: FillResponse.Builder
): Boolean {
if (providerList.isEmpty()) {
return false
@@ -197,7 +201,7 @@ class CredentialAutofillService : AutofillService() {
var i = 0
var datasetAdded = false
- providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@ {
+ providerDisplayInfo.sortedUserNameToCredentialEntryList.forEach usernameLoop@{
val primaryEntry = it.sortedCredentialEntryList.first()
val pendingIntent = primaryEntry.pendingIntent
val fillInIntent = primaryEntry.fillInIntent
@@ -206,37 +210,48 @@ class CredentialAutofillService : AutofillService() {
Log.e(TAG, "PendingIntent was missing from the entry.")
return@usernameLoop
}
- if (inlinePresentationSpecs == null || i >= maxItemCount) {
+ if (inlinePresentationSpecs == null) {
+ Log.i(TAG, "Inline presentation spec is null, " +
+ "building dropdown presentation only")
+ }
+ if (i >= maxItemCount) {
Log.e(TAG, "Skipping because reached the max item count.")
return@usernameLoop
}
- // Create inline presentation
- val spec: InlinePresentationSpec
- if (i < inlinePresentationSpecsCount) {
- spec = inlinePresentationSpecs[i]
- } else {
- spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
- }
- val sliceBuilder = InlineSuggestionUi
- .newContentBuilder(pendingIntent)
- .setTitle(primaryEntry.userName)
- val icon: Icon
- if (primaryEntry.icon == null) {
+ val icon: Icon = if (primaryEntry.icon == null) {
// The empty entry icon has non-null icon reference but null drawable reference.
// If the drawable reference is null, then use the default icon.
- icon = getDefaultIcon()
+ getDefaultIcon()
} else {
- icon = entryIconMap[primaryEntry.entryKey + primaryEntry.entrySubkey]
+ entryIconMap[primaryEntry.entryKey + primaryEntry.entrySubkey]
?: getDefaultIcon()
}
- sliceBuilder.setStartIcon(icon)
- val inlinePresentation = InlinePresentation(
- sliceBuilder.build().slice, spec, /* pinned= */ false)
+ // Create inline presentation
+ var inlinePresentation: InlinePresentation? = null;
+ if (inlinePresentationSpecs != null) {
+ val spec: InlinePresentationSpec
+ if (i < inlinePresentationSpecsCount) {
+ spec = inlinePresentationSpecs[i]
+ } else {
+ spec = inlinePresentationSpecs[inlinePresentationSpecsCount - 1]
+ }
+ val sliceBuilder = InlineSuggestionUi
+ .newContentBuilder(pendingIntent)
+ .setTitle(primaryEntry.userName)
+ sliceBuilder.setStartIcon(icon)
+ inlinePresentation = InlinePresentation(
+ sliceBuilder.build().slice, spec, /* pinned= */ false)
+ }
+ val dropdownPresentation = RemoteViewsFactory.createDropdownPresentation(
+ this, icon, primaryEntry)
i++
val dataSetBuilder = Dataset.Builder()
val presentationBuilder = Presentations.Builder()
- .setInlinePresentation(inlinePresentation)
+ .setMenuPresentation(dropdownPresentation)
+ if (inlinePresentation != null) {
+ presentationBuilder.setInlinePresentation(inlinePresentation)
+ }
fillResponseBuilder.addDataset(
dataSetBuilder
@@ -305,7 +320,7 @@ class CredentialAutofillService : AutofillService() {
): MutableMap<AutofillId, MutableList<CredentialEntryInfo>> {
val autofillIdToCredentialEntries:
MutableMap<AutofillId, MutableList<CredentialEntryInfo>> = mutableMapOf()
- credentialEntryList.forEach entryLoop@ { credentialEntry ->
+ credentialEntryList.forEach entryLoop@{ credentialEntry ->
val autofillId: AutofillId? = credentialEntry
.fillInIntent
?.getParcelableExtra(
@@ -323,8 +338,8 @@ class CredentialAutofillService : AutofillService() {
}
private fun copyProviderInfo(
- providerInfo: ProviderInfo,
- credentialList: List<CredentialEntryInfo>
+ providerInfo: ProviderInfo,
+ credentialList: List<CredentialEntryInfo>
): ProviderInfo {
return ProviderInfo(
providerInfo.id,
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
new file mode 100644
index 000000000000..4dc7f00c1550
--- /dev/null
+++ b/packages/CredentialManager/src/com/android/credentialmanager/common/ui/RemoteViewsFactory.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.credentialmanager.common.ui
+
+import android.content.Context
+import android.content.res.Configuration
+import android.widget.RemoteViews
+import androidx.core.content.ContextCompat
+import com.android.credentialmanager.model.get.CredentialEntryInfo
+import android.graphics.drawable.Icon
+
+class RemoteViewsFactory {
+
+ companion object {
+ private const val setAdjustViewBoundsMethodName = "setAdjustViewBounds"
+ private const val setMaxHeightMethodName = "setMaxHeight"
+ private const val setBackgroundResourceMethodName = "setBackgroundResource"
+
+ fun createDropdownPresentation(
+ context: Context,
+ icon: Icon,
+ credentialEntryInfo: CredentialEntryInfo
+ ): RemoteViews {
+ val padding = context.resources.getDimensionPixelSize(com.android
+ .credentialmanager.R.dimen.autofill_view_padding)
+ var layoutId: Int = com.android.credentialmanager.R.layout
+ .autofill_dataset_left_with_item_tag_hint
+ val remoteViews = RemoteViews(context.packageName, layoutId)
+ setRemoteViewsPaddings(remoteViews, padding)
+ val textColorPrimary = getTextColorPrimary(isDarkMode(context), context);
+ remoteViews.setTextColor(android.R.id.text1, textColorPrimary);
+ remoteViews.setTextViewText(android.R.id.text1, credentialEntryInfo.userName)
+
+ remoteViews.setImageViewIcon(android.R.id.icon1, icon);
+ remoteViews.setBoolean(
+ android.R.id.icon1, setAdjustViewBoundsMethodName, true);
+ remoteViews.setInt(
+ android.R.id.icon1,
+ setMaxHeightMethodName,
+ context.resources.getDimensionPixelSize(
+ com.android.credentialmanager.R.dimen.autofill_icon_size));
+ val drawableId = if (isDarkMode(context))
+ com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one_dark
+ else com.android.credentialmanager.R.drawable.fill_dialog_dynamic_list_item_one
+ remoteViews.setInt(
+ android.R.id.content, setBackgroundResourceMethodName, drawableId);
+ return remoteViews
+ }
+
+ private fun setRemoteViewsPaddings(
+ remoteViews: RemoteViews,
+ padding: Int) {
+ val halfPadding = padding / 2
+ remoteViews.setViewPadding(
+ android.R.id.text1,
+ halfPadding,
+ halfPadding,
+ halfPadding,
+ halfPadding)
+ }
+
+ private fun isDarkMode(context: Context): Boolean {
+ val currentNightMode = context.resources.configuration.uiMode and
+ Configuration.UI_MODE_NIGHT_MASK
+ return currentNightMode == Configuration.UI_MODE_NIGHT_YES
+ }
+
+ private fun getTextColorPrimary(darkMode: Boolean, context: Context): Int {
+ return if (darkMode) ContextCompat.getColor(
+ context, com.android.credentialmanager.R.color.text_primary_dark_mode)
+ else ContextCompat.getColor(context, com.android.credentialmanager.R.color.text_primary)
+ }
+ }
+}
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
index 557fbf21d5c4..e6122a094707 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_view.xml
@@ -43,7 +43,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<FrameLayout
- android:id="@+id/status_view_media_container"
+ android:id="@id/status_view_media_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/qs_media_padding"
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index d511caba941b..80725c2bd4b5 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -225,6 +225,8 @@
<item type="id" name="communal_tutorial_indicator" />
<item type="id" name="nssl_placeholder_barrier_bottom" />
<item type="id" name="ambient_indication_container" />
+ <item type="id" name="status_view_media_container" />
+ <item type="id" name="smart_space_barrier_bottom" />
<!-- Privacy dialog -->
<item type="id" name="privacy_dialog_close_app_button" />
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 83d415fa936e..ab23564a1df4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -403,13 +403,6 @@ public class AuthContainerView extends LinearLayout
final BiometricPromptLayout view = (BiometricPromptLayout) layoutInflater.inflate(
R.layout.biometric_prompt_layout, null, false);
- /**
- * View is only set visible in BiometricViewSizeBinder once PromptSize is determined
- * that accounts for iconView size, to prevent prompt resizing being visible to the
- * user.
- * TODO(b/288175072): May be able to remove this once constraint layout is implemented
- */
- view.setVisibility(View.INVISIBLE);
mBiometricView = BiometricViewBinder.bind(view, viewModel, mPanelController,
// TODO(b/201510778): This uses the wrong timeout in some cases
getJankListener(view, TRANSIT,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
index a7fb6f72a41e..90e4a3821634 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewBinder.kt
@@ -97,13 +97,7 @@ object BiometricViewBinder {
val iconOverlayView = view.requireViewById<LottieAnimationView>(R.id.biometric_icon_overlay)
val iconView = view.requireViewById<LottieAnimationView>(R.id.biometric_icon)
- /**
- * View is only set visible in BiometricViewSizeBinder once PromptSize is determined that
- * accounts for iconView size, to prevent prompt resizing being visible to the user.
- *
- * TODO(b/288175072): May be able to remove this once constraint layout is implemented
- */
- iconView.addLottieOnCompositionLoadedListener { viewModel.setIsIconViewLoaded(true) }
+
PromptIconViewBinder.bind(
iconView,
iconOverlayView,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
index f340bd81f951..7e16d1e1d668 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/BiometricViewSizeBinder.kt
@@ -30,6 +30,7 @@ import androidx.core.animation.addListener
import androidx.core.view.doOnLayout
import androidx.core.view.isGone
import androidx.lifecycle.lifecycleScope
+import com.android.systemui.res.R
import com.android.systemui.biometrics.AuthPanelController
import com.android.systemui.biometrics.Utils
import com.android.systemui.biometrics.ui.BiometricPromptLayout
@@ -40,8 +41,6 @@ import com.android.systemui.biometrics.ui.viewmodel.isMedium
import com.android.systemui.biometrics.ui.viewmodel.isNullOrNotSmall
import com.android.systemui.biometrics.ui.viewmodel.isSmall
import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.res.R
-import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.launch
/** Helper for [BiometricViewBinder] to handle resize transitions. */
@@ -93,22 +92,8 @@ object BiometricViewSizeBinder {
// TODO(b/251476085): migrate the legacy panel controller and simplify this
view.repeatWhenAttached {
var currentSize: PromptSize? = null
-
lifecycleScope.launch {
- /**
- * View is only set visible in BiometricViewSizeBinder once PromptSize is
- * determined that accounts for iconView size, to prevent prompt resizing being
- * visible to the user.
- *
- * TODO(b/288175072): May be able to remove isIconViewLoaded once constraint
- * layout is implemented
- */
- combine(viewModel.isIconViewLoaded, viewModel.size, ::Pair).collect {
- (isIconViewLoaded, size) ->
- if (!isIconViewLoaded) {
- return@collect
- }
-
+ viewModel.size.collect { size ->
// prepare for animated size transitions
for (v in viewsToHideWhenSmall) {
v.showTextOrHide(forceHide = size.isSmall)
@@ -211,9 +196,8 @@ object BiometricViewSizeBinder {
}
}
}
+
currentSize = size
- view.visibility = View.VISIBLE
- viewModel.setIsIconViewLoaded(false)
notifyAccessibilityChanged()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
index d899827ebb2e..6d0a58e202bd 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/PromptViewModel.kt
@@ -192,28 +192,6 @@ constructor(
val iconViewModel: PromptIconViewModel =
PromptIconViewModel(this, displayStateInteractor, promptSelectorInteractor)
- private val _isIconViewLoaded = MutableStateFlow(false)
-
- /**
- * For prompts with an iconView, false until the prompt's iconView animation has been loaded in
- * the view, otherwise true by default. Used for BiometricViewSizeBinder to wait for the icon
- * asset to be loaded before determining the prompt size.
- */
- val isIconViewLoaded: Flow<Boolean> =
- combine(credentialKind, _isIconViewLoaded.asStateFlow()) { credentialKind, isIconViewLoaded
- ->
- if (credentialKind is PromptKind.Biometric) {
- isIconViewLoaded
- } else {
- true
- }
- }
-
- // Sets whether the prompt's iconView animation has been loaded in the view yet.
- fun setIsIconViewLoaded(iconViewLoaded: Boolean) {
- _isIconViewLoaded.value = iconViewLoaded
- }
-
/** Padding for prompt UI elements */
val promptPadding: Flow<Rect> =
combine(size, displayStateInteractor.currentRotation) { size, rotation ->
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 1f69cc0a8ec3..0d405119f25b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -397,8 +397,10 @@ public class KeyguardSliceProvider extends SliceProvider implements
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_DATE_CHANGED);
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
- null /* scheduler */);
+ mBgHandler.post(() -> {
+ getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
+ null /* scheduler */);
+ });
mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
mRegistered = true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
index 16539db648bc..5344696b92fe 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/blueprints/SplitShadeKeyguardBlueprint.kt
@@ -33,6 +33,7 @@ import com.android.systemui.keyguard.ui.view.layout.sections.KeyguardSectionsMod
import com.android.systemui.keyguard.ui.view.layout.sections.SmartspaceSection
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeClockSection
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeGuidelines
+import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeMediaSection
import com.android.systemui.keyguard.ui.view.layout.sections.SplitShadeNotificationStackScrollLayoutSection
import com.android.systemui.util.kotlin.getOrNull
import java.util.Optional
@@ -63,6 +64,7 @@ constructor(
communalTutorialIndicatorSection: CommunalTutorialIndicatorSection,
smartspaceSection: SmartspaceSection,
clockSection: SplitShadeClockSection,
+ mediaSection: SplitShadeMediaSection,
) : KeyguardBlueprint {
override val id: String = ID
@@ -81,6 +83,7 @@ constructor(
aodBurnInSection,
communalTutorialIndicatorSection,
clockSection,
+ mediaSection,
defaultDeviceEntrySection, // Add LAST: Intentionally has z-order above other views.
)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
new file mode 100644
index 000000000000..5afdbaa47d95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeMediaSection.kt
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.keyguard.ui.view.layout.sections
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
+import android.widget.FrameLayout
+import androidx.constraintlayout.widget.Barrier
+import androidx.constraintlayout.widget.ConstraintLayout
+import androidx.constraintlayout.widget.ConstraintSet
+import androidx.constraintlayout.widget.ConstraintSet.BOTTOM
+import androidx.constraintlayout.widget.ConstraintSet.END
+import androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT
+import androidx.constraintlayout.widget.ConstraintSet.PARENT_ID
+import androidx.constraintlayout.widget.ConstraintSet.START
+import androidx.constraintlayout.widget.ConstraintSet.TOP
+import com.android.systemui.Flags.migrateClocksToBlueprint
+import com.android.systemui.keyguard.shared.model.KeyguardSection
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
+import com.android.systemui.media.controls.ui.KeyguardMediaController
+import com.android.systemui.res.R
+import com.android.systemui.shade.NotificationPanelView
+import javax.inject.Inject
+
+/** Aligns media on left side for split shade, below smartspace, date, and weather. */
+class SplitShadeMediaSection
+@Inject
+constructor(
+ private val context: Context,
+ private val notificationPanelView: NotificationPanelView,
+ private val keyguardSmartspaceViewModel: KeyguardSmartspaceViewModel,
+ private val keyguardMediaController: KeyguardMediaController
+) : KeyguardSection() {
+ private val mediaContainerId = R.id.status_view_media_container
+ private val smartSpaceBarrier = R.id.smart_space_barrier_bottom
+
+ override fun addViews(constraintLayout: ConstraintLayout) {
+ if (!migrateClocksToBlueprint()) {
+ return
+ }
+
+ notificationPanelView.findViewById<View>(mediaContainerId)?.let {
+ notificationPanelView.removeView(it)
+ }
+
+ val mediaFrame =
+ FrameLayout(context, null).apply {
+ id = mediaContainerId
+ val padding = context.resources.getDimensionPixelSize(R.dimen.qs_media_padding)
+ val horizontalPadding =
+ padding +
+ context.resources.getDimensionPixelSize(
+ R.dimen.status_view_margin_horizontal
+ )
+
+ setPaddingRelative(horizontalPadding, padding, horizontalPadding, padding)
+ }
+ constraintLayout.addView(mediaFrame)
+ keyguardMediaController.attachSplitShadeContainer(mediaFrame)
+ }
+
+ override fun bindData(constraintLayout: ConstraintLayout) {}
+
+ override fun applyConstraints(constraintSet: ConstraintSet) {
+ if (!migrateClocksToBlueprint()) {
+ return
+ }
+
+ constraintSet.apply {
+ constrainWidth(mediaContainerId, MATCH_CONSTRAINT)
+ constrainHeight(mediaContainerId, WRAP_CONTENT)
+
+ createBarrier(
+ smartSpaceBarrier,
+ Barrier.BOTTOM,
+ 0,
+ *intArrayOf(
+ keyguardSmartspaceViewModel.smartspaceViewId,
+ keyguardSmartspaceViewModel.dateId,
+ keyguardSmartspaceViewModel.weatherId,
+ )
+ )
+ connect(mediaContainerId, TOP, smartSpaceBarrier, BOTTOM)
+ connect(mediaContainerId, START, PARENT_ID, START)
+ connect(mediaContainerId, END, R.id.split_shade_guideline, END)
+ }
+ }
+
+ override fun removeViews(constraintLayout: ConstraintLayout) {
+ if (!migrateClocksToBlueprint()) {
+ return
+ }
+
+ constraintLayout.removeView(mediaContainerId)
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
index 945bf9a5c0b2..e15e03822610 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/KeyguardMediaController.kt
@@ -27,6 +27,7 @@ import android.view.View
import android.view.ViewGroup
import androidx.annotation.VisibleForTesting
import com.android.systemui.Dumpable
+import com.android.systemui.Flags.migrateClocksToBlueprint
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dump.DumpManager
@@ -180,7 +181,11 @@ constructor(
/** Called whenever the media hosts visibility changes */
private fun onMediaHostVisibilityChanged(visible: Boolean) {
refreshMediaPosition(reason = "onMediaHostVisibilityChanged")
+
if (visible) {
+ if (migrateClocksToBlueprint() && useSplitShade) {
+ return
+ }
mediaHost.hostView.layoutParams.apply {
height = ViewGroup.LayoutParams.WRAP_CONTENT
width = ViewGroup.LayoutParams.MATCH_PARENT
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 17eb3c83fefe..286037ef1961 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1160,9 +1160,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
// Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher);
- if (!KeyguardShadeMigrationNssl.isEnabled()) {
- collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
collectFlow(mView,
mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY(),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1192,8 +1192,10 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
mLockscreenToOccludedTransition, mMainDispatcher);
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
- collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
- setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+ }
// Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
@@ -1463,6 +1465,9 @@ public final class NotificationPanelViewController implements ShadeSurface, Dump
}
private void attachSplitShadeMediaPlayerContainer(FrameLayout container) {
+ if (migrateClocksToBlueprint()) {
+ return;
+ }
mKeyguardMediaController.attachSplitShadeContainer(container);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
index 70ccc4f3ae43..80ef14bb4673 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.notification.collection.inflation;
+import static com.android.systemui.Flags.screenshareNotificationHiding;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_CONTRACTED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED;
import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC;
@@ -243,7 +244,11 @@ public class NotificationRowBinderImpl implements NotificationRowBinder {
params.setUseIncreasedCollapsedHeight(useIncreasedCollapsedHeight);
params.setUseLowPriority(isLowPriority);
- if (mNotificationLockscreenUserManager.needsRedaction(entry)) {
+ // If screenshareNotificationHiding is enabled, both public and private views should be
+ // inflated to avoid any latency associated with reinflating all notification views when
+ // screen share starts and stops
+ if (screenshareNotificationHiding()
+ || mNotificationLockscreenUserManager.needsRedaction(entry)) {
params.requireContentViews(FLAG_CONTENT_VIEW_PUBLIC);
} else {
params.markContentViewsFreeable(FLAG_CONTENT_VIEW_PUBLIC);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index eff91e55d9a8..5ee38bebc99b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -25,6 +25,8 @@ import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -71,6 +73,20 @@ constructor(
KeyguardState.PRIMARY_BOUNCER
)
+ private val lockscreenToOccludedRunning =
+ keyguardTransitionInteractor
+ .transition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
+ .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+ .distinctUntilChanged()
+ .onStart { emit(false) }
+
+ private val occludedToLockscreenRunning =
+ keyguardTransitionInteractor
+ .transition(KeyguardState.OCCLUDED, KeyguardState.LOCKSCREEN)
+ .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+ .distinctUntilChanged()
+ .onStart { emit(false) }
+
val shadeCollapseFadeInComplete = MutableStateFlow(false)
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
@@ -122,7 +138,11 @@ constructor(
) { isKeyguard, isShadeVisible, qsExpansion ->
isKeyguard && !(isShadeVisible || qsExpansion)
}
- .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
/** Fade in only for use after the shade collapses */
val shadeCollpaseFadeIn: Flow<Boolean> =
@@ -182,26 +202,37 @@ constructor(
)
val alpha: Flow<Float> =
- isOnLockscreenWithoutShade
- .flatMapLatest { isOnLockscreenWithoutShade ->
- combineTransform(
- merge(
- occludedToLockscreenTransitionViewModel.lockscreenAlpha,
- lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
- keyguardInteractor.keyguardAlpha,
- ),
- shadeCollpaseFadeIn,
- ) { alpha, shadeCollpaseFadeIn ->
- if (isOnLockscreenWithoutShade) {
- if (!shadeCollpaseFadeIn) {
- emit(alpha)
- }
+ // Due to issues with the legacy shade, some shade expansion events are sent incorrectly,
+ // such as when the shade resets. This can happen while the LOCKSCREEN<->OCCLUDED transition
+ // is running. Therefore use a series of flatmaps to prevent unwanted interruptions while
+ // those transitions are in progress. Without this, the alpha value will produce a visible
+ // flicker.
+ lockscreenToOccludedRunning.flatMapLatest { isLockscreenToOccludedRunning ->
+ if (isLockscreenToOccludedRunning) {
+ lockscreenToOccludedTransitionViewModel.lockscreenAlpha
+ } else {
+ occludedToLockscreenRunning.flatMapLatest { isOccludedToLockscreenRunning ->
+ if (isOccludedToLockscreenRunning) {
+ occludedToLockscreenTransitionViewModel.lockscreenAlpha.onStart { emit(0f) }
} else {
- emit(1f)
+ isOnLockscreenWithoutShade.flatMapLatest { isOnLockscreenWithoutShade ->
+ combineTransform(
+ keyguardInteractor.keyguardAlpha,
+ shadeCollpaseFadeIn,
+ ) { alpha, shadeCollpaseFadeIn ->
+ if (isOnLockscreenWithoutShade) {
+ if (!shadeCollpaseFadeIn) {
+ emit(alpha)
+ }
+ } else {
+ emit(1f)
+ }
+ }
+ }
}
}
}
- .distinctUntilChanged()
+ }
/**
* Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
index 5e57c832074e..bc50c25a77a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/plugins/PluginInstanceTest.java
@@ -198,7 +198,7 @@ public class PluginInstanceTest extends SysuiTestCase {
AtomicBoolean isBgThreadFailed = new AtomicBoolean(false);
Thread bgThread = new Thread(() -> {
assertTrue(getLock(unloadLock, 10));
- assertTrue(getLock(loadLock, 3000)); // Wait for the foreground thread
+ assertTrue(getLock(loadLock, 4000)); // Wait for the foreground thread
assertNotNull(mPluginInstance.getPlugin());
// Attempt to delete the plugin, this should block until the load completes
mPluginInstance.unloadPlugin();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 36a471238c8a..20020f23b2df 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -43,6 +43,7 @@ import com.android.systemui.statusbar.notification.stack.domain.interactor.share
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -418,13 +419,13 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
}
@Test
- fun shadeCollpaseFadeIn() =
+ fun shadeCollapseFadeIn() =
testScope.runTest {
+ val fadeIn by collectLastValue(underTest.shadeCollpaseFadeIn)
+
// Start on lockscreen without the shade
underTest.setShadeCollapseFadeInComplete(false)
showLockscreen()
-
- val fadeIn by collectLastValue(underTest.shadeCollpaseFadeIn)
assertThat(fadeIn).isEqualTo(false)
// ... then the shade expands
@@ -440,10 +441,12 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
assertThat(fadeIn).isEqualTo(false)
}
- private suspend fun showLockscreen() {
+ private suspend fun TestScope.showLockscreen() {
shadeRepository.setLockscreenShadeExpansion(0f)
shadeRepository.setQsExpansion(0f)
+ runCurrent()
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
@@ -451,10 +454,12 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
)
}
- private suspend fun showLockscreenWithShadeExpanded() {
+ private suspend fun TestScope.showLockscreenWithShadeExpanded() {
shadeRepository.setLockscreenShadeExpansion(1f)
shadeRepository.setQsExpansion(0f)
+ runCurrent()
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
@@ -462,10 +467,12 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
)
}
- private suspend fun showLockscreenWithQSExpanded() {
+ private suspend fun TestScope.showLockscreenWithQSExpanded() {
shadeRepository.setLockscreenShadeExpansion(0f)
shadeRepository.setQsExpansion(1f)
+ runCurrent()
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 96b1650d9575..02f4485d5b40 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2118,11 +2118,6 @@ public final class ActiveServices {
// anyway, so we just remove the SHORT_SERVICE type.
foregroundServiceType &= ~FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
}
- if (!shouldAllowBootCompletedStart(r, foregroundServiceType)) {
- throw new ForegroundServiceStartNotAllowedException("FGS type "
- + ServiceInfo.foregroundServiceTypeToLabel(foregroundServiceType)
- + " not allowed to start from BOOT_COMPLETED!");
- }
boolean alreadyStartedOp = false;
boolean stopProcStatsOp = false;
@@ -2137,6 +2132,12 @@ public final class ActiveServices {
mServiceFGAnrTimer.cancel(r);
}
+ if (!shouldAllowBootCompletedStart(r, foregroundServiceType)) {
+ throw new ForegroundServiceStartNotAllowedException("FGS type "
+ + ServiceInfo.foregroundServiceTypeToLabel(foregroundServiceType)
+ + " not allowed to start from BOOT_COMPLETED!");
+ }
+
final ProcessServiceRecord psr = r.app.mServices;
try {
boolean ignoreForeground = false;
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
index 4df25811cc99..5d609bca334c 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationStatsCollector.java
@@ -54,8 +54,8 @@ public class AuthenticationStatsCollector {
@NonNull private final Context mContext;
@NonNull private final PackageManager mPackageManager;
- @NonNull private final FaceManager mFaceManager;
- @NonNull private final FingerprintManager mFingerprintManager;
+ @Nullable private final FaceManager mFaceManager;
+ @Nullable private final FingerprintManager mFingerprintManager;
private final boolean mEnabled;
private final float mThreshold;
@@ -197,11 +197,11 @@ public class AuthenticationStatsCollector {
}
private boolean hasEnrolledFace(int userId) {
- return mFaceManager.hasEnrolledTemplates(userId);
+ return mFaceManager != null && mFaceManager.hasEnrolledTemplates(userId);
}
private boolean hasEnrolledFingerprint(int userId) {
- return mFingerprintManager.hasEnrolledTemplates(userId);
+ return mFingerprintManager != null && mFingerprintManager.hasEnrolledTemplates(userId);
}
/**
diff --git a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
index e546f42c9c22..1660c3ef952a 100644
--- a/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
+++ b/services/core/java/com/android/server/os/BugreportManagerServiceImpl.java
@@ -21,11 +21,13 @@ import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
import android.Manifest;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
+import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.admin.DevicePolicyManager;
import android.app.role.RoleManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
@@ -37,7 +39,6 @@ import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
-import android.os.UserManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -95,7 +96,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
private static final long DEFAULT_BUGREPORT_SERVICE_TIMEOUT_MILLIS = 30 * 1000;
private final Object mLock = new Object();
- private final Injector mInjector;
private final Context mContext;
private final AppOpsManager mAppOps;
private final TelephonyManager mTelephonyManager;
@@ -346,14 +346,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
AtomicFile getMappingFile() {
return mMappingFile;
}
-
- UserManager getUserManager() {
- return mContext.getSystemService(UserManager.class);
- }
-
- DevicePolicyManager getDevicePolicyManager() {
- return mContext.getSystemService(DevicePolicyManager.class);
- }
}
BugreportManagerServiceImpl(Context context) {
@@ -365,7 +357,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
BugreportManagerServiceImpl(Injector injector) {
- mInjector = injector;
mContext = injector.getContext();
mAppOps = mContext.getSystemService(AppOpsManager.class);
mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
@@ -398,7 +389,12 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
int callingUid = Binder.getCallingUid();
enforcePermission(callingPackage, callingUid, bugreportMode
== BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
- ensureUserCanTakeBugReport(bugreportMode);
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ ensureUserCanTakeBugReport(bugreportMode);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
Slogf.i(TAG, "Starting bugreport for %s / %d", callingPackage, callingUid);
synchronized (mLock) {
@@ -437,6 +433,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
@RequiresPermission(value = Manifest.permission.DUMP, conditional = true)
public void retrieveBugreport(int callingUidUnused, String callingPackage, int userId,
FileDescriptor bugreportFd, String bugreportFile,
+
boolean keepBugreportOnRetrievalUnused, IDumpstateListener listener) {
int callingUid = Binder.getCallingUid();
enforcePermission(callingPackage, callingUid, false);
@@ -568,48 +565,54 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
}
/**
- * Validates that the calling user is an admin user or, when bugreport is requested remotely
- * that the user is an affiliated user.
+ * Validates that the current user is an admin user or, when bugreport is requested remotely
+ * that the current user is an affiliated user.
*
- * @throws IllegalArgumentException if the calling user is not an admin user
+ * @throws IllegalArgumentException if the current user is not an admin user
*/
private void ensureUserCanTakeBugReport(int bugreportMode) {
- // Get the calling userId before clearing the caller identity.
- int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
- boolean isAdminUser = false;
- final long identity = Binder.clearCallingIdentity();
+ UserInfo currentUser = null;
try {
- isAdminUser = mInjector.getUserManager().isUserAdmin(callingUserId);
- } finally {
- Binder.restoreCallingIdentity(identity);
+ currentUser = ActivityManager.getService().getCurrentUser();
+ } catch (RemoteException e) {
+ // Impossible to get RemoteException for an in-process call.
+ }
+
+ if (currentUser == null) {
+ logAndThrow("There is no current user, so no bugreport can be requested.");
}
- if (!isAdminUser) {
+
+ if (!currentUser.isAdmin()) {
if (bugreportMode == BugreportParams.BUGREPORT_MODE_REMOTE
- && isUserAffiliated(callingUserId)) {
+ && isCurrentUserAffiliated(currentUser.id)) {
return;
}
- logAndThrow(TextUtils.formatSimple("Calling user %s is not an admin user."
- + " Only admin users are allowed to take bugreport.", callingUserId));
+ logAndThrow(TextUtils.formatSimple("Current user %s is not an admin user."
+ + " Only admin users are allowed to take bugreport.", currentUser.id));
}
}
/**
- * Returns {@code true} if the device has device owner and the specified user is affiliated
+ * Returns {@code true} if the device has device owner and the current user is affiliated
* with the device owner.
*/
- private boolean isUserAffiliated(int userId) {
- DevicePolicyManager dpm = mInjector.getDevicePolicyManager();
+ private boolean isCurrentUserAffiliated(int currentUserId) {
+ DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
int deviceOwnerUid = dpm.getDeviceOwnerUserId();
if (deviceOwnerUid == UserHandle.USER_NULL) {
return false;
}
- if (DEBUG) {
- Slog.d(TAG, "callingUid: " + userId + " deviceOwnerUid: " + deviceOwnerUid);
- }
+ int callingUserId = UserHandle.getUserId(Binder.getCallingUid());
- if (userId != deviceOwnerUid && !dpm.isAffiliatedUser(userId)) {
- logAndThrow("User " + userId + " is not affiliated to the device owner.");
+ Slog.i(TAG, "callingUid: " + callingUserId + " deviceOwnerUid: " + deviceOwnerUid
+ + " currentUserId: " + currentUserId);
+
+ if (callingUserId != deviceOwnerUid) {
+ logAndThrow("Caller is not device owner on provisioned device.");
+ }
+ if (!dpm.isAffiliatedUser(currentUserId)) {
+ logAndThrow("Current user is not affiliated to the device owner.");
}
return true;
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5b13d3fead90..edce3ec4b37c 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -473,6 +473,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
private TalkbackShortcutController mTalkbackShortcutController;
+ private WindowWakeUpPolicy mWindowWakeUpPolicy;
+
boolean mSafeMode;
// Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key.
@@ -640,15 +642,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Whether to lock the device after the next dreaming transition has finished.
private boolean mLockAfterDreamingTransitionFinished;
- // Allowed theater mode wake actions
- private boolean mAllowTheaterModeWakeFromKey;
- private boolean mAllowTheaterModeWakeFromPowerKey;
- private boolean mAllowTheaterModeWakeFromMotion;
- private boolean mAllowTheaterModeWakeFromMotionWhenNotDreaming;
- private boolean mAllowTheaterModeWakeFromCameraLens;
- private boolean mAllowTheaterModeWakeFromLidSwitch;
- private boolean mAllowTheaterModeWakeFromWakeGesture;
-
// If true, the power button long press behavior will be invoked even if the default display is
// non-interactive. If false, the power button long press behavior will be skipped if the
// default display is non-interactive.
@@ -930,8 +923,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (shouldEnableWakeGestureLp()) {
performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
"Wake Up");
- wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
- PowerManager.WAKE_REASON_GESTURE, "android.policy:GESTURE");
+ mWindowWakeUpPolicy.wakeUpFromWakeGesture();
}
}
}
@@ -1067,7 +1059,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
|| handledByPowerManager || mKeyCombinationManager.isPowerKeyIntercepted();
if (!mPowerKeyHandled) {
if (!interactive) {
- wakeUpFromPowerKey(event.getDownTime());
+ wakeUpFromWakeKey(event);
}
} else {
// handled by another power key policy.
@@ -1309,7 +1301,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.THEATER_MODE_ON, 0);
if (!interactive) {
- wakeUpFromPowerKey(eventTime);
+ wakeUpFromWakeKey(eventTime, KEYCODE_POWER);
}
} else {
Slog.i(TAG, "Toggling theater mode on.");
@@ -1325,7 +1317,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
case MULTI_PRESS_POWER_BRIGHTNESS_BOOST:
Slog.i(TAG, "Starting brightness boost.");
if (!interactive) {
- wakeUpFromPowerKey(eventTime);
+ wakeUpFromWakeKey(eventTime, KEYCODE_POWER);
}
mPowerManager.boostScreenBrightness(eventTime);
break;
@@ -2312,22 +2304,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
mLidNavigationAccessibility = mContext.getResources().getInteger(
com.android.internal.R.integer.config_lidNavigationAccessibility);
- mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
- mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey
- || mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey);
- mAllowTheaterModeWakeFromMotion = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion);
- mAllowTheaterModeWakeFromMotionWhenNotDreaming = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromMotionWhenNotDreaming);
- mAllowTheaterModeWakeFromCameraLens = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens);
- mAllowTheaterModeWakeFromLidSwitch = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch);
- mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
-
mGoToSleepOnButtonPressTheaterMode = mContext.getResources().getBoolean(
com.android.internal.R.bool.config_goToSleepOnButtonPressTheaterMode);
@@ -2457,6 +2433,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
com.android.internal.R.integer.config_keyguardDrawnTimeout);
mKeyguardDelegate = injector.getKeyguardServiceDelegate();
mTalkbackShortcutController = injector.getTalkbackShortcutController();
+ mWindowWakeUpPolicy = new WindowWakeUpPolicy(mContext);
initKeyCombinationRules();
initSingleKeyGestureRules(injector.getLooper());
mButtonOverridePermissionChecker = injector.getButtonOverridePermissionChecker();
@@ -4483,8 +4460,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
updateRotation(true);
if (lidOpen) {
- wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch,
- PowerManager.WAKE_REASON_LID, "android.policy:LID");
+ mWindowWakeUpPolicy.wakeUpFromLid();
} else if (getLidBehavior() != LID_BEHAVIOR_SLEEP) {
mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
}
@@ -4510,8 +4486,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
} else {
intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
}
- wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens,
- PowerManager.WAKE_REASON_CAMERA_LAUNCH, "android.policy:CAMERA_COVER");
+ mWindowWakeUpPolicy.wakeUpFromCameraCover(whenNanos / 1000000);
startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
}
mCameraLensCoverState = lensCoverState;
@@ -4589,7 +4564,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean shouldTurnOnTv = false;
if (down && (keyCode == KeyEvent.KEYCODE_POWER
|| keyCode == KeyEvent.KEYCODE_TV_POWER)) {
- wakeUpFromPowerKey(event.getDownTime());
+ wakeUpFromWakeKey(event);
shouldTurnOnTv = true;
} else if (down && (isWakeKey || keyCode == KeyEvent.KEYCODE_WAKEUP)
&& isWakeKeyWhenScreenOff(keyCode)) {
@@ -5104,9 +5079,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
if (mRequestedOrSleepingDefaultDisplay) {
mCameraGestureTriggeredDuringGoingToSleep = true;
// Wake device up early to prevent display doing redundant turning off/on stuff.
- wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromPowerKey,
- PowerManager.WAKE_REASON_CAMERA_LAUNCH,
- "android.policy:CAMERA_GESTURE_PREVENT_LOCK");
+ mWindowWakeUpPolicy.wakeUpFromPowerKeyCameraGesture();
}
return true;
}
@@ -5204,8 +5177,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
public int interceptMotionBeforeQueueingNonInteractive(int displayId, int source, int action,
long whenNanos, int policyFlags) {
if ((policyFlags & FLAG_WAKE) != 0) {
- if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
- PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
+ if (mWindowWakeUpPolicy.wakeUpFromMotion(whenNanos / 1000000)) {
// Woke up. Pass motion events to user.
return ACTION_PASS_TO_USER;
}
@@ -5219,8 +5191,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// there will be no dream to intercept the touch and wake into ambient. The device should
// wake up in this case.
if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
- if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming,
- PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
+ if (mWindowWakeUpPolicy.wakeUpFromMotion(whenNanos / 1000000)) {
// Woke up. Pass motion events to user.
return ACTION_PASS_TO_USER;
}
@@ -5554,39 +5525,24 @@ public class PhoneWindowManager implements WindowManagerPolicy {
return sleepDurationRealtime > mWakeUpToLastStateTimeout;
}
- private void wakeUpFromPowerKey(long eventTime) {
- if (wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
- PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER")) {
- // Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
- if (shouldWakeUpWithHomeIntent()) {
- startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ false, /*wakenFromDreams*/ true,
- PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_POWER_BUTTON));
- }
- }
+ private void wakeUpFromWakeKey(KeyEvent event) {
+ wakeUpFromWakeKey(event.getEventTime(), event.getKeyCode());
}
- private void wakeUpFromWakeKey(KeyEvent event) {
- if (wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
- PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY")) {
+ private void wakeUpFromWakeKey(long eventTime, int keyCode) {
+ if (mWindowWakeUpPolicy.wakeUpFromKey(eventTime, keyCode)) {
+ final boolean keyCanLaunchHome = keyCode == KEYCODE_HOME || keyCode == KEYCODE_POWER;
// Start HOME with "reason" extra if sleeping for more than mWakeUpToLastStateTimeout
- if (shouldWakeUpWithHomeIntent() && event.getKeyCode() == KEYCODE_HOME) {
- startDockOrHome(DEFAULT_DISPLAY, /*fromHomeKey*/ true, /*wakenFromDreams*/ true,
- PowerManager.wakeReasonToString(PowerManager.WAKE_REASON_WAKE_KEY));
+ if (shouldWakeUpWithHomeIntent() && keyCanLaunchHome) {
+ startDockOrHome(
+ DEFAULT_DISPLAY,
+ /*fromHomeKey*/ keyCode == KEYCODE_HOME,
+ /*wakenFromDreams*/ true,
+ "Wake from " + KeyEvent. keyCodeToString(keyCode));
}
}
}
- private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
- String details) {
- final boolean theaterModeEnabled = isTheaterModeEnabled();
- if (!wakeInTheaterMode && theaterModeEnabled) {
- return false;
- }
-
- mPowerManager.wakeUp(wakeTime, reason, details);
- return true;
- }
-
private void finishKeyguardDrawn() {
if (!mDefaultDisplayPolicy.finishKeyguardDrawn()) {
return;
diff --git a/services/core/java/com/android/server/policy/WindowWakeUpPolicy.java b/services/core/java/com/android/server/policy/WindowWakeUpPolicy.java
new file mode 100644
index 000000000000..392d0d4fdb52
--- /dev/null
+++ b/services/core/java/com/android/server/policy/WindowWakeUpPolicy.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import static android.os.PowerManager.WAKE_REASON_CAMERA_LAUNCH;
+import static android.os.PowerManager.WAKE_REASON_GESTURE;
+import static android.os.PowerManager.WAKE_REASON_LID;
+import static android.os.PowerManager.WAKE_REASON_POWER_BUTTON;
+import static android.os.PowerManager.WAKE_REASON_WAKE_KEY;
+import static android.os.PowerManager.WAKE_REASON_WAKE_MOTION;
+import static android.view.KeyEvent.KEYCODE_POWER;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.PowerManager;
+import android.os.PowerManager.WakeReason;
+import android.os.SystemClock;
+import android.provider.Settings;
+import android.util.Slog;
+
+
+/** Policy controlling the decision and execution of window-related wake ups. */
+class WindowWakeUpPolicy {
+ private static final String TAG = "WindowWakeUpPolicy";
+
+ private static final boolean DEBUG = false;
+
+ private final Context mContext;
+ private final PowerManager mPowerManager;
+
+ private final boolean mAllowTheaterModeWakeFromKey;
+ private final boolean mAllowTheaterModeWakeFromPowerKey;
+ private final boolean mAllowTheaterModeWakeFromMotion;
+ private final boolean mAllowTheaterModeWakeFromMotionWhenNotDreaming;
+ private final boolean mAllowTheaterModeWakeFromCameraLens;
+ private final boolean mAllowTheaterModeWakeFromLidSwitch;
+ private final boolean mAllowTheaterModeWakeFromWakeGesture;
+
+ WindowWakeUpPolicy(Context context) {
+ mContext = context;
+ mPowerManager = context.getSystemService(PowerManager.class);
+
+ final Resources res = context.getResources();
+ mAllowTheaterModeWakeFromKey = res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromKey);
+ mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey
+ || res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey);
+ mAllowTheaterModeWakeFromMotion = res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion);
+ mAllowTheaterModeWakeFromMotionWhenNotDreaming = res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromMotionWhenNotDreaming);
+ mAllowTheaterModeWakeFromCameraLens = res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens);
+ mAllowTheaterModeWakeFromLidSwitch = res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch);
+ mAllowTheaterModeWakeFromWakeGesture = res.getBoolean(
+ com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture);
+ }
+
+ /**
+ * Wakes up from a key event.
+ *
+ * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
+ * @param keyCode the {@link android.view.KeyEvent} key code of the key event.
+ * @return {@code true} if the policy allows the requested wake up and the request has been
+ * executed; {@code false} otherwise.
+ */
+ boolean wakeUpFromKey(long eventTime, int keyCode) {
+ final boolean wakeAllowedDuringTheaterMode =
+ keyCode == KEYCODE_POWER
+ ? mAllowTheaterModeWakeFromPowerKey
+ : mAllowTheaterModeWakeFromKey;
+ return wakeUp(
+ eventTime,
+ wakeAllowedDuringTheaterMode,
+ keyCode == KEYCODE_POWER ? WAKE_REASON_POWER_BUTTON : WAKE_REASON_WAKE_KEY,
+ keyCode == KEYCODE_POWER ? "POWER" : "KEY");
+ }
+
+ /**
+ * Wakes up from a motion event.
+ *
+ * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
+ * @return {@code true} if the policy allows the requested wake up and the request has been
+ * executed; {@code false} otherwise.
+ */
+ boolean wakeUpFromMotion(long eventTime) {
+ return wakeUp(
+ eventTime, mAllowTheaterModeWakeFromMotion, WAKE_REASON_WAKE_MOTION, "MOTION");
+ }
+
+ /**
+ * Wakes up due to an opened camera cover.
+ *
+ * @param eventTime the timestamp of the event in {@link SystemClock#uptimeMillis()}.
+ * @return {@code true} if the policy allows the requested wake up and the request has been
+ * executed; {@code false} otherwise.
+ */
+ boolean wakeUpFromCameraCover(long eventTime) {
+ return wakeUp(
+ eventTime,
+ mAllowTheaterModeWakeFromCameraLens,
+ WAKE_REASON_CAMERA_LAUNCH,
+ "CAMERA_COVER");
+ }
+
+ /**
+ * Wakes up due to an opened lid.
+ *
+ * @return {@code true} if the policy allows the requested wake up and the request has been
+ * executed; {@code false} otherwise.
+ */
+ boolean wakeUpFromLid() {
+ return wakeUp(
+ SystemClock.uptimeMillis(),
+ mAllowTheaterModeWakeFromLidSwitch,
+ WAKE_REASON_LID,
+ "LID");
+ }
+
+ /**
+ * Wakes up to prevent sleeping when opening camera through power button.
+ *
+ * @return {@code true} if the policy allows the requested wake up and the request has been
+ * executed; {@code false} otherwise.
+ */
+ boolean wakeUpFromPowerKeyCameraGesture() {
+ return wakeUp(
+ SystemClock.uptimeMillis(),
+ mAllowTheaterModeWakeFromPowerKey,
+ WAKE_REASON_CAMERA_LAUNCH,
+ "CAMERA_GESTURE_PREVENT_LOCK");
+ }
+
+ /**
+ * Wake up from a wake gesture.
+ *
+ * @return {@code true} if the policy allows the requested wake up and the request has been
+ * executed; {@code false} otherwise.
+ */
+ boolean wakeUpFromWakeGesture() {
+ return wakeUp(
+ SystemClock.uptimeMillis(),
+ mAllowTheaterModeWakeFromWakeGesture,
+ WAKE_REASON_GESTURE,
+ "GESTURE");
+ }
+
+ private boolean wakeUp(
+ long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason, String details) {
+ final boolean isTheaterModeEnabled =
+ Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0) == 1;
+ if (!wakeInTheaterMode && isTheaterModeEnabled) {
+ if (DEBUG) Slog.d(TAG, "Unable to wake up from " + details);
+ return false;
+ }
+ mPowerManager.wakeUp(wakeTime, reason, "android.policy:" + details);
+ return true;
+ }
+}
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 4a2e1cba5cce..686b2a813bd3 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -65,7 +65,6 @@ import android.util.Slog;
import android.util.SparseArray;
import com.android.internal.annotations.GuardedBy;
-import com.android.internal.content.PackageMonitor;
import com.android.server.credentials.metrics.ApiName;
import com.android.server.credentials.metrics.ApiStatus;
import com.android.server.infra.AbstractMasterSystemService;
@@ -1204,6 +1203,9 @@ public final class CredentialManagerService
// If the app being removed matches any of the package names from
// this list then don't add it in the output.
Set<String> providers = new HashSet<>();
+ if (rawProviders == null || packageName == null) {
+ return providers;
+ }
for (String rawComponentName : rawProviders.split(":")) {
if (TextUtils.isEmpty(rawComponentName)
|| rawComponentName.equals("null")) {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
index d2e83e9b0708..9eeb4f3f218f 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthenticationStatsCollectorTest.java
@@ -271,6 +271,7 @@ public class AuthenticationStatsCollectorTest {
.thenReturn(true);
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_FACE)).thenReturn(false);
when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(true);
+ when(mContext.getSystemService(Context.FACE_SERVICE)).thenReturn(null);
mAuthenticationStatsCollector.authenticate(USER_ID_1, false /* authenticated */);
diff --git a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
index fd1abff8610b..d850c73ebc26 100644
--- a/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/credentials/CredentialManagerServiceTest.java
@@ -53,6 +53,12 @@ public final class CredentialManagerServiceTest {
}
@Test
+ public void getStoredProviders_nullValue_success() {
+ Set<String> providers = CredentialManagerService.getStoredProviders(null, null);
+ assertThat(providers.size()).isEqualTo(0);
+ }
+
+ @Test
public void getStoredProviders_success() {
Set<String> providers =
CredentialManagerService.getStoredProviders(
diff --git a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
index 21b8a94d17fb..dc1d2c5e54b6 100644
--- a/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/os/BugreportManagerServiceImplTest.java
@@ -16,26 +16,23 @@
package com.android.server.os;
+import android.app.admin.flags.Flags;
+import static android.app.admin.flags.Flags.onboardingBugreportV2Enabled;
+
import static com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.Mockito.when;
-import android.app.admin.DevicePolicyManager;
-import android.app.admin.flags.Flags;
import android.app.role.RoleManager;
import android.content.Context;
import android.os.Binder;
import android.os.BugreportManager.BugreportCallback;
-import android.os.BugreportParams;
import android.os.IBinder;
import android.os.IDumpstateListener;
import android.os.Process;
import android.os.RemoteException;
-import android.os.UserManager;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
@@ -51,8 +48,6 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
import java.io.FileDescriptor;
import java.util.concurrent.CompletableFuture;
@@ -71,11 +66,6 @@ public class BugreportManagerServiceImplTest {
private BugreportManagerServiceImpl mService;
private BugreportManagerServiceImpl.BugreportFileManager mBugreportFileManager;
- @Mock
- private UserManager mMockUserManager;
- @Mock
- private DevicePolicyManager mMockDevicePolicyManager;
-
private int mCallingUid = 1234;
private String mCallingPackage = "test.package";
private AtomicFile mMappingFile;
@@ -85,17 +75,14 @@ public class BugreportManagerServiceImplTest {
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getInstrumentation().getContext();
mMappingFile = new AtomicFile(mContext.getFilesDir(), "bugreport-mapping.xml");
ArraySet<String> mAllowlistedPackages = new ArraySet<>();
mAllowlistedPackages.add(mContext.getPackageName());
mService = new BugreportManagerServiceImpl(
- new TestInjector(mContext, mAllowlistedPackages, mMappingFile,
- mMockUserManager, mMockDevicePolicyManager));
+ new BugreportManagerServiceImpl.Injector(mContext, mAllowlistedPackages,
+ mMappingFile));
mBugreportFileManager = new BugreportManagerServiceImpl.BugreportFileManager(mMappingFile);
- // The calling user is an admin user by default.
- when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(true);
}
@After
@@ -178,36 +165,6 @@ public class BugreportManagerServiceImplTest {
}
@Test
- public void testStartBugreport_throwsForNonAdminUser() throws Exception {
- when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
-
- Exception thrown = assertThrows(Exception.class,
- () -> mService.startBugreport(mCallingUid, mContext.getPackageName(),
- new FileDescriptor(), /* screenshotFd= */ null,
- BugreportParams.BUGREPORT_MODE_FULL,
- /* flags= */ 0, new Listener(new CountDownLatch(1)),
- /* isScreenshotRequested= */ false));
-
- assertThat(thrown.getMessage()).contains("not an admin user");
- }
-
- @Test
- public void testStartBugreport_throwsForNotAffiliatedUser() throws Exception {
- when(mMockUserManager.isUserAdmin(anyInt())).thenReturn(false);
- when(mMockDevicePolicyManager.getDeviceOwnerUserId()).thenReturn(-1);
- when(mMockDevicePolicyManager.isAffiliatedUser(anyInt())).thenReturn(false);
-
- Exception thrown = assertThrows(Exception.class,
- () -> mService.startBugreport(mCallingUid, mContext.getPackageName(),
- new FileDescriptor(), /* screenshotFd= */ null,
- BugreportParams.BUGREPORT_MODE_REMOTE,
- /* flags= */ 0, new Listener(new CountDownLatch(1)),
- /* isScreenshotRequested= */ false));
-
- assertThat(thrown.getMessage()).contains("not affiliated to the device owner");
- }
-
- @Test
public void testRetrieveBugreportWithoutFilesForCaller() throws Exception {
CountDownLatch latch = new CountDownLatch(1);
Listener listener = new Listener(latch);
@@ -250,8 +207,7 @@ public class BugreportManagerServiceImplTest {
private void clearAllowlist() {
mService = new BugreportManagerServiceImpl(
- new TestInjector(mContext, new ArraySet<>(), mMappingFile,
- mMockUserManager, mMockDevicePolicyManager));
+ new BugreportManagerServiceImpl.Injector(mContext, new ArraySet<>(), mMappingFile));
}
private static class Listener implements IDumpstateListener {
@@ -302,27 +258,4 @@ public class BugreportManagerServiceImplTest {
complete(successful);
}
}
-
- private static class TestInjector extends BugreportManagerServiceImpl.Injector {
-
- private final UserManager mUserManager;
- private final DevicePolicyManager mDevicePolicyManager;
-
- TestInjector(Context context, ArraySet<String> allowlistedPackages, AtomicFile mappingFile,
- UserManager um, DevicePolicyManager dpm) {
- super(context, allowlistedPackages, mappingFile);
- mUserManager = um;
- mDevicePolicyManager = dpm;
- }
-
- @Override
- public UserManager getUserManager() {
- return mUserManager;
- }
-
- @Override
- public DevicePolicyManager getDevicePolicyManager() {
- return mDevicePolicyManager;
- }
- }
}