Merge changes Ic18aa7c6,I444398f0,Ib6c66ade into main
* changes:
Revert "Revert "Enable the Compose implementation of the QS footer actions""
Fix the Compose footer actions paddings
Set the elevation on the Compose implementation of QS footer actions
diff --git a/core/api/current.txt b/core/api/current.txt
index 2e81528..0e5a515 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -9681,14 +9681,24 @@
public final class VirtualDevice implements android.os.Parcelable {
method public int describeContents();
method public int getDeviceId();
+ method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @NonNull public int[] getDisplayIds();
method @Nullable public String getName();
method @Nullable public String getPersistentDeviceId();
+ method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public boolean hasCustomSensorSupport();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.companion.virtual.VirtualDevice> CREATOR;
}
public final class VirtualDeviceManager {
+ method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) @Nullable public android.companion.virtual.VirtualDevice getVirtualDevice(int);
method @NonNull public java.util.List<android.companion.virtual.VirtualDevice> getVirtualDevices();
+ method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void registerVirtualDeviceListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+ method @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public void unregisterVirtualDeviceListener(@NonNull android.companion.virtual.VirtualDeviceManager.VirtualDeviceListener);
+ }
+
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS) public static interface VirtualDeviceManager.VirtualDeviceListener {
+ method public default void onVirtualDeviceClosed(int);
+ method public default void onVirtualDeviceCreated(int);
}
}
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index ac629d0..642813f 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -499,14 +499,14 @@
method public int describeContents();
method public int getActivityType();
method @Nullable public android.graphics.Rect getAppBounds();
- method public android.graphics.Rect getBounds();
+ method @NonNull public android.graphics.Rect getBounds();
method @NonNull public android.graphics.Rect getMaxBounds();
method public int getRotation();
method public int getWindowingMode();
method public static boolean isFloating(int);
method public void setActivityType(int);
method public void setAppBounds(@Nullable android.graphics.Rect);
- method public void setBounds(android.graphics.Rect);
+ method public void setBounds(@Nullable android.graphics.Rect);
method public void setMaxBounds(@Nullable android.graphics.Rect);
method public void setRotation(int);
method public void setTo(android.app.WindowConfiguration);
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index bf238c3..019a1a8 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -267,12 +267,13 @@
}
};
- // TODO(b/297672475): make this take @Nullable
/**
* Sets the bounds to the provided {@link Rect}.
+ * Passing {@code null} sets the bounds {@link Rect} to empty.
+ *
* @param rect the new bounds value.
*/
- public void setBounds(Rect rect) {
+ public void setBounds(@Nullable Rect rect) {
if (rect == null) {
mBounds.setEmpty();
return;
@@ -282,8 +283,10 @@
}
/**
- * Set {@link #mAppBounds} to the input Rect.
- * @param rect The rect value to set {@link #mAppBounds} to.
+ * Sets the app bounds to the provided {@link Rect}.
+ * Passing {@code null} sets the bounds to {@code null}.
+ *
+ * @param rect the new app bounds value.
* @see #getAppBounds()
*/
public void setAppBounds(@Nullable Rect rect) {
@@ -297,7 +300,9 @@
/**
* Sets the maximum bounds to the provided {@link Rect}.
- * @param rect the new bounds value.
+ * Passing {@code null} sets the bounds {@link Rect} to empty.
+ *
+ * @param rect the new max bounds value.
* @see #getMaxBounds()
*/
public void setMaxBounds(@Nullable Rect rect) {
@@ -364,8 +369,8 @@
return mAppBounds;
}
- // TODO(b/297672475): make this return @NonNull
/** @see #setBounds(Rect) */
+ @NonNull
public Rect getBounds() {
return mBounds;
}
diff --git a/core/java/android/companion/virtual/IVirtualDevice.aidl b/core/java/android/companion/virtual/IVirtualDevice.aidl
index be699f4..c58561d 100644
--- a/core/java/android/companion/virtual/IVirtualDevice.aidl
+++ b/core/java/android/companion/virtual/IVirtualDevice.aidl
@@ -64,6 +64,16 @@
String getPersistentDeviceId();
/**
+ * Returns the IDs of all virtual displays of this device.
+ */
+ int[] getDisplayIds();
+
+ /**
+ * Returns the device policy for the given policy type.
+ */
+ int getDevicePolicy(int policyType);
+
+ /**
* Closes the virtual device and frees all associated resources.
*/
@EnforcePermission("CREATE_VIRTUAL_DEVICE")
diff --git a/core/java/android/companion/virtual/IVirtualDeviceListener.aidl b/core/java/android/companion/virtual/IVirtualDeviceListener.aidl
new file mode 100644
index 0000000..c6dd227
--- /dev/null
+++ b/core/java/android/companion/virtual/IVirtualDeviceListener.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtual;
+
+/**
+ * Interface to listen for changes in the available virtual devices.
+ *
+ * @hide
+ */
+oneway interface IVirtualDeviceListener {
+
+ /**
+ * Called whenever a new virtual device has been added to the system.
+ */
+ void onVirtualDeviceCreated(int deviceId);
+
+ /**
+ * Called whenever a virtual device has been removed from the system.
+ */
+ void onVirtualDeviceClosed(int deviceId);
+}
diff --git a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
index ed8484f..b665036 100644
--- a/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
+++ b/core/java/android/companion/virtual/IVirtualDeviceManager.aidl
@@ -18,6 +18,7 @@
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.IVirtualDeviceListener;
import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
@@ -56,12 +57,27 @@
*/
List<VirtualDevice> getVirtualDevices();
- /**
+ /**
+ * Returns the details of the virtual device with the given ID, if any.
+ */
+ VirtualDevice getVirtualDevice(int deviceId);
+
+ /**
+ * Registers a virtual device listener to receive notifications for virtual device events.
+ */
+ void registerVirtualDeviceListener(in IVirtualDeviceListener listener);
+
+ /**
+ * Unregisters a previously registered virtual device listener.
+ */
+ void unregisterVirtualDeviceListener(in IVirtualDeviceListener listener);
+
+ /**
* Returns the ID of the device which owns the display with the given ID.
*/
int getDeviceIdForDisplayId(int displayId);
- /**
+ /**
* Checks whether the passed {@code deviceId} is a valid virtual device ID or not.
* {@link VirtualDeviceManager#DEVICE_ID_DEFAULT} is not valid as it is the ID of the default
* device which is not a virtual device. {@code deviceId} must correspond to a virtual device
diff --git a/core/java/android/companion/virtual/VirtualDevice.java b/core/java/android/companion/virtual/VirtualDevice.java
index ceaf7e4..4692f92 100644
--- a/core/java/android/companion/virtual/VirtualDevice.java
+++ b/core/java/android/companion/virtual/VirtualDevice.java
@@ -16,13 +16,17 @@
package android.companion.virtual;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
+
+import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.companion.virtual.flags.Flags;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
-
-import java.util.Objects;
+import android.os.RemoteException;
/**
* Details of a particular virtual device.
@@ -31,9 +35,12 @@
*
* <p class="note">Not to be confused with {@link VirtualDeviceManager.VirtualDevice}, which is used
* by the virtual device creator and allows them to manage the device.
+ *
+ * @see VirtualDeviceManager#registerVirtualDeviceListener
*/
public final class VirtualDevice implements Parcelable {
+ private final @NonNull IVirtualDevice mVirtualDevice;
private final int mId;
private final @Nullable String mPersistentId;
private final @Nullable String mName;
@@ -44,17 +51,20 @@
*
* @hide
*/
- public VirtualDevice(int id, @Nullable String persistentId, @Nullable String name) {
+ public VirtualDevice(@NonNull IVirtualDevice virtualDevice, int id,
+ @Nullable String persistentId, @Nullable String name) {
if (id <= Context.DEVICE_ID_DEFAULT) {
throw new IllegalArgumentException("VirtualDevice ID must be greater than "
+ Context.DEVICE_ID_DEFAULT);
}
+ mVirtualDevice = virtualDevice;
mId = id;
mPersistentId = persistentId;
mName = name;
}
private VirtualDevice(@NonNull Parcel parcel) {
+ mVirtualDevice = IVirtualDevice.Stub.asInterface(parcel.readStrongBinder());
mId = parcel.readInt();
mPersistentId = parcel.readString8();
mName = parcel.readString8();
@@ -101,6 +111,40 @@
return mName;
}
+ /**
+ * Returns the IDs of all virtual displays that belong to this device, if any.
+ *
+ * <p>The actual {@link android.view.Display} objects can be obtained by passing the returned
+ * IDs to {@link android.hardware.display.DisplayManager#getDisplay(int)}.</p>
+ */
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+ public @NonNull int[] getDisplayIds() {
+ try {
+ return mVirtualDevice.getDisplayIds();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether this device may have custom sensors.
+ *
+ * <p>Returning {@code true} does not necessarily mean that this device has sensors, it only
+ * means that a {@link android.hardware.SensorManager} instance created from a {@link Context}
+ * associated with this device will return this device's sensors, if any.</p>
+ *
+ * @see Context#getDeviceId()
+ * @see Context#createDeviceContext(int)
+ */
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+ public boolean hasCustomSensorSupport() {
+ try {
+ return mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS) == DEVICE_POLICY_CUSTOM;
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
@Override
public int describeContents() {
return 0;
@@ -108,31 +152,13 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeStrongBinder(mVirtualDevice.asBinder());
dest.writeInt(mId);
dest.writeString8(mPersistentId);
dest.writeString8(mName);
}
@Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (!(o instanceof VirtualDevice)) {
- return false;
- }
- VirtualDevice that = (VirtualDevice) o;
- return mId == that.mId
- && Objects.equals(mPersistentId, that.mPersistentId)
- && Objects.equals(mName, that.mName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mId, mPersistentId, mName);
- }
-
- @Override
@NonNull
public String toString() {
return "VirtualDevice("
diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java
index 923e689..29b0ff3 100644
--- a/core/java/android/companion/virtual/VirtualDeviceManager.java
+++ b/core/java/android/companion/virtual/VirtualDeviceManager.java
@@ -55,11 +55,13 @@
import android.hardware.input.VirtualTouchscreen;
import android.hardware.input.VirtualTouchscreenConfig;
import android.media.AudioManager;
+import android.os.Binder;
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
import android.view.Surface;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.AnnotationValidations;
import java.lang.annotation.ElementType;
@@ -67,6 +69,7 @@
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
@@ -147,6 +150,9 @@
private final IVirtualDeviceManager mService;
private final Context mContext;
+ @GuardedBy("mVirtualDeviceListeners")
+ private final List<VirtualDeviceListenerDelegate> mVirtualDeviceListeners = new ArrayList<>();
+
/** @hide */
public VirtualDeviceManager(
@Nullable IVirtualDeviceManager service, @NonNull Context context) {
@@ -207,6 +213,88 @@
}
/**
+ * Returns the details of the virtual device with the given ID, if any.
+ *
+ * <p>The returned object is a read-only representation of the virtual device that expose its
+ * properties.</p>
+ */
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+ @Nullable
+ public android.companion.virtual.VirtualDevice getVirtualDevice(int deviceId) {
+ if (mService == null) {
+ Log.w(TAG, "Failed to retrieve virtual devices; no virtual device manager service.");
+ return null;
+ }
+ if (deviceId == Context.DEVICE_ID_INVALID || deviceId == Context.DEVICE_ID_DEFAULT) {
+ return null; // Don't even bother making a Binder call.
+ }
+ try {
+ return mService.getVirtualDevice(deviceId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Registers a virtual device listener to receive notifications when virtual devices are created
+ * or closed.
+ *
+ * @param executor The executor where the listener is executed on.
+ * @param listener The listener to add.
+ * @see #unregisterVirtualDeviceListener
+ */
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+ public void registerVirtualDeviceListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull VirtualDeviceListener listener) {
+ if (mService == null) {
+ Log.w(TAG, "Failed to register listener; no virtual device manager service.");
+ return;
+ }
+ final VirtualDeviceListenerDelegate delegate =
+ new VirtualDeviceListenerDelegate(Objects.requireNonNull(executor),
+ Objects.requireNonNull(listener));
+ synchronized (mVirtualDeviceListeners) {
+ try {
+ mService.registerVirtualDeviceListener(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ mVirtualDeviceListeners.add(delegate);
+ }
+ }
+
+ /**
+ * Unregisters a virtual device listener previously registered with
+ * {@link #registerVirtualDeviceListener}.
+ *
+ * @param listener The listener to unregister.
+ * @see #registerVirtualDeviceListener
+ */
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+ public void unregisterVirtualDeviceListener(@NonNull VirtualDeviceListener listener) {
+ if (mService == null) {
+ Log.w(TAG, "Failed to unregister listener; no virtual device manager service.");
+ return;
+ }
+ Objects.requireNonNull(listener);
+ synchronized (mVirtualDeviceListeners) {
+ final Iterator<VirtualDeviceListenerDelegate> it = mVirtualDeviceListeners.iterator();
+ while (it.hasNext()) {
+ final VirtualDeviceListenerDelegate delegate = it.next();
+ if (delegate.mListener == listener) {
+ try {
+ mService.unregisterVirtualDeviceListener(delegate);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ it.remove();
+ }
+ }
+ }
+ }
+
+ /**
* Returns the device policy for the given virtual device and policy type.
*
* <p>In case the virtual device identifier is not valid, or there's no explicitly specified
@@ -748,7 +836,7 @@
*
* @param executor The executor where the listener is executed on.
* @param soundEffectListener The listener to add.
- * @see #removeActivityListener(ActivityListener)
+ * @see #removeSoundEffectListener(SoundEffectListener)
*/
public void addSoundEffectListener(@CallbackExecutor @NonNull Executor executor,
@NonNull SoundEffectListener soundEffectListener) {
@@ -877,4 +965,59 @@
*/
void onPlaySoundEffect(@AudioManager.SystemSoundEffect int effectType);
}
+
+ /**
+ * Listener for changes in the available virtual devices.
+ */
+ @FlaggedApi(Flags.FLAG_VDM_PUBLIC_APIS)
+ public interface VirtualDeviceListener {
+ /**
+ * Called whenever a new virtual device has been added to the system.
+ * Use {@link VirtualDeviceManager#getVirtualDevice(int)} to get more information about
+ * the device.
+ *
+ * @param deviceId The id of the virtual device that was added.
+ */
+ default void onVirtualDeviceCreated(int deviceId) {}
+
+ /**
+ * Called whenever a virtual device has been removed from the system.
+ *
+ * @param deviceId The id of the virtual device that was removed.
+ */
+ default void onVirtualDeviceClosed(int deviceId) {}
+ }
+
+ /**
+ * A wrapper for {@link VirtualDeviceListener} that executes callbacks on the given executor.
+ */
+ private static class VirtualDeviceListenerDelegate extends IVirtualDeviceListener.Stub {
+ private final VirtualDeviceListener mListener;
+ private final Executor mExecutor;
+
+ private VirtualDeviceListenerDelegate(Executor executor, VirtualDeviceListener listener) {
+ mExecutor = executor;
+ mListener = listener;
+ }
+
+ @Override
+ public void onVirtualDeviceCreated(int deviceId) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mListener.onVirtualDeviceCreated(deviceId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void onVirtualDeviceClosed(int deviceId) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ mExecutor.execute(() -> mListener.onVirtualDeviceClosed(deviceId));
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ }
}
diff --git a/core/java/android/companion/virtual/VirtualDeviceParams.java b/core/java/android/companion/virtual/VirtualDeviceParams.java
index 037e814a..51df257 100644
--- a/core/java/android/companion/virtual/VirtualDeviceParams.java
+++ b/core/java/android/companion/virtual/VirtualDeviceParams.java
@@ -202,14 +202,12 @@
private final int mLockState;
@NonNull private final ArraySet<UserHandle> mUsersWithMatchingAccounts;
- @NonNull private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
- @NonNull private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
@NavigationPolicy
private final int mDefaultNavigationPolicy;
- @NonNull private final ArraySet<ComponentName> mAllowedActivities;
- @NonNull private final ArraySet<ComponentName> mBlockedActivities;
+ @NonNull private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
@ActivityPolicy
private final int mDefaultActivityPolicy;
+ @NonNull private final ArraySet<ComponentName> mActivityPolicyExceptions;
@Nullable private final String mName;
// Mapping of @PolicyType to @DevicePolicy
@NonNull private final SparseIntArray mDevicePolicies;
@@ -221,12 +219,10 @@
private VirtualDeviceParams(
@LockState int lockState,
@NonNull Set<UserHandle> usersWithMatchingAccounts,
- @NonNull Set<ComponentName> allowedCrossTaskNavigations,
- @NonNull Set<ComponentName> blockedCrossTaskNavigations,
@NavigationPolicy int defaultNavigationPolicy,
- @NonNull Set<ComponentName> allowedActivities,
- @NonNull Set<ComponentName> blockedActivities,
+ @NonNull Set<ComponentName> crossTaskNavigationExceptions,
@ActivityPolicy int defaultActivityPolicy,
+ @NonNull Set<ComponentName> activityPolicyExceptions,
@Nullable String name,
@NonNull SparseIntArray devicePolicies,
@NonNull List<VirtualSensorConfig> virtualSensorConfigs,
@@ -236,14 +232,12 @@
mLockState = lockState;
mUsersWithMatchingAccounts =
new ArraySet<>(Objects.requireNonNull(usersWithMatchingAccounts));
- mAllowedCrossTaskNavigations =
- new ArraySet<>(Objects.requireNonNull(allowedCrossTaskNavigations));
- mBlockedCrossTaskNavigations =
- new ArraySet<>(Objects.requireNonNull(blockedCrossTaskNavigations));
mDefaultNavigationPolicy = defaultNavigationPolicy;
- mAllowedActivities = new ArraySet<>(Objects.requireNonNull(allowedActivities));
- mBlockedActivities = new ArraySet<>(Objects.requireNonNull(blockedActivities));
+ mCrossTaskNavigationExceptions =
+ new ArraySet<>(Objects.requireNonNull(crossTaskNavigationExceptions));
mDefaultActivityPolicy = defaultActivityPolicy;
+ mActivityPolicyExceptions =
+ new ArraySet<>(Objects.requireNonNull(activityPolicyExceptions));
mName = name;
mDevicePolicies = Objects.requireNonNull(devicePolicies);
mVirtualSensorConfigs = Objects.requireNonNull(virtualSensorConfigs);
@@ -256,12 +250,10 @@
private VirtualDeviceParams(Parcel parcel) {
mLockState = parcel.readInt();
mUsersWithMatchingAccounts = (ArraySet<UserHandle>) parcel.readArraySet(null);
- mAllowedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
- mBlockedCrossTaskNavigations = (ArraySet<ComponentName>) parcel.readArraySet(null);
mDefaultNavigationPolicy = parcel.readInt();
- mAllowedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
- mBlockedActivities = (ArraySet<ComponentName>) parcel.readArraySet(null);
+ mCrossTaskNavigationExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
mDefaultActivityPolicy = parcel.readInt();
+ mActivityPolicyExceptions = (ArraySet<ComponentName>) parcel.readArraySet(null);
mName = parcel.readString8();
mDevicePolicies = parcel.readSparseIntArray();
mVirtualSensorConfigs = new ArrayList<>();
@@ -301,7 +293,9 @@
*/
@NonNull
public Set<ComponentName> getAllowedCrossTaskNavigations() {
- return Collections.unmodifiableSet(mAllowedCrossTaskNavigations);
+ return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_ALLOWED
+ ? Collections.emptySet()
+ : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
}
/**
@@ -314,7 +308,9 @@
*/
@NonNull
public Set<ComponentName> getBlockedCrossTaskNavigations() {
- return Collections.unmodifiableSet(mBlockedCrossTaskNavigations);
+ return mDefaultNavigationPolicy == NAVIGATION_POLICY_DEFAULT_BLOCKED
+ ? Collections.emptySet()
+ : Collections.unmodifiableSet(mCrossTaskNavigationExceptions);
}
/**
@@ -338,7 +334,9 @@
*/
@NonNull
public Set<ComponentName> getAllowedActivities() {
- return Collections.unmodifiableSet(mAllowedActivities);
+ return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_ALLOWED
+ ? Collections.emptySet()
+ : Collections.unmodifiableSet(mActivityPolicyExceptions);
}
/**
@@ -349,7 +347,9 @@
*/
@NonNull
public Set<ComponentName> getBlockedActivities() {
- return Collections.unmodifiableSet(mBlockedActivities);
+ return mDefaultActivityPolicy == ACTIVITY_POLICY_DEFAULT_BLOCKED
+ ? Collections.emptySet()
+ : Collections.unmodifiableSet(mActivityPolicyExceptions);
}
/**
@@ -439,12 +439,10 @@
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mLockState);
dest.writeArraySet(mUsersWithMatchingAccounts);
- dest.writeArraySet(mAllowedCrossTaskNavigations);
- dest.writeArraySet(mBlockedCrossTaskNavigations);
dest.writeInt(mDefaultNavigationPolicy);
- dest.writeArraySet(mAllowedActivities);
- dest.writeArraySet(mBlockedActivities);
+ dest.writeArraySet(mCrossTaskNavigationExceptions);
dest.writeInt(mDefaultActivityPolicy);
+ dest.writeArraySet(mActivityPolicyExceptions);
dest.writeString8(mName);
dest.writeSparseIntArray(mDevicePolicies);
dest.writeTypedList(mVirtualSensorConfigs);
@@ -477,11 +475,10 @@
}
return mLockState == that.mLockState
&& mUsersWithMatchingAccounts.equals(that.mUsersWithMatchingAccounts)
- && Objects.equals(mAllowedCrossTaskNavigations, that.mAllowedCrossTaskNavigations)
- && Objects.equals(mBlockedCrossTaskNavigations, that.mBlockedCrossTaskNavigations)
+ && Objects.equals(
+ mCrossTaskNavigationExceptions, that.mCrossTaskNavigationExceptions)
&& mDefaultNavigationPolicy == that.mDefaultNavigationPolicy
- && Objects.equals(mAllowedActivities, that.mAllowedActivities)
- && Objects.equals(mBlockedActivities, that.mBlockedActivities)
+ && Objects.equals(mActivityPolicyExceptions, that.mActivityPolicyExceptions)
&& mDefaultActivityPolicy == that.mDefaultActivityPolicy
&& Objects.equals(mName, that.mName)
&& mAudioPlaybackSessionId == that.mAudioPlaybackSessionId
@@ -491,10 +488,9 @@
@Override
public int hashCode() {
int hashCode = Objects.hash(
- mLockState, mUsersWithMatchingAccounts, mAllowedCrossTaskNavigations,
- mBlockedCrossTaskNavigations, mDefaultNavigationPolicy, mAllowedActivities,
- mBlockedActivities, mDefaultActivityPolicy, mName, mDevicePolicies,
- mAudioPlaybackSessionId, mAudioRecordingSessionId);
+ mLockState, mUsersWithMatchingAccounts, mCrossTaskNavigationExceptions,
+ mDefaultNavigationPolicy, mActivityPolicyExceptions, mDefaultActivityPolicy, mName,
+ mDevicePolicies, mAudioPlaybackSessionId, mAudioRecordingSessionId);
for (int i = 0; i < mDevicePolicies.size(); i++) {
hashCode = 31 * hashCode + mDevicePolicies.keyAt(i);
hashCode = 31 * hashCode + mDevicePolicies.valueAt(i);
@@ -508,12 +504,10 @@
return "VirtualDeviceParams("
+ " mLockState=" + mLockState
+ " mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts
- + " mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations
- + " mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations
+ " mDefaultNavigationPolicy=" + mDefaultNavigationPolicy
- + " mAllowedActivities=" + mAllowedActivities
- + " mBlockedActivities=" + mBlockedActivities
+ + " mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions
+ " mDefaultActivityPolicy=" + mDefaultActivityPolicy
+ + " mActivityPolicyExceptions=" + mActivityPolicyExceptions
+ " mName=" + mName
+ " mDevicePolicies=" + mDevicePolicies
+ " mAudioPlaybackSessionId=" + mAudioPlaybackSessionId
@@ -529,13 +523,11 @@
pw.println(prefix + "mName=" + mName);
pw.println(prefix + "mLockState=" + mLockState);
pw.println(prefix + "mUsersWithMatchingAccounts=" + mUsersWithMatchingAccounts);
- pw.println(prefix + "mAllowedCrossTaskNavigations=" + mAllowedCrossTaskNavigations);
- pw.println(prefix + "mBlockedCrossTaskNavigations=" + mBlockedCrossTaskNavigations);
- pw.println(prefix + "mAllowedActivities=" + mAllowedActivities);
- pw.println(prefix + "mBlockedActivities=" + mBlockedActivities);
- pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
pw.println(prefix + "mDefaultNavigationPolicy=" + mDefaultNavigationPolicy);
+ pw.println(prefix + "mCrossTaskNavigationExceptions=" + mCrossTaskNavigationExceptions);
pw.println(prefix + "mDefaultActivityPolicy=" + mDefaultActivityPolicy);
+ pw.println(prefix + "mActivityPolicyExceptions=" + mActivityPolicyExceptions);
+ pw.println(prefix + "mDevicePolicies=" + mDevicePolicies);
pw.println(prefix + "mVirtualSensorConfigs=" + mVirtualSensorConfigs);
pw.println(prefix + "mAudioPlaybackSessionId=" + mAudioPlaybackSessionId);
pw.println(prefix + "mAudioRecordingSessionId=" + mAudioRecordingSessionId);
@@ -560,13 +552,11 @@
private @LockState int mLockState = LOCK_STATE_DEFAULT;
@NonNull private Set<UserHandle> mUsersWithMatchingAccounts = Collections.emptySet();
- @NonNull private Set<ComponentName> mAllowedCrossTaskNavigations = Collections.emptySet();
- @NonNull private Set<ComponentName> mBlockedCrossTaskNavigations = Collections.emptySet();
+ @NonNull private Set<ComponentName> mCrossTaskNavigationExceptions = Collections.emptySet();
@NavigationPolicy
private int mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
private boolean mDefaultNavigationPolicyConfigured = false;
- @NonNull private Set<ComponentName> mBlockedActivities = Collections.emptySet();
- @NonNull private Set<ComponentName> mAllowedActivities = Collections.emptySet();
+ @NonNull private Set<ComponentName> mActivityPolicyExceptions = Collections.emptySet();
@ActivityPolicy
private int mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
private boolean mDefaultActivityPolicyConfigured = false;
@@ -705,12 +695,12 @@
if (mDefaultNavigationPolicyConfigured
&& mDefaultNavigationPolicy != NAVIGATION_POLICY_DEFAULT_BLOCKED) {
throw new IllegalArgumentException(
- "Allowed cross task navigation and blocked task navigation cannot "
+ "Allowed cross task navigations and blocked cross task navigations cannot "
+ " both be set.");
}
mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_BLOCKED;
mDefaultNavigationPolicyConfigured = true;
- mAllowedCrossTaskNavigations = Objects.requireNonNull(allowedCrossTaskNavigations);
+ mCrossTaskNavigationExceptions = Objects.requireNonNull(allowedCrossTaskNavigations);
return this;
}
@@ -741,7 +731,7 @@
}
mDefaultNavigationPolicy = NAVIGATION_POLICY_DEFAULT_ALLOWED;
mDefaultNavigationPolicyConfigured = true;
- mBlockedCrossTaskNavigations = Objects.requireNonNull(blockedCrossTaskNavigations);
+ mCrossTaskNavigationExceptions = Objects.requireNonNull(blockedCrossTaskNavigations);
return this;
}
@@ -767,7 +757,7 @@
}
mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_BLOCKED;
mDefaultActivityPolicyConfigured = true;
- mAllowedActivities = Objects.requireNonNull(allowedActivities);
+ mActivityPolicyExceptions = Objects.requireNonNull(allowedActivities);
return this;
}
@@ -793,7 +783,7 @@
}
mDefaultActivityPolicy = ACTIVITY_POLICY_DEFAULT_ALLOWED;
mDefaultActivityPolicyConfigured = true;
- mBlockedActivities = Objects.requireNonNull(blockedActivities);
+ mActivityPolicyExceptions = Objects.requireNonNull(blockedActivities);
return this;
}
@@ -988,12 +978,10 @@
return new VirtualDeviceParams(
mLockState,
mUsersWithMatchingAccounts,
- mAllowedCrossTaskNavigations,
- mBlockedCrossTaskNavigations,
mDefaultNavigationPolicy,
- mAllowedActivities,
- mBlockedActivities,
+ mCrossTaskNavigationExceptions,
mDefaultActivityPolicy,
+ mActivityPolicyExceptions,
mName,
mDevicePolicies,
mVirtualSensorConfigs,
diff --git a/core/java/android/companion/virtual/flags.aconfig b/core/java/android/companion/virtual/flags.aconfig
index 057b856..9ab3be6 100644
--- a/core/java/android/companion/virtual/flags.aconfig
+++ b/core/java/android/companion/virtual/flags.aconfig
@@ -13,3 +13,10 @@
description: "Enable dynamic policy API"
bug: "298401780"
}
+
+flag {
+ name: "vdm_public_apis"
+ namespace: "virtual_devices"
+ description: "Enable public VDM API for device capabilities"
+ bug: "297253526"
+}
diff --git a/core/java/android/content/pm/ArchivedPackageParcel.aidl b/core/java/android/content/pm/ArchivedPackageParcel.aidl
index b34b708..6aeee89 100644
--- a/core/java/android/content/pm/ArchivedPackageParcel.aidl
+++ b/core/java/android/content/pm/ArchivedPackageParcel.aidl
@@ -29,7 +29,6 @@
int versionCode;
int versionCodeMajor;
int targetSdkVersion;
- boolean clearUserDataAllowed;
boolean backupAllowed;
boolean defaultToDeviceProtectedStorage;
boolean requestLegacyExternalStorage;
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 71cfd1b..8e7592a 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -140,11 +140,6 @@
private final boolean mIsSdkLibrary;
/**
- * Indicates whether this application's data will be cleared on a failed restore.
- */
- private final boolean mClearUserDataAllowed;
-
- /**
* Set to <code>false</code> if the application does not wish to permit any OS-driven
* backups of its data; <code>true</code> otherwise.
*/
@@ -219,7 +214,6 @@
mRollbackDataPolicy = rollbackDataPolicy;
mHasDeviceAdminReceiver = hasDeviceAdminReceiver;
mIsSdkLibrary = isSdkLibrary;
- mClearUserDataAllowed = clearUserDataAllowed;
mBackupAllowed = backupAllowed;
mDefaultToDeviceProtectedStorage = defaultToDeviceProtectedStorage;
mRequestLegacyExternalStorage = requestLegacyExternalStorage;
@@ -261,7 +255,6 @@
mRollbackDataPolicy = 0;
mHasDeviceAdminReceiver = false;
mIsSdkLibrary = false;
- mClearUserDataAllowed = archivedPackage.clearUserDataAllowed;
mBackupAllowed = archivedPackage.backupAllowed;
mDefaultToDeviceProtectedStorage = archivedPackage.defaultToDeviceProtectedStorage;
mRequestLegacyExternalStorage = archivedPackage.requestLegacyExternalStorage;
@@ -576,14 +569,6 @@
}
/**
- * Indicates whether this application's data will be cleared on a failed restore.
- */
- @DataClass.Generated.Member
- public boolean isClearUserDataAllowed() {
- return mClearUserDataAllowed;
- }
-
- /**
* Set to <code>false</code> if the application does not wish to permit any OS-driven
* backups of its data; <code>true</code> otherwise.
*/
@@ -627,10 +612,10 @@
}
@DataClass.Generated(
- time = 1693422809896L,
+ time = 1693513509013L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mClearUserDataAllowed\nprivate final boolean mBackupAllowed\nprivate final boolean mDefaultToDeviceProtectedStorage\nprivate final boolean mRequestLegacyExternalStorage\nprivate final boolean mUserDataFragile\nprivate final boolean mClearUserDataOnFailedRestoreAllowed\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyName\nprivate final @android.annotation.Nullable java.lang.String mRequiredSystemPropertyValue\nprivate final int mRollbackDataPolicy\nprivate final boolean mHasDeviceAdminReceiver\nprivate final boolean mIsSdkLibrary\nprivate final boolean mBackupAllowed\nprivate final boolean mDefaultToDeviceProtectedStorage\nprivate final boolean mRequestLegacyExternalStorage\nprivate final boolean mUserDataFragile\nprivate final boolean mClearUserDataOnFailedRestoreAllowed\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 4638af7..ccef9de 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -113,10 +113,6 @@
*/
private final boolean mIsSdkLibrary;
/**
- * Indicates whether this application's data will be cleared on a failed restore.
- */
- private final boolean mClearUserDataAllowed;
- /**
* Set to <code>false</code> if the application does not wish to permit any OS-driven
* backups of its data; <code>true</code> otherwise.
*/
@@ -175,7 +171,6 @@
mSplitApkPaths = splitApkPaths;
mSplitRevisionCodes = splitRevisionCodes;
mTargetSdk = targetSdk;
- mClearUserDataAllowed = baseApk.isClearUserDataAllowed();
mBackupAllowed = baseApk.isBackupAllowed();
mDefaultToDeviceProtectedStorage = baseApk.isDefaultToDeviceProtectedStorage();
mRequestLegacyExternalStorage = baseApk.isRequestLegacyExternalStorage();
@@ -460,14 +455,6 @@
}
/**
- * Indicates whether this application's data will be cleared on a failed restore.
- */
- @DataClass.Generated.Member
- public boolean isClearUserDataAllowed() {
- return mClearUserDataAllowed;
- }
-
- /**
* Set to <code>false</code> if the application does not wish to permit any OS-driven
* backups of its data; <code>true</code> otherwise.
*/
@@ -511,10 +498,10 @@
}
@DataClass.Generated(
- time = 1693423910860L,
+ time = 1693513525097L,
codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final boolean mClearUserDataAllowed\nprivate final boolean mBackupAllowed\nprivate final boolean mDefaultToDeviceProtectedStorage\nprivate final boolean mRequestLegacyExternalStorage\nprivate final boolean mUserDataFragile\nprivate final boolean mClearUserDataOnFailedRestoreAllowed\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\nprivate final boolean mIsSdkLibrary\nprivate final boolean mBackupAllowed\nprivate final boolean mDefaultToDeviceProtectedStorage\nprivate final boolean mRequestLegacyExternalStorage\nprivate final boolean mUserDataFragile\nprivate final boolean mClearUserDataOnFailedRestoreAllowed\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 82756af..f823dbc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4871,13 +4871,13 @@
public static final String PEAK_REFRESH_RATE = "peak_refresh_rate";
/**
- * Control whether to stay awake on fold
+ * Control lock behavior on fold
*
* If this isn't set, the system falls back to a device specific default.
* @hide
*/
@Readable
- public static final String STAY_AWAKE_ON_FOLD = "stay_awake_on_fold";
+ public static final String FOLD_LOCK_BEHAVIOR = "fold_lock_behavior_setting";
/**
* The amount of time in milliseconds before the device goes to sleep or begins
diff --git a/core/java/com/android/internal/util/SettingsWrapper.java b/core/java/com/android/internal/util/SettingsWrapper.java
new file mode 100644
index 0000000..8cf6c18
--- /dev/null
+++ b/core/java/com/android/internal/util/SettingsWrapper.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+
+/**
+ * A wrapper class for accessing and modifying system settings that would help with testing.
+ */
+public class SettingsWrapper {
+
+ /** Retrieves the string value of a system setting */
+ public String getStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+ return Settings.System.getStringForUser(contentResolver, name, userHandle);
+ }
+
+ /** Updates the string value of a system setting */
+ public String putStringForUser(ContentResolver contentResolver, String name, int userHandle) {
+ return Settings.System.getStringForUser(contentResolver, name, userHandle);
+ }
+}
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 302c7fa..367a4f5 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -935,6 +935,9 @@
without impacting power, performance, and app compatibility (e.g. protected content). -->
<bool name="config_reduceBrightColorsAvailable">@bool/config_setColorTransformAccelerated</bool>
+ <!-- Whether to show Fold lock behavior setting feature in Settings App -->
+ <bool name="config_fold_lock_behavior">false</bool>
+
<string-array name="config_reduceBrightColorsCoefficientsNonlinear">
<!-- a-coefficient --> <item>-0.4429953456</item>
<!-- b-coefficient --> <item>-0.2434077725</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 02209a7..1965172 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -343,6 +343,7 @@
<java-symbol type="string" name="config_defaultHealthConnectApp" />
<java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
<java-symbol type="bool" name="config_enableScreenshotChord" />
+ <java-symbol type="bool" name="config_fold_lock_behavior" />
<java-symbol type="bool" name="config_enableWifiDisplay" />
<java-symbol type="bool" name="config_allowAnimationsInLowPowerMode" />
<java-symbol type="bool" name="config_useDevInputEventForAudioJack" />
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
index de46b31..5c0e04a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DragPositioningCallbackUtilityTest.kt
@@ -76,7 +76,7 @@
minHeight = MIN_HEIGHT
defaultMinSize = DEFAULT_MIN
displayId = DISPLAY_ID
- configuration.windowConfiguration.bounds = STARTING_BOUNDS
+ configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
}
mockWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
index 6f0599a..c0c4498 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/FluidResizeTaskPositionerTest.kt
@@ -88,7 +88,7 @@
minHeight = MIN_HEIGHT
defaultMinSize = DEFAULT_MIN
displayId = DISPLAY_ID
- configuration.windowConfiguration.bounds = STARTING_BOUNDS
+ configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
}
mockWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
index 3465ddd..8913453 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/VeiledResizeTaskPositionerTest.kt
@@ -104,7 +104,7 @@
minHeight = MIN_HEIGHT
defaultMinSize = DEFAULT_MIN
displayId = DISPLAY_ID
- configuration.windowConfiguration.bounds = STARTING_BOUNDS
+ configuration.windowConfiguration.setBounds(STARTING_BOUNDS)
}
mockDesktopWindowDecoration.mDisplay = mockDisplay
whenever(mockDisplay.displayId).thenAnswer { DISPLAY_ID }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
index 6b0a906..248c60c 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SystemSettings.java
@@ -61,7 +61,7 @@
Settings.System.TTY_MODE,
Settings.System.MASTER_MONO,
Settings.System.MASTER_BALANCE,
- Settings.System.STAY_AWAKE_ON_FOLD,
+ Settings.System.FOLD_LOCK_BEHAVIOR,
Settings.System.SOUND_EFFECTS_ENABLED,
Settings.System.HAPTIC_FEEDBACK_ENABLED,
Settings.System.POWER_SOUNDS_ENABLED, // moved to global
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
index 20740dc..17ce7c7 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SystemSettingsValidators.java
@@ -134,6 +134,7 @@
VALIDATORS.put(System.HAPTIC_FEEDBACK_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.RINGTONE, URI_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_SOUND, URI_VALIDATOR);
+ VALIDATORS.put(System.FOLD_LOCK_BEHAVIOR, ANY_STRING_VALIDATOR);
VALIDATORS.put(System.ALARM_ALERT, URI_VALIDATOR);
VALIDATORS.put(System.TEXT_AUTO_REPLACE, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.TEXT_AUTO_CAPS, BOOLEAN_VALIDATOR);
@@ -219,7 +220,6 @@
VALIDATORS.put(System.WIFI_STATIC_DNS1, LENIENT_IP_ADDRESS_VALIDATOR);
VALIDATORS.put(System.WIFI_STATIC_DNS2, LENIENT_IP_ADDRESS_VALIDATOR);
VALIDATORS.put(System.SHOW_BATTERY_PERCENT, BOOLEAN_VALIDATOR);
- VALIDATORS.put(System.STAY_AWAKE_ON_FOLD, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.NOTIFICATION_LIGHT_PULSE, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED, BOOLEAN_VALIDATOR);
VALIDATORS.put(System.WEAR_ACCESSIBILITY_GESTURE_ENABLED_DURING_OOBE, BOOLEAN_VALIDATOR);
diff --git a/packages/SystemUI/res/xml/media_session_expanded.xml b/packages/SystemUI/res/xml/media_session_expanded.xml
index 0cdc0f9..8bf7560d 100644
--- a/packages/SystemUI/res/xml/media_session_expanded.xml
+++ b/packages/SystemUI/res/xml/media_session_expanded.xml
@@ -54,10 +54,12 @@
android:layout_marginStart="@dimen/qs_media_padding"
android:layout_marginEnd="@dimen/qs_media_padding"
app:layout_constraintEnd_toStartOf="@id/actionPlayPause"
+ app:layout_constraintTop_toBottomOf="@id/media_seamless"
app:layout_constrainedWidth="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toTopOf="@id/header_artist"
- app:layout_constraintHorizontal_bias="0" />
+ app:layout_constraintHorizontal_bias="0"
+ app:layout_constraintVertical_bias="1" />
<Constraint
android:id="@+id/media_explicit_indicator"
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index 08d11c2..7ee0ff4 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -124,7 +124,6 @@
import com.android.systemui.util.concurrency.SysUIConcurrencyModule;
import com.android.systemui.util.dagger.UtilModule;
import com.android.systemui.util.kotlin.CoroutinesModule;
-import com.android.systemui.util.leak.GarbageMonitorModule;
import com.android.systemui.util.sensors.SensorModule;
import com.android.systemui.util.settings.SettingsUtilModule;
import com.android.systemui.util.time.SystemClock;
@@ -177,7 +176,6 @@
FlagsModule.class,
SystemPropertiesFlagsModule.class,
FooterActionsModule.class,
- GarbageMonitorModule.class,
KeyboardModule.class,
LetterboxModule.class,
KeyguardBlueprintModule.class,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
index ee61f57..587da2d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotPolicyImplTest.kt
@@ -140,7 +140,7 @@
private val pipTask = RootTaskInfo().apply {
configuration.windowConfiguration.apply {
windowingMode = WINDOWING_MODE_PINNED
- bounds = Rect(628, 1885, 1038, 2295)
+ setBounds(Rect(628, 1885, 1038, 2295))
activityType = ACTIVITY_TYPE_STANDARD
}
displayId = DISPLAY_ID
@@ -164,7 +164,7 @@
private val fullScreenWorkProfileTask = RootTaskInfo().apply {
configuration.windowConfiguration.apply {
windowingMode = WINDOWING_MODE_FULLSCREEN
- bounds = Rect(0, 0, 1080, 2400)
+ setBounds(Rect(0, 0, 1080, 2400))
activityType = ACTIVITY_TYPE_STANDARD
}
displayId = DISPLAY_ID
@@ -188,7 +188,7 @@
private val launcherTask = RootTaskInfo().apply {
configuration.windowConfiguration.apply {
windowingMode = WINDOWING_MODE_FULLSCREEN
- bounds = Rect(0, 0, 1080, 2400)
+ setBounds(Rect(0, 0, 1080, 2400))
activityType = ACTIVITY_TYPE_HOME
}
displayId = DISPLAY_ID
@@ -212,7 +212,7 @@
private val emptyTask = RootTaskInfo().apply {
configuration.windowConfiguration.apply {
windowingMode = WINDOWING_MODE_FULLSCREEN
- bounds = Rect(0, 0, 1080, 2400)
+ setBounds(Rect(0, 0, 1080, 2400))
activityType = ACTIVITY_TYPE_UNDEFINED
}
displayId = DISPLAY_ID
diff --git a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
index 9e7b897..b07a0bb 100644
--- a/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
+++ b/services/companion/java/com/android/server/companion/virtual/GenericWindowPolicyController.java
@@ -27,8 +27,6 @@
import android.app.WindowConfiguration;
import android.app.compat.CompatChanges;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
-import android.companion.virtual.VirtualDeviceParams;
-import android.companion.virtual.VirtualDeviceParams.ActivityPolicy;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.ComponentName;
@@ -108,18 +106,14 @@
public static final long ALLOW_SECURE_ACTIVITY_DISPLAY_ON_REMOTE_DEVICE = 201712607L;
@NonNull
private final ArraySet<UserHandle> mAllowedUsers;
- @Nullable
- private final ArraySet<ComponentName> mAllowedCrossTaskNavigations;
- @Nullable
- private final ArraySet<ComponentName> mBlockedCrossTaskNavigations;
- @Nullable
- private final ArraySet<ComponentName> mAllowedActivities;
- @Nullable
- private final ArraySet<ComponentName> mBlockedActivities;
+ private final boolean mActivityLaunchAllowedByDefault;
+ @NonNull
+ private final ArraySet<ComponentName> mActivityPolicyExceptions;
+ private final boolean mCrossTaskNavigationAllowedByDefault;
+ @NonNull
+ private final ArraySet<ComponentName> mCrossTaskNavigationExceptions;
private final Object mGenericWindowPolicyControllerLock = new Object();
- @ActivityPolicy
- private final int mDefaultActivityPolicy;
- private final ActivityBlockedCallback mActivityBlockedCallback;
+ @Nullable private final ActivityBlockedCallback mActivityBlockedCallback;
private int mDisplayId = Display.INVALID_DISPLAY;
@NonNull
@@ -134,7 +128,7 @@
private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners =
new ArraySet<>();
@Nullable private final SecureWindowCallback mSecureWindowCallback;
- @Nullable private final Set<String> mDisplayCategories;
+ @NonNull private final Set<String> mDisplayCategories;
@GuardedBy("mGenericWindowPolicyControllerLock")
private boolean mShowTasksInHostDeviceRecents;
@@ -146,18 +140,14 @@
* @param windowFlags The window flags that this controller is interested in.
* @param systemWindowFlags The system window flags that this controller is interested in.
* @param allowedUsers The set of users that are allowed to stream in this display.
- * @param allowedCrossTaskNavigations The set of components explicitly allowed to navigate
- * across tasks on this device.
- * @param blockedCrossTaskNavigations The set of components explicitly blocked from
- * navigating across tasks on this device.
- * @param allowedActivities The set of activities explicitly allowed to stream on this device.
- * Used only if the {@code activityPolicy} is
- * {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_BLOCKED}.
- * @param blockedActivities The set of activities explicitly blocked from streaming on this
- * device. Used only if the {@code activityPolicy} is
- * {@link VirtualDeviceParams#ACTIVITY_POLICY_DEFAULT_ALLOWED}
- * @param defaultActivityPolicy Whether activities are default allowed to be displayed or
- * blocked.
+ * @param activityLaunchAllowedByDefault Whether activities are default allowed to be launched
+ * or blocked.
+ * @param activityPolicyExceptions The set of activities explicitly exempt from the default
+ * activity policy.
+ * @param crossTaskNavigationAllowedByDefault Whether cross task navigations are allowed by
+ * default or not.
+ * @param crossTaskNavigationExceptions The set of components explicitly exempt from the default
+ * navigation policy.
* @param activityListener Activity listener to listen for activity changes.
* @param activityBlockedCallback Callback that is called when an activity is blocked from
* launching.
@@ -169,25 +159,23 @@
*/
public GenericWindowPolicyController(int windowFlags, int systemWindowFlags,
@NonNull ArraySet<UserHandle> allowedUsers,
- @NonNull Set<ComponentName> allowedCrossTaskNavigations,
- @NonNull Set<ComponentName> blockedCrossTaskNavigations,
- @NonNull Set<ComponentName> allowedActivities,
- @NonNull Set<ComponentName> blockedActivities,
- @ActivityPolicy int defaultActivityPolicy,
- @NonNull ActivityListener activityListener,
- @NonNull PipBlockedCallback pipBlockedCallback,
- @NonNull ActivityBlockedCallback activityBlockedCallback,
- @NonNull SecureWindowCallback secureWindowCallback,
- @NonNull IntentListenerCallback intentListenerCallback,
+ boolean activityLaunchAllowedByDefault,
+ @NonNull Set<ComponentName> activityPolicyExceptions,
+ boolean crossTaskNavigationAllowedByDefault,
+ @NonNull Set<ComponentName> crossTaskNavigationExceptions,
+ @Nullable ActivityListener activityListener,
+ @Nullable PipBlockedCallback pipBlockedCallback,
+ @Nullable ActivityBlockedCallback activityBlockedCallback,
+ @Nullable SecureWindowCallback secureWindowCallback,
+ @Nullable IntentListenerCallback intentListenerCallback,
@NonNull Set<String> displayCategories,
boolean showTasksInHostDeviceRecents) {
super();
mAllowedUsers = allowedUsers;
- mAllowedCrossTaskNavigations = new ArraySet<>(allowedCrossTaskNavigations);
- mBlockedCrossTaskNavigations = new ArraySet<>(blockedCrossTaskNavigations);
- mAllowedActivities = new ArraySet<>(allowedActivities);
- mBlockedActivities = new ArraySet<>(blockedActivities);
- mDefaultActivityPolicy = defaultActivityPolicy;
+ mActivityLaunchAllowedByDefault = activityLaunchAllowedByDefault;
+ mActivityPolicyExceptions = new ArraySet<>(activityPolicyExceptions);
+ mCrossTaskNavigationAllowedByDefault = crossTaskNavigationAllowedByDefault;
+ mCrossTaskNavigationExceptions = new ArraySet<>(crossTaskNavigationExceptions);
mActivityBlockedCallback = activityBlockedCallback;
setInterestedWindowFlags(windowFlags, systemWindowFlags);
mActivityListener = activityListener;
@@ -233,7 +221,9 @@
@Nullable Intent intent, @WindowConfiguration.WindowingMode int windowingMode,
int launchingFromDisplayId, boolean isNewTask) {
if (!canContainActivity(activityInfo, windowingMode, launchingFromDisplayId, isNewTask)) {
- mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+ if (mActivityBlockedCallback != null) {
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+ }
return false;
}
if (mIntentListenerCallback != null && intent != null
@@ -275,22 +265,17 @@
+ mDisplayCategories);
return false;
}
- if ((mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED
- && mBlockedActivities.contains(activityComponent))
- || (mDefaultActivityPolicy == VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_BLOCKED
- && !mAllowedActivities.contains(activityComponent))) {
+ if (!isAllowedByPolicy(mActivityLaunchAllowedByDefault, mActivityPolicyExceptions,
+ activityComponent)) {
Slog.d(TAG, "Virtual device launch disallowed by policy: " + activityComponent);
return false;
}
- if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY) {
- if ((!mBlockedCrossTaskNavigations.isEmpty()
- && mBlockedCrossTaskNavigations.contains(activityComponent))
- || ((!mAllowedCrossTaskNavigations.isEmpty()
- && !mAllowedCrossTaskNavigations.contains(activityComponent)))) {
- Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
- + activityComponent);
- return false;
- }
+ if (isNewTask && launchingFromDisplayId != DEFAULT_DISPLAY
+ && !isAllowedByPolicy(mCrossTaskNavigationAllowedByDefault,
+ mCrossTaskNavigationExceptions, activityComponent)) {
+ Slog.d(TAG, "Virtual device cross task navigation disallowed by policy: "
+ + activityComponent);
+ return false;
}
return true;
@@ -302,7 +287,7 @@
int systemWindowFlags) {
// The callback is fired only when windowFlags are changed. To let VirtualDevice owner
// aware that the virtual display has a secure window on top.
- if ((windowFlags & FLAG_SECURE) != 0) {
+ if ((windowFlags & FLAG_SECURE) != 0 && mSecureWindowCallback != null) {
// Post callback on the main thread, so it doesn't block activity launching.
mHandler.post(() -> mSecureWindowCallback.onSecureWindowShown(mDisplayId,
activityInfo.applicationInfo.uid));
@@ -314,7 +299,9 @@
// TODO(b/201712607): Add checks for the apps that use SurfaceView#setSecure.
if ((windowFlags & FLAG_SECURE) != 0
|| (systemWindowFlags & SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS) != 0) {
- mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+ if (mActivityBlockedCallback != null) {
+ mActivityBlockedCallback.onActivityBlocked(mDisplayId, activityInfo);
+ }
return false;
}
}
@@ -367,9 +354,9 @@
if (super.isEnteringPipAllowed(uid)) {
return true;
}
- mHandler.post(() -> {
- mPipBlockedCallback.onEnteringPipBlocked(uid);
- });
+ if (mPipBlockedCallback != null) {
+ mHandler.post(() -> mPipBlockedCallback.onEnteringPipBlocked(uid));
+ }
return false;
}
@@ -389,7 +376,13 @@
}
return activityInfo.requiredDisplayCategory != null
&& mDisplayCategories.contains(activityInfo.requiredDisplayCategory);
+ }
+ private boolean isAllowedByPolicy(boolean allowedByDefault, ArraySet<ComponentName> exceptions,
+ ComponentName component) {
+ // Either allowed and the exceptions do not contain the component,
+ // or disallowed and the exceptions contain the component.
+ return allowedByDefault != exceptions.contains(component);
}
@VisibleForTesting
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
index 56afeb1..8f765e4 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java
@@ -19,7 +19,9 @@
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_ENABLED;
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_NOT_CONTROLLED_BY_POLICY;
import static android.app.admin.DevicePolicyManager.NEARBY_STREAMING_SAME_MANAGED_ACCOUNT_ONLY;
+import static android.companion.virtual.VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.NAVIGATION_POLICY_DEFAULT_ALLOWED;
import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_RECENTS;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
@@ -39,6 +41,7 @@
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.IVirtualDeviceIntentInterceptor;
import android.companion.virtual.IVirtualDeviceSoundEffectListener;
+import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
@@ -168,6 +171,9 @@
@Nullable
private LocaleList mLocaleList = null;
+ @NonNull
+ private final VirtualDevice mPublicVirtualDeviceObject;
+
private ActivityListener createListenerAdapter() {
return new ActivityListener() {
@@ -286,6 +292,9 @@
throw e.rethrowFromSystemServer();
}
mVirtualDeviceLog.logCreated(deviceId, mOwnerUid);
+
+ mPublicVirtualDeviceObject = new VirtualDevice(
+ this, getDeviceId(), getPersistentDeviceId(), mParams.getName());
}
@VisibleForTesting
@@ -315,9 +324,9 @@
return mAssociationInfo.getDisplayName();
}
- /** Returns the optional name of the device. */
- String getDeviceName() {
- return mParams.getName();
+ /** Returns the public representation of the device. */
+ VirtualDevice getPublicVirtualDeviceObject() {
+ return mPublicVirtualDeviceObject;
}
/** Returns the locale of the device. */
@@ -327,7 +336,7 @@
}
}
- /** Returns the policy specified for this policy type */
+ @Override // Binder call
public @VirtualDeviceParams.DevicePolicy int getDevicePolicy(
@VirtualDeviceParams.PolicyType int policyType) {
if (Flags.dynamicPolicy()) {
@@ -754,8 +763,10 @@
synchronized (mVirtualDeviceLock) {
mDefaultShowPointerIcon = showPointerIcon;
}
- getDisplayIds().forEach(
- displayId -> mInputController.setShowPointerIcon(showPointerIcon, displayId));
+ final int[] displayIds = getDisplayIds();
+ for (int i = 0; i < displayIds.length; ++i) {
+ mInputController.setShowPointerIcon(showPointerIcon, displayIds[i]);
+ }
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -831,22 +842,31 @@
private GenericWindowPolicyController createWindowPolicyController(
@NonNull Set<String> displayCategories) {
- final GenericWindowPolicyController gwpc =
- new GenericWindowPolicyController(FLAG_SECURE,
- SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
- getAllowedUserHandles(),
- mParams.getAllowedCrossTaskNavigations(),
- mParams.getBlockedCrossTaskNavigations(),
- mParams.getAllowedActivities(),
- mParams.getBlockedActivities(),
- mParams.getDefaultActivityPolicy(),
- createListenerAdapter(),
- this::onEnteringPipBlocked,
- this::onActivityBlocked,
- this::onSecureWindowShown,
- this::shouldInterceptIntent,
- displayCategories,
- mParams.getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT);
+ final boolean activityLaunchAllowedByDefault =
+ mParams.getDefaultActivityPolicy() == ACTIVITY_POLICY_DEFAULT_ALLOWED;
+ final boolean crossTaskNavigationAllowedByDefault =
+ mParams.getDefaultNavigationPolicy() == NAVIGATION_POLICY_DEFAULT_ALLOWED;
+ final boolean showTasksInHostDeviceRecents =
+ mParams.getDevicePolicy(POLICY_TYPE_RECENTS) == DEVICE_POLICY_DEFAULT;
+
+ final GenericWindowPolicyController gwpc = new GenericWindowPolicyController(
+ FLAG_SECURE,
+ SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
+ getAllowedUserHandles(),
+ activityLaunchAllowedByDefault,
+ /*activityPolicyExceptions=*/activityLaunchAllowedByDefault
+ ? mParams.getBlockedActivities() : mParams.getAllowedActivities(),
+ crossTaskNavigationAllowedByDefault,
+ /*crossTaskNavigationExceptions=*/crossTaskNavigationAllowedByDefault
+ ? mParams.getBlockedCrossTaskNavigations()
+ : mParams.getAllowedCrossTaskNavigations(),
+ createListenerAdapter(),
+ this::onEnteringPipBlocked,
+ this::onActivityBlocked,
+ this::onSecureWindowShown,
+ this::shouldInterceptIntent,
+ displayCategories,
+ showTasksInHostDeviceRecents);
gwpc.registerRunningAppsChangedListener(/* listener= */ this);
return gwpc;
}
@@ -1018,14 +1038,15 @@
return mOwnerUid;
}
- ArraySet<Integer> getDisplayIds() {
+ @Override // Binder call
+ public int[] getDisplayIds() {
synchronized (mVirtualDeviceLock) {
final int size = mVirtualDisplays.size();
- ArraySet<Integer> arraySet = new ArraySet<>(size);
+ int[] displayIds = new int[size];
for (int i = 0; i < size; i++) {
- arraySet.append(mVirtualDisplays.keyAt(i));
+ displayIds[i] = mVirtualDisplays.keyAt(i);
}
- return arraySet;
+ return displayIds;
}
}
diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
index 4da9298..cfe56e9 100644
--- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java
@@ -30,6 +30,7 @@
import android.companion.CompanionDeviceManager;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
+import android.companion.virtual.IVirtualDeviceListener;
import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
@@ -49,6 +50,7 @@
import android.os.Looper;
import android.os.Parcel;
import android.os.Process;
+import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.ArraySet;
@@ -70,6 +72,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -77,6 +80,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
+import java.util.stream.Collectors;
@SuppressLint("LongLogTag")
@@ -103,6 +107,9 @@
}
};
+ private final RemoteCallbackList<IVirtualDeviceListener> mVirtualDeviceListeners =
+ new RemoteCallbackList<>();
+
/**
* Mapping from device IDs to virtual devices.
*/
@@ -225,6 +232,17 @@
mVirtualDevices.remove(deviceId);
}
+ if (Flags.vdmPublicApis()) {
+ mVirtualDeviceListeners.broadcast(listener -> {
+ try {
+ listener.onVirtualDeviceClosed(deviceId);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to invoke onVirtualDeviceClosed listener: "
+ + e.getMessage());
+ }
+ });
+ }
+
Intent i = new Intent(VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED);
i.putExtra(VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, deviceId);
i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -376,6 +394,17 @@
}
mVirtualDevices.put(deviceId, virtualDevice);
}
+
+ if (Flags.vdmPublicApis()) {
+ mVirtualDeviceListeners.broadcast(listener -> {
+ try {
+ listener.onVirtualDeviceCreated(deviceId);
+ } catch (RemoteException e) {
+ Slog.i(TAG, "Failed to invoke onVirtualDeviceCreated listener: "
+ + e.getMessage());
+ }
+ });
+ }
return virtualDevice;
}
@@ -415,14 +444,31 @@
synchronized (mVirtualDeviceManagerLock) {
for (int i = 0; i < mVirtualDevices.size(); i++) {
final VirtualDeviceImpl device = mVirtualDevices.valueAt(i);
- virtualDevices.add(
- new VirtualDevice(device.getDeviceId(), device.getPersistentDeviceId(),
- device.getDeviceName()));
+ virtualDevices.add(device.getPublicVirtualDeviceObject());
}
}
return virtualDevices;
}
+ @Override // Binder call
+ public VirtualDevice getVirtualDevice(int deviceId) {
+ VirtualDeviceImpl device;
+ synchronized (mVirtualDeviceManagerLock) {
+ device = mVirtualDevices.get(deviceId);
+ }
+ return device == null ? null : device.getPublicVirtualDeviceObject();
+ }
+
+ @Override // Binder call
+ public void registerVirtualDeviceListener(IVirtualDeviceListener listener) {
+ mVirtualDeviceListeners.register(listener);
+ }
+
+ @Override // Binder call
+ public void unregisterVirtualDeviceListener(IVirtualDeviceListener listener) {
+ mVirtualDeviceListeners.unregister(listener);
+ }
+
@Override // BinderCall
@VirtualDeviceParams.DevicePolicy
public int getDevicePolicy(int deviceId, @VirtualDeviceParams.PolicyType int policyType) {
@@ -705,7 +751,9 @@
synchronized (mVirtualDeviceManagerLock) {
virtualDevice = mVirtualDevices.get(deviceId);
}
- return virtualDevice == null ? new ArraySet<>() : virtualDevice.getDisplayIds();
+ return virtualDevice == null ? new ArraySet<>()
+ : Arrays.stream(virtualDevice.getDisplayIds()).boxed()
+ .collect(Collectors.toCollection(ArraySet::new));
}
@Override
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index f3ad4b4..90c7ce7 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -146,6 +146,7 @@
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.SettingsWrapper;
import com.android.server.AnimationThread;
import com.android.server.DisplayThread;
import com.android.server.LocalServices;
@@ -159,7 +160,7 @@
import com.android.server.display.mode.DisplayModeDirector;
import com.android.server.display.utils.SensorUtils;
import com.android.server.input.InputManagerInternal;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
import com.android.server.wm.SurfaceAnimationThread;
import com.android.server.wm.WindowManagerInternal;
@@ -549,9 +550,9 @@
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
- mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo,
- new LogicalDisplayListener(), mSyncRoot, mHandler,
- new FoldSettingWrapper(mContext.getContentResolver()), mFlags);
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mContext,
+ new FoldSettingProvider(mContext, new SettingsWrapper()), mDisplayDeviceRepo,
+ new LogicalDisplayListener(), mSyncRoot, mHandler, mFlags);
mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
mBrightnessSynchronizer = new BrightnessSynchronizer(mContext);
Resources resources = mContext.getResources();
diff --git a/services/core/java/com/android/server/display/LogicalDisplayMapper.java b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
index cbe0fc7..b3b16ad 100644
--- a/services/core/java/com/android/server/display/LogicalDisplayMapper.java
+++ b/services/core/java/com/android/server/display/LogicalDisplayMapper.java
@@ -43,7 +43,7 @@
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -149,7 +149,7 @@
private final Listener mListener;
private final DisplayManagerService.SyncRoot mSyncRoot;
private final LogicalDisplayMapperHandler mHandler;
- private final FoldSettingWrapper mFoldSettingWrapper;
+ private final FoldSettingProvider mFoldSettingProvider;
private final PowerManager mPowerManager;
/**
@@ -196,26 +196,27 @@
private boolean mInteractive;
private final DisplayManagerFlags mFlags;
- LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+ LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+ @NonNull DisplayDeviceRepository repo,
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
- @NonNull Handler handler, FoldSettingWrapper foldSettingWrapper,
- DisplayManagerFlags flags) {
- this(context, repo, listener, syncRoot, handler, new DeviceStateToLayoutMap(
- (isDefault) -> isDefault ? DEFAULT_DISPLAY : sNextNonDefaultDisplayId++),
- foldSettingWrapper, flags);
+ @NonNull Handler handler, DisplayManagerFlags flags) {
+ this(context, foldSettingProvider, repo, listener, syncRoot, handler,
+ new DeviceStateToLayoutMap((isDefault) -> isDefault ? DEFAULT_DISPLAY
+ : sNextNonDefaultDisplayId++), flags);
}
- LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
+ LogicalDisplayMapper(@NonNull Context context, FoldSettingProvider foldSettingProvider,
+ @NonNull DisplayDeviceRepository repo,
@NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
@NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap,
- FoldSettingWrapper foldSettingWrapper, DisplayManagerFlags flags) {
+ DisplayManagerFlags flags) {
mSyncRoot = syncRoot;
mPowerManager = context.getSystemService(PowerManager.class);
mInteractive = mPowerManager.isInteractive();
mHandler = new LogicalDisplayMapperHandler(handler.getLooper());
mDisplayDeviceRepo = repo;
mListener = listener;
- mFoldSettingWrapper = foldSettingWrapper;
+ mFoldSettingProvider = foldSettingProvider;
mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
mSupportsConcurrentInternalDisplays = context.getResources().getBoolean(
com.android.internal.R.bool.config_supportsConcurrentInternalDisplays);
@@ -488,10 +489,13 @@
});
} else if (sleepDevice) {
// Send the device to sleep when required.
+ int goToSleepFlag =
+ mFoldSettingProvider.shouldSleepOnFold() ? 0
+ : PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP;
mHandler.post(() -> {
mPowerManager.goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_FOLD,
- PowerManager.GO_TO_SLEEP_FLAG_SOFT_SLEEP);
+ goToSleepFlag);
});
}
}
@@ -565,7 +569,8 @@
&& mDeviceStatesOnWhichToSleep.get(pendingState)
&& !mDeviceStatesOnWhichToSleep.get(currentState)
&& !isOverrideActive
- && isInteractive && isBootCompleted && !mFoldSettingWrapper.shouldStayAwakeOnFold();
+ && isInteractive && isBootCompleted
+ && !mFoldSettingProvider.shouldStayAwakeOnFold();
}
private boolean areAllTransitioningDisplaysOffLocked() {
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java
index 04abbec..2712fa7 100644
--- a/services/core/java/com/android/server/pm/InstallPackageHelper.java
+++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java
@@ -44,7 +44,6 @@
import static android.os.storage.StorageManager.FLAG_STORAGE_CE;
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
-
import static com.android.server.pm.DexOptHelper.useArtService;
import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
@@ -1144,8 +1143,7 @@
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "parsePackage");
final ParsedPackage parsedPackage;
try (PackageParser2 pp = mPm.mInjector.getPreparingPackageParser()) {
- if (request.getPackageLite() == null || !PackageInstallerSession.isArchivedInstallation(
- request.getInstallFlags())) {
+ if (request.getPackageLite() == null || !request.isArchived()) {
// TODO: pass packageLite from install request instead of reparsing the package
parsedPackage = pp.parsePackage(tmpPackageFile, parseFlags, false);
AndroidPackageUtils.validatePackageDexMetadata(parsedPackage);
diff --git a/services/core/java/com/android/server/pm/InstallRequest.java b/services/core/java/com/android/server/pm/InstallRequest.java
index fe7c086..e1cfc41 100644
--- a/services/core/java/com/android/server/pm/InstallRequest.java
+++ b/services/core/java/com/android/server/pm/InstallRequest.java
@@ -21,7 +21,6 @@
import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.os.Process.INVALID_UID;
-
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
import static com.android.server.pm.PackageManagerService.TAG;
@@ -327,6 +326,10 @@
return mRemovedInfo != null && mRemovedInfo.mRemovedPackage != null;
}
+ public boolean isArchived() {
+ return PackageInstallerSession.isArchivedInstallation(getInstallFlags());
+ }
+
@Nullable
public String getRemovedPackage() {
return mRemovedInfo != null ? mRemovedInfo.mRemovedPackage : null;
diff --git a/services/core/java/com/android/server/pm/PackageArchiverService.java b/services/core/java/com/android/server/pm/PackageArchiverService.java
index 29f49c8..c7f067b 100644
--- a/services/core/java/com/android/server/pm/PackageArchiverService.java
+++ b/services/core/java/com/android/server/pm/PackageArchiverService.java
@@ -112,16 +112,15 @@
callerPackageName, DELETE_KEEP_DATA, intentSender, userId);
}
- private ArchiveState createArchiveState(String packageName, int userId)
+ /**
+ * Creates archived state for the package and user.
+ */
+ public ArchiveState createArchiveState(String packageName, int userId)
throws PackageManager.NameNotFoundException {
PackageStateInternal ps = getPackageState(packageName, mPm.snapshotComputer(),
Binder.getCallingUid(), userId);
String responsibleInstallerPackage = getResponsibleInstallerPackage(ps);
- if (responsibleInstallerPackage == null) {
- throw new PackageManager.NameNotFoundException(
- TextUtils.formatSimple("No installer found to archive app %s.",
- packageName));
- }
+ verifyInstaller(responsibleInstallerPackage);
List<LauncherActivityInfo> mainActivities = getLauncherActivityInfos(ps, userId);
List<ArchiveActivityInfo> archiveActivityInfos = new ArrayList<>();
@@ -136,6 +135,26 @@
return new ArchiveState(archiveActivityInfos, responsibleInstallerPackage);
}
+ private void verifyInstaller(String installerPackage)
+ throws PackageManager.NameNotFoundException {
+ if (TextUtils.isEmpty(installerPackage)) {
+ throw new PackageManager.NameNotFoundException("No installer found");
+ }
+ if (!verifySupportsUnarchival(installerPackage)) {
+ throw new PackageManager.NameNotFoundException("Installer does not support unarchival");
+ }
+ }
+
+ /**
+ * @return true if installerPackage support unarchival:
+ * - has an action Intent.ACTION_UNARCHIVE_PACKAGE,
+ * - has permissions to install packages.
+ */
+ public boolean verifySupportsUnarchival(String installerPackage) {
+ // TODO(b/278553670) Check if installerPackage supports unarchival.
+ return true;
+ }
+
@Override
public void requestUnarchive(
@NonNull String packageName,
@@ -246,7 +265,7 @@
}
private String getResponsibleInstallerPackage(PackageStateInternal ps) {
- return ps.getInstallSource().mUpdateOwnerPackageName == null
+ return TextUtils.isEmpty(ps.getInstallSource().mUpdateOwnerPackageName)
? ps.getInstallSource().mInstallerPackageName
: ps.getInstallSource().mUpdateOwnerPackageName;
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1bdade2..0dd4111ad 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -40,7 +40,6 @@
import static android.system.OsConstants.O_CREAT;
import static android.system.OsConstants.O_RDONLY;
import static android.system.OsConstants.O_WRONLY;
-
import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE;
import static com.android.internal.util.XmlUtils.readBitmapAttribute;
import static com.android.internal.util.XmlUtils.readByteArrayAttribute;
@@ -1166,6 +1165,11 @@
throw new IllegalArgumentException(
"Archived installation can only use Streaming System DataLoader.");
}
+ if (!TextUtils.isEmpty(params.appPackageName) && !isArchivedInstallationAllowed(
+ params.appPackageName)) {
+ throw new IllegalArgumentException(
+ "Archived installation of this package is not allowed.");
+ }
}
}
@@ -2220,6 +2224,19 @@
}
/**
+ * Check if this package can be installed archived.
+ */
+ private static boolean isArchivedInstallationAllowed(String packageName) {
+ final PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class);
+ final PackageStateInternal existingPkgSetting = pmi.getPackageStateInternal(packageName);
+ if (existingPkgSetting == null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
* Checks if the package can be installed on IncFs.
*/
private static boolean isIncrementalInstallationAllowed(String packageName) {
@@ -3371,6 +3388,23 @@
}
}
+ if (isArchivedInstallation()) {
+ if (!isArchivedInstallationAllowed(mPackageName)) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_SESSION_INVALID,
+ "Archived installation of this package is not allowed.");
+ }
+
+ if (!isInstalledByAdb(getInstallSource().mInitiatingPackageName)
+ && !mPm.mArchiverService.verifySupportsUnarchival(
+ getInstallSource().mInstallerPackageName)) {
+ throw new PackageManagerException(
+ PackageManager.INSTALL_FAILED_SESSION_INVALID,
+ "Installer has to support unarchival in order to install archived "
+ + "packages.");
+ }
+ }
+
if (isIncrementalInstallation()) {
if (!isIncrementalInstallationAllowed(mPackageName)) {
throw new PackageManagerException(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index bb4fd66..0c2f1ca 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -36,7 +36,6 @@
import static android.os.storage.StorageManager.FLAG_STORAGE_DE;
import static android.os.storage.StorageManager.FLAG_STORAGE_EXTERNAL;
import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE;
-
import static com.android.internal.annotations.VisibleForTesting.Visibility;
import static com.android.internal.util.FrameworkStatsLog.BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME;
import static com.android.server.pm.DexOptHelper.useArtService;
@@ -6323,7 +6322,6 @@
archPkg.targetSdkVersion = apk.getTargetSdkVersion();
// These get translated in flags important for user data management.
- archPkg.clearUserDataAllowed = apk.isClearUserDataAllowed();
archPkg.backupAllowed = apk.isBackupAllowed();
archPkg.defaultToDeviceProtectedStorage =
apk.isDefaultToDeviceProtectedStorage();
diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
index 2d55b9f..81c2f07 100644
--- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
+++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java
@@ -28,7 +28,6 @@
import static android.os.Build.VERSION_CODES.DONUT;
import static android.os.Build.VERSION_CODES.O;
import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
-
import static com.android.server.pm.pkg.parsing.ParsingUtils.parseKnownActivityEmbeddingCerts;
import android.annotation.AnyRes;
@@ -514,7 +513,7 @@
pkg
// Default true
.setBackupAllowed(lite.isBackupAllowed())
- .setClearUserDataAllowed(lite.isClearUserDataAllowed())
+ .setClearUserDataAllowed(true)
.setClearUserDataOnFailedRestoreAllowed(
lite.isClearUserDataOnFailedRestoreAllowed())
.setAllowNativeHeapPointerTagging(true)
diff --git a/services/core/java/com/android/server/utils/FoldSettingProvider.java b/services/core/java/com/android/server/utils/FoldSettingProvider.java
new file mode 100644
index 0000000..d62628b
--- /dev/null
+++ b/services/core/java/com/android/server/utils/FoldSettingProvider.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import java.util.Set;
+
+/**
+ * This class provides a convenient way to access the {@link Settings.System#FOLD_LOCK_BEHAVIOR}.
+ * The {@link Settings.System#FOLD_LOCK_BEHAVIOR} setting controls the behavior of the device when
+ * it is folded, and provides the user with three different options to choose from. Those are:
+ * 1. Stay awake on fold: The device will remain unlocked when it is folded.
+ * 2. Selective stay awake: The device will remain unlocked when it is folded only if there are
+ * apps with wakelocks running. This is also the set default behavior.
+ * 3. Sleep on fold: The device will lock when it is folded, regardless of which apps are running
+ * or whether any wakelocks are held.
+ *
+ * Keep the setting values in this class in sync with the values in
+ * {@link com.android.settings.display.FoldLockBehaviorSettings}
+ */
+public class FoldSettingProvider {
+
+ public static final String SETTING_VALUE_STAY_AWAKE_ON_FOLD = "stay_awake_on_fold_key";
+ public static final String SETTING_VALUE_SELECTIVE_STAY_AWAKE = "selective_stay_awake_key";
+ public static final String SETTING_VALUE_SLEEP_ON_FOLD = "sleep_on_fold_key";
+ private static final String SETTING_VALUE_DEFAULT = SETTING_VALUE_SELECTIVE_STAY_AWAKE;
+ private static final Set<String> SETTING_VALUES = Set.of(SETTING_VALUE_STAY_AWAKE_ON_FOLD,
+ SETTING_VALUE_SELECTIVE_STAY_AWAKE, SETTING_VALUE_SLEEP_ON_FOLD);
+ private static final String TAG = "FoldSettingProvider";
+
+ private final ContentResolver mContentResolver;
+ private final boolean mIsFoldLockBehaviorAvailable;
+ private final SettingsWrapper mSettingsWrapper;
+
+ public FoldSettingProvider(Context context, SettingsWrapper settingsWrapper) {
+ mContentResolver = context.getContentResolver();
+ mSettingsWrapper = settingsWrapper;
+ mIsFoldLockBehaviorAvailable = context.getResources().getBoolean(
+ R.bool.config_fold_lock_behavior);
+ }
+
+ /**
+ * Returns whether the device should remain awake after folding.
+ */
+ public boolean shouldStayAwakeOnFold() {
+ return getFoldSettingValue().equals(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+ }
+
+ /**
+ * Returns whether the device should selective remain awake after folding.
+ */
+ public boolean shouldSelectiveStayAwakeOnFold() {
+ return getFoldSettingValue().equals(SETTING_VALUE_SELECTIVE_STAY_AWAKE);
+ }
+
+ /**
+ * Returns whether the device should strictly sleep after folding.
+ */
+ public boolean shouldSleepOnFold() {
+ return getFoldSettingValue().equals(SETTING_VALUE_SLEEP_ON_FOLD);
+ }
+
+ private String getFoldSettingValue() {
+ if (!mIsFoldLockBehaviorAvailable) {
+ return SETTING_VALUE_DEFAULT;
+ }
+ String foldSettingValue = mSettingsWrapper.getStringForUser(
+ mContentResolver,
+ Settings.System.FOLD_LOCK_BEHAVIOR,
+ UserHandle.USER_CURRENT);
+ foldSettingValue = (foldSettingValue != null) ? foldSettingValue : SETTING_VALUE_DEFAULT;
+ if (!SETTING_VALUES.contains(foldSettingValue)) {
+ Log.e(TAG,
+ "getFoldSettingValue: Invalid setting value, returning default setting value");
+ foldSettingValue = SETTING_VALUE_DEFAULT;
+ }
+
+ return foldSettingValue;
+ }
+}
diff --git a/services/core/java/com/android/server/utils/FoldSettingWrapper.java b/services/core/java/com/android/server/utils/FoldSettingWrapper.java
deleted file mode 100644
index 97a1ac0..0000000
--- a/services/core/java/com/android/server/utils/FoldSettingWrapper.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.utils;
-
-import android.content.ContentResolver;
-import android.provider.Settings;
-
-/**
- * A wrapper class for the {@link Settings.System#STAY_AWAKE_ON_FOLD} setting.
- *
- * This class provides a convenient way to access the {@link Settings.System#STAY_AWAKE_ON_FOLD}
- * setting for testing.
- */
-public class FoldSettingWrapper {
- private final ContentResolver mContentResolver;
-
- public FoldSettingWrapper(ContentResolver contentResolver) {
- mContentResolver = contentResolver;
- }
-
- /**
- * Returns whether the device should remain awake after folding.
- */
- public boolean shouldStayAwakeOnFold() {
- try {
- return (Settings.System.getIntForUser(
- mContentResolver,
- Settings.System.STAY_AWAKE_ON_FOLD,
- 0) == 1);
- } catch (Settings.SettingNotFoundException e) {
- return false;
- }
- }
-}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
index 9a8e421..8684dbe 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -111,7 +111,7 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ cancelNotification();
if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
onBugreportSharingAccepted();
} else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
@@ -213,8 +213,7 @@
mRemoteBugreportServiceIsActive.set(true);
mRemoteBugreportSharingAccepted.set(false);
registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_STARTED);
mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
return true;
} catch (RemoteException re) {
@@ -258,13 +257,10 @@
final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
if (mRemoteBugreportSharingAccepted.get()) {
shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- NOTIFICATION_ID);
+ cancelNotification();
} else {
mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
}
mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
}
@@ -274,7 +270,7 @@
mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
mRemoteBugreportSharingAccepted.set(false);
mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ cancelNotification();
final Bundle extras = new Bundle();
extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
@@ -289,9 +285,7 @@
if (uriAndHash != null) {
shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
} else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
- UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED);
}
}
@@ -340,7 +334,16 @@
filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
- buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+ notify(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED);
+ }
+
+ private void notify(@RemoteBugreportNotificationType int type) {
+ mInjector.getNotificationManager()
+ .notifyAsUser(LOG_TAG, NOTIFICATION_ID, buildNotification(type), UserHandle.ALL);
+ }
+
+ private void cancelNotification() {
+ mInjector.getNotificationManager()
+ .cancelAsUser(LOG_TAG, NOTIFICATION_ID, UserHandle.ALL);
}
}
diff --git a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
index 6954435..065dd1f 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/LogicalDisplayMapperTest.java
@@ -44,9 +44,13 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -58,6 +62,7 @@
import android.os.IThermalService;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RemoteException;
import android.os.test.TestLooper;
import android.view.Display;
import android.view.DisplayAddress;
@@ -69,7 +74,7 @@
import com.android.server.display.feature.DisplayManagerFlags;
import com.android.server.display.layout.DisplayIdProducer;
import com.android.server.display.layout.Layout;
-import com.android.server.utils.FoldSettingWrapper;
+import com.android.server.utils.FoldSettingProvider;
import org.junit.Before;
import org.junit.Test;
@@ -93,6 +98,7 @@
private static int sUniqueTestDisplayId = 0;
private static final int DEVICE_STATE_CLOSED = 0;
private static final int DEVICE_STATE_OPEN = 2;
+ private static final int FLAG_GO_TO_SLEEP_ON_FOLD = 0;
private static int sNextNonDefaultDisplayId = DEFAULT_DISPLAY + 1;
private static final File NON_EXISTING_FILE = new File("/non_existing_folder/should_not_exist");
@@ -107,7 +113,7 @@
@Mock LogicalDisplayMapper.Listener mListenerMock;
@Mock Context mContextMock;
- @Mock FoldSettingWrapper mFoldSettingWrapperMock;
+ @Mock FoldSettingProvider mFoldSettingProviderMock;
@Mock Resources mResourcesMock;
@Mock IPowerManager mIPowerManagerMock;
@Mock IThermalService mIThermalServiceMock;
@@ -120,7 +126,7 @@
@Captor ArgumentCaptor<Integer> mDisplayEventCaptor;
@Before
- public void setUp() {
+ public void setUp() throws RemoteException {
// Share classloader to allow package private access.
System.setProperty("dexmaker.share_classloader", "true");
MockitoAnnotations.initMocks(this);
@@ -150,7 +156,9 @@
when(mContextMock.getSystemServiceName(PowerManager.class))
.thenReturn(Context.POWER_SERVICE);
- when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(false);
+ when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(false);
+ when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+ when(mIPowerManagerMock.isInteractive()).thenReturn(true);
when(mContextMock.getSystemService(PowerManager.class)).thenReturn(mPowerManager);
when(mContextMock.getResources()).thenReturn(mResourcesMock);
when(mResourcesMock.getBoolean(
@@ -166,9 +174,10 @@
when(mFlagsMock.isConnectedDisplayManagementEnabled()).thenReturn(false);
mLooper = new TestLooper();
mHandler = new Handler(mLooper.getLooper());
- mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mDisplayDeviceRepo,
+ mLogicalDisplayMapper = new LogicalDisplayMapper(mContextMock, mFoldSettingProviderMock,
+ mDisplayDeviceRepo,
mListenerMock, new DisplayManagerService.SyncRoot(), mHandler,
- mDeviceStateToLayoutMapSpy, mFoldSettingWrapperMock, mFlagsMock);
+ mDeviceStateToLayoutMapSpy, mFlagsMock);
}
@@ -645,8 +654,8 @@
}
@Test
- public void testDeviceShouldNotSleepWhenFoldSettingTrue() {
- when(mFoldSettingWrapperMock.shouldStayAwakeOnFold()).thenReturn(true);
+ public void testDeviceShouldNotSleepWhenStayAwakeSettingTrue() {
+ when(mFoldSettingProviderMock.shouldStayAwakeOnFold()).thenReturn(true);
assertFalse(mLogicalDisplayMapper.shouldDeviceBePutToSleep(DEVICE_STATE_CLOSED,
DEVICE_STATE_OPEN,
@@ -679,6 +688,26 @@
}
@Test
+ public void testDeviceShouldPutToSleepWhenSleepSettingTrue() throws RemoteException {
+ when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(true);
+
+ finishBootAndFoldDevice();
+
+ verify(mIPowerManagerMock, atLeastOnce()).goToSleep(anyLong(), anyInt(),
+ eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+ }
+
+ @Test
+ public void testDeviceShouldNotBePutToSleepWhenSleepSettingFalse() throws RemoteException {
+ when(mFoldSettingProviderMock.shouldSleepOnFold()).thenReturn(false);
+
+ finishBootAndFoldDevice();
+
+ verify(mIPowerManagerMock, never()).goToSleep(anyLong(), anyInt(),
+ eq(FLAG_GO_TO_SLEEP_ON_FOLD));
+ }
+
+ @Test
public void testDeviceStateLocked() {
DisplayDevice device1 = createDisplayDevice(TYPE_INTERNAL, 600, 800,
FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY);
@@ -930,6 +959,15 @@
// Helper Methods
/////////////////
+ private void finishBootAndFoldDevice() {
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_OPEN, false);
+ advanceTime(1000);
+ mLogicalDisplayMapper.onBootCompleted();
+ advanceTime(1000);
+ mLogicalDisplayMapper.setDeviceStateLocked(DEVICE_STATE_CLOSED, false);
+ advanceTime(1000);
+ }
+
private void createDefaultDisplay(Layout layout, DisplayDevice device) {
createDefaultDisplay(layout, info(device).address);
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
index e58a234..80576a6 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/PackageArchiverServiceTest.java
@@ -18,9 +18,7 @@
import static android.content.Intent.FLAG_RECEIVER_FOREGROUND;
import static android.content.pm.PackageManager.DELETE_KEEP_DATA;
-
import static com.google.common.truth.Truth.assertThat;
-
import static org.junit.Assert.assertThrows;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -207,8 +205,7 @@
() -> mArchiveService.requestArchive(PACKAGE, CALLER_PACKAGE, mIntentSender,
UserHandle.CURRENT));
assertThat(e.getCause()).isInstanceOf(PackageManager.NameNotFoundException.class);
- assertThat(e.getCause()).hasMessageThat().isEqualTo(
- String.format("No installer found to archive app %s.", PACKAGE));
+ assertThat(e.getCause()).hasMessageThat().isEqualTo("No installer found");
}
@Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
new file mode 100644
index 0000000..3514276
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/FoldSettingProviderTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.utils;
+
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_SLEEP_ON_FOLD;
+import static com.android.server.utils.FoldSettingProvider.SETTING_VALUE_STAY_AWAKE_ON_FOLD;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.res.Resources;
+import android.os.UserHandle;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.internal.R;
+import com.android.internal.util.SettingsWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+public class FoldSettingProviderTest {
+
+ private static final String SETTING_VALUE_INVALID = "invalid_fold_lock_behavior";
+
+ @Mock
+ private Context mContext;
+ @Mock
+ private Resources mResources;
+ @Mock
+ private SettingsWrapper mSettingsWrapper;
+ private ContentResolver mContentResolver;
+ private FoldSettingProvider mFoldSettingProvider;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+
+ mContentResolver =
+ InstrumentationRegistry.getInstrumentation().getContext().getContentResolver();
+ when(mContext.getContentResolver()).thenReturn(mContentResolver);
+ when(mContext.getResources()).thenReturn(mResources);
+ setFoldLockBehaviorAvailability(true);
+
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+ }
+
+ @Test
+ public void foldSettingNotAvailable_returnDefaultSetting() {
+ setFoldLockBehaviorAvailability(false);
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+ boolean shouldSelectiveStayAwakeOnFold =
+ mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+ assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+ }
+
+ @Test
+ public void foldSettingNotAvailable_notReturnStayAwakeOnFoldTrue() {
+ setFoldLockBehaviorAvailability(false);
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+ boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+ assertThat(shouldStayAwakeOnFold).isFalse();
+ }
+
+ @Test
+ public void foldSettingNotAvailable_notReturnSleepOnFoldTrue() {
+ setFoldLockBehaviorAvailability(false);
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_SLEEP_ON_FOLD);
+ mFoldSettingProvider = new FoldSettingProvider(mContext, mSettingsWrapper);
+
+ boolean shouldSleepOnFold = mFoldSettingProvider.shouldSleepOnFold();
+
+ assertThat(shouldSleepOnFold).isFalse();
+ }
+
+ @Test
+ public void foldSettingAvailable_returnCorrectFoldSetting() {
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_STAY_AWAKE_ON_FOLD);
+
+ boolean shouldStayAwakeOnFold = mFoldSettingProvider.shouldStayAwakeOnFold();
+
+ assertThat(shouldStayAwakeOnFold).isTrue();
+ }
+
+ @Test
+ public void foldSettingInvalid_returnDefaultSetting() {
+ setFoldLockBehaviorSettingValue(SETTING_VALUE_INVALID);
+
+ boolean shouldSelectiveStayAwakeOnFold =
+ mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+ assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+ }
+
+ @Test
+ public void foldSettingNotDefined_returnDefaultSetting() {
+ setFoldLockBehaviorSettingValue(null);
+
+ boolean shouldSelectiveStayAwakeOnFold =
+ mFoldSettingProvider.shouldSelectiveStayAwakeOnFold();
+
+ assertThat(shouldSelectiveStayAwakeOnFold).isTrue();
+ }
+
+ private void setFoldLockBehaviorAvailability(boolean isFoldLockBehaviorEnabled) {
+ when(mResources.getBoolean(R.bool.config_fold_lock_behavior)).thenReturn(
+ isFoldLockBehaviorEnabled);
+ }
+
+ private void setFoldLockBehaviorSettingValue(String foldLockBehaviorSettingValue) {
+ when(mSettingsWrapper.getStringForUser(any(),
+ eq(Settings.System.FOLD_LOCK_BEHAVIOR),
+ eq(UserHandle.USER_CURRENT))).thenReturn(foldLockBehaviorSettingValue);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
index 28df24c..c65452a 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/VirtualDeviceTest.java
@@ -16,21 +16,31 @@
package com.android.server.companion.virtual;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_CUSTOM;
+import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT;
+import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS;
import static android.content.Context.DEVICE_ID_DEFAULT;
import static android.content.Context.DEVICE_ID_INVALID;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.when;
+import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.VirtualDevice;
+import android.companion.virtual.flags.Flags;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresFlagsEnabled;
import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
@Presubmit
@RunWith(AndroidJUnit4.class)
@@ -40,24 +50,35 @@
private static final String PERSISTENT_ID = "persistentId";
private static final String DEVICE_NAME = "VirtualDeviceName";
+ @Mock
+ private IVirtualDevice mVirtualDevice;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ }
+
@Test
public void build_invalidId_shouldThrowIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
- () -> new VirtualDevice(DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
+ () -> new VirtualDevice(
+ mVirtualDevice, DEVICE_ID_INVALID, PERSISTENT_ID, DEVICE_NAME));
}
@Test
public void build_defaultId_shouldThrowIllegalArgumentException() {
assertThrows(
IllegalArgumentException.class,
- () -> new VirtualDevice(DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
+ () -> new VirtualDevice(
+ mVirtualDevice, DEVICE_ID_DEFAULT, PERSISTENT_ID, DEVICE_NAME));
}
@Test
public void build_onlyRequiredFields() {
VirtualDevice virtualDevice =
- new VirtualDevice(VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+ new VirtualDevice(
+ mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
assertThat(virtualDevice.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
assertThat(virtualDevice.getPersistentDeviceId()).isNull();
assertThat(virtualDevice.getName()).isNull();
@@ -66,15 +87,43 @@
@Test
public void parcelable_shouldRecreateSuccessfully() {
VirtualDevice originalDevice =
- new VirtualDevice(VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
+ new VirtualDevice(mVirtualDevice, VIRTUAL_DEVICE_ID, PERSISTENT_ID, DEVICE_NAME);
Parcel parcel = Parcel.obtain();
originalDevice.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
VirtualDevice device = VirtualDevice.CREATOR.createFromParcel(parcel);
- assertThat(device).isEqualTo(originalDevice);
assertThat(device.getDeviceId()).isEqualTo(VIRTUAL_DEVICE_ID);
assertThat(device.getPersistentDeviceId()).isEqualTo(PERSISTENT_ID);
assertThat(device.getName()).isEqualTo(DEVICE_NAME);
}
+
+ @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
+ @Test
+ public void virtualDevice_getDisplayIds() throws Exception {
+ VirtualDevice virtualDevice =
+ new VirtualDevice(
+ mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+
+ when(mVirtualDevice.getDisplayIds()).thenReturn(new int[0]);
+ assertThat(virtualDevice.getDisplayIds()).hasLength(0);
+
+ final int[] displayIds = new int[]{7, 18};
+ when(mVirtualDevice.getDisplayIds()).thenReturn(displayIds);
+ assertThat(virtualDevice.getDisplayIds()).isEqualTo(displayIds);
+ }
+
+ @RequiresFlagsEnabled(Flags.FLAG_VDM_PUBLIC_APIS)
+ @Test
+ public void virtualDevice_hasCustomSensorSupport() throws Exception {
+ VirtualDevice virtualDevice =
+ new VirtualDevice(
+ mVirtualDevice, VIRTUAL_DEVICE_ID, /*persistentId=*/null, /*name=*/null);
+
+ when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS)).thenReturn(DEVICE_POLICY_DEFAULT);
+ assertThat(virtualDevice.hasCustomSensorSupport()).isFalse();
+
+ when(mVirtualDevice.getDevicePolicy(POLICY_TYPE_SENSORS)).thenReturn(DEVICE_POLICY_CUSTOM);
+ assertThat(virtualDevice.hasCustomSensorSupport()).isTrue();
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
index 2bfa44e..78655a5 100644
--- a/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/companion/virtual/audio/VirtualAudioControllerTest.java
@@ -25,7 +25,6 @@
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
import android.content.Context;
@@ -79,11 +78,10 @@
FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
/* allowedUsers= */ new ArraySet<>(),
- /* allowedCrossTaskNavigations= */ new ArraySet<>(),
- /* blockedCrossTaskNavigations= */ new ArraySet<>(),
- /* allowedActivities= */ new ArraySet<>(),
- /* blockedActivities= */ new ArraySet<>(),
- VirtualDeviceParams.ACTIVITY_POLICY_DEFAULT_ALLOWED,
+ /* activityLaunchAllowedByDefault= */ true,
+ /* activityPolicyExceptions= */ new ArraySet<>(),
+ /* crossTaskNavigationAllowedByDefault= */ true,
+ /* crossTaskNavigationExceptions= */ new ArraySet<>(),
/* activityListener= */ null,
/* pipBlockedCallback= */ null,
/* activityBlockedCallback= */ null,