Merge "Not resume TaskFragment behind translucent others" 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/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/SideStage.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
index 1ba1d22..122fc9f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SideStage.java
@@ -19,7 +19,6 @@
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.Context;
-import android.graphics.Rect;
import android.view.SurfaceSession;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -45,11 +44,6 @@
stageTaskUnfoldController);
}
- void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
- final WindowContainerToken rootToken = mRootTaskInfo.token;
- wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
- }
-
boolean removeAllTasks(WindowContainerTransaction wct, boolean toTop) {
// No matter if the root task is empty or not, moving the root to bottom because it no
// longer preserves visible child task.
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 912e2a4..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,7 +367,12 @@
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);
+ prepareEvictChildTasks(SPLIT_POSITION_BOTTOM_OR_RIGHT, evictWct);
// Need to add another wrapper here in shell so that we can inject the divider bar
// and also manage the process elevation via setRunningRemote
IRemoteAnimationRunner wrapper = new IRemoteAnimationRunner.Stub() {
@@ -390,6 +395,8 @@
@Override
public void onAnimationFinished() throws RemoteException {
mIsDividerRemoteAnimating = false;
+ mShouldUpdateRecents = true;
+ mSyncQueue.queue(evictWct);
mSyncQueue.runInSync(t -> applyDividerVisibility(t));
finishedCallback.onAnimationFinished();
}
@@ -412,6 +419,9 @@
@Override
public void onAnimationCancelled() {
mIsDividerRemoteAnimating = false;
+ mShouldUpdateRecents = true;
+ mSyncQueue.queue(evictWct);
+ mSyncQueue.runInSync(t -> applyDividerVisibility(t));
try {
adapter.getRunner().onAnimationCancelled();
} catch (RemoteException e) {
@@ -434,10 +444,14 @@
setSideStagePosition(sidePosition, wct);
mSplitLayout.setDivideRatio(splitRatio);
- // Build a request WCT that will launch both apps such that task 0 is on the main stage
- // while task 1 is on the side stage.
- mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
- mSideStage.setBounds(getSideStageBounds(), wct);
+ if (mMainStage.isActive()) {
+ mMainStage.moveToTop(getMainStageBounds(), wct);
+ } else {
+ // Build a request WCT that will launch both apps such that task 0 is on the main stage
+ // while task 1 is on the side stage.
+ mMainStage.activate(getMainStageBounds(), wct, false /* reparent */);
+ }
+ mSideStage.moveToTop(getSideStageBounds(), wct);
// Make sure the launch options will put tasks in the corresponding split roots
addActivityOptions(mainOptions, mMainStage);
@@ -772,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);
@@ -788,7 +804,6 @@
if (!mShouldUpdateRecents) {
return;
}
-
mRecentTasks.ifPresent(recentTasks -> {
Rect topLeftBounds = mSplitLayout.getBounds1();
Rect bottomRightBounds = mSplitLayout.getBounds2();
@@ -902,6 +917,7 @@
if (mDividerVisible) {
t.show(dividerLeash)
+ .setAlpha(dividerLeash, 1)
.setLayer(dividerLeash, SPLIT_DIVIDER_LAYER)
.setPosition(dividerLeash,
mSplitLayout.getDividerBounds().left,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 2c853c1..04e20db 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -34,6 +34,7 @@
import android.util.SparseArray;
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
import androidx.annotation.NonNull;
@@ -304,6 +305,11 @@
wct.reparent(task.token, mRootTaskInfo.token, true /* onTop*/);
}
+ void moveToTop(Rect rootBounds, WindowContainerTransaction wct) {
+ final WindowContainerToken rootToken = mRootTaskInfo.token;
+ wct.setBounds(rootToken, rootBounds).reorder(rootToken, true /* onTop */);
+ }
+
void setBounds(Rect bounds, WindowContainerTransaction wct) {
wct.setBounds(mRootTaskInfo.token, bounds);
}
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/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/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index baf5336..e69582f 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -53,21 +53,22 @@
</LinearLayout>
<LinearLayout
- android:layout_width="match_parent"
+ android:layout_width="@dimen/internet_dialog_progress_bar_width"
android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
android:orientation="vertical">
<View
android:id="@+id/divider"
- android:layout_gravity="center_vertical|center_horizontal"
- android:layout_width="340dp"
+ android:layout_width="match_parent"
android:layout_height="4dp"
+ android:layout_gravity="center_vertical|center_horizontal"
android:background="?androidprv:attr/colorSurfaceVariant"/>
<ProgressBar
android:id="@+id/wifi_searching_progress"
- android:layout_width="340dp"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:visibility="gone"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index a67d5c2..4c4a3bb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1254,6 +1254,8 @@
<!-- Internet dialog related dimensions -->
<dimen name="internet_dialog_corner_radius">24dp</dimen>
+ <!-- Width of progress bar -->
+ <dimen name="internet_dialog_progress_bar_width">152dp</dimen>
<!-- End margin of network layout -->
<dimen name="internet_dialog_network_layout_margin">16dp</dimen>
<!-- Size of switch bar in internet dialog -->
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/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/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/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index cde99b4..3c5c5dd 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -2846,10 +2846,13 @@
@Override
public void sendResult(Bundle data) {
+ final long identity = Binder.clearCallingIdentity();
try {
mWakeLock.release();
} catch (RuntimeException e) {
Log.e(TAG, "wakelock over-released by " + mIdentity, e);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
}
}
}
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/policy/AppOpsPolicy.java b/services/core/java/com/android/server/policy/AppOpsPolicy.java
index 18c45e4..8b46906 100644
--- a/services/core/java/com/android/server/policy/AppOpsPolicy.java
+++ b/services/core/java/com/android/server/policy/AppOpsPolicy.java
@@ -196,9 +196,8 @@
}
private static boolean isHotwordDetectionServiceRequired(PackageManager pm) {
- // The HotwordDetectionService APIs aren't ready yet for Auto or TV.
- return !(pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
- || pm.hasSystemFeature(PackageManager.FEATURE_LEANBACK));
+ // Usage of the HotwordDetectionService won't be enforced until a later release.
+ return false;
}
@Override
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/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
index 9999aff..3fbcd93 100644
--- a/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
+++ b/services/core/java/com/android/server/soundtrigger_middleware/SoundTriggerMiddlewarePermission.java
@@ -125,16 +125,27 @@
* originator temporarily doesn't have the right permissions to use this service.
*/
private void enforcePermissionsForPreflight(@NonNull Identity identity) {
- enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO);
- enforcePermissionForPreflight(mContext, identity, CAPTURE_AUDIO_HOTWORD);
+ enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO,
+ /* allowSoftDenial= */ true);
+ enforcePermissionForPreflight(mContext, identity, CAPTURE_AUDIO_HOTWORD,
+ /* allowSoftDenial= */ true);
}
/**
* Throws a {@link SecurityException} iff the originator has permission to receive data.
*/
void enforcePermissionsForDataDelivery(@NonNull Identity identity, @NonNull String reason) {
- enforcePermissionForDataDelivery(mContext, identity, RECORD_AUDIO,
- reason);
+ // SoundTrigger data is treated the same as Hotword-source audio. This should incur the
+ // HOTWORD op instead of the RECORD_AUDIO op. The RECORD_AUDIO permission is still required,
+ // and since this is a data delivery check, soft denials aren't accepted.
+ // TODO(b/212458940): Find a better approach for checking the permission that doesn't
+ // require the client to know such details about the permissions logic.
+ enforcePermissionForPreflight(mContext, identity, RECORD_AUDIO,
+ /* allowSoftDenial= */ false);
+ int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD);
+ mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(hotwordOp, identity.uid,
+ identity.packageName, identity.attributionTag, reason);
+
enforcePermissionForDataDelivery(mContext, identity, CAPTURE_AUDIO_HOTWORD,
reason);
}
@@ -163,20 +174,25 @@
/**
* Throws a {@link SecurityException} if originator permanently doesn't have the given
* permission.
- * Soft (temporary) denials are considered OK for preflight purposes.
*
- * @param context A {@link Context}, used for permission checks.
- * @param identity The identity to check.
- * @param permission The identifier of the permission we want to check.
+ * @param context A {@link Context}, used for permission checks.
+ * @param identity The identity to check.
+ * @param permission The identifier of the permission we want to check.
+ * @param allowSoftDenial If true, the operation succeeds even for soft (temporary) denials.
*/
+ // TODO: Consider splitting up this method instead of using `allowSoftDenial`, to make it
+ // clearer when soft denials are not allowed.
private static void enforcePermissionForPreflight(@NonNull Context context,
- @NonNull Identity identity, @NonNull String permission) {
+ @NonNull Identity identity, @NonNull String permission, boolean allowSoftDenial) {
final int status = PermissionUtil.checkPermissionForPreflight(context, identity,
permission);
switch (status) {
case PermissionChecker.PERMISSION_GRANTED:
- case PermissionChecker.PERMISSION_SOFT_DENIED:
return;
+ case PermissionChecker.PERMISSION_SOFT_DENIED:
+ if (allowSoftDenial) {
+ return;
+ } // else fall through
case PermissionChecker.PERMISSION_HARD_DENIED:
throw new SecurityException(
String.format("Failed to obtain permission %s for identity %s", permission,
diff --git a/services/core/java/com/android/server/wm/RunningTasks.java b/services/core/java/com/android/server/wm/RunningTasks.java
index 7ba772c..9864297 100644
--- a/services/core/java/com/android/server/wm/RunningTasks.java
+++ b/services/core/java/com/android/server/wm/RunningTasks.java
@@ -54,6 +54,7 @@
private boolean mAllowed;
private boolean mFilterOnlyVisibleRecents;
private Task mTopDisplayFocusRootTask;
+ private Task mTopDisplayAdjacentTask;
private RecentTasks mRecentTasks;
private boolean mKeepIntentExtra;
@@ -77,6 +78,12 @@
mRecentTasks = root.mService.getRecentTasks();
mKeepIntentExtra = (flags & FLAG_KEEP_INTENT_EXTRA) == FLAG_KEEP_INTENT_EXTRA;
+ if (mTopDisplayFocusRootTask.getAdjacentTaskFragment() != null) {
+ mTopDisplayAdjacentTask = mTopDisplayFocusRootTask.getAdjacentTaskFragment().asTask();
+ } else {
+ mTopDisplayAdjacentTask = null;
+ }
+
final PooledConsumer c = PooledLambda.obtainConsumer(RunningTasks::processTask, this,
PooledLambda.__(Task.class));
root.forAllLeafTasks(c, false);
@@ -126,6 +133,12 @@
// can be used to determine the order of the tasks (it may not be set for newly
// created tasks)
task.touchActiveTime();
+ } else if (rootTask == mTopDisplayAdjacentTask && rootTask.getTopMostTask() == task) {
+ // The short-term workaround for launcher could get suitable running task info in
+ // split screen.
+ task.touchActiveTime();
+ // TreeSet doesn't allow same value and make sure this task is lower than focus one.
+ task.lastActiveTime--;
}
mTmpSortedSet.add(task);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
index e19ea47..36bb375 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/HotwordDetectionConnection.java
@@ -23,11 +23,8 @@
import static android.service.voice.HotwordDetectionService.INITIALIZATION_STATUS_UNKNOWN;
import static android.service.voice.HotwordDetectionService.KEY_INITIALIZATION_STATUS;
-import static com.android.server.voiceinteraction.SoundTriggerSessionPermissionsDecorator.enforcePermissionForPreflight;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
-import android.app.AppOpsManager;
import android.content.ComponentName;
import android.content.ContentCaptureOptions;
import android.content.Context;
@@ -933,11 +930,12 @@
// TODO: Share this code with SoundTriggerMiddlewarePermission.
private void enforcePermissionsForDataDelivery() {
Binder.withCleanCallingIdentity(() -> {
- enforcePermissionForPreflight(mContext, mVoiceInteractorIdentity, RECORD_AUDIO);
- int hotwordOp = AppOpsManager.strOpToOp(AppOpsManager.OPSTR_RECORD_AUDIO_HOTWORD);
- mContext.getSystemService(AppOpsManager.class).noteOpNoThrow(hotwordOp,
- mVoiceInteractorIdentity.uid, mVoiceInteractorIdentity.packageName,
- mVoiceInteractorIdentity.attributionTag, OP_MESSAGE);
+ // Hack to make sure we show the mic privacy-indicator since the Trusted Hotword
+ // requirement isn't being enforced for now. Normally, we would note the HOTWORD op here
+ // instead.
+ enforcePermissionForDataDelivery(mContext, mVoiceInteractorIdentity,
+ RECORD_AUDIO, OP_MESSAGE);
+
enforcePermissionForDataDelivery(mContext, mVoiceInteractorIdentity,
CAPTURE_AUDIO_HOTWORD, OP_MESSAGE);
});