Merge "Fix flaky test WindowInputTestsi#testTrustedOverlapWindow" into sc-v2-dev
diff --git a/core/java/android/permission/PermissionUsageHelper.java b/core/java/android/permission/PermissionUsageHelper.java
index 20f6c10..cf2361a 100644
--- a/core/java/android/permission/PermissionUsageHelper.java
+++ b/core/java/android/permission/PermissionUsageHelper.java
@@ -199,22 +199,24 @@
// if any link in the chain is finished, remove the chain. Then, find any other chains that
// contain this op/package/uid/tag combination, and remove them, as well.
// TODO ntmyren: be smarter about this
- mAttributionChains.remove(attributionChainId);
- int numChains = mAttributionChains.size();
- ArrayList<Integer> toRemove = new ArrayList<>();
- for (int i = 0; i < numChains; i++) {
- int chainId = mAttributionChains.keyAt(i);
- ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i);
- int chainSize = chain.size();
- for (int j = 0; j < chainSize; j++) {
- AccessChainLink link = chain.get(j);
- if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) {
- toRemove.add(chainId);
- break;
+ synchronized(mAttributionChains) {
+ mAttributionChains.remove(attributionChainId);
+ int numChains = mAttributionChains.size();
+ ArrayList<Integer> toRemove = new ArrayList<>();
+ for (int i = 0; i < numChains; i++) {
+ int chainId = mAttributionChains.keyAt(i);
+ ArrayList<AccessChainLink> chain = mAttributionChains.valueAt(i);
+ int chainSize = chain.size();
+ for (int j = 0; j < chainSize; j++) {
+ AccessChainLink link = chain.get(j);
+ if (link.packageAndOpEquals(op, packageName, attributionTag, uid)) {
+ toRemove.add(chainId);
+ break;
+ }
}
}
+ mAttributionChains.removeAll(toRemove);
}
- mAttributionChains.removeAll(toRemove);
}
@Override
@@ -234,8 +236,10 @@
// If this is not a successful start, or it is not a chain, or it is untrusted, return
return;
}
- addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid,
- attributionTag, attributionFlags, attributionChainId);
+ synchronized(mAttributionChains) {
+ addLinkToChainIfNotPresent(AppOpsManager.opToPublicName(op), packageName, uid,
+ attributionTag, attributionFlags, attributionChainId);
+ }
}
private void addLinkToChainIfNotPresent(String op, String packageName, int uid,
@@ -310,7 +314,7 @@
String permGroup = usedPermGroups.get(permGroupNum);
ArrayMap<OpUsage, CharSequence> usagesWithLabels =
- getUniqueUsagesWithLabels(rawUsages.get(permGroup));
+ getUniqueUsagesWithLabels(permGroup, rawUsages.get(permGroup));
if (permGroup.equals(OPSTR_PHONE_CALL_MICROPHONE)) {
isPhone = true;
@@ -431,7 +435,8 @@
return ListFormatter.getInstance().format(labels);
}
- private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(List<OpUsage> usages) {
+ private ArrayMap<OpUsage, CharSequence> getUniqueUsagesWithLabels(String permGroup,
+ List<OpUsage> usages) {
ArrayMap<OpUsage, CharSequence> usagesAndLabels = new ArrayMap<>();
if (usages == null || usages.isEmpty()) {
@@ -466,7 +471,7 @@
// If this usage has a proxy, but is not a proxy, it is the end of a chain.
// TODO remove once camera converted
if (!proxies.containsKey(usageAttr) && usage.proxy != null
- && !usage.op.equals(OPSTR_RECORD_AUDIO)) {
+ && !MICROPHONE.equals(permGroup)) {
proxyLabels.put(usage, new ArrayList<>());
proxyPackages.add(usage.getPackageIdHash());
}
@@ -538,48 +543,51 @@
// TODO ntmyren: remove this proxy logic once camera is converted to AttributionSource
// For now: don't add mic proxy usages
- if (!start.op.equals(OPSTR_RECORD_AUDIO)) {
+ if (!MICROPHONE.equals(permGroup)) {
usagesAndLabels.put(start,
proxyLabelList.isEmpty() ? null : formatLabelList(proxyLabelList));
}
}
- for (int i = 0; i < mAttributionChains.size(); i++) {
- List<AccessChainLink> usageList = mAttributionChains.valueAt(i);
- int lastVisible = usageList.size() - 1;
- // TODO ntmyren: remove this mic code once camera is converted to AttributionSource
- // if the list is empty or incomplete, do not show it.
- if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd()
- || !usageList.get(0).isStart()
- || !usageList.get(lastVisible).usage.op.equals(OPSTR_RECORD_AUDIO)) {
- continue;
- }
-
- //TODO ntmyren: remove once camera etc. etc.
- for (AccessChainLink link: usageList) {
- proxyPackages.add(link.usage.getPackageIdHash());
- }
-
- AccessChainLink start = usageList.get(0);
- AccessChainLink lastVisibleLink = usageList.get(lastVisible);
- while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) {
- lastVisible--;
- lastVisibleLink = usageList.get(lastVisible);
- }
- String proxyLabel = null;
- if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) {
- try {
- PackageManager userPkgManager =
- getUserContext(lastVisibleLink.usage.getUser()).getPackageManager();
- ApplicationInfo appInfo = userPkgManager.getApplicationInfo(
- lastVisibleLink.usage.packageName, 0);
- proxyLabel = appInfo.loadLabel(userPkgManager).toString();
- } catch (PackageManager.NameNotFoundException e) {
- // do nothing
+ synchronized (mAttributionChains) {
+ for (int i = 0; i < mAttributionChains.size(); i++) {
+ List<AccessChainLink> usageList = mAttributionChains.valueAt(i);
+ int lastVisible = usageList.size() - 1;
+ // TODO ntmyren: remove this mic code once camera is converted to AttributionSource
+ // if the list is empty or incomplete, do not show it.
+ if (usageList.isEmpty() || !usageList.get(lastVisible).isEnd()
+ || !usageList.get(0).isStart()
+ || !permGroup.equals(getGroupForOp(usageList.get(0).usage.op))
+ || !MICROPHONE.equals(permGroup)) {
+ continue;
}
+ //TODO ntmyren: remove once camera etc. etc.
+ for (AccessChainLink link : usageList) {
+ proxyPackages.add(link.usage.getPackageIdHash());
+ }
+
+ AccessChainLink start = usageList.get(0);
+ AccessChainLink lastVisibleLink = usageList.get(lastVisible);
+ while (lastVisible > 0 && !shouldShowPackage(lastVisibleLink.usage.packageName)) {
+ lastVisible--;
+ lastVisibleLink = usageList.get(lastVisible);
+ }
+ String proxyLabel = null;
+ if (!lastVisibleLink.usage.packageName.equals(start.usage.packageName)) {
+ try {
+ PackageManager userPkgManager =
+ getUserContext(lastVisibleLink.usage.getUser()).getPackageManager();
+ ApplicationInfo appInfo = userPkgManager.getApplicationInfo(
+ lastVisibleLink.usage.packageName, 0);
+ proxyLabel = appInfo.loadLabel(userPkgManager).toString();
+ } catch (PackageManager.NameNotFoundException e) {
+ // do nothing
+ }
+
+ }
+ usagesAndLabels.put(start.usage, proxyLabel);
}
- usagesAndLabels.put(start.usage, proxyLabel);
}
for (int packageHash : mostRecentUsages.keySet()) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 07feb44..54952fc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6364,6 +6364,27 @@
public static final String ALLOW_MOCK_LOCATION = "mock_location";
/**
+ * This is used by Bluetooth Manager to store adapter name
+ * @hide
+ */
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ public static final String BLUETOOTH_NAME = "bluetooth_name";
+
+ /**
+ * This is used by Bluetooth Manager to store adapter address
+ * @hide
+ */
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ public static final String BLUETOOTH_ADDRESS = "bluetooth_address";
+
+ /**
+ * This is used by Bluetooth Manager to store whether adapter address is valid
+ * @hide
+ */
+ @Readable(maxTargetSdk = Build.VERSION_CODES.S)
+ public static final String BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
+
+ /**
* Setting to indicate that on device captions are enabled.
*
* @hide
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index dfd853a..1784dcf 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -301,6 +301,13 @@
public static final int FLAG_USE_LIGHT_BACKGROUND_LAYOUT = 4;
/**
+ * A ReadWriteHelper which has the same behavior as ReadWriteHelper.DEFAULT, but which is
+ * intentionally a different instance in order to trick Bundle reader so that it doesn't allow
+ * lazy initialization.
+ */
+ private static final Parcel.ReadWriteHelper ALTERNATIVE_DEFAULT = new Parcel.ReadWriteHelper();
+
+ /**
* Used to restrict the views which can be inflated
*
* @see android.view.LayoutInflater.Filter#onLoadClass(java.lang.Class)
@@ -1856,7 +1863,18 @@
this.value = in.readTypedObject(Bitmap.CREATOR);
break;
case BUNDLE:
- this.value = in.readBundle();
+ // Because we use Parcel.allowSquashing() when writing, and that affects
+ // how the contents of Bundles are written, we need to ensure the bundle is
+ // unparceled immediately, not lazily. Setting a custom ReadWriteHelper
+ // just happens to have that effect on Bundle.readFromParcel().
+ // TODO(b/212731590): build this state tracking into Bundle
+ if (in.hasReadWriteHelper()) {
+ this.value = in.readBundle();
+ } else {
+ in.setReadWriteHelper(ALTERNATIVE_DEFAULT);
+ this.value = in.readBundle();
+ in.setReadWriteHelper(null);
+ }
break;
case INTENT:
this.value = in.readTypedObject(Intent.CREATOR);
diff --git a/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml b/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml
index 4ac972c..44b2f45 100644
--- a/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml
+++ b/libs/WindowManager/Shell/res/layout/compat_mode_hint.xml
@@ -21,7 +21,7 @@
android:orientation="vertical"
android:clipToPadding="false"
android:paddingEnd="@dimen/compat_hint_padding_end"
- android:paddingBottom="5dp"
+ android:paddingBottom="8dp"
android:clickable="true">
<TextView
diff --git a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
index c99f3fe..dfaeeeb 100644
--- a/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
+++ b/libs/WindowManager/Shell/res/layout/compat_ui_layout.xml
@@ -33,8 +33,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:clipToPadding="false"
- android:layout_marginEnd="16dp"
- android:layout_marginBottom="16dp"
+ android:layout_marginEnd="@dimen/compat_button_margin"
+ android:layout_marginBottom="@dimen/compat_button_margin"
android:orientation="vertical">
<ImageButton
@@ -62,8 +62,10 @@
<ImageButton
android:id="@+id/size_compat_restart_button"
android:visibility="gone"
- android:layout_width="@dimen/size_compat_button_width"
- android:layout_height="@dimen/size_compat_button_height"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="@dimen/compat_button_margin"
+ android:layout_marginBottom="@dimen/compat_button_margin"
android:src="@drawable/size_compat_restart_button_ripple"
android:background="@android:color/transparent"
android:contentDescription="@string/restart_button_description"/>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index d338e3b..1c19a10 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -200,11 +200,8 @@
<!-- Size of user education views on large screens (phone is just match parent). -->
<dimen name="bubbles_user_education_width_large_screen">400dp</dimen>
- <!-- The width of the size compat restart button including padding. -->
- <dimen name="size_compat_button_width">80dp</dimen>
-
- <!-- The height of the size compat restart button including padding. -->
- <dimen name="size_compat_button_height">64dp</dimen>
+ <!-- Bottom and end margin for compat buttons. -->
+ <dimen name="compat_button_margin">16dp</dimen>
<!-- The radius of the corners of the compat hint bubble. -->
<dimen name="compat_hint_corner_radius">28dp</dimen>
@@ -212,8 +209,8 @@
<!-- The width of the compat hint point. -->
<dimen name="compat_hint_point_width">10dp</dimen>
- <!-- The end padding for the compat hint. Computed as (size_compat_button_width / 2
- - compat_hint_corner_radius - compat_hint_point_width /2). -->
+ <!-- The end padding for the compat hint. Computed as (compat button width (=48) / 2
+ + compat_button_margin - compat_hint_corner_radius - compat_hint_point_width / 2). -->
<dimen name="compat_hint_padding_end">7dp</dimen>
<!-- The width of the size compat hint. -->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 3de59b4..7decb54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -292,6 +292,7 @@
* Invalidates this instance, preventing future calls from updating the controller.
*/
void invalidate() {
+ Slog.d("b/206648922", "invalidating controller: " + mController);
mController = null;
}
@@ -317,7 +318,8 @@
(controller) -> out[0] = controller.getRecentTasks(maxNum, flags, userId)
.toArray(new GroupedRecentTaskInfo[0]),
true /* blocking */);
- Slog.d("b/206648922", "getRecentTasks(" + maxNum + "): " + out[0]);
+ Slog.d("b/206648922", "getRecentTasks(" + maxNum + "): " + out[0]
+ + " mController=" + mController);
return out[0];
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 53681e6..5d1d159 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -367,6 +367,8 @@
float splitRatio, RemoteAnimationAdapter adapter) {
// Init divider first to make divider leash for remote animation target.
setDividerVisibility(true /* visible */);
+ // Set false to avoid record new bounds with old task still on top;
+ mShouldUpdateRecents = false;
final WindowContainerTransaction wct = new WindowContainerTransaction();
final WindowContainerTransaction evictWct = new WindowContainerTransaction();
prepareEvictChildTasks(SPLIT_POSITION_TOP_OR_LEFT, evictWct);
@@ -393,6 +395,7 @@
@Override
public void onAnimationFinished() throws RemoteException {
mIsDividerRemoteAnimating = false;
+ mShouldUpdateRecents = true;
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> applyDividerVisibility(t));
finishedCallback.onAnimationFinished();
@@ -416,6 +419,7 @@
@Override
public void onAnimationCancelled() {
mIsDividerRemoteAnimating = false;
+ mShouldUpdateRecents = true;
mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> applyDividerVisibility(t));
try {
@@ -782,7 +786,9 @@
mLogger.logSideStageAppChange(getSideStagePosition(), mSideStage.getTopChildTaskUid(),
mSplitLayout.isLandscape());
}
- updateRecentTasksSplitPair();
+ if (present && visible) {
+ updateRecentTasksSplitPair();
+ }
for (int i = mListeners.size() - 1; i >= 0; --i) {
mListeners.get(i).onTaskStageChanged(taskId, stage, visible);
@@ -798,7 +804,6 @@
if (!mShouldUpdateRecents) {
return;
}
-
mRecentTasks.ifPresent(recentTasks -> {
Rect topLeftBounds = mSplitLayout.getBounds1();
Rect bottomRightBounds = mSplitLayout.getBounds2();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java
index e904f6a..4849163 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskUnfoldController.java
@@ -100,6 +100,9 @@
* @param leash surface leash for the appeared task
*/
public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) {
+ // Only handle child task surface here.
+ if (!taskInfo.hasParentTask()) return;
+
AnimationContext context = new AnimationContext(leash);
mAnimationContextByTaskId.put(taskInfo.taskId, context);
}
@@ -109,6 +112,8 @@
* @param taskInfo info for the vanished task
*/
public void onTaskVanished(ActivityManager.RunningTaskInfo taskInfo) {
+ if (!taskInfo.hasParentTask()) return;
+
AnimationContext context = mAnimationContextByTaskId.get(taskInfo.taskId);
if (context != null) {
final SurfaceControl.Transaction transaction = mTransactionPool.acquire();
diff --git a/media/packages/BluetoothMidiService/AndroidManifest.xml b/media/packages/BluetoothMidiService/AndroidManifest.xml
index 03606ba..9039011 100644
--- a/media/packages/BluetoothMidiService/AndroidManifest.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifest.xml
@@ -20,7 +20,7 @@
xmlns:tools="http://schemas.android.com/tools"
package="com.android.bluetoothmidiservice"
>
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
<uses-feature android:name="android.hardware.bluetooth_le"
android:required="true"/>
diff --git a/media/packages/BluetoothMidiService/AndroidManifestBase.xml b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
index bfb0546..5a900c7 100644
--- a/media/packages/BluetoothMidiService/AndroidManifestBase.xml
+++ b/media/packages/BluetoothMidiService/AndroidManifestBase.xml
@@ -19,7 +19,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.bluetoothmidiservice"
>
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29" />
+ <uses-sdk android:minSdkVersion="30" android:targetSdkVersion="30" />
<application
android:label="BluetoothMidi"
android:defaultToDeviceProtectedStorage="true"
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 693a027..d818ffc 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -298,7 +298,7 @@
auto& aSurfaceControlStats = aSurfaceTransactionStats.aSurfaceControlStats;
- for (const auto& [surfaceControl, latchTime, acquireTime, presentFence, previousReleaseFence, transformHint, frameEvents] : surfaceControlStats) {
+ for (const auto& [surfaceControl, latchTime, acquireTime, presentFence, previousReleaseFence, transformHint, frameEvents, ignore] : surfaceControlStats) {
ASurfaceControl* aSurfaceControl = reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
aSurfaceControlStats[aSurfaceControl].previousReleaseFence = previousReleaseFence;
@@ -650,7 +650,7 @@
for (const auto&
[surfaceControl, latchTime, acquireTime, presentFence,
previousReleaseFence, transformHint,
- frameEvents] : surfaceControlStats) {
+ frameEvents, ignore] : surfaceControlStats) {
ASurfaceControl* aSurfaceControl =
reinterpret_cast<ASurfaceControl*>(surfaceControl.get());
aSurfaceControlStats[aSurfaceControl].acquireTime = acquireTime;
@@ -662,4 +662,4 @@
Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction);
transaction->addTransactionCommittedCallback(callback, context);
-}
\ No newline at end of file
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
index 2b357c5..1e8cb9f 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtilsInternal.java
@@ -38,6 +38,7 @@
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.text.style.ImageSpan;
+import android.util.Log;
import android.view.MenuItem;
import android.widget.TextView;
@@ -54,6 +55,7 @@
public class RestrictedLockUtilsInternal extends RestrictedLockUtils {
private static final String LOG_TAG = "RestrictedLockUtils";
+ private static final boolean DEBUG = Log.isLoggable(LOG_TAG, Log.DEBUG);
/**
* @return drawables for displaying with settings that are locked by a device admin.
@@ -92,14 +94,25 @@
}
final UserManager um = UserManager.get(context);
+ final UserHandle userHandle = UserHandle.of(userId);
final List<UserManager.EnforcingUser> enforcingUsers =
- um.getUserRestrictionSources(userRestriction, UserHandle.of(userId));
+ um.getUserRestrictionSources(userRestriction, userHandle);
if (enforcingUsers.isEmpty()) {
// Restriction is not enforced.
return null;
- } else if (enforcingUsers.size() > 1) {
- return EnforcedAdmin.createDefaultEnforcedAdminWithRestriction(userRestriction);
+ }
+ final int size = enforcingUsers.size();
+ if (size > 1) {
+ final EnforcedAdmin enforcedAdmin = EnforcedAdmin
+ .createDefaultEnforcedAdminWithRestriction(userRestriction);
+ enforcedAdmin.user = userHandle;
+ if (DEBUG) {
+ Log.d(LOG_TAG, "Multiple (" + size + ") enforcing users for restriction '"
+ + userRestriction + "' on user " + userHandle + "; returning default admin "
+ + "(" + enforcedAdmin + ")");
+ }
+ return enforcedAdmin;
}
final int restrictionSource = enforcingUsers.get(0).getUserRestrictionSource();
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java
new file mode 100644
index 0000000..7ffae40
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiRestrictionsCache.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+import android.util.SparseArray;
+
+import androidx.annotation.VisibleForTesting;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This is a singleton class for Wi-Fi restrictions caching.
+ */
+public class WifiRestrictionsCache {
+ private static final String TAG = "WifiResCache";
+
+ /**
+ * Manages mapping between user ID and corresponding singleton {@link WifiRestrictionsCache}
+ * object.
+ */
+ @VisibleForTesting
+ protected static final SparseArray<WifiRestrictionsCache> sInstances = new SparseArray<>();
+
+ @VisibleForTesting
+ protected UserManager mUserManager;
+ @VisibleForTesting
+ protected Bundle mUserRestrictions;
+ @VisibleForTesting
+ protected final Map<String, Boolean> mRestrictions = new HashMap<>();
+
+ /**
+ * @return an instance of {@link WifiRestrictionsCache} object.
+ */
+ @NonNull
+ public static WifiRestrictionsCache getInstance(@NonNull Context context) {
+ final int requestUserId = context.getUserId();
+ WifiRestrictionsCache cache;
+ synchronized (sInstances) {
+ // We have same user context as request.
+ if (sInstances.indexOfKey(requestUserId) >= 0) {
+ return sInstances.get(requestUserId);
+ }
+ // Request by a new user context.
+ cache = new WifiRestrictionsCache(context);
+ sInstances.put(context.getUserId(), cache);
+ }
+ return cache;
+ }
+
+ /**
+ * Removes all the instances.
+ */
+ public static void clearInstance() {
+ synchronized (sInstances) {
+ for (int i = 0; i < sInstances.size(); i++) {
+ int key = sInstances.keyAt(i);
+ WifiRestrictionsCache cache = sInstances.get(key);
+ cache.clearRestrictions();
+ sInstances.remove(key);
+ }
+ sInstances.clear();
+ }
+ }
+
+ /**
+ * Constructor to create a singleton class for Wi-Fi restrictions cache.
+ *
+ * @param context The Context this is associated with.
+ */
+ protected WifiRestrictionsCache(@NonNull Context context) {
+ mUserManager = context.getSystemService(UserManager.class);
+ if (mUserManager != null) {
+ mUserRestrictions = mUserManager.getUserRestrictions();
+ }
+ }
+
+ /**
+ * @return the boolean value of the restrictions
+ */
+ public Boolean getRestriction(String key) {
+ if (mUserRestrictions == null) {
+ return false;
+ }
+ Boolean restriction;
+ synchronized (mRestrictions) {
+ if (mRestrictions.containsKey(key)) {
+ return mRestrictions.get(key);
+ }
+ restriction = mUserRestrictions.getBoolean(key);
+ mRestrictions.put(key, restriction);
+ }
+ return restriction;
+ }
+
+ /**
+ * Removes all the restrictions.
+ */
+ public void clearRestrictions() {
+ synchronized (mRestrictions) {
+ mRestrictions.clear();
+ }
+ }
+
+ /**
+ * @return Whether the user is allowed to config Wi-Fi.
+ */
+ public Boolean isConfigWifiAllowed() {
+ return !getRestriction(DISALLOW_CONFIG_WIFI);
+ }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java
new file mode 100644
index 0000000..404e0e8
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/wifi/WifiRestrictionsCacheTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.wifi;
+
+import static android.os.UserManager.DISALLOW_CONFIG_WIFI;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserManager;
+
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class WifiRestrictionsCacheTest {
+
+ private static final int USER_OWNER = 0;
+ private static final int USER_1 = 1;
+ private static final int USER_2 = 2;
+ private static final int USER_3 = 3;
+ private static final int USER_GUEST = 10;
+
+ @Rule
+ public final MockitoRule mMockitoRule = MockitoJUnit.rule();
+ @Mock
+ UserManager mUserManager;
+ @Mock
+ Bundle mUserRestrictionsOwner;
+ @Mock
+ Bundle mUserRestrictionsGuest;
+
+ private Context mContext;
+ private WifiRestrictionsCache mWifiRestrictionsCacheOwner;
+ private WifiRestrictionsCache mWifiRestrictionsCacheGuest;
+
+ @Before
+ public void setUp() {
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager);
+
+ when(mContext.getUserId()).thenReturn(USER_OWNER);
+ when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictionsOwner);
+ when(mUserRestrictionsOwner.getBoolean(anyString())).thenReturn(false);
+ mWifiRestrictionsCacheOwner = WifiRestrictionsCache.getInstance(mContext);
+
+ when(mContext.getUserId()).thenReturn(USER_GUEST);
+ when(mUserManager.getUserRestrictions()).thenReturn(mUserRestrictionsGuest);
+ when(mUserRestrictionsGuest.getBoolean(anyString())).thenReturn(true);
+ mWifiRestrictionsCacheGuest = WifiRestrictionsCache.getInstance(mContext);
+ }
+
+ @After
+ public void tearDown() {
+ WifiRestrictionsCache.clearInstance();
+ }
+
+ @Test
+ public void getInstance_sameUserId_sameInstance() {
+ when(mContext.getUserId()).thenReturn(USER_OWNER);
+ WifiRestrictionsCache instance1 = WifiRestrictionsCache.getInstance(mContext);
+
+ WifiRestrictionsCache instance2 = WifiRestrictionsCache.getInstance(mContext);
+
+ assertThat(instance1).isEqualTo(instance2);
+ }
+
+ @Test
+ public void getInstance_diffUserId_diffInstance() {
+ when(mContext.getUserId()).thenReturn(USER_OWNER);
+ WifiRestrictionsCache instance1 = WifiRestrictionsCache.getInstance(mContext);
+
+ when(mContext.getUserId()).thenReturn(USER_GUEST);
+ WifiRestrictionsCache instance2 = WifiRestrictionsCache.getInstance(mContext);
+
+ assertThat(instance1).isNotEqualTo(instance2);
+ }
+
+ @Test
+ public void clearInstance_instanceShouldBeEmpty() {
+ WifiRestrictionsCache.clearInstance();
+
+ assertThat(WifiRestrictionsCache.sInstances.size()).isEqualTo(0);
+ }
+
+ @Test
+ public void getRestriction_firstTime_getFromSystem() {
+ Bundle userRestrictions = mock(Bundle.class);
+ WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_1, userRestrictions);
+
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+ verify(userRestrictions).getBoolean(DISALLOW_CONFIG_WIFI);
+ }
+
+ @Test
+ public void getRestriction_secondTime_notGetFromSystem() {
+ Bundle userRestrictions = mock(Bundle.class);
+ WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_2, userRestrictions);
+ // First time to get the restriction value
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+ reset(userRestrictions);
+
+ // Second time to get the restriction value
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+ verify(userRestrictions, never()).getBoolean(DISALLOW_CONFIG_WIFI);
+ }
+
+ @Test
+ public void clearRestrictions_shouldGetRestrictionFromSystemAgain() {
+ Bundle userRestrictions = mock(Bundle.class);
+ WifiRestrictionsCache wifiRestrictionsCache = mockInstance(USER_3, userRestrictions);
+ // First time to get the restriction value
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+ reset(userRestrictions);
+
+ // Clear the cache and then second time to get the restriction value
+ wifiRestrictionsCache.clearRestrictions();
+ wifiRestrictionsCache.getRestriction(DISALLOW_CONFIG_WIFI);
+
+ verify(userRestrictions).getBoolean(DISALLOW_CONFIG_WIFI);
+ }
+
+ @Test
+ public void isConfigWifiAllowed_ownerUser_returnTrue() {
+ assertThat(mWifiRestrictionsCacheOwner.isConfigWifiAllowed()).isTrue();
+ }
+
+ @Test
+ public void isConfigWifiAllowed_guestUser_returnFalse() {
+ assertThat(mWifiRestrictionsCacheGuest.isConfigWifiAllowed()).isFalse();
+ }
+
+ private WifiRestrictionsCache mockInstance(int userId, Bundle userRestrictions) {
+ when(mContext.getUserId()).thenReturn(userId);
+ when(mUserManager.getUserRestrictions()).thenReturn(userRestrictions);
+ return WifiRestrictionsCache.getInstance(mContext);
+ }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 86b3765..4c9500c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2102,7 +2102,7 @@
}
if ((ai.flags & ApplicationInfo.FLAG_TEST_ONLY) == 0) {
// Skip checking readable annotations for test_only apps
- checkReadableAnnotation(settingsType, settingName, ai.targetSandboxVersion);
+ checkReadableAnnotation(settingsType, settingName, ai.targetSdkVersion);
}
/**
* some settings need additional permission check, this is to have a matching security
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 30db136..2583e09 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -278,7 +278,9 @@
* @see SurfaceControl#release()
*/
public void release() {
- leash.mSurfaceControl.release();
+ if (leash.mSurfaceControl != null) {
+ leash.mSurfaceControl.release();
+ }
if (mStartLeash != null) {
mStartLeash.release();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index ad1c232..98b5dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -645,7 +645,7 @@
if (biometricSourceType.equals(BiometricSourceType.FINGERPRINT)
&& mUpdateMonitor.isUdfpsSupported()
&& mNumConsecutiveFpFailures >= FP_ATTEMPTS_BEFORE_SHOW_BOUNCER) {
- mKeyguardViewController.showBouncer(true);
+ startWakeAndUnlock(MODE_SHOW_BOUNCER);
UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
mNumConsecutiveFpFailures = 0;
}
@@ -668,7 +668,8 @@
&& mUpdateMonitor.isUdfpsSupported()
&& (mStatusBarStateController.getState() == StatusBarState.SHADE
|| mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED)) {
- mKeyguardViewController.showBouncer(true);
+ startWakeAndUnlock(MODE_SHOW_BOUNCER);
+ UI_EVENT_LOGGER.log(BiometricUiEvent.BIOMETRIC_BOUNCER_SHOWN);
}
cleanup();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 7ca8652..732e5f0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -57,8 +57,7 @@
private int mUserSwitchPreferredY;
/**
- * Minimum top margin to avoid overlap with status bar, lock icon, or multi-user switcher
- * avatar.
+ * Minimum top margin to avoid overlap with status bar or multi-user switcher avatar.
*/
private int mMinTopMargin;
@@ -203,7 +202,7 @@
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
- return getClockY(1.0f, mDarkAmount);
+ return getClockY(1.0f, mDarkAmount) + mUserSwitchHeight;
} else {
return getClockY(1.0f, mDarkAmount) + mKeyguardStatusHeight;
}
@@ -213,7 +212,7 @@
if (mBypassEnabled) {
return (int) (mUnlockedStackScrollerPadding + mOverStretchAmount);
} else if (mIsSplitShade) {
- return Math.max(0, clockYPosition - mSplitShadeTopNotificationsMargin);
+ return clockYPosition - mSplitShadeTopNotificationsMargin + mUserSwitchHeight;
} else {
return clockYPosition + mKeyguardStatusHeight;
}
@@ -223,7 +222,7 @@
if (mBypassEnabled) {
return mUnlockedStackScrollerPadding;
} else if (mIsSplitShade) {
- return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ return mSplitShadeTargetTopMargin + mUserSwitchHeight;
} else {
return mMinTopMargin + mKeyguardStatusHeight;
}
@@ -231,7 +230,7 @@
private int getExpandedPreferredClockY() {
if (mIsSplitShade) {
- return Math.max(mSplitShadeTargetTopMargin, mMinTopMargin);
+ return mSplitShadeTargetTopMargin;
} else {
return mMinTopMargin;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index 5eb35ac..33c4109 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -1303,8 +1303,11 @@
mKeyguardStatusViewController.displayClock(LARGE);
}
updateKeyguardStatusViewAlignment(true /* animate */);
- int userIconHeight = mKeyguardQsUserSwitchController != null
+ int userSwitcherHeight = mKeyguardQsUserSwitchController != null
? mKeyguardQsUserSwitchController.getUserIconHeight() : 0;
+ if (mKeyguardUserSwitcherController != null) {
+ userSwitcherHeight = mKeyguardUserSwitcherController.getHeight();
+ }
float expandedFraction =
mUnlockedScreenOffAnimationController.isScreenOffAnimationPlaying()
? 1.0f : getExpandedFraction();
@@ -1324,7 +1327,7 @@
mStatusBarHeaderHeightKeyguard,
expandedFraction,
mKeyguardStatusViewController.getLockscreenHeight(),
- userIconHeight,
+ userSwitcherHeight,
userSwitcherPreferredY,
darkamount, mOverStretchAmount,
bypassEnabled, getUnlockedStackScrollerPadding(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
index 43b2061..8e4778e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherController.java
@@ -245,6 +245,10 @@
return mUserSwitcherController.isSimpleUserSwitcher();
}
+ public int getHeight() {
+ return mListView.getHeight();
+ }
+
/**
* @param animate if the transition should be animated
* @return true if the switcher state changed
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index cd8894c..850a4b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -97,9 +97,12 @@
} else {
// Update clickable state immediately so that the menu feels more responsive
userItemViews[i].setClickable(open);
- // Before running the animation, ensure visibility is set correctly
- userItemViews[i].updateVisibilities(animate || open /* showItem */,
- true /* showTextName */, false /* animate */);
+ // when opening we need to make views visible beforehand so they can be animated
+ if (open) {
+ userItemViews[i].updateVisibilities(true /* showItem */,
+ true /* showTextName */, false /* animate */);
+ }
+
}
}
@@ -117,6 +120,13 @@
setClipChildren(true);
setClipToPadding(true);
mAnimating = false;
+ if (!open) {
+ // after closing we hide children so that height of this view is correct
+ for (int i = 1; i < userItemViews.length; i++) {
+ userItemViews[i].updateVisibilities(false /* showItem */,
+ true /* showTextName */, false /* animate */);
+ }
+ }
});
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index 592fa15..70cb9d3 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -48,6 +48,8 @@
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
+import android.util.SparseIntArray;
import android.util.TypedValue;
import androidx.annotation.NonNull;
@@ -104,14 +106,15 @@
private final UserManager mUserManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final Executor mBgExecutor;
- private SecureSettings mSecureSettings;
+ private final SecureSettings mSecureSettings;
private final Executor mMainExecutor;
private final Handler mBgHandler;
private final boolean mIsMonetEnabled;
- private UserTracker mUserTracker;
- private DeviceProvisionedController mDeviceProvisionedController;
- private WallpaperColors mCurrentColors;
- private WallpaperManager mWallpaperManager;
+ private final UserTracker mUserTracker;
+ private final DeviceProvisionedController mDeviceProvisionedController;
+ // Current wallpaper colors associated to a user.
+ private final SparseArray<WallpaperColors> mCurrentColors = new SparseArray<>();
+ private final WallpaperManager mWallpaperManager;
private ColorScheme mColorScheme;
// If fabricated overlays were already created for the current theme.
private boolean mNeedsOverlayCreation;
@@ -125,11 +128,11 @@
private FabricatedOverlay mNeutralOverlay;
// If wallpaper color event will be accepted and change the UI colors.
private boolean mAcceptColorEvents = true;
- // If non-null, colors that were sent to the framework, and processing was deferred until
- // the next time the screen is off.
- private WallpaperColors mDeferredWallpaperColors;
- private int mDeferredWallpaperColorsFlags;
- private WakefulnessLifecycle mWakefulnessLifecycle;
+ // If non-null (per user), colors that were sent to the framework, and processing was deferred
+ // until the next time the screen is off.
+ private final SparseArray<WallpaperColors> mDeferredWallpaperColors = new SparseArray<>();
+ private final SparseIntArray mDeferredWallpaperColorsFlags = new SparseIntArray();
+ private final WakefulnessLifecycle mWakefulnessLifecycle;
// Defers changing themes until Setup Wizard is done.
private boolean mDeferredThemeEvaluation;
@@ -152,27 +155,53 @@
}
};
- private final OnColorsChangedListener mOnColorsChangedListener = (wallpaperColors, which) -> {
- if (!mAcceptColorEvents && mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP) {
- mDeferredWallpaperColors = wallpaperColors;
- mDeferredWallpaperColorsFlags = which;
- Log.i(TAG, "colors received; processing deferred until screen off: " + wallpaperColors);
- return;
+ private final OnColorsChangedListener mOnColorsChangedListener = new OnColorsChangedListener() {
+ @Override
+ public void onColorsChanged(WallpaperColors wallpaperColors, int which) {
+ throw new IllegalStateException("This should never be invoked, all messages should "
+ + "arrive on the overload that has a user id");
}
- if (wallpaperColors != null) {
- mAcceptColorEvents = false;
- // Any cache of colors deferred for process is now stale.
- mDeferredWallpaperColors = null;
- mDeferredWallpaperColorsFlags = 0;
- }
+ @Override
+ public void onColorsChanged(WallpaperColors wallpaperColors, int which, int userId) {
+ boolean currentUser = userId == mUserTracker.getUserId();
+ if (currentUser && !mAcceptColorEvents
+ && mWakefulnessLifecycle.getWakefulness() != WAKEFULNESS_ASLEEP) {
+ mDeferredWallpaperColors.put(userId, wallpaperColors);
+ mDeferredWallpaperColorsFlags.put(userId, which);
+ Log.i(TAG, "colors received; processing deferred until screen off: "
+ + wallpaperColors + " user: " + userId);
+ return;
+ }
- handleWallpaperColors(wallpaperColors, which);
+ if (currentUser && wallpaperColors != null) {
+ mAcceptColorEvents = false;
+ // Any cache of colors deferred for process is now stale.
+ mDeferredWallpaperColors.put(userId, null);
+ mDeferredWallpaperColorsFlags.put(userId, 0);
+ }
+
+ handleWallpaperColors(wallpaperColors, which, userId);
+ }
};
- private int getLatestWallpaperType() {
- return mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)
- > mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)
+ private final UserTracker.Callback mUserTrackerCallback = new UserTracker.Callback() {
+ @Override
+ public void onUserChanged(int newUser, @NonNull Context userContext) {
+ boolean isManagedProfile = mUserManager.isManagedProfile(newUser);
+ if (!mDeviceProvisionedController.isCurrentUserSetup() && isManagedProfile) {
+ Log.i(TAG, "User setup not finished when new user event was received. "
+ + "Deferring... Managed profile? " + isManagedProfile);
+ return;
+ }
+ if (DEBUG) Log.d(TAG, "Updating overlays for user switch / profile added.");
+ reevaluateSystemTheme(true /* forceReload */);
+ }
+ };
+
+ private int getLatestWallpaperType(int userId) {
+ return mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, userId)
+ > mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, userId)
? WallpaperManager.FLAG_LOCK : WallpaperManager.FLAG_SYSTEM;
}
@@ -204,14 +233,21 @@
return false;
}
- private void handleWallpaperColors(WallpaperColors wallpaperColors, int flags) {
- final boolean hadWallpaperColors = mCurrentColors != null;
- int latestWallpaperType = getLatestWallpaperType();
+ private void handleWallpaperColors(WallpaperColors wallpaperColors, int flags, int userId) {
+ final int currentUser = mUserTracker.getUserId();
+ final boolean hadWallpaperColors = mCurrentColors.get(userId) != null;
+ int latestWallpaperType = getLatestWallpaperType(userId);
if ((flags & latestWallpaperType) != 0) {
- mCurrentColors = wallpaperColors;
+ mCurrentColors.put(userId, wallpaperColors);
if (DEBUG) Log.d(TAG, "got new colors: " + wallpaperColors + " where: " + flags);
}
+ if (userId != currentUser) {
+ Log.d(TAG, "Colors " + wallpaperColors + " for user " + userId + ". "
+ + "Not for current user: " + currentUser);
+ return;
+ }
+
if (mDeviceProvisionedController != null
&& !mDeviceProvisionedController.isCurrentUserSetup()) {
if (hadWallpaperColors) {
@@ -226,13 +262,12 @@
} else {
if (DEBUG) {
Log.i(TAG, "During user setup, but allowing first color event: had? "
- + hadWallpaperColors + " has? " + (mCurrentColors != null));
+ + hadWallpaperColors + " has? " + (mCurrentColors.get(userId) != null));
}
}
}
// Check if we need to reset to default colors (if a color override was set that is sourced
// from the wallpaper)
- int currentUser = mUserTracker.getUserId();
String overlayPackageJson = mSecureSettings.getStringForUser(
Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES,
currentUser);
@@ -278,10 +313,9 @@
@Override
public void onReceive(Context context, Intent intent) {
boolean newWorkProfile = Intent.ACTION_MANAGED_PROFILE_ADDED.equals(intent.getAction());
- boolean userStarted = Intent.ACTION_USER_SWITCHED.equals(intent.getAction());
boolean isManagedProfile = mUserManager.isManagedProfile(
intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
- if (userStarted || newWorkProfile) {
+ if (newWorkProfile) {
if (!mDeviceProvisionedController.isCurrentUserSetup() && isManagedProfile) {
Log.i(TAG, "User setup not finished when " + intent.getAction()
+ " was received. Deferring... Managed profile? " + isManagedProfile);
@@ -330,7 +364,6 @@
public void start() {
if (DEBUG) Log.d(TAG, "Start");
final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
filter.addAction(Intent.ACTION_WALLPAPER_CHANGED);
mBroadcastDispatcher.registerReceiver(mBroadcastReceiver, filter, mMainExecutor,
@@ -365,15 +398,17 @@
return;
}
+ mUserTracker.addCallback(mUserTrackerCallback, mMainExecutor);
+
mDeviceProvisionedController.addCallback(mDeviceProvisionedListener);
// Upon boot, make sure we have the most up to date colors
Runnable updateColors = () -> {
WallpaperColors systemColor = mWallpaperManager.getWallpaperColors(
- getLatestWallpaperType());
+ getLatestWallpaperType(mUserTracker.getUserId()));
Runnable applyColors = () -> {
if (DEBUG) Log.d(TAG, "Boot colors: " + systemColor);
- mCurrentColors = systemColor;
+ mCurrentColors.put(mUserTracker.getUserId(), systemColor);
reevaluateSystemTheme(false /* forceReload */);
};
if (mDeviceProvisionedController.isCurrentUserSetup()) {
@@ -395,21 +430,22 @@
mWakefulnessLifecycle.addObserver(new WakefulnessLifecycle.Observer() {
@Override
public void onFinishedGoingToSleep() {
- if (mDeferredWallpaperColors != null) {
- WallpaperColors colors = mDeferredWallpaperColors;
- int flags = mDeferredWallpaperColorsFlags;
+ final int userId = mUserTracker.getUserId();
+ final WallpaperColors colors = mDeferredWallpaperColors.get(userId);
+ if (colors != null) {
+ int flags = mDeferredWallpaperColorsFlags.get(userId);
- mDeferredWallpaperColors = null;
- mDeferredWallpaperColorsFlags = 0;
+ mDeferredWallpaperColors.put(userId, null);
+ mDeferredWallpaperColorsFlags.put(userId, 0);
- handleWallpaperColors(colors, flags);
+ handleWallpaperColors(colors, flags, userId);
}
}
});
}
private void reevaluateSystemTheme(boolean forceReload) {
- final WallpaperColors currentColors = mCurrentColors;
+ final WallpaperColors currentColors = mCurrentColors.get(mUserTracker.getUserId());
final int mainColor;
final int accentCandidate;
if (currentColors == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
index 8b394bf..a3b2932 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
+++ b/packages/SystemUI/src/com/android/systemui/toast/SystemUIToast.java
@@ -200,7 +200,9 @@
iconView.setVisibility(View.GONE);
} else {
iconView.setImageDrawable(icon);
- if (appInfo.labelRes != 0) {
+ if (appInfo == null) {
+ Log.d(TAG, "No appInfo for pkg=" + mPackageName + " usr=" + mUserId);
+ } else if (appInfo.labelRes != 0) {
try {
Resources res = mContext.getPackageManager().getResourcesForApplication(
appInfo,
diff --git a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
index 2e183b3..ba9b638 100644
--- a/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
+++ b/packages/SystemUI/src/com/android/systemui/wallet/ui/WalletScreenController.java
@@ -223,8 +223,7 @@
}
mUiEventLogger.log(WalletUiEvent.QAW_CLICK_CARD);
- mActivityStarter.startActivity(
- ((QAWalletCardViewInfo) cardInfo).mWalletCard.getPendingIntent().getIntent(), true);
+ mActivityStarter.startPendingIntentDismissingKeyguard(cardInfo.getPendingIntent());
}
@Override
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
index 1182695..1827c7f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithmTest.java
@@ -62,6 +62,7 @@
private float mPanelExpansion;
private int mKeyguardStatusBarHeaderHeight;
private int mKeyguardStatusHeight;
+ private int mUserSwitchHeight;
private float mDark;
private float mQsExpansion;
private int mCutoutTopInset = 0;
@@ -264,8 +265,7 @@
@Test
public void clockPositionedDependingOnMarginInSplitShade() {
- when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
- .thenReturn(400);
+ setSplitShadeTopMargin(400);
mClockPositionAlgorithm.loadDimens(mResources);
givenLockScreen();
mIsSplitShade = true;
@@ -291,6 +291,32 @@
}
@Test
+ public void notifPaddingAccountsForMultiUserSwitcherInSplitShade() {
+ setSplitShadeTopMargin(100);
+ mUserSwitchHeight = 150;
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN the notif padding is split shade top margin + user switch height
+ assertThat(mClockPosition.stackScrollerPadding).isEqualTo(250);
+ }
+
+ @Test
+ public void clockDoesntAccountForMultiUserSwitcherInSplitShade() {
+ setSplitShadeTopMargin(100);
+ mUserSwitchHeight = 150;
+ mClockPositionAlgorithm.loadDimens(mResources);
+ givenLockScreen();
+ mIsSplitShade = true;
+ // WHEN the position algorithm is run
+ positionClock();
+ // THEN clockY = split shade top margin
+ assertThat(mClockPosition.clockY).isEqualTo(100);
+ }
+
+ @Test
public void notifPaddingExpandedAlignedWithClockInSplitShadeMode() {
givenLockScreen();
mIsSplitShade = true;
@@ -495,6 +521,11 @@
assertThat(mClockPosition.clockY).isEqualTo(mCutoutTopInset);
}
+ private void setSplitShadeTopMargin(int value) {
+ when(mResources.getDimensionPixelSize(R.dimen.keyguard_split_shade_top_margin))
+ .thenReturn(value);
+ }
+
private void givenHighestBurnInOffset() {
when(BurnInHelperKt.getBurnInOffset(anyInt(), anyBoolean())).then(returnsFirstArg());
}
@@ -529,7 +560,7 @@
mKeyguardStatusBarHeaderHeight,
mPanelExpansion,
mKeyguardStatusHeight,
- 0 /* userSwitchHeight */,
+ mUserSwitchHeight,
0 /* userSwitchPreferredY */,
mDark,
ZERO_DRAG,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index 3ff5666..b357c78 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -76,6 +76,9 @@
@RunWith(AndroidTestingRunner.class)
public class ThemeOverlayControllerTest extends SysuiTestCase {
+ private static final int USER_SYSTEM = UserHandle.USER_SYSTEM;
+ private static final int USER_SECONDARY = 10;
+
private ThemeOverlayController mThemeOverlayController;
@Mock
private Executor mBgExecutor;
@@ -111,6 +114,9 @@
private ArgumentCaptor<DeviceProvisionedListener> mDeviceProvisionedListener;
@Captor
private ArgumentCaptor<WakefulnessLifecycle.Observer> mWakefulnessLifecycleObserver;
+ @Captor
+ private ArgumentCaptor<UserTracker.Callback> mUserTrackerCallback;
+
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
@@ -133,6 +139,7 @@
mWakefulnessLifecycle.dispatchFinishedWakingUp();
mThemeOverlayController.start();
+ verify(mUserTracker).addCallback(mUserTrackerCallback.capture(), eq(mMainExecutor));
verify(mWallpaperManager).addOnColorsChangedListener(mColorsListener.capture(), eq(null),
eq(UserHandle.USER_ALL));
verify(mBroadcastDispatcher).registerReceiver(mBroadcastReceiver.capture(), any(),
@@ -156,7 +163,8 @@
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
@@ -170,12 +178,13 @@
.isEqualTo(new OverlayIdentifier("ffff0000"));
// Should not ask again if changed to same value
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
verifyNoMoreInteractions(mThemeOverlayApplier);
// Should not ask again even for new colors until we change wallpapers
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
- null, null), WallpaperManager.FLAG_SYSTEM);
+ null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM);
verifyNoMoreInteractions(mThemeOverlayApplier);
// But should change theme after changing wallpapers
@@ -184,7 +193,7 @@
intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
mBroadcastReceiver.getValue().onReceive(null, intent);
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
- null, null), WallpaperManager.FLAG_SYSTEM);
+ null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -193,7 +202,8 @@
// Should ask for a new theme when wallpaper colors change
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
@@ -211,7 +221,7 @@
clearInvocations(mThemeOverlayApplier);
mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
- null, null), WallpaperManager.FLAG_SYSTEM);
+ null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM);
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
}
@@ -229,7 +239,8 @@
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
@@ -257,7 +268,8 @@
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -289,10 +301,13 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(20);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(21);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(20);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(21);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -320,10 +335,11 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(-1);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(-1);
mColorsListener.getValue().onColorsChanged(mainColors,
- WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK);
+ WallpaperManager.FLAG_SYSTEM | WallpaperManager.FLAG_LOCK, USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -349,9 +365,11 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(1);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK,
+ USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -377,9 +395,11 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(-1);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(-1);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -407,11 +427,14 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(1);
// SYSTEM wallpaper is the last applied one
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(2);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(2);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings).putString(
@@ -437,11 +460,14 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(1);
// SYSTEM wallpaper is the last applied one
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(2);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(2);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<String> updatedSetting = ArgumentCaptor.forClass(String.class);
verify(mSecureSettings, never()).putString(
@@ -467,11 +493,14 @@
when(mSecureSettings.getStringForUser(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_LOCK)).thenReturn(1);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_LOCK, USER_SYSTEM))
+ .thenReturn(1);
// SYSTEM wallpaper is the last applied one
- when(mWallpaperManager.getWallpaperId(WallpaperManager.FLAG_SYSTEM)).thenReturn(2);
+ when(mWallpaperManager.getWallpaperIdForUser(WallpaperManager.FLAG_SYSTEM, USER_SYSTEM))
+ .thenReturn(2);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_LOCK,
+ USER_SYSTEM);
verify(mSecureSettings, never()).putString(
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), any());
@@ -482,6 +511,34 @@
}
@Test
+ public void onUserSwitching_setsTheme() {
+ // Setup users with different colors
+ WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED), null, null);
+ WallpaperColors secondaryColors =
+ new WallpaperColors(Color.valueOf(Color.BLUE), null, null);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(secondaryColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SECONDARY);
+
+ // When changing users
+ clearInvocations(mThemeOverlayApplier);
+ when(mUserTracker.getUserId()).thenReturn(USER_SECONDARY);
+ mUserTrackerCallback.getValue().onUserChanged(USER_SECONDARY, mContext);
+
+ ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
+ ArgumentCaptor.forClass(Map.class);
+ verify(mThemeOverlayApplier)
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+
+ // Assert that we received secondary user colors
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
+ .isEqualTo(new OverlayIdentifier("ff0000ff"));
+ assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_ACCENT_COLOR))
+ .isEqualTo(new OverlayIdentifier("ff0000ff"));
+ }
+
+ @Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
@@ -515,7 +572,8 @@
reset(mDeviceProvisionedController);
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
@@ -525,11 +583,11 @@
Intent intent = new Intent(Intent.ACTION_WALLPAPER_CHANGED);
intent.putExtra(WallpaperManager.EXTRA_FROM_FOREGROUND_APP, true);
mBroadcastReceiver.getValue().onReceive(null, intent);
- mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM, USER_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
any());
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN),
- null, null), WallpaperManager.FLAG_SYSTEM);
+ null, null), WallpaperManager.FLAG_SYSTEM, USER_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
any());
}
@@ -607,7 +665,8 @@
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
// Defers event because we already have initial colors.
verify(mThemeOverlayApplier, never())
@@ -628,14 +687,16 @@
// Second color application is not applied.
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
clearInvocations(mThemeOverlayApplier);
// Device went to sleep and second set of colors was applied.
mainColors = new WallpaperColors(Color.valueOf(Color.BLUE),
Color.valueOf(Color.RED), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
@@ -652,14 +713,16 @@
// Second color application is not applied.
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
Color.valueOf(Color.BLUE), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
clearInvocations(mThemeOverlayApplier);
// Device went to sleep and second set of colors was applied.
mainColors = new WallpaperColors(Color.valueOf(Color.BLUE),
Color.valueOf(Color.RED), null);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
verify(mThemeOverlayApplier, never())
.applyCurrentUserOverlays(any(), any(), anyInt(), any());
@@ -678,7 +741,8 @@
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), anyInt()))
.thenReturn(jsonString);
- mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
+ mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM,
+ USER_SYSTEM);
ArgumentCaptor<Map<String, OverlayIdentifier>> themeOverlays =
ArgumentCaptor.forClass(Map.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
index e3b07b3..01769e5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wallet/ui/WalletScreenControllerTest.java
@@ -21,7 +21,6 @@
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -96,7 +95,7 @@
@Mock
UiEventLogger mUiEventLogger;
@Captor
- ArgumentCaptor<Intent> mIntentCaptor;
+ ArgumentCaptor<PendingIntent> mIntentCaptor;
@Captor
ArgumentCaptor<QuickAccessWalletClient.OnWalletCardsRetrievedCallback> mCallbackCaptor;
private WalletScreenController mController;
@@ -374,10 +373,12 @@
mController.onCardClicked(walletCardViewInfo);
- verify(mActivityStarter).startActivity(mIntentCaptor.capture(), eq(true));
+ verify(mActivityStarter).startPendingIntentDismissingKeyguard(mIntentCaptor.capture());
- assertEquals(mWalletIntent.getAction(), mIntentCaptor.getValue().getAction());
- assertEquals(mWalletIntent.getComponent(), mIntentCaptor.getValue().getComponent());
+ Intent actualIntent = mIntentCaptor.getValue().getIntent();
+
+ assertEquals(mWalletIntent.getAction(), actualIntent.getAction());
+ assertEquals(mWalletIntent.getComponent(), actualIntent.getComponent());
verify(mUiEventLogger, times(1)).log(WalletUiEvent.QAW_CLICK_CARD);
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index ea63792..ff24c6f 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -110,10 +110,6 @@
private static final String BLUETOOTH_PRIVILEGED =
android.Manifest.permission.BLUETOOTH_PRIVILEGED;
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDR_VALID = "bluetooth_addr_valid";
- private static final String SECURE_SETTINGS_BLUETOOTH_ADDRESS = "bluetooth_address";
- private static final String SECURE_SETTINGS_BLUETOOTH_NAME = "bluetooth_name";
-
private static final int ACTIVE_LOG_MAX_SIZE = 20;
private static final int CRASH_LOG_MAX_SIZE = 100;
@@ -636,7 +632,7 @@
if (mContext.getResources()
.getBoolean(com.android.internal.R.bool.config_bluetooth_address_validation)
&& Settings.Secure.getIntForUser(mContentResolver,
- SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0, mUserId)
+ Settings.Secure.BLUETOOTH_NAME, 0, mUserId)
== 0) {
// if the valid flag is not set, don't load the address and name
if (DBG) {
@@ -645,9 +641,9 @@
return;
}
mName = Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, mUserId);
+ mContentResolver, Settings.Secure.BLUETOOTH_NAME, mUserId);
mAddress = Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS, mUserId);
+ mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS, mUserId);
if (DBG) {
Slog.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
}
@@ -661,30 +657,30 @@
*/
private void storeNameAndAddress(String name, String address) {
if (name != null) {
- Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME, name,
+ Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_NAME, name,
mUserId);
mName = name;
if (DBG) {
Slog.d(TAG, "Stored Bluetooth name: " + Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME,
+ mContentResolver, Settings.Secure.BLUETOOTH_NAME,
mUserId));
}
}
if (address != null) {
- Settings.Secure.putStringForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+ Settings.Secure.putStringForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
address, mUserId);
mAddress = address;
if (DBG) {
Slog.d(TAG,
"Stored Bluetoothaddress: " + Settings.Secure.getStringForUser(
- mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS,
+ mContentResolver, Settings.Secure.BLUETOOTH_ADDRESS,
mUserId));
}
}
if ((name != null) && (address != null)) {
- Settings.Secure.putIntForUser(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 1,
+ Settings.Secure.putIntForUser(mContentResolver, Settings.Secure.BLUETOOTH_ADDR_VALID, 1,
mUserId);
}
}
diff --git a/services/core/java/com/android/server/am/CachedAppOptimizer.java b/services/core/java/com/android/server/am/CachedAppOptimizer.java
index 9da6d52..8199d94 100644
--- a/services/core/java/com/android/server/am/CachedAppOptimizer.java
+++ b/services/core/java/com/android/server/am/CachedAppOptimizer.java
@@ -900,7 +900,7 @@
void unfreezeTemporarily(ProcessRecord app) {
if (mUseFreezer) {
synchronized (mProcLock) {
- if (app.mOptRecord.isFrozen()) {
+ if (app.mOptRecord.isFrozen() || app.mOptRecord.isPendingFreeze()) {
unfreezeAppLSP(app);
freezeAppAsyncLSP(app);
}
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 22dd2c0..cbc2c0c 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -50,6 +50,8 @@
import android.provider.Settings;
import android.util.Log;
import android.util.MathUtils;
+import android.util.MutableFloat;
+import android.util.MutableInt;
import android.util.Slog;
import android.util.TimeUtils;
import android.view.Display;
@@ -1323,6 +1325,7 @@
// Animate the screen brightness when the screen is on or dozing.
// Skip the animation when the screen is off or suspended or transition to/from VR.
+ boolean brightnessAdjusted = false;
if (!mPendingScreenOff) {
if (mSkipScreenOnBrightnessRamp) {
if (state == Display.STATE_ON) {
@@ -1410,15 +1413,19 @@
// slider event so notify as if the system changed the brightness.
userInitiatedChange = false;
}
- notifyBrightnessChanged(brightnessState, userInitiatedChange,
+ notifyBrightnessTrackerChanged(brightnessState, userInitiatedChange,
hadUserBrightnessPoint);
}
// We save the brightness info *after* the brightness setting has been changed and
// adjustments made so that the brightness info reflects the latest value.
- saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
+ brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting(), animateValue);
} else {
- saveBrightnessInfo(getScreenBrightnessSetting());
+ brightnessAdjusted = saveBrightnessInfo(getScreenBrightnessSetting());
+ }
+
+ if (brightnessAdjusted) {
+ postBrightnessChangeRunnable();
}
// Log any changes to what is currently driving the brightness setting.
@@ -1534,31 +1541,50 @@
public BrightnessInfo getBrightnessInfo() {
synchronized (mCachedBrightnessInfo) {
return new BrightnessInfo(
- mCachedBrightnessInfo.brightness,
- mCachedBrightnessInfo.adjustedBrightness,
- mCachedBrightnessInfo.brightnessMin,
- mCachedBrightnessInfo.brightnessMax,
- mCachedBrightnessInfo.hbmMode,
- mCachedBrightnessInfo.highBrightnessTransitionPoint);
+ mCachedBrightnessInfo.brightness.value,
+ mCachedBrightnessInfo.adjustedBrightness.value,
+ mCachedBrightnessInfo.brightnessMin.value,
+ mCachedBrightnessInfo.brightnessMax.value,
+ mCachedBrightnessInfo.hbmMode.value,
+ mCachedBrightnessInfo.hbmTransitionPoint.value);
}
}
- private void saveBrightnessInfo(float brightness) {
- saveBrightnessInfo(brightness, brightness);
+ private boolean saveBrightnessInfo(float brightness) {
+ return saveBrightnessInfo(brightness, brightness);
}
- private void saveBrightnessInfo(float brightness, float adjustedBrightness) {
+ private boolean saveBrightnessInfo(float brightness, float adjustedBrightness) {
synchronized (mCachedBrightnessInfo) {
- mCachedBrightnessInfo.brightness = brightness;
- mCachedBrightnessInfo.adjustedBrightness = adjustedBrightness;
- mCachedBrightnessInfo.brightnessMin = mHbmController.getCurrentBrightnessMin();
- mCachedBrightnessInfo.brightnessMax = mHbmController.getCurrentBrightnessMax();
- mCachedBrightnessInfo.hbmMode = mHbmController.getHighBrightnessMode();
- mCachedBrightnessInfo.highBrightnessTransitionPoint =
- mHbmController.getTransitionPoint();
+ boolean changed = false;
+
+ changed |=
+ mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightness,
+ brightness);
+ changed |=
+ mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.adjustedBrightness,
+ adjustedBrightness);
+ changed |=
+ mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMin,
+ mHbmController.getCurrentBrightnessMin());
+ changed |=
+ mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.brightnessMax,
+ mHbmController.getCurrentBrightnessMax());
+ changed |=
+ mCachedBrightnessInfo.checkAndSetInt(mCachedBrightnessInfo.hbmMode,
+ mHbmController.getHighBrightnessMode());
+ changed |=
+ mCachedBrightnessInfo.checkAndSetFloat(mCachedBrightnessInfo.hbmTransitionPoint,
+ mHbmController.getTransitionPoint());
+
+ return changed;
}
}
+ void postBrightnessChangeRunnable() {
+ mHandler.post(mOnBrightnessChangeRunnable);
+ }
+
private HighBrightnessModeController createHbmControllerLocked() {
final DisplayDevice device = mLogicalDisplay.getPrimaryDisplayDeviceLocked();
final DisplayDeviceConfig ddConfig = device.getDisplayDeviceConfig();
@@ -1571,7 +1597,7 @@
PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX, hbmData,
() -> {
sendUpdatePowerStateLocked();
- mHandler.post(mOnBrightnessChangeRunnable);
+ postBrightnessChangeRunnable();
// TODO(b/192258832): Switch the HBMChangeCallback to a listener pattern.
if (mAutomaticBrightnessController != null) {
mAutomaticBrightnessController.update();
@@ -2073,7 +2099,7 @@
private void setCurrentScreenBrightness(float brightnessValue) {
if (brightnessValue != mCurrentScreenBrightnessSetting) {
mCurrentScreenBrightnessSetting = brightnessValue;
- mHandler.post(mOnBrightnessChangeRunnable);
+ postBrightnessChangeRunnable();
}
}
@@ -2125,7 +2151,7 @@
return true;
}
- private void notifyBrightnessChanged(float brightness, boolean userInitiated,
+ private void notifyBrightnessTrackerChanged(float brightness, boolean userInitiated,
boolean hadUserDataPoint) {
final float brightnessInNits = convertToNits(brightness);
if (mPowerRequest.useAutoBrightness && brightnessInNits >= 0.0f
@@ -2236,16 +2262,17 @@
pw.println(" mColorFadeFadesConfig=" + mColorFadeFadesConfig);
pw.println(" mColorFadeEnabled=" + mColorFadeEnabled);
synchronized (mCachedBrightnessInfo) {
- pw.println(" mCachedBrightnessInfo.brightness=" + mCachedBrightnessInfo.brightness);
+ pw.println(" mCachedBrightnessInfo.brightness=" +
+ mCachedBrightnessInfo.brightness.value);
pw.println(" mCachedBrightnessInfo.adjustedBrightness=" +
- mCachedBrightnessInfo.adjustedBrightness);
+ mCachedBrightnessInfo.adjustedBrightness.value);
pw.println(" mCachedBrightnessInfo.brightnessMin=" +
- mCachedBrightnessInfo.brightnessMin);
+ mCachedBrightnessInfo.brightnessMin.value);
pw.println(" mCachedBrightnessInfo.brightnessMax=" +
- mCachedBrightnessInfo.brightnessMax);
- pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode);
- pw.println(" mCachedBrightnessInfo.highBrightnessTransitionPoint=" +
- mCachedBrightnessInfo.highBrightnessTransitionPoint);
+ mCachedBrightnessInfo.brightnessMax.value);
+ pw.println(" mCachedBrightnessInfo.hbmMode=" + mCachedBrightnessInfo.hbmMode.value);
+ pw.println(" mCachedBrightnessInfo.hbmTransitionPoint=" +
+ mCachedBrightnessInfo.hbmTransitionPoint.value);
}
pw.println(" mDisplayBlanksAfterDozeConfig=" + mDisplayBlanksAfterDozeConfig);
pw.println(" mBrightnessBucketsInDozeConfig=" + mBrightnessBucketsInDozeConfig);
@@ -2663,11 +2690,31 @@
}
static class CachedBrightnessInfo {
- public float brightness;
- public float adjustedBrightness;
- public float brightnessMin;
- public float brightnessMax;
- public int hbmMode;
- public float highBrightnessTransitionPoint;
+ public MutableFloat brightness = new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ public MutableFloat adjustedBrightness =
+ new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ public MutableFloat brightnessMin =
+ new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ public MutableFloat brightnessMax =
+ new MutableFloat(PowerManager.BRIGHTNESS_INVALID_FLOAT);
+ public MutableInt hbmMode = new MutableInt(BrightnessInfo.HIGH_BRIGHTNESS_MODE_OFF);
+ public MutableFloat hbmTransitionPoint =
+ new MutableFloat(HighBrightnessModeController.HBM_TRANSITION_POINT_INVALID);
+
+ public boolean checkAndSetFloat(MutableFloat mf, float f) {
+ if (mf.value != f) {
+ mf.value = f;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean checkAndSetInt(MutableInt mi, int i) {
+ if (mi.value != i) {
+ mi.value = i;
+ return true;
+ }
+ return false;
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7a70bfe..c048644 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -4792,7 +4792,7 @@
try {
mDomainVerificationManager.printState(writer, packageName,
UserHandle.USER_ALL, mSettings::getPackageLPr);
- } catch (PackageManager.NameNotFoundException e) {
+ } catch (Exception e) {
pw.println("Failure printing domain verification information");
Slog.e(TAG, "Failure printing domain verification information", e);
}
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 7096f6f..cb28637 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -434,7 +434,8 @@
|| !pm.isGranted(Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
pkg, UserHandle.of(userId))
|| !pm.isGranted(Manifest.permission.READ_PHONE_STATE, pkg,
- UserHandle.of(userId))) {
+ UserHandle.of(userId))
+ || pm.isSysComponentOrPersistentPlatformSignedPrivApp(pkg)) {
continue;
}
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
index 0b48b5c..2208e3c 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationEnforcer.java
@@ -70,8 +70,11 @@
break;
default:
if (!proxy.isCallerVerifier(callingUid)) {
- throw new SecurityException(
- "Caller is not allowed to query domain verification state");
+ mContext.enforcePermission(android.Manifest.permission.DUMP,
+ Binder.getCallingPid(), callingUid,
+ "Caller " + callingUid
+ + " is not allowed to query domain verification state");
+ break;
}
mContext.enforcePermission(android.Manifest.permission.QUERY_ALL_PACKAGES,
diff --git a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
index 4f19009..2270df3 100644
--- a/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
+++ b/services/core/java/com/android/server/pm/verify/domain/DomainVerificationService.java
@@ -1193,6 +1193,7 @@
@Nullable @UserIdInt Integer userId,
@NonNull Function<String, PackageSetting> pkgSettingFunction)
throws NameNotFoundException {
+ mEnforcer.assertApprovedQuerent(mConnection.getCallingUid(), mProxy);
synchronized (mLock) {
mDebug.printState(writer, packageName, userId, pkgSettingFunction, mAttachedPkgStates);
}
diff --git a/services/core/java/com/android/server/policy/KeyCombinationManager.java b/services/core/java/com/android/server/policy/KeyCombinationManager.java
index 268de3e..68e078c 100644
--- a/services/core/java/com/android/server/policy/KeyCombinationManager.java
+++ b/services/core/java/com/android/server/policy/KeyCombinationManager.java
@@ -17,11 +17,13 @@
import static android.view.KeyEvent.KEYCODE_POWER;
+import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseLongArray;
import android.view.KeyEvent;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ToBooleanFunction;
import java.io.PrintWriter;
@@ -35,13 +37,18 @@
private static final String TAG = "KeyCombinationManager";
// Store the received down time of keycode.
+ @GuardedBy("mLock")
private final SparseLongArray mDownTimes = new SparseLongArray(2);
private final ArrayList<TwoKeysCombinationRule> mRules = new ArrayList();
// Selected rules according to current key down.
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
private final ArrayList<TwoKeysCombinationRule> mActiveRules = new ArrayList();
// The rule has been triggered by current keys.
+ @GuardedBy("mLock")
private TwoKeysCombinationRule mTriggeredRule;
+ private final Handler mHandler = new Handler();
// Keys in a key combination must be pressed within this interval of each other.
private static final long COMBINE_KEY_DELAY_MILLIS = 150;
@@ -109,6 +116,12 @@
* Return true if any active rule could be triggered by the key event, otherwise false.
*/
boolean interceptKey(KeyEvent event, boolean interactive) {
+ synchronized (mLock) {
+ return interceptKeyLocked(event, interactive);
+ }
+ }
+
+ private boolean interceptKeyLocked(KeyEvent event, boolean interactive) {
final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
final int keyCode = event.getKeyCode();
final int count = mActiveRules.size();
@@ -154,7 +167,7 @@
return false;
}
Log.v(TAG, "Performing combination rule : " + rule);
- rule.execute();
+ mHandler.post(rule::execute);
mTriggeredRule = rule;
return true;
});
@@ -169,7 +182,7 @@
for (int index = count - 1; index >= 0; index--) {
final TwoKeysCombinationRule rule = mActiveRules.get(index);
if (rule.shouldInterceptKey(keyCode)) {
- rule.cancel();
+ mHandler.post(rule::cancel);
mActiveRules.remove(index);
}
}
@@ -181,31 +194,37 @@
* Return the interceptTimeout to tell InputDispatcher when is ready to deliver to window.
*/
long getKeyInterceptTimeout(int keyCode) {
- if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) {
- return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS;
+ synchronized (mLock) {
+ if (forAllActiveRules((rule) -> rule.shouldInterceptKey(keyCode))) {
+ return mDownTimes.get(keyCode) + COMBINE_KEY_DELAY_MILLIS;
+ }
+ return 0;
}
- return 0;
}
/**
* True if the key event had been handled.
*/
boolean isKeyConsumed(KeyEvent event) {
- if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
- return false;
+ synchronized (mLock) {
+ if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) != 0) {
+ return false;
+ }
+ return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode());
}
- return mTriggeredRule != null && mTriggeredRule.shouldInterceptKey(event.getKeyCode());
}
/**
* True if power key is the candidate.
*/
boolean isPowerKeyIntercepted() {
- if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) {
- // return false if only if power key pressed.
- return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0;
+ synchronized (mLock) {
+ if (forAllActiveRules((rule) -> rule.shouldInterceptKey(KEYCODE_POWER))) {
+ // return false if only if power key pressed.
+ return mDownTimes.size() > 1 || mDownTimes.get(KEYCODE_POWER) == 0;
+ }
+ return false;
}
- return false;
}
/**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index a8032f4..33235d0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5041,8 +5041,7 @@
if (topFragment == f) {
return;
}
- if (!f.isFocusableAndVisible()) {
- // No need to resume activity in TaskFragment that is not visible.
+ if (!f.canBeResumed(null /* starting */)) {
return;
}
resumed[0] |= f.resumeTopActivity(prev, options, deferPause);
diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java
index ec3554a..e0e2876 100644
--- a/services/core/java/com/android/server/wm/TaskDisplayArea.java
+++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java
@@ -38,7 +38,6 @@
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.ActivityTaskManagerService.TAG_ROOT_TASK;
import static com.android.server.wm.DisplayContent.alwaysCreateRootTask;
-import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ROOT_TASK;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -1475,9 +1474,7 @@
leafTask.forAllLeafTaskFragments((taskFrag) -> {
final ActivityRecord resumedActivity = taskFrag.getResumedActivity();
- if (resumedActivity != null
- && (taskFrag.getVisibility(resuming) != TASK_FRAGMENT_VISIBILITY_VISIBLE
- || !taskFrag.isTopActivityFocusable())) {
+ if (resumedActivity != null && !taskFrag.canBeResumed(resuming)) {
if (taskFrag.startPausing(false /* uiSleeping*/, resuming, "pauseBackTasks")) {
someActivityPaused[0]++;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 916fa5b..efd51e9 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -1359,6 +1359,17 @@
return getVisibility(starting) != TASK_FRAGMENT_VISIBILITY_INVISIBLE;
}
+ /**
+ * Returns {@code true} is the activity in this TaskFragment can be resumed.
+ *
+ * @param starting The currently starting activity or {@code null} if there is none.
+ */
+ boolean canBeResumed(@Nullable ActivityRecord starting) {
+ // No need to resume activity in TaskFragment that is not visible.
+ return isTopActivityFocusable()
+ && getVisibility(starting) == TASK_FRAGMENT_VISIBILITY_VISIBLE;
+ }
+
boolean isFocusableAndVisible() {
return isTopActivityFocusable() && shouldBeVisible(null /* starting */);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d0ca298..41e605b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -258,6 +258,7 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManager.UserRestrictionSource;
import android.os.storage.StorageManager;
import android.permission.AdminPermissionControlParams;
import android.permission.IPermissionManager;
@@ -286,6 +287,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
+import android.util.DebugUtils;
import android.util.IndentingPrintWriter;
import android.util.Log;
import android.util.Pair;
@@ -13225,14 +13227,29 @@
try {
List<UserManager.EnforcingUser> sources = mUserManager
.getUserRestrictionSources(restriction, UserHandle.of(userId));
- if (sources == null || sources.isEmpty()) {
+ if (sources == null) {
// The restriction is not enforced.
return null;
- } else if (sources.size() > 1) {
+ }
+ int sizeBefore = sources.size();
+ if (sizeBefore > 1) {
+ Slogf.d(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): "
+ + "%d sources found, excluding those set by UserManager",
+ userId, restriction, sizeBefore);
+ sources = getDevicePolicySources(sources);
+ }
+ if (sources.isEmpty()) {
+ // The restriction is not enforced (or is just enforced by the system)
+ return null;
+ }
+
+ if (sources.size() > 1) {
// In this case, we'll show an admin support dialog that does not
// specify the admin.
// TODO(b/128928355): if this restriction is enforced by multiple DPCs, return
// the admin for the calling user.
+ Slogf.w(LOG_TAG, "getEnforcingAdminAndUserDetailsInternal(%d, %s): multiple "
+ + "sources for restriction %s on user %d", restriction, userId);
result = new Bundle();
result.putInt(Intent.EXTRA_USER_ID, userId);
return result;
@@ -13278,6 +13295,32 @@
}
/**
+ * Excludes restrictions imposed by UserManager.
+ */
+ private List<UserManager.EnforcingUser> getDevicePolicySources(
+ List<UserManager.EnforcingUser> sources) {
+ int sizeBefore = sources.size();
+ List<UserManager.EnforcingUser> realSources = new ArrayList<>(sizeBefore);
+ for (int i = 0; i < sizeBefore; i++) {
+ UserManager.EnforcingUser source = sources.get(i);
+ int type = source.getUserRestrictionSource();
+ if (type != UserManager.RESTRICTION_SOURCE_PROFILE_OWNER
+ && type != UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
+ // TODO(b/128928355): add unit test
+ Slogf.d(LOG_TAG, "excluding source of type %s at index %d",
+ userRestrictionSourceToString(type), i);
+ continue;
+ }
+ realSources.add(source);
+ }
+ return realSources;
+ }
+
+ private static String userRestrictionSourceToString(@UserRestrictionSource int source) {
+ return DebugUtils.flagsToString(UserManager.class, "RESTRICTION_", source);
+ }
+
+ /**
* @param restriction The restriction enforced by admin. It could be any user restriction or
* policy like {@link DevicePolicyManager#POLICY_DISABLE_CAMERA} and
* {@link DevicePolicyManager#POLICY_DISABLE_SCREEN_CAPTURE}.
diff --git a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
index 886b2e0..347952b 100644
--- a/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
+++ b/services/tests/PackageManagerServiceTests/unit/src/com/android/server/pm/test/verify/domain/DomainVerificationEnforcerTest.kt
@@ -19,6 +19,7 @@
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
+import android.content.pm.PackageParser.SigningDetails
import android.content.pm.PackageUserState
import android.content.pm.parsing.component.ParsedActivity
import android.content.pm.parsing.component.ParsedIntentInfo
@@ -27,6 +28,7 @@
import android.os.Build
import android.os.Process
import android.util.ArraySet
+import android.util.IndentingPrintWriter
import android.util.SparseArray
import androidx.test.platform.app.InstrumentationRegistry
import com.android.server.pm.PackageSetting
@@ -47,6 +49,7 @@
import org.mockito.Mockito.anyLong
import org.mockito.Mockito.anyString
import org.mockito.Mockito.eq
+import org.mockito.Mockito.mock
import org.mockito.Mockito.verifyNoMoreInteractions
import java.io.File
import java.util.UUID
@@ -206,6 +209,14 @@
service(Type.QUERENT, "getInfo") {
getDomainVerificationInfo(it.targetPackageName)
},
+ service(Type.QUERENT, "printState") {
+ printState(mock(IndentingPrintWriter::class.java), null, null)
+ },
+ service(Type.QUERENT, "printStateInternal") {
+ printState(mock(IndentingPrintWriter::class.java), null, null) {
+ mockPkgSetting(it, UUID.randomUUID())
+ }
+ },
service(Type.VERIFIER, "setStatus") {
setDomainVerificationStatus(
it.targetDomainSetId,
@@ -311,6 +322,7 @@
}
)
}
+ whenever(signingDetails) { SigningDetails.UNKNOWN }
}
fun mockPkgSetting(packageName: String, domainSetId: UUID) = spyThrowOnUnmocked(
@@ -339,6 +351,7 @@
whenever(readUserState(1)) { PackageUserState() }
whenever(getInstantApp(anyInt())) { false }
whenever(isSystem()) { false }
+ whenever(signingDetails) { SigningDetails.UNKNOWN }
}
}
@@ -385,6 +398,7 @@
val allowUserState = AtomicBoolean(false)
val allowPreferredApps = AtomicBoolean(false)
val allowQueryAll = AtomicBoolean(false)
+ val allowDump = AtomicBoolean(false)
val context: Context = mockThrowOnUnmocked {
initPermission(
allowUserState,
@@ -395,6 +409,7 @@
android.Manifest.permission.SET_PREFERRED_APPLICATIONS
)
initPermission(allowQueryAll, android.Manifest.permission.QUERY_ALL_PACKAGES)
+ initPermission(allowDump, android.Manifest.permission.DUMP)
}
val target = params.construct(context)
@@ -421,6 +436,10 @@
allowQueryAll.set(true)
assertFails { runMethod(target, NON_VERIFIER_UID) }
+
+ allowDump.set(true)
+
+ runMethod(target, NON_VERIFIER_UID)
}
private fun approvedVerifier() {
@@ -806,8 +825,12 @@
}
val valueAsInt = value as? Int
- if (valueAsInt != null && valueAsInt == DomainVerificationManager.STATUS_OK) {
- throw AssertionError("Expected call to return false, was $value")
+ if (valueAsInt != null) {
+ if (valueAsInt == DomainVerificationManager.STATUS_OK) {
+ throw AssertionError("Expected call to return false, was $value")
+ }
+ } else {
+ throw AssertionError("Expected call to fail")
}
} catch (e: SecurityException) {
} catch (e: PackageManager.NameNotFoundException) {
@@ -819,7 +842,7 @@
// System/shell only
INTERNAL,
- // INTERNAL || non-legacy domain verification agent
+ // INTERNAL || non-legacy domain verification agent || DUMP permission
QUERENT,
// INTERNAL || domain verification agent
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
index bfaa815..4ba3f63 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java
@@ -44,6 +44,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
+import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
import static com.google.common.truth.Truth.assertThat;
@@ -66,6 +67,7 @@
import static org.mockito.Mockito.never;
import android.app.ActivityManager;
+import android.app.ActivityOptions;
import android.app.TaskInfo;
import android.app.WindowConfiguration;
import android.content.ComponentName;
@@ -1424,6 +1426,29 @@
verify(task2).moveToFrontInner(anyString(), isNull());
}
+ @Test
+ public void testResumeTask_doNotResumeTaskFragmentBehindTranslucent() {
+ final Task task = createTask(mDisplayContent);
+ final TaskFragment tfBehind = createTaskFragmentWithParentTask(
+ task, false /* createEmbeddedTask */);
+ final TaskFragment tfFront = createTaskFragmentWithParentTask(
+ task, false /* createEmbeddedTask */);
+ spyOn(tfFront);
+ doReturn(true).when(tfFront).isTranslucent(any());
+
+ // TaskFragment behind another translucent TaskFragment should not be resumed.
+ assertEquals(TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+ tfBehind.getVisibility(null /* starting */));
+ assertTrue(tfBehind.isFocusable());
+ assertFalse(tfBehind.canBeResumed(null /* starting */));
+
+ spyOn(tfBehind);
+ task.resumeTopActivityUncheckedLocked(null /* prev */, ActivityOptions.makeBasic(),
+ false /* deferPause */);
+
+ verify(tfBehind, never()).resumeTopActivity(any(), any(), anyBoolean());
+ }
+
private Task getTestTask() {
final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
return task.getBottomMostTask();