Merge "Support extraData in SpaLogger API."
diff --git a/Android.bp b/Android.bp
index 4e7eba2..3d25bc1 100644
--- a/Android.bp
+++ b/Android.bp
@@ -100,7 +100,7 @@
":android.hardware.gnss-V2-java-source",
":android.hardware.graphics.common-V3-java-source",
":android.hardware.keymaster-V4-java-source",
- ":android.hardware.security.keymint-V2-java-source",
+ ":android.hardware.security.keymint-V3-java-source",
":android.hardware.security.secureclock-V1-java-source",
":android.hardware.tv.tuner-V1-java-source",
":android.security.apc-java-source",
diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp
index bb31c11..b2300ce 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -89,7 +89,7 @@
// If the overlay supplies a target overlayable name, the resource must belong to the
// overlayable defined with the specified name to be overlaid.
return Error(R"(<overlay> android:targetName "%s" does not match overlayable name "%s")",
- overlay_info.target_name.c_str(), (*overlayable_info)->name.c_str());
+ overlay_info.target_name.c_str(), (*overlayable_info)->name.data());
}
// Enforce policy restrictions if the resource is declared as overlayable.
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 7d80493..26e20f6 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -29,12 +29,18 @@
import java.util.function.Consumer;
import java.util.concurrent.Executor;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
public class UsbCommand extends Svc.Command {
public UsbCommand() {
super("usb");
}
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
@Override
public String shortHelp() {
return "Control Usb state";
@@ -92,8 +98,10 @@
if ("setFunctions".equals(args[1])) {
try {
+ int operationId = sUsbOperationCount.incrementAndGet();
+ System.out.println("setCurrentFunctions opId:" + operationId);
usbMgr.setCurrentFunctions(UsbManager.usbFunctionsFromString(
- args.length >= 3 ? args[2] : ""));
+ args.length >= 3 ? args[2] : ""), operationId);
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}
diff --git a/core/api/current.txt b/core/api/current.txt
index a03a753..787370a 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -6969,6 +6969,7 @@
method @Deprecated public void onStart(android.content.Intent, int);
method public int onStartCommand(android.content.Intent, int, int);
method public void onTaskRemoved(android.content.Intent);
+ method public void onTimeout(int);
method public void onTrimMemory(int);
method public boolean onUnbind(android.content.Intent);
method public final void startForeground(int, android.app.Notification);
@@ -12475,6 +12476,7 @@
field @Deprecated public static final int FOREGROUND_SERVICE_TYPE_NONE = 0; // 0x0
field @RequiresPermission(allOf={android.Manifest.permission.FOREGROUND_SERVICE_PHONE_CALL}, anyOf={android.Manifest.permission.MANAGE_OWN_CALLS}, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_PHONE_CALL = 4; // 0x4
field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_REMOTE_MESSAGING, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_REMOTE_MESSAGING = 512; // 0x200
+ field public static final int FOREGROUND_SERVICE_TYPE_SHORT_SERVICE = 2048; // 0x800
field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SPECIAL_USE, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE = 1073741824; // 0x40000000
field @RequiresPermission(value=android.Manifest.permission.FOREGROUND_SERVICE_SYSTEM_EXEMPTED, conditional=true) public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1024; // 0x400
field public int flags;
@@ -15481,7 +15483,6 @@
}
public static class PathIterator.Segment {
- ctor public PathIterator.Segment(@NonNull int, @NonNull float[], float);
method public float getConicWeight();
method @NonNull public float[] getPoints();
method @NonNull public int getVerb();
@@ -48693,6 +48694,7 @@
method public float getRefreshRate();
method public int getRotation();
method @Nullable public android.view.RoundedCorner getRoundedCorner(int);
+ method @NonNull public android.view.DisplayShape getShape();
method @Deprecated public void getSize(android.graphics.Point);
method public int getState();
method public android.view.Display.Mode[] getSupportedModes();
@@ -48773,6 +48775,13 @@
method @NonNull public android.view.DisplayCutout.Builder setWaterfallInsets(@NonNull android.graphics.Insets);
}
+ public final class DisplayShape implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.graphics.Path getPath();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.view.DisplayShape> CREATOR;
+ }
+
public final class DragAndDropPermissions implements android.os.Parcelable {
method public int describeContents();
method public void release();
@@ -52154,6 +52163,7 @@
method @Deprecated @NonNull public android.view.WindowInsets consumeStableInsets();
method @Deprecated @NonNull public android.view.WindowInsets consumeSystemWindowInsets();
method @Nullable public android.view.DisplayCutout getDisplayCutout();
+ method @Nullable public android.view.DisplayShape getDisplayShape();
method @NonNull public android.graphics.Insets getInsets(int);
method @NonNull public android.graphics.Insets getInsetsIgnoringVisibility(int);
method @Deprecated @NonNull public android.graphics.Insets getMandatorySystemGestureInsets();
@@ -52189,6 +52199,7 @@
ctor public WindowInsets.Builder(@NonNull android.view.WindowInsets);
method @NonNull public android.view.WindowInsets build();
method @NonNull public android.view.WindowInsets.Builder setDisplayCutout(@Nullable android.view.DisplayCutout);
+ method @NonNull public android.view.WindowInsets.Builder setDisplayShape(@NonNull android.view.DisplayShape);
method @NonNull public android.view.WindowInsets.Builder setInsets(int, @NonNull android.graphics.Insets);
method @NonNull public android.view.WindowInsets.Builder setInsetsIgnoringVisibility(int, @NonNull android.graphics.Insets) throws java.lang.IllegalArgumentException;
method @Deprecated @NonNull public android.view.WindowInsets.Builder setMandatorySystemGestureInsets(@NonNull android.graphics.Insets);
diff --git a/core/api/module-lib-current.txt b/core/api/module-lib-current.txt
index b6e2d2a..3228ce6 100644
--- a/core/api/module-lib-current.txt
+++ b/core/api/module-lib-current.txt
@@ -121,6 +121,7 @@
field public static final int GADGET_HAL_V1_0 = 10; // 0xa
field public static final int GADGET_HAL_V1_1 = 11; // 0xb
field public static final int GADGET_HAL_V1_2 = 12; // 0xc
+ field public static final int GADGET_HAL_V2_0 = 20; // 0x14
field public static final int USB_DATA_TRANSFER_RATE_10G = 10240; // 0x2800
field public static final int USB_DATA_TRANSFER_RATE_20G = 20480; // 0x5000
field public static final int USB_DATA_TRANSFER_RATE_40G = 40960; // 0xa000
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index c10504d..c47e3b2 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -12873,14 +12873,14 @@
method @NonNull public android.telephony.BarringInfo createLocationInfoSanitizedCopy();
}
- public final class CallAttributes implements android.os.Parcelable {
- ctor public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
- method public int describeContents();
- method @NonNull public android.telephony.CallQuality getCallQuality();
- method public int getNetworkType();
- method @NonNull public android.telephony.PreciseCallState getPreciseCallState();
- method public void writeToParcel(android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
+ @Deprecated public final class CallAttributes implements android.os.Parcelable {
+ ctor @Deprecated public CallAttributes(@NonNull android.telephony.PreciseCallState, int, @NonNull android.telephony.CallQuality);
+ method @Deprecated public int describeContents();
+ method @Deprecated @NonNull public android.telephony.CallQuality getCallQuality();
+ method @Deprecated public int getNetworkType();
+ method @Deprecated @NonNull public android.telephony.PreciseCallState getPreciseCallState();
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallAttributes> CREATOR;
}
public final class CallForwardingInfo implements android.os.Parcelable {
@@ -12960,6 +12960,28 @@
method @NonNull public android.telephony.CallQuality.Builder setUplinkCallQualityLevel(int);
}
+ public final class CallState implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.telephony.CallQuality getCallQuality();
+ method public int getCallState();
+ method public int getImsCallServiceType();
+ method @Nullable public String getImsCallSessionId();
+ method public int getImsCallType();
+ method public int getNetworkType();
+ method public void writeToParcel(@Nullable android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CallState> CREATOR;
+ }
+
+ public static final class CallState.Builder {
+ ctor public CallState.Builder(int);
+ method @NonNull public android.telephony.CallState build();
+ method @NonNull public android.telephony.CallState.Builder setCallQuality(@Nullable android.telephony.CallQuality);
+ method @NonNull public android.telephony.CallState.Builder setImsCallServiceType(int);
+ method @NonNull public android.telephony.CallState.Builder setImsCallSessionId(@Nullable String);
+ method @NonNull public android.telephony.CallState.Builder setImsCallType(int);
+ method @NonNull public android.telephony.CallState.Builder setNetworkType(int);
+ }
+
public class CarrierConfigManager {
method @NonNull @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public String getDefaultCarrierServicePackageName();
method @NonNull public static android.os.PersistableBundle getDefaultConfig();
@@ -13710,7 +13732,8 @@
}
public static interface TelephonyCallback.CallAttributesListener {
- method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallAttributesChanged(@NonNull android.telephony.CallAttributes);
+ method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public default void onCallStatesChanged(@NonNull java.util.List<android.telephony.CallState>);
}
public static interface TelephonyCallback.DataEnabledListener {
@@ -14811,6 +14834,7 @@
field public static final int CALL_RESTRICT_CAUSE_HD = 3; // 0x3
field public static final int CALL_RESTRICT_CAUSE_NONE = 0; // 0x0
field public static final int CALL_RESTRICT_CAUSE_RAT = 1; // 0x1
+ field public static final int CALL_TYPE_NONE = 0; // 0x0
field public static final int CALL_TYPE_VIDEO_N_VOICE = 3; // 0x3
field public static final int CALL_TYPE_VOICE = 2; // 0x2
field public static final int CALL_TYPE_VOICE_N_VIDEO = 1; // 0x1
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 725cef6..984e822 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1039,6 +1039,7 @@
method @NonNull public static android.util.Pair<java.util.List<android.graphics.Typeface>,java.util.List<android.graphics.Typeface>> changeDefaultFontForTest(@NonNull java.util.List<android.graphics.Typeface>, @NonNull java.util.List<android.graphics.Typeface>);
method @NonNull public static long[] deserializeFontMap(@NonNull java.nio.ByteBuffer, @NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws java.io.IOException;
method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory();
+ method public void releaseNativeObjectForTest();
method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException;
}
@@ -2887,6 +2888,10 @@
method @NonNull public android.view.Display.Mode.Builder setResolution(int, int);
}
+ public final class DisplayShape implements android.os.Parcelable {
+ method @NonNull public static android.view.DisplayShape fromSpecString(@NonNull String, float, int, int);
+ }
+
public class FocusFinder {
method public static void sort(android.view.View[], int, int, android.view.ViewGroup, boolean);
}
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 6d7a161..3a7d483 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -1128,12 +1128,10 @@
/**
* Callback called on timeout for {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
+ * See {@link ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE} for more details.
*
- * TODO Implement it
- * TODO Javadoc
- *
- * @param startId
- * @hide
+ * @param startId the startId passed to {@link #onStartCommand(Intent, int, int)} when
+ * the service started.
*/
public void onTimeout(int startId) {
}
diff --git a/core/java/android/content/om/OverlayManager.java b/core/java/android/content/om/OverlayManager.java
index 812f6b0..ed1f6a2 100644
--- a/core/java/android/content/om/OverlayManager.java
+++ b/core/java/android/content/om/OverlayManager.java
@@ -17,6 +17,7 @@
package android.content.om;
import android.annotation.NonNull;
+import android.annotation.NonUiContext;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
@@ -25,12 +26,16 @@
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import com.android.internal.content.om.OverlayManagerImpl;
+
+import java.io.IOException;
import java.util.List;
/**
@@ -76,6 +81,7 @@
private final IOverlayManager mService;
private final Context mContext;
+ private final OverlayManagerImpl mOverlayManagerImpl;
/**
* Pre R a {@link java.lang.SecurityException} would only be thrown by setEnabled APIs (e
@@ -117,6 +123,7 @@
public OverlayManager(Context context, IOverlayManager service) {
mContext = context;
mService = service;
+ mOverlayManagerImpl = new OverlayManagerImpl(context);
}
/** @hide */
@@ -301,6 +308,17 @@
* @hide
*/
public void commit(@NonNull final OverlayManagerTransaction transaction) {
+ if (transaction.isSelfTargetingTransaction()
+ || mService == null
+ || mService.asBinder() == null) {
+ try {
+ commitSelfTarget(transaction);
+ } catch (PackageManager.NameNotFoundException | IOException e) {
+ throw new RuntimeException(e);
+ }
+ return;
+ }
+
try {
mService.commit(transaction);
} catch (RemoteException e) {
@@ -332,4 +350,48 @@
throw e;
}
}
+
+ /**
+ * Get a OverlayManagerTransaction.Builder to build out a overlay manager transaction.
+ *
+ * @return a builder of the overlay manager transaction.
+ * @hide
+ */
+ @NonNull
+ public OverlayManagerTransaction.Builder beginTransaction() {
+ return new OverlayManagerTransaction.Builder(this);
+ }
+
+ /**
+ * Commit the self-targeting transaction to register or unregister overlays.
+ *
+ * <p>Applications can request OverlayManager to register overlays and unregister the registered
+ * overlays via {@link OverlayManagerTransaction}.
+ *
+ * @throws IOException if there is a file operation error.
+ * @throws PackageManager.NameNotFoundException if the package name is not found.
+ * @hide
+ */
+ @NonUiContext
+ void commitSelfTarget(@NonNull final OverlayManagerTransaction transaction)
+ throws PackageManager.NameNotFoundException, IOException {
+ synchronized (mOverlayManagerImpl) {
+ mOverlayManagerImpl.commit(transaction);
+ }
+ }
+
+ /**
+ * Get the related information of overlays for {@code targetPackageName}.
+ *
+ * @param targetPackageName the target package name
+ * @return a list of overlay information
+ * @hide
+ */
+ @NonNull
+ @NonUiContext
+ public List<OverlayInfo> getOverlayInfosForTarget(@NonNull final String targetPackageName) {
+ synchronized (mOverlayManagerImpl) {
+ return mOverlayManagerImpl.getOverlayInfosForTarget(targetPackageName);
+ }
+ }
}
diff --git a/core/java/android/content/om/OverlayManagerTransaction.java b/core/java/android/content/om/OverlayManagerTransaction.java
index 868dab2..42b3ef3 100644
--- a/core/java/android/content/om/OverlayManagerTransaction.java
+++ b/core/java/android/content/om/OverlayManagerTransaction.java
@@ -20,19 +20,22 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.NonUiContext;
import android.annotation.Nullable;
-import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
+import java.util.Objects;
/**
* Container for a batch of requests to the OverlayManagerService.
@@ -53,13 +56,16 @@
// TODO: remove @hide from this class when OverlayManager is added to the
// SDK, but keep OverlayManagerTransaction.Request @hidden
private final List<Request> mRequests;
+ private final OverlayManager mOverlayManager;
- OverlayManagerTransaction(@NonNull final List<Request> requests) {
+ OverlayManagerTransaction(
+ @NonNull final List<Request> requests, @Nullable OverlayManager overlayManager) {
checkNotNull(requests);
if (requests.contains(null)) {
throw new IllegalArgumentException("null request");
}
mRequests = requests;
+ mOverlayManager = overlayManager;
}
private OverlayManagerTransaction(@NonNull final Parcel source) {
@@ -72,6 +78,7 @@
final Bundle extras = source.readBundle(null);
mRequests.add(new Request(request, overlay, userId, extras));
}
+ mOverlayManager = null;
}
@Override
@@ -156,6 +163,20 @@
*/
public static class Builder {
private final List<Request> mRequests = new ArrayList<>();
+ @Nullable private final OverlayManager mOverlayManager;
+
+ public Builder() {
+ mOverlayManager = null;
+ }
+
+ /**
+ * The transaction builder for self-targeting.
+ *
+ * @param overlayManager is not null if the transaction is for self-targeting.
+ */
+ Builder(@NonNull OverlayManager overlayManager) {
+ mOverlayManager = Objects.requireNonNull(overlayManager);
+ }
/**
* Request that an overlay package be enabled and change its loading
@@ -205,7 +226,10 @@
*
* @hide
*/
+ @NonNull
public Builder registerFabricatedOverlay(@NonNull FabricatedOverlay overlay) {
+ Objects.requireNonNull(overlay);
+
final Bundle extras = new Bundle();
extras.putParcelable(Request.BUNDLE_FABRICATED_OVERLAY, overlay.mOverlay);
mRequests.add(new Request(Request.TYPE_REGISTER_FABRICATED, overlay.getIdentifier(),
@@ -220,7 +244,10 @@
*
* @hide
*/
+ @NonNull
public Builder unregisterFabricatedOverlay(@NonNull OverlayIdentifier overlay) {
+ Objects.requireNonNull(overlay);
+
mRequests.add(new Request(Request.TYPE_UNREGISTER_FABRICATED, overlay,
UserHandle.USER_ALL));
return this;
@@ -233,8 +260,9 @@
* @see OverlayManager#commit
* @return a new transaction
*/
+ @NonNull
public OverlayManagerTransaction build() {
- return new OverlayManagerTransaction(mRequests);
+ return new OverlayManagerTransaction(mRequests, mOverlayManager);
}
}
@@ -269,4 +297,23 @@
return new OverlayManagerTransaction[size];
}
};
+
+ /**
+ * Commit the overlay manager transaction to register or unregister overlays for self-targeting.
+ *
+ * <p>Applications can register overlays and unregister the registered overlays via {@link
+ * OverlayManagerTransaction}.
+ *
+ * @throws IOException if there is a file operation error.
+ * @throws PackageManager.NameNotFoundException if the package name is not found.
+ * @hide
+ */
+ @NonUiContext
+ public void commit() throws PackageManager.NameNotFoundException, IOException {
+ mOverlayManager.commitSelfTarget(this);
+ }
+
+ boolean isSelfTargetingTransaction() {
+ return mOverlayManager != null;
+ }
}
diff --git a/core/java/android/content/pm/ServiceInfo.java b/core/java/android/content/pm/ServiceInfo.java
index 9e6cf62..7ea6733 100644
--- a/core/java/android/content/pm/ServiceInfo.java
+++ b/core/java/android/content/pm/ServiceInfo.java
@@ -366,24 +366,48 @@
public static final int FOREGROUND_SERVICE_TYPE_SYSTEM_EXEMPTED = 1 << 10;
/**
- * Foreground service type corresponding to {@code shortService} in
- * the {@link android.R.attr#foregroundServiceType} attribute.
+ * A foreground service type for "short-lived" services, which corresponds to
+ * {@code shortService} in the {@link android.R.attr#foregroundServiceType} attribute in the
+ * manifest.
*
- * TODO Implement it
+ * <p>Unlike other foreground service types, this type is not associated with a specific use
+ * case, and it will not require any special permissions
+ * (besides {@link Manifest.permission#FOREGROUND_SERVICE}).
*
- * TODO Expand the javadoc
+ * However, this type has the following restrictions.
*
- * This type is not associated with specific use cases unlike other types, but this has
- * unique restrictions.
* <ul>
- * <li>Has a timeout
- * <li>Cannot start other foreground services from this
* <li>
+ * The type has a 1 minute timeout.
+ * A foreground service of this type must be stopped within the timeout by
+ * {@link android.app.Service#stopSelf),
+ * or {@link android.content.Context#stopService).
+ * {@link android.app.Service#stopForeground) will also work, which will demote the
+ * service to a "background" service, which will soon be stopped by the system.
+ *
+ * <p>The system will <em>not</em> automatically stop it.
+ *
+ * <p>If the service isn't stopped within the timeout,
+ * {@link android.app.Service#onTimeout(int)} will be called.
+ * If the service is still not stopped after the callback,
+ * the app will be declared an ANR.
+ *
+ * <li>
+ * A foreground service of this type cannot be made "sticky"
+ * (see {@link android.app.Service#START_STICKY}). That is, if an app is killed
+ * due to a crash or out-of memory while it's running a short foregorund-service,
+ * the system will not restart the service.
+ * <li>
+ * Other foreground services cannot be started from short foreground services.
+ * Unlike other foreground service types, when an app is running in the background
+ * while only having a "short" foreground service, it's not allowed to start
+ * other foreground services, due to the restriction describe here:
+ * <a href="/guide/components/foreground-services#background-start-restrictions>
+ * Restrictions on background starts
+ * </a>
* </ul>
*
- * @see Service#onTimeout
- *
- * @hide
+ * @see android.app.Service#onTimeout(int)
*/
public static final int FOREGROUND_SERVICE_TYPE_SHORT_SERVICE = 1 << 11;
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
index 51236fe3..248b5d0 100644
--- a/core/java/android/hardware/usb/IUsbManager.aidl
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -122,10 +122,10 @@
boolean isFunctionEnabled(String function);
/* Sets the current USB function. */
- void setCurrentFunctions(long functions);
+ void setCurrentFunctions(long functions, int operationId);
/* Compatibility version of setCurrentFunctions(long). */
- void setCurrentFunction(String function, boolean usbDataUnlocked);
+ void setCurrentFunction(String function, boolean usbDataUnlocked, int operationId);
/* Gets the current USB functions. */
long getCurrentFunctions();
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
index 342c336..7a8117c 100644
--- a/core/java/android/hardware/usb/UsbManager.java
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -38,6 +38,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
@@ -52,6 +53,7 @@
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* This class allows you to access the state of USB and communicate with USB devices.
@@ -95,7 +97,7 @@
* If the sticky intent has not been found, that indicates USB is disconnected,
* USB is not configued, MTP function is enabled, and all the other functions are disabled.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String ACTION_USB_STATE =
@@ -185,7 +187,7 @@
* <p>For more information about communicating with USB accessory handshake, refer to
* <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
*
- * {@hide}
+ * @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@SystemApi
@@ -197,7 +199,7 @@
* Boolean extra indicating whether USB is connected or disconnected.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_CONNECTED = "connected";
@@ -206,7 +208,7 @@
* Boolean extra indicating whether USB is connected or disconnected as host.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
public static final String USB_HOST_CONNECTED = "host_connected";
@@ -214,7 +216,7 @@
* Boolean extra indicating whether USB is configured.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_CONFIGURED = "configured";
@@ -225,7 +227,7 @@
* has explicitly asked for this data to be unlocked.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast.
*
- * {@hide}
+ * @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final String USB_DATA_UNLOCKED = "unlocked";
@@ -234,7 +236,7 @@
* A placeholder indicating that no USB function is being specified.
* Used for compatibility with old init scripts to indicate no functions vs. charging function.
*
- * {@hide}
+ * @hide
*/
@UnsupportedAppUsage
public static final String USB_FUNCTION_NONE = "none";
@@ -243,7 +245,7 @@
* Name of the adb USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_ADB = "adb";
@@ -251,7 +253,7 @@
* Name of the RNDIS ethernet USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_FUNCTION_RNDIS = "rndis";
@@ -260,7 +262,7 @@
* Name of the MTP USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_MTP = "mtp";
@@ -268,7 +270,7 @@
* Name of the PTP USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_PTP = "ptp";
@@ -276,7 +278,7 @@
* Name of the audio source USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_AUDIO_SOURCE = "audio_source";
@@ -284,7 +286,7 @@
* Name of the MIDI USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_MIDI = "midi";
@@ -292,7 +294,7 @@
* Name of the Accessory USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
public static final String USB_FUNCTION_ACCESSORY = "accessory";
@@ -300,7 +302,7 @@
* Name of the NCM USB function.
* Used in extras for the {@link #ACTION_USB_STATE} broadcast
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String USB_FUNCTION_NCM = "ncm";
@@ -308,32 +310,39 @@
/**
* Name of Gadget Hal Not Present;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_UNKNOWN = "unknown";
/**
* Name of the USB Gadget Hal Version v1.0;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_VERSION_1_0 = "V1_0";
/**
* Name of the USB Gadget Hal Version v1.1;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_VERSION_1_1 = "V1_1";
/**
* Name of the USB Gadget Hal Version v1.2;
*
- * {@hide}
+ * @hide
*/
public static final String GADGET_HAL_VERSION_1_2 = "V1_2";
/**
+ * Name of the USB Gadget Hal Version v2.0;
+ *
+ * @hide
+ */
+ public static final String GADGET_HAL_VERSION_2_0 = "V2_0";
+
+ /**
* Name of extra for {@link #ACTION_USB_PORT_CHANGED}
* containing the {@link UsbPort} object for the port.
*
@@ -369,7 +378,7 @@
* This is obtained with SystemClock.elapsedRealtime()
* Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_UEVENT_TIME =
@@ -383,7 +392,7 @@
* between communicating with USB accessory handshake, refer to
* <a href="https://source.android.com/devices/accessories/aoa">AOA</a> developer guide.</p>
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_STRING_COUNT =
@@ -393,7 +402,7 @@
* Boolean extra indicating whether got start accessory or not
* Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_START =
@@ -405,7 +414,7 @@
* sending {@link #ACTION_USB_ACCESSORY_HANDSHAKE}.
* Used in extras for {@link #ACTION_USB_ACCESSORY_HANDSHAKE} broadcasts.
*
- * {@hide}
+ * @hide
*/
@SystemApi
public static final String EXTRA_ACCESSORY_HANDSHAKE_END =
@@ -439,7 +448,7 @@
/**
* The Value for USB gadget hal is not presented.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_NOT_SUPPORTED = -1;
@@ -447,7 +456,7 @@
/**
* Value for Gadget Hal Version v1.0.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_V1_0 = 10;
@@ -455,7 +464,7 @@
/**
* Value for Gadget Hal Version v1.1.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_V1_1 = 11;
@@ -463,15 +472,23 @@
/**
* Value for Gadget Hal Version v1.2.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int GADGET_HAL_V1_2 = 12;
/**
+ * Value for Gadget Hal Version v2.0.
+ *
+ * @hide
+ */
+ @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
+ public static final int GADGET_HAL_V2_0 = 20;
+
+ /**
* Value for USB_STATE is not configured.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_UNKNOWN = -1;
@@ -479,7 +496,7 @@
/**
* Value for USB Transfer Rate of Low Speed in Mbps (real value is 1.5Mbps).
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_LOW_SPEED = 2;
@@ -487,7 +504,7 @@
/**
* Value for USB Transfer Rate of Full Speed in Mbps.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_FULL_SPEED = 12;
@@ -495,7 +512,7 @@
/**
* Value for USB Transfer Rate of High Speed in Mbps.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_HIGH_SPEED = 480;
@@ -503,7 +520,7 @@
/**
* Value for USB Transfer Rate of Super Speed in Mbps.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_5G = 5 * 1024;
@@ -511,7 +528,7 @@
/**
* Value for USB Transfer Rate of 10G.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_10G = 10 * 1024;
@@ -519,7 +536,7 @@
/**
* Value for USB Transfer Rate of 20G.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_20G = 20 * 1024;
@@ -527,7 +544,7 @@
/**
* Value for USB Transfer Rate of 40G.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_DATA_TRANSFER_RATE_40G = 40 * 1024;
@@ -543,7 +560,7 @@
/**
* The Value for USB hal is not presented.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_NOT_SUPPORTED = -1;
@@ -551,7 +568,7 @@
/**
* Value for USB Hal Version v1.0.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_0 = 10;
@@ -559,7 +576,7 @@
/**
* Value for USB Hal Version v1.1.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_1 = 11;
@@ -567,7 +584,7 @@
/**
* Value for USB Hal Version v1.2.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_2 = 12;
@@ -575,7 +592,7 @@
/**
* Value for USB Hal Version v1.3.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final int USB_HAL_V1_3 = 13;
@@ -590,63 +607,63 @@
/**
* Code for the charging usb function. Passed into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_NONE = 0;
/**
* Code for the mtp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_MTP = GadgetFunction.MTP;
/**
* Code for the ptp usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_PTP = GadgetFunction.PTP;
/**
* Code for the rndis usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_RNDIS = GadgetFunction.RNDIS;
/**
* Code for the midi usb function. Passed as a mask into {@link #setCurrentFunctions(long)}
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_MIDI = GadgetFunction.MIDI;
/**
* Code for the accessory usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_ACCESSORY = GadgetFunction.ACCESSORY;
/**
* Code for the audio source usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_AUDIO_SOURCE = GadgetFunction.AUDIO_SOURCE;
/**
* Code for the adb usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_ADB = GadgetFunction.ADB;
/**
* Code for the ncm source usb function.
- * {@hide}
+ * @hide
*/
@SystemApi
public static final long FUNCTION_NCM = 1 << 10;
@@ -656,6 +673,11 @@
private static final Map<String, Long> FUNCTION_NAME_TO_CODE = new HashMap<>();
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
static {
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_MTP, FUNCTION_MTP);
FUNCTION_NAME_TO_CODE.put(UsbManager.USB_FUNCTION_PTP, FUNCTION_PTP);
@@ -687,6 +709,7 @@
GADGET_HAL_V1_0,
GADGET_HAL_V1_1,
GADGET_HAL_V1_2,
+ GADGET_HAL_V2_0,
})
public @interface UsbGadgetHalVersion {}
@@ -705,7 +728,7 @@
private final IUsbManager mService;
/**
- * {@hide}
+ * @hide
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public UsbManager(Context context, IUsbManager service) {
@@ -816,7 +839,7 @@
* {@link #FUNCTION_PTP} are supported.
* @return A ParcelFileDescriptor holding the valid fd, or null if the fd was not found.
*
- * {@hide}
+ * @hide
*/
public ParcelFileDescriptor getControlFd(long function) {
try {
@@ -977,7 +1000,7 @@
* Only system components can call this function.
* @param device to request permissions for
*
- * {@hide}
+ * @hide
*/
public void grantPermission(UsbDevice device) {
grantPermission(device, Process.myUid());
@@ -989,7 +1012,7 @@
* @param device to request permissions for
* @uid uid to give permission
*
- * {@hide}
+ * @hide
*/
public void grantPermission(UsbDevice device, int uid) {
try {
@@ -1005,7 +1028,7 @@
* @param device to request permissions for
* @param packageName of package to grant permissions
*
- * {@hide}
+ * @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1030,7 +1053,7 @@
* @param function name of the USB function
* @return true if the USB function is enabled
*
- * {@hide}
+ * @hide
*/
@Deprecated
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@@ -1062,14 +1085,17 @@
* @param functions the USB function(s) to set, as a bitwise mask.
* Must satisfy {@link UsbManager#areSettableFunctions}
*
- * {@hide}
+ * @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
public void setCurrentFunctions(@UsbFunctionMode long functions) {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
try {
- mService.setCurrentFunctions(functions);
+ mService.setCurrentFunctions(functions, operationId);
} catch (RemoteException e) {
+ Log.e(TAG, "setCurrentFunctions: failed to call setCurrentFunctions. functions:"
+ + functions + ", opId:" + operationId, e);
throw e.rethrowFromSystemServer();
}
}
@@ -1081,14 +1107,17 @@
* @param functions the USB function(s) to set.
* @param usbDataUnlocked unused
- * {@hide}
+ * @hide
*/
@Deprecated
@UnsupportedAppUsage
public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
try {
- mService.setCurrentFunction(functions, usbDataUnlocked);
+ mService.setCurrentFunction(functions, usbDataUnlocked, operationId);
} catch (RemoteException e) {
+ Log.e(TAG, "setCurrentFunction: failed to call setCurrentFunction. functions:"
+ + functions + ", opId:" + operationId, e);
throw e.rethrowFromSystemServer();
}
}
@@ -1103,7 +1132,7 @@
* @return The currently enabled functions, in a bitwise mask.
* A zero mask indicates that the current function is the charging function.
*
- * {@hide}
+ * @hide
*/
@SystemApi
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1129,7 +1158,7 @@
* @param functions functions to set, in a bitwise mask.
* Must satisfy {@link UsbManager#areSettableFunctions}
*
- * {@hide}
+ * @hide
*/
public void setScreenUnlockedFunctions(long functions) {
try {
@@ -1145,7 +1174,7 @@
* @return The currently set screen enabled functions.
* A zero mask indicates that the screen unlocked functions feature is not enabled.
*
- * {@hide}
+ * @hide
*/
public long getScreenUnlockedFunctions() {
try {
@@ -1167,19 +1196,17 @@
*
* @return The value of currently USB Bandwidth.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.MANAGE_USB)
public int getUsbBandwidthMbps() {
int usbSpeed;
-
try {
usbSpeed = mService.getCurrentUsbSpeed();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
-
return usbSpeedToBandwidth(usbSpeed);
}
@@ -1191,7 +1218,7 @@
*
* @return a integer {@code GADGET_HAL_*} represent hal version.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1211,7 +1238,7 @@
*
* @return a integer {@code USB_HAL_*} represent hal version.
*
- * {@hide}
+ * @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@RequiresPermission(Manifest.permission.MANAGE_USB)
@@ -1507,7 +1534,7 @@
* @param usbDeviceConnectionHandler The component to handle usb connections,
* {@code null} to unset.
*
- * {@hide}
+ * @hide
*/
public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
try {
@@ -1526,7 +1553,7 @@
*
* @return Whether the mask is settable.
*
- * {@hide}
+ * @hide
*/
public static boolean areSettableFunctions(long functions) {
return functions == FUNCTION_NONE
@@ -1540,7 +1567,7 @@
*
* @return String representation of given mask
*
- * {@hide}
+ * @hide
*/
public static String usbFunctionsToString(long functions) {
StringJoiner joiner = new StringJoiner(",");
@@ -1576,7 +1603,7 @@
*
* @return A mask of all valid functions in the string
*
- * {@hide}
+ * @hide
*/
public static long usbFunctionsFromString(String functions) {
if (functions == null || functions.equals(USB_FUNCTION_NONE)) {
@@ -1598,7 +1625,7 @@
*
* @return a value of USB bandwidth
*
- * {@hide}
+ * @hide
*/
public static int usbSpeedToBandwidth(int speed) {
switch (speed) {
@@ -1632,12 +1659,14 @@
*
* @return String representation of Usb Gadget Hal Version
*
- * {@hide}
+ * @hide
*/
public static @NonNull String usbGadgetHalVersionToString(int version) {
String halVersion;
- if (version == GADGET_HAL_V1_2) {
+ if (version == GADGET_HAL_V2_0) {
+ halVersion = GADGET_HAL_VERSION_2_0;
+ } else if (version == GADGET_HAL_V1_2) {
halVersion = GADGET_HAL_VERSION_1_2;
} else if (version == GADGET_HAL_V1_1) {
halVersion = GADGET_HAL_VERSION_1_1;
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index fb66cb9..872414a 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -70,11 +70,14 @@
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
import android.database.ContentObserver;
import android.graphics.Rect;
import android.graphics.Region;
@@ -98,6 +101,7 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
+import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import android.view.BatchedInputEventReceiver.SimpleBatchedInputEventReceiver;
import android.view.Choreographer;
@@ -158,6 +162,8 @@
import com.android.internal.inputmethod.SoftInputShowHideReason;
import com.android.internal.util.RingBuffer;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -730,7 +736,6 @@
@Override
public final void initializeInternal(@NonNull IInputMethod.InitParams params) {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "IMS.initializeInternal");
- mConfigTracker.onInitialize(params.configChanges);
mPrivOps.set(params.privilegedOperations);
InputMethodPrivilegedOperationsRegistry.put(params.token, mPrivOps);
mNavigationBarController.onNavButtonFlagsChanged(params.navigationBarFlags);
@@ -1601,6 +1606,8 @@
mHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
com.android.internal.R.bool.config_hideNavBarForKeyboard);
+ initConfigurationTracker();
+
// TODO(b/111364446) Need to address context lifecycle issue if need to re-create
// for update resources & configuration correctly when show soft input
// in non-default display.
@@ -1656,6 +1663,36 @@
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
}
+ private void initConfigurationTracker() {
+ final int flags = PackageManager.GET_META_DATA
+ | PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+ final ComponentName imeComponent = new ComponentName(
+ getPackageName(), getClass().getName());
+ final String imeId = imeComponent.flattenToShortString();
+ final ServiceInfo si;
+ try {
+ si = getPackageManager().getServiceInfo(imeComponent,
+ PackageManager.ComponentInfoFlags.of(flags));
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.wtf(TAG, "Unable to find input method " + imeId, e);
+ return;
+ }
+ try (XmlResourceParser parser = si.loadXmlMetaData(getPackageManager(),
+ InputMethod.SERVICE_META_DATA);
+ TypedArray sa = getResources().obtainAttributes(Xml.asAttributeSet(parser),
+ com.android.internal.R.styleable.InputMethod)) {
+ if (parser == null) {
+ throw new XmlPullParserException(
+ "No " + InputMethod.SERVICE_META_DATA + " meta-data");
+ }
+ final int handledConfigChanges = sa.getInt(
+ com.android.internal.R.styleable.InputMethod_configChanges, 0);
+ mConfigTracker.onInitialize(handledConfigChanges);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Unable to load input method " + imeId, e);
+ }
+ }
+
/**
* This is a hook that subclasses can use to perform initialization of
* their interface. It is called for you prior to any of your UI objects
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index e5c9adb..dded76c 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -26,7 +26,6 @@
import android.os.Handler;
import android.os.HandlerExecutor;
import android.os.Looper;
-import android.telephony.Annotation.CallState;
import android.telephony.Annotation.DisconnectCauses;
import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.Annotation.RadioPowerState;
@@ -726,7 +725,7 @@
*/
@Deprecated
@RequiresPermission(value = android.Manifest.permission.READ_PHONE_STATE, conditional = true)
- public void onCallStateChanged(@CallState int state, String phoneNumber) {
+ public void onCallStateChanged(@Annotation.CallState int state, String phoneNumber) {
// default implementation empty
}
@@ -1569,12 +1568,48 @@
() -> mExecutor.execute(() -> psl.onRadioPowerStateChanged(state)));
}
- public void onCallAttributesChanged(CallAttributes callAttributes) {
+ public void onCallStatesChanged(List<CallState> callStateList) {
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
+ if (callStateList == null) return;
+ CallAttributes ca;
+ if (callStateList.isEmpty()) {
+ ca = new CallAttributes(
+ new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality());
+ } else {
+ int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ for (CallState cs : callStateList) {
+ switch (cs.getCallClassification()) {
+ case CallState.CALL_CLASSIFICATION_FOREGROUND:
+ foregroundCallState = cs.getCallState();
+ break;
+ case CallState.CALL_CLASSIFICATION_BACKGROUND:
+ backgroundCallState = cs.getCallState();
+ break;
+ case CallState.CALL_CLASSIFICATION_RINGING:
+ ringingCallState = cs.getCallState();
+ break;
+ default:
+ break;
+ }
+ }
+ ca = new CallAttributes(
+ new PreciseCallState(
+ ringingCallState, foregroundCallState, backgroundCallState,
+ DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+ callStateList.get(0).getNetworkType(),
+ callStateList.get(0).getCallQuality());
+ }
Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> psl.onCallAttributesChanged(callAttributes)));
+ () -> mExecutor.execute(
+ () -> psl.onCallAttributesChanged(ca)));
}
public void onActiveDataSubIdChanged(int subId) {
diff --git a/core/java/android/telephony/TelephonyCallback.java b/core/java/android/telephony/TelephonyCallback.java
index e8960b8..257f3b7 100644
--- a/core/java/android/telephony/TelephonyCallback.java
+++ b/core/java/android/telephony/TelephonyCallback.java
@@ -27,6 +27,7 @@
import android.os.Build;
import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.ImsReasonInfo;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.IPhoneStateListener;
@@ -62,7 +63,7 @@
* appropriate sub-interfaces.
*/
public class TelephonyCallback {
-
+ private static final String LOG_TAG = "TelephonyCallback";
/**
* Experiment flag to set the per-pid registration limit for TelephonyCallback
*
@@ -1332,7 +1333,9 @@
@SystemApi
public interface CallAttributesListener {
/**
- * Callback invoked when the call attributes changes on the registered subscription.
+ * Callback invoked when the call attributes changes on the active call on the registered
+ * subscription. If the user swaps between a foreground and background call the call
+ * attributes will be reported for the active call only.
* Note, the registration subscription ID comes from {@link TelephonyManager} object
* which registers TelephonyCallback by
* {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
@@ -1346,9 +1349,77 @@
* {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
*
* @param callAttributes the call attributes
+ * @deprecated Use onCallStatesChanged({@link List<CallState>}) to get each of call
+ * state for all ongoing calls on the subscription.
*/
@RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
- void onCallAttributesChanged(@NonNull CallAttributes callAttributes);
+ @Deprecated
+ default void onCallAttributesChanged(@NonNull CallAttributes callAttributes) {
+ Log.w(LOG_TAG, "onCallAttributesChanged(List<CallState>) should be "
+ + "overridden.");
+ }
+
+ /**
+ * Callback invoked when the call attributes changes on the ongoing calls on the registered
+ * subscription. If there are 1 foreground and 1 background call, Two {@link CallState}
+ * will be passed.
+ * Note, the registration subscription ID comes from {@link TelephonyManager} object
+ * which registers TelephonyCallback by
+ * {@link TelephonyManager#registerTelephonyCallback(Executor, TelephonyCallback)}.
+ * If this TelephonyManager object was created with
+ * {@link TelephonyManager#createForSubscriptionId(int)}, then the callback applies to the
+ * subscription ID. Otherwise, this callback applies to
+ * {@link SubscriptionManager#getDefaultSubscriptionId()}.
+ * In the event that there are no active(state is not
+ * {@link PreciseCallState#PRECISE_CALL_STATE_IDLE}) calls, this API will report empty list.
+ *
+ * The calling app should have carrier privileges
+ * (see {@link TelephonyManager#hasCarrierPrivileges}) if it does not have the
+ * {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE}.
+ *
+ * @param callStateList the list of call states for each ongoing call. If there are
+ * a active call and a holding call, 1 call attributes for
+ * {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} and another
+ * for {@link PreciseCallState#PRECISE_CALL_STATE_HOLDING}
+ * will be in this list.
+ */
+ // Added as default for backward compatibility
+ @RequiresPermission(Manifest.permission.READ_PRECISE_PHONE_STATE)
+ default void onCallStatesChanged(@NonNull List<CallState> callStateList) {
+ if (callStateList.size() > 0) {
+ int foregroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ int backgroundCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ int ringingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE;
+ for (CallState cs : callStateList) {
+ switch (cs.getCallClassification()) {
+ case CallState.CALL_CLASSIFICATION_FOREGROUND:
+ foregroundCallState = cs.getCallState();
+ break;
+ case CallState.CALL_CLASSIFICATION_BACKGROUND:
+ backgroundCallState = cs.getCallState();
+ break;
+ case CallState.CALL_CLASSIFICATION_RINGING:
+ ringingCallState = cs.getCallState();
+ break;
+ default:
+ break;
+ }
+ }
+ onCallAttributesChanged(new CallAttributes(
+ new PreciseCallState(
+ ringingCallState, foregroundCallState, backgroundCallState,
+ DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+ callStateList.get(0).getNetworkType(),
+ callStateList.get(0).getCallQuality()));
+ } else {
+ onCallAttributesChanged(new CallAttributes(
+ new PreciseCallState(PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ PreciseCallState.PRECISE_CALL_STATE_IDLE,
+ DisconnectCause.NOT_VALID, PreciseDisconnectCause.NOT_VALID),
+ TelephonyManager.NETWORK_TYPE_UNKNOWN, new CallQuality()));
+ }
+ }
}
/**
@@ -1702,14 +1773,13 @@
() -> mExecutor.execute(() -> listener.onRadioPowerStateChanged(state)));
}
- public void onCallAttributesChanged(CallAttributes callAttributes) {
+ public void onCallStatesChanged(List<CallState> callStateList) {
CallAttributesListener listener =
(CallAttributesListener) mTelephonyCallbackWeakRef.get();
if (listener == null) return;
Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(() -> listener.onCallAttributesChanged(
- callAttributes)));
+ () -> mExecutor.execute(() -> listener.onCallStatesChanged(callStateList)));
}
public void onActiveDataSubIdChanged(int subId) {
diff --git a/core/java/android/telephony/TelephonyRegistryManager.java b/core/java/android/telephony/TelephonyRegistryManager.java
index a3696e3..0a1538de 100644
--- a/core/java/android/telephony/TelephonyRegistryManager.java
+++ b/core/java/android/telephony/TelephonyRegistryManager.java
@@ -32,13 +32,13 @@
import android.telephony.Annotation.DataActivityType;
import android.telephony.Annotation.DisconnectCauses;
import android.telephony.Annotation.NetworkType;
-import android.telephony.Annotation.PreciseCallStates;
import android.telephony.Annotation.PreciseDisconnectCauses;
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SimActivationState;
import android.telephony.Annotation.SrvccState;
import android.telephony.TelephonyManager.CarrierPrivilegesCallback;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
import android.util.ArraySet;
import android.util.Log;
@@ -741,17 +741,20 @@
* @param slotIndex for which precise call state changed. Can be derived from subId except when
* subId is invalid.
* @param subId for which precise call state changed.
- * @param ringCallPreciseState ringCall state.
- * @param foregroundCallPreciseState foreground call state.
- * @param backgroundCallPreciseState background call state.
+ * @param callStates Array of PreciseCallState of foreground, background & ringing calls.
+ * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId} for
+ * ringing, foreground & background calls.
+ * @param imsServiceTypes Array of IMS call service type for ringing, foreground &
+ * background calls.
+ * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls.
*/
public void notifyPreciseCallState(int slotIndex, int subId,
- @PreciseCallStates int ringCallPreciseState,
- @PreciseCallStates int foregroundCallPreciseState,
- @PreciseCallStates int backgroundCallPreciseState) {
+ @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds,
+ @Annotation.ImsCallServiceType int[] imsServiceTypes,
+ @Annotation.ImsCallType int[] imsCallTypes) {
try {
- sRegistry.notifyPreciseCallState(slotIndex, subId, ringCallPreciseState,
- foregroundCallPreciseState, backgroundCallPreciseState);
+ sRegistry.notifyPreciseCallState(slotIndex, subId, callStates,
+ imsCallIds, imsServiceTypes, imsCallTypes);
} catch (RemoteException ex) {
// system process is dead
throw ex.rethrowFromSystemServer();
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index fbca373..2745858 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -1009,6 +1009,28 @@
}
/**
+ * Returns the {@link DisplayShape} which is based on display coordinates.
+ *
+ * To get the {@link DisplayShape} based on the window frame, use
+ * {@link WindowInsets#getDisplayShape()} instead.
+ *
+ * @see DisplayShape
+ */
+ @SuppressLint("VisiblySynchronized")
+ @NonNull
+ public DisplayShape getShape() {
+ synchronized (mLock) {
+ updateDisplayInfoLocked();
+ final DisplayShape displayShape = mDisplayInfo.displayShape;
+ final @Surface.Rotation int rotation = getLocalRotation();
+ if (displayShape != null && rotation != mDisplayInfo.rotation) {
+ return displayShape.setRotation(rotation);
+ }
+ return displayShape;
+ }
+ }
+
+ /**
* Gets the pixel format of the display.
* @return One of the constants defined in {@link android.graphics.PixelFormat}.
*
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 0ba3072..138017c 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -323,6 +323,9 @@
@Surface.Rotation
public int installOrientation;
+ @Nullable
+ public DisplayShape displayShape;
+
public static final @android.annotation.NonNull Creator<DisplayInfo> CREATOR = new Creator<DisplayInfo>() {
@Override
public DisplayInfo createFromParcel(Parcel source) {
@@ -395,7 +398,8 @@
&& brightnessMaximum == other.brightnessMaximum
&& brightnessDefault == other.brightnessDefault
&& Objects.equals(roundedCorners, other.roundedCorners)
- && installOrientation == other.installOrientation;
+ && installOrientation == other.installOrientation
+ && Objects.equals(displayShape, other.displayShape);
}
@Override
@@ -448,6 +452,7 @@
brightnessDefault = other.brightnessDefault;
roundedCorners = other.roundedCorners;
installOrientation = other.installOrientation;
+ displayShape = other.displayShape;
}
public void readFromParcel(Parcel source) {
@@ -506,6 +511,7 @@
userDisabledHdrTypes[i] = source.readInt();
}
installOrientation = source.readInt();
+ displayShape = source.readTypedObject(DisplayShape.CREATOR);
}
@Override
@@ -562,6 +568,7 @@
dest.writeInt(userDisabledHdrTypes[i]);
}
dest.writeInt(installOrientation);
+ dest.writeTypedObject(displayShape, flags);
}
@Override
diff --git a/core/java/android/view/DisplayShape.aidl b/core/java/android/view/DisplayShape.aidl
new file mode 100644
index 0000000..af8b417
--- /dev/null
+++ b/core/java/android/view/DisplayShape.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2022, 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.view;
+
+parcelable DisplayShape;
diff --git a/core/java/android/view/DisplayShape.java b/core/java/android/view/DisplayShape.java
new file mode 100644
index 0000000..43bd773
--- /dev/null
+++ b/core/java/android/view/DisplayShape.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2022 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.view;
+
+import static android.view.Surface.ROTATION_0;
+
+import android.annotation.Nullable;
+import android.annotation.TestApi;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.graphics.Matrix;
+import android.graphics.Path;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.DisplayUtils;
+import android.util.PathParser;
+import android.util.RotationUtils;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Objects;
+
+/**
+ * A class representing the shape of a display. It provides a {@link Path} of the display shape of
+ * the display shape.
+ *
+ * {@link DisplayShape} is immutable.
+ */
+public final class DisplayShape implements Parcelable {
+
+ /** @hide */
+ public static final DisplayShape NONE = new DisplayShape("" /* displayShapeSpec */,
+ 0 /* displayWidth */, 0 /* displayHeight */, 0 /* physicalPixelDisplaySizeRatio */,
+ 0 /* rotation */);
+
+ /** @hide */
+ @VisibleForTesting
+ public final String mDisplayShapeSpec;
+ private final float mPhysicalPixelDisplaySizeRatio;
+ private final int mDisplayWidth;
+ private final int mDisplayHeight;
+ private final int mRotation;
+ private final int mOffsetX;
+ private final int mOffsetY;
+ private final float mScale;
+
+ private DisplayShape(@NonNull String displayShapeSpec, int displayWidth, int displayHeight,
+ float physicalPixelDisplaySizeRatio, int rotation) {
+ this(displayShapeSpec, displayWidth, displayHeight, physicalPixelDisplaySizeRatio,
+ rotation, 0, 0, 1f);
+ }
+
+ private DisplayShape(@NonNull String displayShapeSpec, int displayWidth, int displayHeight,
+ float physicalPixelDisplaySizeRatio, int rotation, int offsetX, int offsetY,
+ float scale) {
+ mDisplayShapeSpec = displayShapeSpec;
+ mDisplayWidth = displayWidth;
+ mDisplayHeight = displayHeight;
+ mPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio;
+ mRotation = rotation;
+ mOffsetX = offsetX;
+ mOffsetY = offsetY;
+ mScale = scale;
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
+ public static DisplayShape fromResources(
+ @NonNull Resources res, @NonNull String displayUniqueId, int physicalDisplayWidth,
+ int physicalDisplayHeight, int displayWidth, int displayHeight) {
+ final boolean isScreenRound = RoundedCorners.getBuiltInDisplayIsRound(res, displayUniqueId);
+ final String spec = getSpecString(res, displayUniqueId);
+ if (spec == null || spec.isEmpty()) {
+ return createDefaultDisplayShape(displayWidth, displayHeight, isScreenRound);
+ }
+ final float physicalPixelDisplaySizeRatio = DisplayUtils.getPhysicalPixelDisplaySizeRatio(
+ physicalDisplayWidth, physicalDisplayHeight, displayWidth, displayHeight);
+ return fromSpecString(spec, physicalPixelDisplaySizeRatio, displayWidth, displayHeight);
+ }
+
+ /**
+ * @hide
+ */
+ @NonNull
+ public static DisplayShape createDefaultDisplayShape(
+ int displayWidth, int displayHeight, boolean isScreenRound) {
+ return fromSpecString(createDefaultSpecString(displayWidth, displayHeight, isScreenRound),
+ 1f, displayWidth, displayHeight);
+ }
+
+ /**
+ * @hide
+ */
+ @TestApi
+ @NonNull
+ public static DisplayShape fromSpecString(@NonNull String spec,
+ float physicalPixelDisplaySizeRatio, int displayWidth, int displayHeight) {
+ return Cache.getDisplayShape(spec, physicalPixelDisplaySizeRatio, displayWidth,
+ displayHeight);
+ }
+
+ private static String createDefaultSpecString(int displayWidth, int displayHeight,
+ boolean isCircular) {
+ final String spec;
+ if (isCircular) {
+ final float xRadius = displayWidth / 2f;
+ final float yRadius = displayHeight / 2f;
+ // Draw a circular display shape.
+ spec = "M0," + yRadius
+ // Draw upper half circle with arcTo command.
+ + " A" + xRadius + "," + yRadius + " 0 1,1 " + displayWidth + "," + yRadius
+ // Draw lower half circle with arcTo command.
+ + " A" + xRadius + "," + yRadius + " 0 1,1 0," + yRadius + " Z";
+ } else {
+ // Draw a rectangular display shape.
+ spec = "M0,0"
+ // Draw top edge.
+ + " L" + displayWidth + ",0"
+ // Draw right edge.
+ + " L" + displayWidth + "," + displayHeight
+ // Draw bottom edge.
+ + " L0," + displayHeight
+ // Draw left edge by close command which draws a line from current position to
+ // the initial points (0,0).
+ + " Z";
+ }
+ return spec;
+ }
+
+ /**
+ * Gets the display shape svg spec string of a display which is determined by the given display
+ * unique id.
+ *
+ * Loads the default config {@link R.string#config_mainDisplayShape} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static String getSpecString(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_displayShapeArray);
+ final String spec;
+ if (index >= 0 && index < array.length()) {
+ spec = array.getString(index);
+ } else {
+ spec = res.getString(R.string.config_mainDisplayShape);
+ }
+ array.recycle();
+ return spec;
+ }
+
+ /**
+ * @hide
+ */
+ public DisplayShape setRotation(int rotation) {
+ return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+ mPhysicalPixelDisplaySizeRatio, rotation, mOffsetX, mOffsetY, mScale);
+ }
+
+ /**
+ * @hide
+ */
+ public DisplayShape setOffset(int offsetX, int offsetY) {
+ return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+ mPhysicalPixelDisplaySizeRatio, mRotation, offsetX, offsetY, mScale);
+ }
+
+ /**
+ * @hide
+ */
+ public DisplayShape setScale(float scale) {
+ return new DisplayShape(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+ mPhysicalPixelDisplaySizeRatio, mRotation, mOffsetX, mOffsetY, scale);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDisplayShapeSpec, mDisplayWidth, mDisplayHeight,
+ mPhysicalPixelDisplaySizeRatio, mRotation, mOffsetX, mOffsetY, mScale);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof DisplayShape) {
+ DisplayShape ds = (DisplayShape) o;
+ return Objects.equals(mDisplayShapeSpec, ds.mDisplayShapeSpec)
+ && mDisplayWidth == ds.mDisplayWidth && mDisplayHeight == ds.mDisplayHeight
+ && mPhysicalPixelDisplaySizeRatio == ds.mPhysicalPixelDisplaySizeRatio
+ && mRotation == ds.mRotation && mOffsetX == ds.mOffsetX
+ && mOffsetY == ds.mOffsetY && mScale == ds.mScale;
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "DisplayShape{"
+ + " spec=" + mDisplayShapeSpec
+ + " displayWidth=" + mDisplayWidth
+ + " displayHeight=" + mDisplayHeight
+ + " physicalPixelDisplaySizeRatio=" + mPhysicalPixelDisplaySizeRatio
+ + " rotation=" + mRotation
+ + " offsetX=" + mOffsetX
+ + " offsetY=" + mOffsetY
+ + " scale=" + mScale + "}";
+ }
+
+ /**
+ * Returns a {@link Path} of the display shape.
+ *
+ * @return a {@link Path} of the display shape.
+ */
+ @NonNull
+ public Path getPath() {
+ return Cache.getPath(this);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeString8(mDisplayShapeSpec);
+ dest.writeInt(mDisplayWidth);
+ dest.writeInt(mDisplayHeight);
+ dest.writeFloat(mPhysicalPixelDisplaySizeRatio);
+ dest.writeInt(mRotation);
+ dest.writeInt(mOffsetX);
+ dest.writeInt(mOffsetY);
+ dest.writeFloat(mScale);
+ }
+
+ public static final @NonNull Creator<DisplayShape> CREATOR = new Creator<DisplayShape>() {
+ @Override
+ public DisplayShape createFromParcel(Parcel in) {
+ final String spec = in.readString8();
+ final int displayWidth = in.readInt();
+ final int displayHeight = in.readInt();
+ final float ratio = in.readFloat();
+ final int rotation = in.readInt();
+ final int offsetX = in.readInt();
+ final int offsetY = in.readInt();
+ final float scale = in.readFloat();
+ return new DisplayShape(spec, displayWidth, displayHeight, ratio, rotation, offsetX,
+ offsetY, scale);
+ }
+
+ @Override
+ public DisplayShape[] newArray(int size) {
+ return new DisplayShape[size];
+ }
+ };
+
+ private static final class Cache {
+ private static final Object CACHE_LOCK = new Object();
+
+ @GuardedBy("CACHE_LOCK")
+ private static String sCachedSpec;
+ @GuardedBy("CACHE_LOCK")
+ private static int sCachedDisplayWidth;
+ @GuardedBy("CACHE_LOCK")
+ private static int sCachedDisplayHeight;
+ @GuardedBy("CACHE_LOCK")
+ private static float sCachedPhysicalPixelDisplaySizeRatio;
+ @GuardedBy("CACHE_LOCK")
+ private static DisplayShape sCachedDisplayShape;
+
+ @GuardedBy("CACHE_LOCK")
+ private static DisplayShape sCacheForPath;
+ @GuardedBy("CACHE_LOCK")
+ private static Path sCachedPath;
+
+ static DisplayShape getDisplayShape(String spec, float physicalPixelDisplaySizeRatio,
+ int displayWidth, int displayHeight) {
+ synchronized (CACHE_LOCK) {
+ if (spec.equals(sCachedSpec)
+ && sCachedDisplayWidth == displayWidth
+ && sCachedDisplayHeight == displayHeight
+ && sCachedPhysicalPixelDisplaySizeRatio == physicalPixelDisplaySizeRatio) {
+ return sCachedDisplayShape;
+ }
+ }
+
+ final DisplayShape shape = new DisplayShape(spec, displayWidth, displayHeight,
+ physicalPixelDisplaySizeRatio, ROTATION_0);
+
+ synchronized (CACHE_LOCK) {
+ sCachedSpec = spec;
+ sCachedDisplayWidth = displayWidth;
+ sCachedDisplayHeight = displayHeight;
+ sCachedPhysicalPixelDisplaySizeRatio = physicalPixelDisplaySizeRatio;
+ sCachedDisplayShape = shape;
+ }
+ return shape;
+ }
+
+ static Path getPath(@NonNull DisplayShape shape) {
+ synchronized (CACHE_LOCK) {
+ if (shape.equals(sCacheForPath)) {
+ return sCachedPath;
+ }
+ }
+
+ final Path path = PathParser.createPathFromPathData(shape.mDisplayShapeSpec);
+
+ if (!path.isEmpty()) {
+ final Matrix matrix = new Matrix();
+ if (shape.mRotation != ROTATION_0) {
+ RotationUtils.transformPhysicalToLogicalCoordinates(
+ shape.mRotation, shape.mDisplayWidth, shape.mDisplayHeight, matrix);
+ }
+ if (shape.mPhysicalPixelDisplaySizeRatio != 1f) {
+ matrix.preScale(shape.mPhysicalPixelDisplaySizeRatio,
+ shape.mPhysicalPixelDisplaySizeRatio);
+ }
+ if (shape.mOffsetX != 0 || shape.mOffsetY != 0) {
+ matrix.postTranslate(shape.mOffsetX, shape.mOffsetY);
+ }
+ if (shape.mScale != 1f) {
+ matrix.postScale(shape.mScale, shape.mScale);
+ }
+ path.transform(matrix);
+ }
+
+ synchronized (CACHE_LOCK) {
+ sCacheForPath = shape;
+ sCachedPath = path;
+ }
+ return path;
+ }
+ }
+}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index a8cc9b6..c56d618 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -197,6 +197,9 @@
private PrivacyIndicatorBounds mPrivacyIndicatorBounds =
new PrivacyIndicatorBounds();
+ /** The display shape */
+ private DisplayShape mDisplayShape = DisplayShape.NONE;
+
public InsetsState() {
}
@@ -271,6 +274,7 @@
alwaysConsumeSystemBars, calculateRelativeCutout(frame),
calculateRelativeRoundedCorners(frame),
calculateRelativePrivacyIndicatorBounds(frame),
+ calculateRelativeDisplayShape(frame),
compatInsetsTypes, (legacySystemUiFlags & SYSTEM_UI_FLAG_LAYOUT_STABLE) != 0);
}
@@ -335,6 +339,16 @@
return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
}
+ private DisplayShape calculateRelativeDisplayShape(Rect frame) {
+ if (mDisplayFrame.equals(frame)) {
+ return mDisplayShape;
+ }
+ if (frame == null) {
+ return DisplayShape.NONE;
+ }
+ return mDisplayShape.setOffset(-frame.left, -frame.top);
+ }
+
public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
@@ -589,6 +603,14 @@
return mPrivacyIndicatorBounds;
}
+ public void setDisplayShape(DisplayShape displayShape) {
+ mDisplayShape = displayShape;
+ }
+
+ public DisplayShape getDisplayShape() {
+ return mDisplayShape;
+ }
+
/**
* Modifies the state of this class to exclude a certain type to make it ready for dispatching
* to the client.
@@ -628,6 +650,7 @@
mRoundedCorners = mRoundedCorners.scale(scale);
mRoundedCornerFrame.scale(scale);
mPrivacyIndicatorBounds = mPrivacyIndicatorBounds.scale(scale);
+ mDisplayShape = mDisplayShape.setScale(scale);
for (int i = 0; i < SIZE; i++) {
final InsetsSource source = mSources[i];
if (source != null) {
@@ -650,6 +673,7 @@
mRoundedCorners = other.getRoundedCorners();
mRoundedCornerFrame.set(other.mRoundedCornerFrame);
mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
+ mDisplayShape = other.getDisplayShape();
if (copySources) {
for (int i = 0; i < SIZE; i++) {
InsetsSource source = other.mSources[i];
@@ -675,6 +699,7 @@
mRoundedCorners = other.getRoundedCorners();
mRoundedCornerFrame.set(other.mRoundedCornerFrame);
mPrivacyIndicatorBounds = other.getPrivacyIndicatorBounds();
+ mDisplayShape = other.getDisplayShape();
final ArraySet<Integer> t = toInternalType(types);
for (int i = t.size() - 1; i >= 0; i--) {
final int type = t.valueAt(i);
@@ -807,6 +832,7 @@
pw.println(newPrefix + "mRoundedCorners=" + mRoundedCorners);
pw.println(newPrefix + "mRoundedCornerFrame=" + mRoundedCornerFrame);
pw.println(newPrefix + "mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds);
+ pw.println(newPrefix + "mDisplayShape=" + mDisplayShape);
for (int i = 0; i < SIZE; i++) {
InsetsSource source = mSources[i];
if (source == null) continue;
@@ -911,7 +937,8 @@
|| !mDisplayCutout.equals(state.mDisplayCutout)
|| !mRoundedCorners.equals(state.mRoundedCorners)
|| !mRoundedCornerFrame.equals(state.mRoundedCornerFrame)
- || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)) {
+ || !mPrivacyIndicatorBounds.equals(state.mPrivacyIndicatorBounds)
+ || !mDisplayShape.equals(state.mDisplayShape)) {
return false;
}
for (int i = 0; i < SIZE; i++) {
@@ -941,7 +968,7 @@
@Override
public int hashCode() {
return Objects.hash(mDisplayFrame, mDisplayCutout, Arrays.hashCode(mSources),
- mRoundedCorners, mPrivacyIndicatorBounds, mRoundedCornerFrame);
+ mRoundedCorners, mPrivacyIndicatorBounds, mRoundedCornerFrame, mDisplayShape);
}
public InsetsState(Parcel in) {
@@ -961,6 +988,7 @@
dest.writeTypedObject(mRoundedCorners, flags);
mRoundedCornerFrame.writeToParcel(dest, flags);
dest.writeTypedObject(mPrivacyIndicatorBounds, flags);
+ dest.writeTypedObject(mDisplayShape, flags);
}
public static final @NonNull Creator<InsetsState> CREATOR = new Creator<InsetsState>() {
@@ -981,6 +1009,7 @@
mRoundedCorners = in.readTypedObject(RoundedCorners.CREATOR);
mRoundedCornerFrame.readFromParcel(in);
mPrivacyIndicatorBounds = in.readTypedObject(PrivacyIndicatorBounds.CREATOR);
+ mDisplayShape = in.readTypedObject(DisplayShape.CREATOR);
}
@Override
@@ -998,6 +1027,7 @@
+ ", mRoundedCorners=" + mRoundedCorners
+ " mRoundedCornerFrame=" + mRoundedCornerFrame
+ ", mPrivacyIndicatorBounds=" + mPrivacyIndicatorBounds
+ + ", mDisplayShape=" + mDisplayShape
+ ", mSources= { " + joiner
+ " }";
}
diff --git a/core/java/android/view/WindowInsets.java b/core/java/android/view/WindowInsets.java
index 03b25c2..8de15c1 100644
--- a/core/java/android/view/WindowInsets.java
+++ b/core/java/android/view/WindowInsets.java
@@ -42,7 +42,6 @@
import android.content.Intent;
import android.graphics.Insets;
import android.graphics.Rect;
-import android.util.SparseArray;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.WindowInsets.Type.InsetsType;
import android.view.inputmethod.EditorInfo;
@@ -83,6 +82,7 @@
@Nullable private final DisplayCutout mDisplayCutout;
@Nullable private final RoundedCorners mRoundedCorners;
@Nullable private final PrivacyIndicatorBounds mPrivacyIndicatorBounds;
+ @Nullable private final DisplayShape mDisplayShape;
/**
* In multi-window we force show the navigation bar. Because we don't want that the surface size
@@ -115,24 +115,9 @@
public static final @NonNull WindowInsets CONSUMED;
static {
- CONSUMED = new WindowInsets((Rect) null, null, false, false, null);
- }
-
- /**
- * Construct a new WindowInsets from individual insets.
- *
- * A {@code null} inset indicates that the respective inset is consumed.
- *
- * @hide
- * @deprecated Use {@link WindowInsets(SparseArray, SparseArray, boolean, boolean, DisplayCutout)}
- */
- @Deprecated
- public WindowInsets(Rect systemWindowInsetsRect, Rect stableInsetsRect, boolean isRound,
- boolean alwaysConsumeSystemBars, DisplayCutout displayCutout) {
- this(createCompatTypeMap(systemWindowInsetsRect), createCompatTypeMap(stableInsetsRect),
- createCompatVisibilityMap(createCompatTypeMap(systemWindowInsetsRect)),
- isRound, alwaysConsumeSystemBars, displayCutout, null, null,
- systemBars(), false /* compatIgnoreVisibility */);
+ CONSUMED = new WindowInsets(createCompatTypeMap(null), createCompatTypeMap(null),
+ createCompatVisibilityMap(createCompatTypeMap(null)), false, false, null, null,
+ null, null, systemBars(), false);
}
/**
@@ -154,6 +139,7 @@
boolean alwaysConsumeSystemBars, DisplayCutout displayCutout,
RoundedCorners roundedCorners,
PrivacyIndicatorBounds privacyIndicatorBounds,
+ DisplayShape displayShape,
@InsetsType int compatInsetsTypes, boolean compatIgnoreVisibility) {
mSystemWindowInsetsConsumed = typeInsetsMap == null;
mTypeInsetsMap = mSystemWindowInsetsConsumed
@@ -177,6 +163,7 @@
mRoundedCorners = roundedCorners;
mPrivacyIndicatorBounds = privacyIndicatorBounds;
+ mDisplayShape = displayShape;
}
/**
@@ -191,6 +178,7 @@
src.mAlwaysConsumeSystemBars, displayCutoutCopyConstructorArgument(src),
src.mRoundedCorners,
src.mPrivacyIndicatorBounds,
+ src.mDisplayShape,
src.mCompatInsetsTypes,
src.mCompatIgnoreVisibility);
}
@@ -244,15 +232,18 @@
@UnsupportedAppUsage
public WindowInsets(Rect systemWindowInsets) {
this(createCompatTypeMap(systemWindowInsets), null, new boolean[SIZE], false, false, null,
- null, null, systemBars(), false /* compatIgnoreVisibility */);
+ null, null, null, systemBars(), false /* compatIgnoreVisibility */);
}
/**
* Creates a indexOf(type) -> inset map for which the {@code insets} is just mapped to
* {@link Type#statusBars()} and {@link Type#navigationBars()}, depending on the
* location of the inset.
+ *
+ * @hide
*/
- private static Insets[] createCompatTypeMap(@Nullable Rect insets) {
+ @VisibleForTesting
+ public static Insets[] createCompatTypeMap(@Nullable Rect insets) {
if (insets == null) {
return null;
}
@@ -271,6 +262,10 @@
Insets.of(insets.left, 0, insets.right, insets.bottom);
}
+ /**
+ * @hide
+ */
+ @VisibleForTesting
private static boolean[] createCompatVisibilityMap(@Nullable Insets[] typeInsetsMap) {
boolean[] typeVisibilityMap = new boolean[SIZE];
if (typeInsetsMap == null) {
@@ -533,6 +528,17 @@
}
/**
+ * Returns the display shape in the coordinate space of the window.
+ *
+ * @return the display shape
+ * @see DisplayShape
+ */
+ @Nullable
+ public DisplayShape getDisplayShape() {
+ return mDisplayShape;
+ }
+
+ /**
* Returns a copy of this WindowInsets with the cutout fully consumed.
*
* @return A modified copy of this WindowInsets
@@ -547,7 +553,7 @@
mStableInsetsConsumed ? null : mTypeMaxInsetsMap,
mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars,
- null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds,
+ null /* displayCutout */, mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape,
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -602,7 +608,7 @@
// it.
(mCompatInsetsTypes & displayCutout()) != 0
? null : displayCutoutCopyConstructorArgument(this),
- mRoundedCorners, mPrivacyIndicatorBounds, mCompatInsetsTypes,
+ mRoundedCorners, mPrivacyIndicatorBounds, mDisplayShape, mCompatInsetsTypes,
mCompatIgnoreVisibility);
}
@@ -911,6 +917,8 @@
result.append(mPrivacyIndicatorBounds != null ? "privacyIndicatorBounds="
+ mPrivacyIndicatorBounds : "");
result.append("\n ");
+ result.append(mDisplayShape != null ? "displayShape=" + mDisplayShape : "");
+ result.append("\n ");
result.append("compatInsetsTypes=" + mCompatInsetsTypes);
result.append("\n ");
result.append("compatIgnoreVisibility=" + mCompatIgnoreVisibility);
@@ -1018,6 +1026,7 @@
mPrivacyIndicatorBounds == null
? null
: mPrivacyIndicatorBounds.inset(left, top, right, bottom),
+ mDisplayShape,
mCompatInsetsTypes, mCompatIgnoreVisibility);
}
@@ -1037,7 +1046,8 @@
&& Arrays.equals(mTypeVisibilityMap, that.mTypeVisibilityMap)
&& Objects.equals(mDisplayCutout, that.mDisplayCutout)
&& Objects.equals(mRoundedCorners, that.mRoundedCorners)
- && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds);
+ && Objects.equals(mPrivacyIndicatorBounds, that.mPrivacyIndicatorBounds)
+ && Objects.equals(mDisplayShape, that.mDisplayShape);
}
@Override
@@ -1045,7 +1055,7 @@
return Objects.hash(Arrays.hashCode(mTypeInsetsMap), Arrays.hashCode(mTypeMaxInsetsMap),
Arrays.hashCode(mTypeVisibilityMap), mIsRound, mDisplayCutout, mRoundedCorners,
mAlwaysConsumeSystemBars, mSystemWindowInsetsConsumed, mStableInsetsConsumed,
- mDisplayCutoutConsumed, mPrivacyIndicatorBounds);
+ mDisplayCutoutConsumed, mPrivacyIndicatorBounds, mDisplayShape);
}
@@ -1106,6 +1116,7 @@
private DisplayCutout mDisplayCutout;
private RoundedCorners mRoundedCorners = RoundedCorners.NO_ROUNDED_CORNERS;
+ private DisplayShape mDisplayShape = DisplayShape.NONE;
private boolean mIsRound;
private boolean mAlwaysConsumeSystemBars;
@@ -1137,6 +1148,7 @@
mIsRound = insets.mIsRound;
mAlwaysConsumeSystemBars = insets.mAlwaysConsumeSystemBars;
mPrivacyIndicatorBounds = insets.mPrivacyIndicatorBounds;
+ mDisplayShape = insets.mDisplayShape;
}
/**
@@ -1381,6 +1393,19 @@
return this;
}
+ /**
+ * Sets the display shape.
+ *
+ * @see #getDisplayShape().
+ * @param displayShape the display shape.
+ * @return itself.
+ */
+ @NonNull
+ public Builder setDisplayShape(@NonNull DisplayShape displayShape) {
+ mDisplayShape = displayShape;
+ return this;
+ }
+
/** @hide */
@NonNull
public Builder setRound(boolean round) {
@@ -1405,7 +1430,8 @@
return new WindowInsets(mSystemInsetsConsumed ? null : mTypeInsetsMap,
mStableInsetsConsumed ? null : mTypeMaxInsetsMap, mTypeVisibilityMap,
mIsRound, mAlwaysConsumeSystemBars, mDisplayCutout, mRoundedCorners,
- mPrivacyIndicatorBounds, systemBars(), false /* compatIgnoreVisibility */);
+ mPrivacyIndicatorBounds, mDisplayShape, systemBars(),
+ false /* compatIgnoreVisibility */);
}
}
diff --git a/core/java/com/android/internal/inputmethod/IInputMethod.aidl b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
index 1e3714e..8cb568d 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethod.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethod.aidl
@@ -40,7 +40,6 @@
parcelable InitParams {
IBinder token;
IInputMethodPrivilegedOperations privilegedOperations;
- int configChanges;
int navigationBarFlags;
}
diff --git a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
index 4b1753a..9cb2e68 100644
--- a/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/core/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -17,7 +17,7 @@
package com.android.internal.telephony;
import android.telephony.BarringInfo;
-import android.telephony.CallAttributes;
+import android.telephony.CallState;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.DataConnectionRealTimeInfo;
@@ -62,7 +62,7 @@
void onPhoneCapabilityChanged(in PhoneCapability capability);
void onActiveDataSubIdChanged(in int subId);
void onRadioPowerStateChanged(in int state);
- void onCallAttributesChanged(in CallAttributes callAttributes);
+ void onCallStatesChanged(in List<CallState> callStateList);
@SuppressWarnings(value={"untyped-collection"})
void onEmergencyNumberListChanged(in Map emergencyNumberList);
void onOutgoingEmergencyCall(in EmergencyNumber placedEmergencyNumber, int subscriptionId);
diff --git a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index c7fa757..7ba2686 100644
--- a/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/core/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -66,8 +66,8 @@
void notifyCellLocationForSubscriber(in int subId, in CellIdentity cellLocation);
@UnsupportedAppUsage
void notifyCellInfo(in List<CellInfo> cellInfo);
- void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
- int foregroundCallState, int backgroundCallState);
+ void notifyPreciseCallState(int phoneId, int subId, in int[] callStates, in String[] imsCallIds,
+ in int[] imsCallServiceTypes, in int[] imsCallTypes);
void notifyDisconnectCause(int phoneId, int subId, int disconnectCause,
int preciseDisconnectCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6460007..eb70344 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1705,8 +1705,7 @@
-->
<flag name="systemExempted" value="0x400" />
<!-- "Short service" foreground service type. See
- TODO: Change it to a real link
- {@code android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
+ {@link android.content.pm.ServiceInfo#FOREGROUND_SERVICE_TYPE_SHORT_SERVICE}.
for more details.
-->
<flag name="shortService" value="0x800" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9c2643b..2ab5b75 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -5985,4 +5985,35 @@
<string-array translatable="false" name="config_fontManagerServiceCerts">
</string-array>
+ <!-- A string config in svg path format for the main display shape.
+ (@see https://www.w3.org/TR/SVG/paths.html#PathData).
+
+ This config must be set unless:
+ 1. {@link Configuration#isScreenRound} is true which means the display shape is circular
+ and the system will auto-generate a circular shape.
+ 2. The display has no rounded corner and the system will auto-generate a rectangular shape.
+ (@see DisplayShape#createDefaultDisplayShape)
+
+ Note: If the display supports multiple resolutions, please define the path config based on
+ the highest resolution so that it can be scaled correctly in each resolution. -->
+ <string name="config_mainDisplayShape" translatable="false"></string>
+
+ <!-- A string config in svg path format for the secondary display shape.
+ (@see https://www.w3.org/TR/SVG/paths.html#PathData).
+
+ This config must be set unless:
+ 1. {@link Configuration#isScreenRound} is true which means the display shape is circular
+ and the system will auto-generate a circular shape.
+ 2. The display has no rounded corner and the system will auto-generate a rectangular shape.
+ (@see DisplayShape#createDefaultDisplayShape)
+
+ Note: If the display supports multiple resolutions, please define the path config based on
+ the highest resolution so that it can be scaled correctly in each resolution. -->
+ <string name="config_secondaryDisplayShape" translatable="false"></string>
+
+ <!-- The display shape config for each display in a multi-display device. -->
+ <string-array name="config_displayShapeArray" translatable="false">
+ <item>@string/config_mainDisplayShape</item>
+ <item>@string/config_secondaryDisplayShape</item>
+ </string-array>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index cd93932..168806a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4915,4 +4915,8 @@
<java-symbol type="dimen" name="status_bar_height_default" />
<java-symbol type="string" name="default_card_name"/>
+
+ <java-symbol type="string" name="config_mainDisplayShape"/>
+ <java-symbol type="string" name="config_secondaryDisplayShape"/>
+ <java-symbol type="array" name="config_displayShapeArray" />
</resources>
diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java
index a528c19..6bf8f56 100644
--- a/core/tests/coretests/src/android/graphics/TypefaceTest.java
+++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java
@@ -203,16 +203,22 @@
fallbackMap);
SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
Map<String, Typeface> copiedFontMap = new ArrayMap<>();
- Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
- copiedFontMap);
- assertEquals(systemFontMap.size(), copiedFontMap.size());
- for (String key : systemFontMap.keySet()) {
- assertTrue(copiedFontMap.containsKey(key));
- Typeface original = systemFontMap.get(key);
- Typeface copied = copiedFontMap.get(key);
- assertEquals(original.getStyle(), copied.getStyle());
- assertEquals(original.getWeight(), copied.getWeight());
- assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+ try {
+ Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
+ copiedFontMap);
+ assertEquals(systemFontMap.size(), copiedFontMap.size());
+ for (String key : systemFontMap.keySet()) {
+ assertTrue(copiedFontMap.containsKey(key));
+ Typeface original = systemFontMap.get(key);
+ Typeface copied = copiedFontMap.get(key);
+ assertEquals(original.getStyle(), copied.getStyle());
+ assertEquals(original.getWeight(), copied.getWeight());
+ assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
+ }
+ } finally {
+ for (Typeface typeface : copiedFontMap.values()) {
+ typeface.releaseNativeObjectForTest();
+ }
}
}
diff --git a/core/tests/coretests/src/android/view/DisplayShapeTest.java b/core/tests/coretests/src/android/view/DisplayShapeTest.java
new file mode 100644
index 0000000..77dd8bd
--- /dev/null
+++ b/core/tests/coretests/src/android/view/DisplayShapeTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 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.view;
+
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertEquals;
+
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests for {@link DisplayShape}.
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class DisplayShapeTest {
+ // Rectangle with w=100, height=200
+ private static final String SPEC_RECTANGULAR_SHAPE = "M0,0 L100,0 L100,200 L0,200 Z";
+
+ @Test
+ public void testGetPath() {
+ final DisplayShape displayShape = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+ final Path path = displayShape.getPath();
+ final RectF actualRect = new RectF();
+ path.computeBounds(actualRect, false);
+
+ final RectF expectRect = new RectF(0f, 0f, 100f, 200f);
+ assertEquals(actualRect, expectRect);
+ }
+
+ @Test
+ public void testDefaultShape_screenIsRound() {
+ final DisplayShape displayShape = DisplayShape.createDefaultDisplayShape(100, 100, true);
+
+ // A circle with radius = 50.
+ final String expect = "M0,50.0 A50.0,50.0 0 1,1 100,50.0 A50.0,50.0 0 1,1 0,50.0 Z";
+ assertEquals(displayShape.mDisplayShapeSpec, expect);
+ }
+
+ @Test
+ public void testDefaultShape_screenIsNotRound() {
+ final DisplayShape displayShape = DisplayShape.createDefaultDisplayShape(100, 200, false);
+
+ // A rectangle with width/height = 100/200.
+ final String expect = "M0,0 L100,0 L100,200 L0,200 Z";
+ assertEquals(displayShape.mDisplayShapeSpec, expect);
+ }
+
+ @Test
+ public void testFromSpecString_cache() {
+ final DisplayShape cached = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+ assertThat(DisplayShape.fromSpecString(SPEC_RECTANGULAR_SHAPE, 1f, 100, 200),
+ sameInstance(cached));
+ }
+
+ @Test
+ public void testGetPath_cache() {
+ final Path cached = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200).getPath();
+ assertThat(DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200).getPath(),
+ sameInstance(cached));
+ }
+
+ @Test
+ public void testRotate_90() {
+ DisplayShape displayShape = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+ displayShape = displayShape.setRotation(ROTATION_90);
+ final Path path = displayShape.getPath();
+ final RectF actualRect = new RectF();
+ path.computeBounds(actualRect, false);
+
+ final RectF expectRect = new RectF(0f, 0f, 200f, 100f);
+ assertEquals(actualRect, expectRect);
+ }
+
+ @Test
+ public void testRotate_270() {
+ DisplayShape displayShape = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+ displayShape = displayShape.setRotation(ROTATION_270);
+ final Path path = displayShape.getPath();
+ final RectF actualRect = new RectF();
+ path.computeBounds(actualRect, false);
+
+ final RectF expectRect = new RectF(0f, 0f, 200f, 100f);
+ assertEquals(actualRect, expectRect);
+ }
+
+ @Test
+ public void testOffset() {
+ DisplayShape displayShape = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 1f, 100, 200);
+ displayShape = displayShape.setOffset(-10, -20);
+ final Path path = displayShape.getPath();
+ final RectF actualRect = new RectF();
+ path.computeBounds(actualRect, false);
+
+ final RectF expectRect = new RectF(-10f, -20f, 90f, 180f);
+ assertEquals(actualRect, expectRect);
+ }
+
+ @Test
+ public void testPhysicalPixelDisplaySizeRatio() {
+ final DisplayShape displayShape = DisplayShape.fromSpecString(
+ SPEC_RECTANGULAR_SHAPE, 0.5f, 100, 200);
+ final Path path = displayShape.getPath();
+ final RectF actualRect = new RectF();
+ path.computeBounds(actualRect, false);
+
+ final RectF expectRect = new RectF(0f, 0f, 50f, 100f);
+ assertEquals(actualRect, expectRect);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index be9da11..6a96f28 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -517,6 +517,19 @@
windowInsets.getRoundedCorner(POSITION_BOTTOM_LEFT));
}
+ @Test
+ public void testCalculateRelativeDisplayShape() {
+ mState.setDisplayFrame(new Rect(0, 0, 200, 400));
+ mState.setDisplayShape(DisplayShape.createDefaultDisplayShape(200, 400, false));
+ WindowInsets windowInsets = mState.calculateInsets(new Rect(10, 20, 200, 400), null, false,
+ false, SOFT_INPUT_ADJUST_UNSPECIFIED, 0, 0, TYPE_APPLICATION,
+ WINDOWING_MODE_UNDEFINED, new SparseIntArray());
+
+ final DisplayShape expect =
+ DisplayShape.createDefaultDisplayShape(200, 400, false).setOffset(-10, -20);
+ assertEquals(expect, windowInsets.getDisplayShape());
+ }
+
private void assertEqualsAndHashCode() {
assertEquals(mState, mState2);
assertEquals(mState.hashCode(), mState2.hashCode());
diff --git a/core/tests/coretests/src/android/view/WindowInsetsTest.java b/core/tests/coretests/src/android/view/WindowInsetsTest.java
index dd9634b..4fed396 100644
--- a/core/tests/coretests/src/android/view/WindowInsetsTest.java
+++ b/core/tests/coretests/src/android/view/WindowInsetsTest.java
@@ -39,13 +39,16 @@
@Test
public void systemWindowInsets_afterConsuming_isConsumed() {
- assertTrue(new WindowInsets(new Rect(1, 2, 3, 4), null, false, false, null)
+ assertTrue(new WindowInsets(WindowInsets.createCompatTypeMap(new Rect(1, 2, 3, 4)), null,
+ null, false, false, null, null, null, null,
+ WindowInsets.Type.systemBars(), false)
.consumeSystemWindowInsets().isConsumed());
}
@Test
public void multiNullConstructor_isConsumed() {
- assertTrue(new WindowInsets((Rect) null, null, false, false, null).isConsumed());
+ assertTrue(new WindowInsets(null, null, null, false, false, null, null, null, null,
+ WindowInsets.Type.systemBars(), false).isConsumed());
}
@Test
@@ -61,7 +64,8 @@
WindowInsets.assignCompatInsets(maxInsets, new Rect(0, 10, 0, 0));
WindowInsets.assignCompatInsets(insets, new Rect(0, 0, 0, 0));
WindowInsets windowInsets = new WindowInsets(insets, maxInsets, visible, false, false, null,
- null, null, systemBars(), true /* compatIgnoreVisibility */);
+ null, null, DisplayShape.NONE, systemBars(),
+ true /* compatIgnoreVisibility */);
assertEquals(Insets.of(0, 10, 0, 0), windowInsets.getSystemWindowInsets());
}
}
diff --git a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
index d10f173..4d4ec35 100644
--- a/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/ActionBarOverlayLayoutTest.java
@@ -168,7 +168,8 @@
}
private WindowInsets insetsWith(Insets content, DisplayCutout cutout) {
- return new WindowInsets(content.toRect(), null, false, false, cutout);
+ return new WindowInsets(WindowInsets.createCompatTypeMap(content.toRect()), null, null,
+ false, false, cutout, null, null, null, WindowInsets.Type.systemBars(), false);
}
private ViewGroup createViewGroupWithId(int id) {
diff --git a/data/keyboards/Generic.kl b/data/keyboards/Generic.kl
index 215b60e..a43e225 100644
--- a/data/keyboards/Generic.kl
+++ b/data/keyboards/Generic.kl
@@ -371,6 +371,10 @@
# key 413 "KEY_DIGITS"
# key 414 "KEY_TEEN"
# key 415 "KEY_TWEN"
+# key 418 "KEY_ZOOM_IN"
+key 418 ZOOM_IN
+# key 419 "KEY_ZOOM_OUT"
+key 419 ZOOM_OUT
key 528 FOCUS
key 429 CONTACTS
diff --git a/graphics/java/android/graphics/PathIterator.java b/graphics/java/android/graphics/PathIterator.java
index 33b9a47..bfda690 100644
--- a/graphics/java/android/graphics/PathIterator.java
+++ b/graphics/java/android/graphics/PathIterator.java
@@ -281,7 +281,7 @@
return mConicWeight;
}
- public Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
+ Segment(@NonNull @Verb int verb, @NonNull float[] points, float conicWeight) {
mVerb = verb;
mPoints = points;
mConicWeight = conicWeight;
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index 3b7d0e1..9fb627f 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -1207,6 +1207,7 @@
* It is safe to call this method twice or more on the same instance.
* @hide
*/
+ @TestApi
public void releaseNativeObjectForTest() {
mCleaner.run();
}
@@ -1294,6 +1295,13 @@
/**
* Deserialize the font mapping from the serialized byte buffer.
*
+ * <p>Warning: the given {@code buffer} must outlive generated Typeface
+ * objects in {@code out}. In production code, this is guaranteed by
+ * storing the buffer in {@link #sSystemFontMapBuffer}.
+ * If you call this method in a test, please make sure to destroy the
+ * generated Typeface objects by calling
+ * {@link #releaseNativeObjectForTest()}.
+ *
* @hide
*/
@TestApi
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
old mode 100755
new mode 100644
index c0fa63a..15aaae2
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -18,6 +18,7 @@
#include "android-base/errors.h"
#include "android-base/logging.h"
+#include "android-base/utf8.h"
namespace android {
@@ -84,7 +85,7 @@
}
std::string overlay_path(loaded_idmap->OverlayApkPath());
- auto fd = unique_fd(::open(overlay_path.c_str(), O_RDONLY|O_CLOEXEC));
+ auto fd = unique_fd(base::utf8::open(overlay_path.c_str(), O_RDONLY | O_CLOEXEC));
std::unique_ptr<AssetsProvider> overlay_assets;
if (IsFabricatedOverlay(fd)) {
// Fabricated overlays do not contain resource definitions. All of the overlay resource values
@@ -92,7 +93,7 @@
overlay_assets = EmptyAssetsProvider::Create(std::move(overlay_path));
} else {
// The overlay should be an APK.
- overlay_assets = ZipAssetsProvider::Create(std::move(fd), std::move(overlay_path), flags);
+ overlay_assets = ZipAssetsProvider::Create(std::move(overlay_path), flags, std::move(fd));
}
if (overlay_assets == nullptr) {
return {};
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index c3d153d..cc7e871 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -374,7 +374,7 @@
const std::string name = ToFormattedResourceString(*res_name);
output.append(base::StringPrintf(
"resource='%s' overlayable='%s' actor='%s' policy='0x%08x'\n",
- name.c_str(), info->name.c_str(), info->actor.c_str(), info->policy_flags));
+ name.c_str(), info->name.data(), info->actor.data(), info->policy_flags));
}
}
}
@@ -1356,21 +1356,22 @@
void AssetManager2::RebuildFilterList() {
for (PackageGroup& group : package_groups_) {
- for (ConfiguredPackage& impl : group.packages_) {
- impl.filtered_configs_.clear();
-
+ for (ConfiguredPackage& package : group.packages_) {
+ package.filtered_configs_.forEachItem([](auto, auto& fcg) { fcg.type_entries.clear(); });
// Create the filters here.
- impl.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
+ package.loaded_package_->ForEachTypeSpec([&](const TypeSpec& type_spec, uint8_t type_id) {
FilteredConfigGroup* group = nullptr;
for (const auto& type_entry : type_spec.type_entries) {
if (type_entry.config.match(configuration_)) {
if (!group) {
- group = &impl.filtered_configs_.editItemAt(type_id - 1);
+ group = &package.filtered_configs_.editItemAt(type_id - 1);
}
group->type_entries.push_back(&type_entry);
}
}
});
+ package.filtered_configs_.trimBuckets(
+ [](const auto& fcg) { return fcg.type_entries.empty(); });
}
}
}
@@ -1411,30 +1412,34 @@
std::unique_ptr<Theme> AssetManager2::NewTheme() {
constexpr size_t kInitialReserveSize = 32;
auto theme = std::unique_ptr<Theme>(new Theme(this));
+ theme->keys_.reserve(kInitialReserveSize);
theme->entries_.reserve(kInitialReserveSize);
return theme;
}
+void AssetManager2::ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
+ package_property_t excluded_property_flags) const {
+ for (const PackageGroup& package_group : package_groups_) {
+ const auto loaded_package = package_group.packages_.front().loaded_package_;
+ if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U
+ && !func(loaded_package->GetPackageName(),
+ package_group.dynamic_ref_table->mAssignedPackageId)) {
+ return;
+ }
+ }
+}
+
Theme::Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {
}
Theme::~Theme() = default;
struct Theme::Entry {
- uint32_t attr_res_id;
ApkAssetsCookie cookie;
uint32_t type_spec_flags;
Res_value value;
};
-namespace {
-struct ThemeEntryKeyComparer {
- bool operator() (const Theme::Entry& entry, uint32_t attr_res_id) const noexcept {
- return entry.attr_res_id < attr_res_id;
- }
-};
-} // namespace
-
base::expected<std::monostate, NullOrIOError> Theme::ApplyStyle(uint32_t resid, bool force) {
ATRACE_NAME("Theme::ApplyStyle");
@@ -1463,18 +1468,20 @@
continue;
}
- auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), attr_res_id,
- ThemeEntryKeyComparer{});
- if (entry_it != entries_.end() && entry_it->attr_res_id == attr_res_id) {
+ const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), attr_res_id);
+ const auto entry_it = entries_.begin() + (key_it - keys_.begin());
+ if (key_it != keys_.end() && *key_it == attr_res_id) {
if (is_undefined) {
// DATA_NULL_UNDEFINED clears the value of the attribute in the theme only when `force` is
- /// true.
+ // true.
+ keys_.erase(key_it);
entries_.erase(entry_it);
} else if (force) {
- *entry_it = Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value};
+ *entry_it = Entry{it->cookie, (*bag)->type_spec_flags, it->value};
}
} else {
- entries_.insert(entry_it, Entry{attr_res_id, it->cookie, (*bag)->type_spec_flags, it->value});
+ keys_.insert(key_it, attr_res_id);
+ entries_.insert(entry_it, Entry{it->cookie, (*bag)->type_spec_flags, it->value});
}
}
return {};
@@ -1485,6 +1492,7 @@
ATRACE_NAME("Theme::Rebase");
// Reset the entries without changing the vector capacity to prevent reallocations during
// ApplyStyle.
+ keys_.clear();
entries_.clear();
asset_manager_ = am;
for (size_t i = 0; i < style_count; i++) {
@@ -1493,16 +1501,14 @@
}
std::optional<AssetManager2::SelectedValue> Theme::GetAttribute(uint32_t resid) const {
-
constexpr const uint32_t kMaxIterations = 20;
uint32_t type_spec_flags = 0u;
for (uint32_t i = 0; i <= kMaxIterations; i++) {
- auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), resid,
- ThemeEntryKeyComparer{});
- if (entry_it == entries_.end() || entry_it->attr_res_id != resid) {
+ const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), resid);
+ if (key_it == keys_.end() || *key_it != resid) {
return std::nullopt;
}
-
+ const auto entry_it = entries_.begin() + (key_it - keys_.begin());
type_spec_flags |= entry_it->type_spec_flags;
if (entry_it->value.dataType == Res_value::TYPE_ATTRIBUTE) {
resid = entry_it->value.data;
@@ -1536,6 +1542,7 @@
}
void Theme::Clear() {
+ keys_.clear();
entries_.clear();
}
@@ -1547,11 +1554,12 @@
type_spec_flags_ = source.type_spec_flags_;
if (asset_manager_ == source.asset_manager_) {
+ keys_ = source.keys_;
entries_ = source.entries_;
} else {
- std::map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
- typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
- std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
+ std::unordered_map<ApkAssetsCookie, ApkAssetsCookie> src_to_dest_asset_cookies;
+ using SourceToDestinationRuntimePackageMap = std::unordered_map<int, int>;
+ std::unordered_map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
// Determine which ApkAssets are loaded in both theme AssetManagers.
const auto src_assets = source.asset_manager_->GetApkAssets();
@@ -1579,15 +1587,17 @@
}
src_to_dest_asset_cookies.insert(std::make_pair(i, j));
- src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
+ src_asset_cookie_id_map.insert(std::make_pair(i, std::move(package_map)));
break;
}
}
// Reset the data in the destination theme.
+ keys_.clear();
entries_.clear();
- for (const auto& entry : source.entries_) {
+ for (size_t i = 0, size = source.entries_.size(); i != size; ++i) {
+ const auto& entry = source.entries_[i];
bool is_reference = (entry.value.dataType == Res_value::TYPE_ATTRIBUTE
|| entry.value.dataType == Res_value::TYPE_REFERENCE
|| entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
@@ -1627,13 +1637,15 @@
}
}
+ const auto source_res_id = source.keys_[i];
+
// The package id of the attribute needs to be rewritten to the package id of the
// attribute in the destination.
- int attribute_dest_package_id = get_package_id(entry.attr_res_id);
+ int attribute_dest_package_id = get_package_id(source_res_id);
if (attribute_dest_package_id != 0x01) {
// Find the cookie of the attribute resource id in the source AssetManager
base::expected<FindEntryResult, NullOrIOError> attribute_entry_result =
- source.asset_manager_->FindEntry(entry.attr_res_id, 0 /* density_override */ ,
+ source.asset_manager_->FindEntry(source_res_id, 0 /* density_override */ ,
true /* stop_at_first_match */,
true /* ignore_configuration */);
if (UNLIKELY(IsIOError(attribute_entry_result))) {
@@ -1657,16 +1669,15 @@
attribute_dest_package_id = attribute_dest_package->second;
}
- auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(entry.attr_res_id),
- get_entry_id(entry.attr_res_id));
- Theme::Entry new_entry{dest_attr_id, data_dest_cookie, entry.type_spec_flags,
- Res_value{.dataType = entry.value.dataType,
- .data = attribute_data}};
-
+ auto dest_attr_id = make_resid(attribute_dest_package_id, get_type_id(source_res_id),
+ get_entry_id(source_res_id));
+ const auto key_it = std::lower_bound(keys_.begin(), keys_.end(), dest_attr_id);
+ const auto entry_it = entries_.begin() + (key_it - keys_.begin());
// Since the entries were cleared, the attribute resource id has yet been mapped to any value.
- auto entry_it = std::lower_bound(entries_.begin(), entries_.end(), dest_attr_id,
- ThemeEntryKeyComparer{});
- entries_.insert(entry_it, new_entry);
+ keys_.insert(key_it, dest_attr_id);
+ entries_.insert(entry_it, Entry{data_dest_cookie, entry.type_spec_flags,
+ Res_value{.dataType = entry.value.dataType,
+ .data = attribute_data}});
}
}
return {};
@@ -1674,9 +1685,11 @@
void Theme::Dump() const {
LOG(INFO) << base::StringPrintf("Theme(this=%p, AssetManager2=%p)", this, asset_manager_);
- for (auto& entry : entries_) {
+ for (size_t i = 0, size = keys_.size(); i != size; ++i) {
+ auto res_id = keys_[i];
+ const auto& entry = entries_[i];
LOG(INFO) << base::StringPrintf(" entry(0x%08x)=(0x%08x) type=(0x%02x), cookie(%d)",
- entry.attr_res_id, entry.value.data, entry.value.dataType,
+ res_id, entry.value.data, entry.value.dataType,
entry.cookie);
}
}
diff --git a/libs/androidfw/AssetsProvider.cpp b/libs/androidfw/AssetsProvider.cpp
index 80e5607..b9264c5 100644
--- a/libs/androidfw/AssetsProvider.cpp
+++ b/libs/androidfw/AssetsProvider.cpp
@@ -92,21 +92,27 @@
last_mod_time_(last_mod_time) {}
std::unique_ptr<ZipAssetsProvider> ZipAssetsProvider::Create(std::string path,
- package_property_t flags) {
+ package_property_t flags,
+ base::unique_fd fd) {
+ const auto released_fd = fd.ok() ? fd.release() : -1;
ZipArchiveHandle handle;
- if (int32_t result = OpenArchive(path.c_str(), &handle); result != 0) {
+ if (int32_t result = released_fd < 0 ? OpenArchive(path.c_str(), &handle)
+ : OpenArchiveFd(released_fd, path.c_str(), &handle)) {
LOG(ERROR) << "Failed to open APK '" << path << "': " << ::ErrorCodeString(result);
CloseArchive(handle);
return {};
}
struct stat sb{.st_mtime = -1};
- if (stat(path.c_str(), &sb) < 0) {
- // Stat requires execute permissions on all directories path to the file. If the process does
- // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
- // always have to return true.
- LOG(WARNING) << "Failed to stat file '" << path << "': "
- << base::SystemErrorCodeToString(errno);
+ // Skip all up-to-date checks if the file won't ever change.
+ if (!isReadonlyFilesystem(path.c_str())) {
+ if ((released_fd < 0 ? stat(path.c_str(), &sb) : fstat(released_fd, &sb)) < 0) {
+ // Stat requires execute permissions on all directories path to the file. If the process does
+ // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+ // always have to return true.
+ LOG(WARNING) << "Failed to stat file '" << path << "': "
+ << base::SystemErrorCodeToString(errno);
+ }
}
return std::unique_ptr<ZipAssetsProvider>(
@@ -133,12 +139,15 @@
}
struct stat sb{.st_mtime = -1};
- if (fstat(released_fd, &sb) < 0) {
- // Stat requires execute permissions on all directories path to the file. If the process does
- // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
- // always have to return true.
- LOG(WARNING) << "Failed to fstat file '" << friendly_name << "': "
- << base::SystemErrorCodeToString(errno);
+ // Skip all up-to-date checks if the file won't ever change.
+ if (!isReadonlyFilesystem(released_fd)) {
+ if (fstat(released_fd, &sb) < 0) {
+ // Stat requires execute permissions on all directories path to the file. If the process does
+ // not have execute permissions on this file, allow the zip to be opened but IsUpToDate() will
+ // always have to return true.
+ LOG(WARNING) << "Failed to fstat file '" << friendly_name
+ << "': " << base::SystemErrorCodeToString(errno);
+ }
}
return std::unique_ptr<ZipAssetsProvider>(
@@ -275,6 +284,9 @@
}
bool ZipAssetsProvider::IsUpToDate() const {
+ if (last_mod_time_ == -1) {
+ return true;
+ }
struct stat sb{};
if (fstat(GetFileDescriptor(zip_handle_.get()), &sb) < 0) {
// If fstat fails on the zip archive, return true so the zip archive the resource system does
@@ -288,7 +300,7 @@
: dir_(std::forward<std::string>(path)), last_mod_time_(last_mod_time) {}
std::unique_ptr<DirectoryAssetsProvider> DirectoryAssetsProvider::Create(std::string path) {
- struct stat sb{};
+ struct stat sb;
const int result = stat(path.c_str(), &sb);
if (result == -1) {
LOG(ERROR) << "Failed to find directory '" << path << "'.";
@@ -304,8 +316,9 @@
path += OS_PATH_SEPARATOR;
}
- return std::unique_ptr<DirectoryAssetsProvider>(new DirectoryAssetsProvider(std::move(path),
- sb.st_mtime));
+ const bool isReadonly = isReadonlyFilesystem(path.c_str());
+ return std::unique_ptr<DirectoryAssetsProvider>(
+ new DirectoryAssetsProvider(std::move(path), isReadonly ? -1 : sb.st_mtime));
}
std::unique_ptr<Asset> DirectoryAssetsProvider::OpenInternal(const std::string& path,
@@ -335,7 +348,10 @@
}
bool DirectoryAssetsProvider::IsUpToDate() const {
- struct stat sb{};
+ if (last_mod_time_ == -1) {
+ return true;
+ }
+ struct stat sb;
if (stat(dir_.c_str(), &sb) < 0) {
// If stat fails on the zip archive, return true so the zip archive the resource system does
// attempt to refresh the ApkAsset.
@@ -431,4 +447,4 @@
return true;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index 386f718..c0fdfe2 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -645,16 +645,16 @@
}
std::string name;
- util::ReadUtf16StringFromDevice(overlayable->name, arraysize(overlayable->name), &name);
+ util::ReadUtf16StringFromDevice(overlayable->name, std::size(overlayable->name), &name);
std::string actor;
- util::ReadUtf16StringFromDevice(overlayable->actor, arraysize(overlayable->actor), &actor);
-
- if (loaded_package->overlayable_map_.find(name) !=
- loaded_package->overlayable_map_.end()) {
- LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'.";
+ util::ReadUtf16StringFromDevice(overlayable->actor, std::size(overlayable->actor), &actor);
+ auto [name_to_actor_it, inserted] =
+ loaded_package->overlayable_map_.emplace(std::move(name), std::move(actor));
+ if (!inserted) {
+ LOG(ERROR) << "Multiple <overlayable> blocks with the same name '"
+ << name_to_actor_it->first << "'.";
return {};
}
- loaded_package->overlayable_map_.emplace(name, actor);
// Iterate over the overlayable policy chunks contained within the overlayable chunk data
ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
@@ -669,7 +669,6 @@
LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small.";
return {};
}
-
if ((overlayable_child_chunk.data_size() / sizeof(ResTable_ref))
< dtohl(policy_header->entry_count)) {
LOG(ERROR) << "RES_TABLE_OVERLAYABLE_POLICY_TYPE too small to hold entries.";
@@ -691,8 +690,8 @@
// Add the pairing of overlayable properties and resource ids to the package
OverlayableInfo overlayable_info {
- .name = name,
- .actor = actor,
+ .name = name_to_actor_it->first,
+ .actor = name_to_actor_it->second,
.policy_flags = policy_header->policy_flags
};
loaded_package->overlayable_infos_.emplace_back(std::move(overlayable_info), std::move(ids));
@@ -736,6 +735,7 @@
const auto entry_end = entry_begin + dtohl(lib_alias->count);
std::unordered_set<uint32_t> finalized_ids;
finalized_ids.reserve(entry_end - entry_begin);
+ loaded_package->alias_id_map_.reserve(entry_end - entry_begin);
for (auto entry_iter = entry_begin; entry_iter != entry_end; ++entry_iter) {
if (!entry_iter) {
LOG(ERROR) << "NULL ResTable_staged_alias_entry record??";
@@ -749,13 +749,20 @@
}
auto staged_id = dtohl(entry_iter->stagedResId);
- auto [_, success] = loaded_package->alias_id_map_.emplace(staged_id, finalized_id);
- if (!success) {
+ loaded_package->alias_id_map_.emplace_back(staged_id, finalized_id);
+ }
+
+ std::sort(loaded_package->alias_id_map_.begin(), loaded_package->alias_id_map_.end(),
+ [](auto&& l, auto&& r) { return l.first < r.first; });
+ const auto duplicate_it =
+ std::adjacent_find(loaded_package->alias_id_map_.begin(),
+ loaded_package->alias_id_map_.end(),
+ [](auto&& l, auto&& r) { return l.first == r.first; });
+ if (duplicate_it != loaded_package->alias_id_map_.end()) {
LOG(ERROR) << StringPrintf("Repeated staged resource id '%08x' in staged aliases.",
- staged_id);
+ duplicate_it->first);
return {};
}
- }
} break;
default:
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index e9aaedc..e4d1218 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -17,6 +17,7 @@
#ifndef ANDROIDFW_ASSETMANAGER2_H_
#define ANDROIDFW_ASSETMANAGER2_H_
+#include "android-base/function_ref.h"
#include "android-base/macros.h"
#include <array>
@@ -320,17 +321,8 @@
// Creates a new Theme from this AssetManager.
std::unique_ptr<Theme> NewTheme();
- void ForEachPackage(const std::function<bool(const std::string&, uint8_t)> func,
- package_property_t excluded_property_flags = 0U) const {
- for (const PackageGroup& package_group : package_groups_) {
- const auto loaded_package = package_group.packages_.front().loaded_package_;
- if ((loaded_package->GetPropertyFlags() & excluded_property_flags) == 0U
- && !func(loaded_package->GetPackageName(),
- package_group.dynamic_ref_table->mAssignedPackageId)) {
- return;
- }
- }
- }
+ void ForEachPackage(base::function_ref<bool(const std::string&, uint8_t)> func,
+ package_property_t excluded_property_flags = 0U) const;
void DumpToLog() const;
@@ -571,6 +563,7 @@
AssetManager2* asset_manager_ = nullptr;
uint32_t type_spec_flags_ = 0u;
+ std::vector<uint32_t> keys_;
std::vector<Entry> entries_;
};
diff --git a/libs/androidfw/include/androidfw/AssetsProvider.h b/libs/androidfw/include/androidfw/AssetsProvider.h
index af6e7f4..7891194 100644
--- a/libs/androidfw/include/androidfw/AssetsProvider.h
+++ b/libs/androidfw/include/androidfw/AssetsProvider.h
@@ -80,8 +80,8 @@
// Supplies assets from a zip archive.
struct ZipAssetsProvider : public AssetsProvider {
- static std::unique_ptr<ZipAssetsProvider> Create(std::string path,
- package_property_t flags);
+ static std::unique_ptr<ZipAssetsProvider> Create(std::string path, package_property_t flags,
+ base::unique_fd fd = {});
static std::unique_ptr<ZipAssetsProvider> Create(base::unique_fd fd,
std::string friendly_name,
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index 05a2c4d..ca0a9ed 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -17,6 +17,7 @@
#ifndef __BYTE_BUCKET_ARRAY_H
#define __BYTE_BUCKET_ARRAY_H
+#include <algorithm>
#include <cstdint>
#include <cstring>
@@ -36,15 +37,11 @@
}
~ByteBucketArray() {
- clear();
+ deleteBuckets();
}
void clear() {
- for (size_t i = 0; i < kNumBuckets; i++) {
- if (buckets_[i] != NULL) {
- delete[] buckets_[i];
- }
- }
+ deleteBuckets();
memset(buckets_, 0, sizeof(buckets_));
}
@@ -59,7 +56,7 @@
uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
T* bucket = buckets_[bucket_index];
- if (bucket == NULL) {
+ if (bucket == nullptr) {
return default_;
}
return bucket[0x0f & static_cast<uint8_t>(index)];
@@ -70,9 +67,9 @@
<< ") with size=" << size();
uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
- T* bucket = buckets_[bucket_index];
- if (bucket == NULL) {
- bucket = buckets_[bucket_index] = new T[kBucketSize]();
+ T*& bucket = buckets_[bucket_index];
+ if (bucket == nullptr) {
+ bucket = new T[kBucketSize]();
}
return bucket[0x0f & static_cast<uint8_t>(index)];
}
@@ -86,9 +83,42 @@
return true;
}
+ template <class Func>
+ void forEachItem(Func f) {
+ for (size_t i = 0; i < kNumBuckets; i++) {
+ const auto bucket = buckets_[i];
+ if (bucket != nullptr) {
+ for (size_t j = 0; j < kBucketSize; j++) {
+ f((i << 4) | j, bucket[j]);
+ }
+ }
+ }
+ }
+
+ template <class Func>
+ void trimBuckets(Func isEmptyFunc) {
+ for (size_t i = 0; i < kNumBuckets; i++) {
+ const auto bucket = buckets_[i];
+ if (bucket != nullptr) {
+ if (std::all_of(bucket, bucket + kBucketSize, isEmptyFunc)) {
+ delete[] bucket;
+ buckets_[i] = nullptr;
+ }
+ }
+ }
+ }
+
private:
enum { kNumBuckets = 16, kBucketSize = 16 };
+ void deleteBuckets() {
+ for (size_t i = 0; i < kNumBuckets; i++) {
+ if (buckets_[i] != nullptr) {
+ delete[] buckets_[i];
+ }
+ }
+ }
+
T* buckets_[kNumBuckets];
static inline const T default_ = {};
};
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index 79d96282..4d12885 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -99,8 +99,8 @@
};
struct OverlayableInfo {
- std::string name;
- std::string actor;
+ std::string_view name;
+ std::string_view actor;
uint32_t policy_flags;
};
@@ -275,7 +275,7 @@
return overlayable_map_;
}
- const std::map<uint32_t, uint32_t>& GetAliasResourceIdMap() const {
+ const std::vector<std::pair<uint32_t, uint32_t>>& GetAliasResourceIdMap() const {
return alias_id_map_;
}
@@ -295,8 +295,8 @@
std::unordered_map<uint8_t, TypeSpec> type_specs_;
ByteBucketArray<uint32_t> resource_ids_;
std::vector<DynamicPackageEntry> dynamic_package_map_;
- std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
- std::map<uint32_t, uint32_t> alias_id_map_;
+ std::vector<std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+ std::vector<std::pair<uint32_t, uint32_t>> alias_id_map_;
// A map of overlayable name to actor
std::unordered_map<std::string, std::string> overlayable_map_;
diff --git a/libs/androidfw/include/androidfw/misc.h b/libs/androidfw/include/androidfw/misc.h
index 5a5a0e2..d40d24e 100644
--- a/libs/androidfw/include/androidfw/misc.h
+++ b/libs/androidfw/include/androidfw/misc.h
@@ -44,6 +44,10 @@
/* get the file's modification date; returns -1 w/errno set on failure */
time_t getFileModDate(const char* fileName);
+// Check if |path| or |fd| resides on a readonly filesystem.
+bool isReadonlyFilesystem(const char* path);
+bool isReadonlyFilesystem(int fd);
+
}; // namespace android
#endif // _LIBS_ANDROID_FW_MISC_H
diff --git a/libs/androidfw/misc.cpp b/libs/androidfw/misc.cpp
index 5285420..7af5066 100644
--- a/libs/androidfw/misc.cpp
+++ b/libs/androidfw/misc.cpp
@@ -21,12 +21,17 @@
//
#include <androidfw/misc.h>
-#include <sys/stat.h>
-#include <cstring>
-#include <errno.h>
-#include <cstdio>
+#include "android-base/logging.h"
-using namespace android;
+#ifndef _WIN32
+#include <sys/statvfs.h>
+#include <sys/vfs.h>
+#endif // _WIN32
+
+#include <cstring>
+#include <cstdio>
+#include <errno.h>
+#include <sys/stat.h>
namespace android {
@@ -41,8 +46,7 @@
if (errno == ENOENT || errno == ENOTDIR)
return kFileTypeNonexistent;
else {
- fprintf(stderr, "getFileType got errno=%d on '%s'\n",
- errno, fileName);
+ PLOG(ERROR) << "getFileType(): stat(" << fileName << ") failed";
return kFileTypeUnknown;
}
} else {
@@ -82,4 +86,32 @@
return sb.st_mtime;
}
+#ifdef _WIN32
+// No need to implement these for Windows, the functions only matter on a device.
+bool isReadonlyFilesystem(const char*) {
+ return false;
+}
+bool isReadonlyFilesystem(int) {
+ return false;
+}
+#else // _WIN32
+bool isReadonlyFilesystem(const char* path) {
+ struct statfs sfs;
+ if (::statfs(path, &sfs)) {
+ PLOG(ERROR) << "isReadonlyFilesystem(): statfs(" << path << ") failed";
+ return false;
+ }
+ return (sfs.f_flags & ST_RDONLY) != 0;
+}
+
+bool isReadonlyFilesystem(int fd) {
+ struct statfs sfs;
+ if (::fstatfs(fd, &sfs)) {
+ PLOG(ERROR) << "isReadonlyFilesystem(): fstatfs(" << fd << ") failed";
+ return false;
+ }
+ return (sfs.f_flags & ST_RDONLY) != 0;
+}
+#endif // _WIN32
+
}; // namespace android
diff --git a/libs/androidfw/tests/ByteBucketArray_test.cpp b/libs/androidfw/tests/ByteBucketArray_test.cpp
index 5d464c7..9c36cfb 100644
--- a/libs/androidfw/tests/ByteBucketArray_test.cpp
+++ b/libs/androidfw/tests/ByteBucketArray_test.cpp
@@ -52,4 +52,57 @@
}
}
+TEST(ByteBucketArrayTest, TestForEach) {
+ ByteBucketArray<int> bba;
+ ASSERT_TRUE(bba.set(0, 1));
+ ASSERT_TRUE(bba.set(10, 2));
+ ASSERT_TRUE(bba.set(26, 3));
+ ASSERT_TRUE(bba.set(129, 4));
+ ASSERT_TRUE(bba.set(234, 5));
+
+ int count = 0;
+ bba.forEachItem([&count](auto i, auto val) {
+ ++count;
+ switch (i) {
+ case 0:
+ EXPECT_EQ(1, val);
+ break;
+ case 10:
+ EXPECT_EQ(2, val);
+ break;
+ case 26:
+ EXPECT_EQ(3, val);
+ break;
+ case 129:
+ EXPECT_EQ(4, val);
+ break;
+ case 234:
+ EXPECT_EQ(5, val);
+ break;
+ default:
+ EXPECT_EQ(0, val);
+ break;
+ }
+ });
+ ASSERT_EQ(4 * 16, count);
+}
+
+TEST(ByteBucketArrayTest, TestTrimBuckets) {
+ ByteBucketArray<int> bba;
+ ASSERT_TRUE(bba.set(0, 1));
+ ASSERT_TRUE(bba.set(255, 2));
+ {
+ bba.trimBuckets([](auto val) { return val < 2; });
+ int count = 0;
+ bba.forEachItem([&count](auto, auto) { ++count; });
+ ASSERT_EQ(1 * 16, count);
+ }
+ {
+ bba.trimBuckets([](auto val) { return val < 3; });
+ int count = 0;
+ bba.forEachItem([&count](auto, auto) { ++count; });
+ ASSERT_EQ(0, count);
+ }
+}
+
} // namespace android
diff --git a/services/core/java/com/android/server/BinaryTransparencyService.java b/services/core/java/com/android/server/BinaryTransparencyService.java
index 68880bd..59024e7 100644
--- a/services/core/java/com/android/server/BinaryTransparencyService.java
+++ b/services/core/java/com/android/server/BinaryTransparencyService.java
@@ -489,24 +489,10 @@
Integer algorithmId = entry.getKey();
byte[] contentDigest = entry.getValue();
- // TODO(b/259348134): consider refactoring the following to a helper method
- switch (algorithmId) {
- case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
- pw.print("CHUNKED_SHA256:");
- break;
- case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
- pw.print("CHUNKED_SHA512:");
- break;
- case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
- pw.print("VERITY_CHUNKED_SHA256:");
- break;
- case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
- pw.print("SHA256:");
- break;
- default:
- pw.print("UNKNOWN_ALGO_ID(" + algorithmId + "):");
- }
+ pw.print(translateContentDigestAlgorithmIdToString(algorithmId));
+ pw.print(":");
pw.print(HexEncoding.encodeToString(contentDigest, false));
+ pw.print("\n");
}
}
@@ -533,31 +519,13 @@
pw.println("ERROR: Failed to compute package content digest for "
+ origPackageFilepath);
} else {
- // TODO(b/259348134): consider refactoring this to a helper method
for (Map.Entry<Integer, byte[]> entry : contentDigests.entrySet()) {
Integer algorithmId = entry.getKey();
byte[] contentDigest = entry.getValue();
- pw.print("|--> Pre-installed package content digest algorithm: ");
- switch (algorithmId) {
- case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
- pw.print("CHUNKED_SHA256");
- break;
- case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
- pw.print("CHUNKED_SHA512");
- break;
- case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
- pw.print("VERITY_CHUNKED_SHA256");
- break;
- case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
- pw.print("SHA256");
- break;
- default:
- pw.print("UNKNOWN");
- }
- pw.print("\n");
- pw.print("|--> Pre-installed package content digest: ");
- pw.print(HexEncoding.encodeToString(contentDigest, false));
- pw.print("\n");
+ pw.println("|--> Pre-installed package content digest: "
+ + HexEncoding.encodeToString(contentDigest, false));
+ pw.println("|--> Pre-installed package content digest algorithm: "
+ + translateContentDigestAlgorithmIdToString(algorithmId));
}
}
}
@@ -739,7 +707,6 @@
pw.print(packageName + ","
+ packageInfo.getLongVersionCode() + ",");
printPackageMeasurements(packageInfo, pw);
- pw.print("\n");
if (verbose) {
ModuleInfo moduleInfo;
@@ -802,7 +769,6 @@
pw.print(packageInfo.packageName + ",");
pw.print(packageInfo.getLongVersionCode() + ",");
printPackageMeasurements(packageInfo, pw);
- pw.print("\n");
if (verbose) {
printModuleDetails(module, pw);
@@ -858,7 +824,6 @@
pw.print(packageInfo.packageName + ",");
pw.print(packageInfo.getLongVersionCode() + ",");
printPackageMeasurements(packageInfo, pw);
- pw.print("\n");
if (verbose) {
printAppDetails(packageInfo, printLibraries, pw);
@@ -1079,6 +1044,21 @@
FrameworkStatsLog.write(FrameworkStatsLog.VBMETA_DIGEST_REPORTED, mVbmetaDigest);
}
+ private String translateContentDigestAlgorithmIdToString(int algorithmId) {
+ switch (algorithmId) {
+ case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA256:
+ return "CHUNKED_SHA256";
+ case ApkSigningBlockUtils.CONTENT_DIGEST_CHUNKED_SHA512:
+ return "CHUNKED_SHA512";
+ case ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256:
+ return "VERITY_CHUNKED_SHA256";
+ case ApkSigningBlockUtils.CONTENT_DIGEST_SHA256:
+ return "SHA256";
+ default:
+ return "UNKNOWN_ALGO_ID(" + algorithmId + ")";
+ }
+ }
+
@NonNull
private List<PackageInfo> getCurrentInstalledApexs() {
List<PackageInfo> results = new ArrayList<>();
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index b56d1fc..b4ab254 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -447,6 +447,13 @@
thread.start();
break;
case LEVEL_FACTORY_RESET:
+ // Before the completion of Reboot, if any crash happens then PackageWatchdog
+ // escalates to next level i.e. factory reset, as they happen in separate threads.
+ // Adding a check to prevent factory reset to execute before above reboot completes.
+ // Note: this reboot property is not persistent resets after reboot is completed.
+ if (isRebootPropertySet()) {
+ break;
+ }
SystemProperties.set(PROP_ATTEMPTING_FACTORY_RESET, "true");
runnable = new Runnable() {
@Override
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index ca86021c..bd90d85 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -52,8 +52,8 @@
import android.telephony.Annotation.RadioPowerState;
import android.telephony.Annotation.SrvccState;
import android.telephony.BarringInfo;
-import android.telephony.CallAttributes;
import android.telephony.CallQuality;
+import android.telephony.CallState;
import android.telephony.CellIdentity;
import android.telephony.CellInfo;
import android.telephony.CellSignalStrength;
@@ -82,6 +82,7 @@
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.emergency.EmergencyNumber;
+import android.telephony.ims.ImsCallSession;
import android.telephony.ims.ImsReasonInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -349,9 +350,9 @@
private CallQuality[] mCallQuality;
- private CallAttributes[] mCallAttributes;
+ private ArrayList<List<CallState>> mCallStateLists;
- // network type of the call associated with the mCallAttributes and mCallQuality
+ // network type of the call associated with the mCallStateLists and mCallQuality
private int[] mCallNetworkType;
private int[] mSrvccState;
@@ -687,7 +688,6 @@
mCallPreciseDisconnectCause = copyOf(mCallPreciseDisconnectCause, mNumPhones);
mCallQuality = copyOf(mCallQuality, mNumPhones);
mCallNetworkType = copyOf(mCallNetworkType, mNumPhones);
- mCallAttributes = copyOf(mCallAttributes, mNumPhones);
mOutgoingCallEmergencyNumber = copyOf(mOutgoingCallEmergencyNumber, mNumPhones);
mOutgoingSmsEmergencyNumber = copyOf(mOutgoingSmsEmergencyNumber, mNumPhones);
mTelephonyDisplayInfos = copyOf(mTelephonyDisplayInfos, mNumPhones);
@@ -707,6 +707,7 @@
cutListToSize(mLinkCapacityEstimateLists, mNumPhones);
cutListToSize(mCarrierPrivilegeStates, mNumPhones);
cutListToSize(mCarrierServiceStates, mNumPhones);
+ cutListToSize(mCallStateLists, mNumPhones);
return;
}
@@ -730,8 +731,7 @@
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
mCallQuality[i] = createCallQuality();
- mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+ mCallStateLists.add(i, new ArrayList<>());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = createPreciseCallState();
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -799,7 +799,7 @@
mCallPreciseDisconnectCause = new int[numPhones];
mCallQuality = new CallQuality[numPhones];
mCallNetworkType = new int[numPhones];
- mCallAttributes = new CallAttributes[numPhones];
+ mCallStateLists = new ArrayList<>();
mPreciseDataConnectionStates = new ArrayList<>();
mCellInfo = new ArrayList<>(numPhones);
mImsReasonInfo = new ArrayList<>();
@@ -837,8 +837,7 @@
mCallDisconnectCause[i] = DisconnectCause.NOT_VALID;
mCallPreciseDisconnectCause[i] = PreciseDisconnectCause.NOT_VALID;
mCallQuality[i] = createCallQuality();
- mCallAttributes[i] = new CallAttributes(createPreciseCallState(),
- TelephonyManager.NETWORK_TYPE_UNKNOWN, createCallQuality());
+ mCallStateLists.add(i, new ArrayList<>());
mCallNetworkType[i] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mPreciseCallState[i] = createPreciseCallState();
mRingingCallState[i] = PreciseCallState.PRECISE_CALL_STATE_IDLE;
@@ -1336,7 +1335,7 @@
}
if (events.contains(TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)) {
try {
- r.callback.onCallAttributesChanged(mCallAttributes[r.phoneId]);
+ r.callback.onCallStatesChanged(mCallStateLists.get(r.phoneId));
} catch (RemoteException ex) {
remove(r.binder);
}
@@ -2171,11 +2170,30 @@
}
}
- public void notifyPreciseCallState(int phoneId, int subId, int ringingCallState,
- int foregroundCallState, int backgroundCallState) {
+ /**
+ * Send a notification to registrants that the precise call state has changed.
+ *
+ * @param phoneId the phoneId carrying the data connection
+ * @param subId the subscriptionId for the data connection
+ * @param callStates Array of PreciseCallState of foreground, background & ringing calls.
+ * @param imsCallIds Array of IMS call session ID{@link ImsCallSession#getCallId()} for
+ * ringing, foreground & background calls.
+ * @param imsServiceTypes Array of IMS call service type for ringing, foreground &
+ * background calls.
+ * @param imsCallTypes Array of IMS call type for ringing, foreground & background calls.
+ */
+ public void notifyPreciseCallState(int phoneId, int subId,
+ @Annotation.PreciseCallStates int[] callStates, String[] imsCallIds,
+ @Annotation.ImsCallServiceType int[] imsServiceTypes,
+ @Annotation.ImsCallType int[] imsCallTypes) {
if (!checkNotifyPermission("notifyPreciseCallState()")) {
return;
}
+
+ int ringingCallState = callStates[CallState.CALL_CLASSIFICATION_RINGING];
+ int foregroundCallState = callStates[CallState.CALL_CLASSIFICATION_FOREGROUND];
+ int backgroundCallState = callStates[CallState.CALL_CLASSIFICATION_BACKGROUND];
+
synchronized (mRecords) {
if (validatePhoneId(phoneId)) {
mRingingCallState[phoneId] = ringingCallState;
@@ -2186,11 +2204,11 @@
backgroundCallState,
DisconnectCause.NOT_VALID,
PreciseDisconnectCause.NOT_VALID);
- boolean notifyCallAttributes = true;
+ boolean notifyCallState = true;
if (mCallQuality == null) {
log("notifyPreciseCallState: mCallQuality is null, "
+ "skipping call attributes");
- notifyCallAttributes = false;
+ notifyCallState = false;
} else {
// If the precise call state is no longer active, reset the call network type
// and call quality.
@@ -2199,8 +2217,65 @@
mCallNetworkType[phoneId] = TelephonyManager.NETWORK_TYPE_UNKNOWN;
mCallQuality[phoneId] = createCallQuality();
}
- mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
- mCallNetworkType[phoneId], mCallQuality[phoneId]);
+ mCallStateLists.get(phoneId).clear();
+ if (foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+ && foregroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+ CallQuality callQuality = mCallQuality[phoneId];
+ CallState.Builder builder = new CallState.Builder(
+ callStates[CallState.CALL_CLASSIFICATION_FOREGROUND])
+ .setNetworkType(mCallNetworkType[phoneId])
+ .setCallQuality(callQuality)
+ .setCallClassification(
+ CallState.CALL_CLASSIFICATION_FOREGROUND);
+ if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+ builder = builder
+ .setImsCallSessionId(imsCallIds[
+ CallState.CALL_CLASSIFICATION_FOREGROUND])
+ .setImsCallServiceType(imsServiceTypes[
+ CallState.CALL_CLASSIFICATION_FOREGROUND])
+ .setImsCallType(imsCallTypes[
+ CallState.CALL_CLASSIFICATION_FOREGROUND]);
+ }
+ mCallStateLists.get(phoneId).add(builder.build());
+ }
+ if (backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+ && backgroundCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+ CallState.Builder builder = new CallState.Builder(
+ callStates[CallState.CALL_CLASSIFICATION_BACKGROUND])
+ .setNetworkType(mCallNetworkType[phoneId])
+ .setCallQuality(createCallQuality())
+ .setCallClassification(
+ CallState.CALL_CLASSIFICATION_BACKGROUND);
+ if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+ builder = builder
+ .setImsCallSessionId(imsCallIds[
+ CallState.CALL_CLASSIFICATION_BACKGROUND])
+ .setImsCallServiceType(imsServiceTypes[
+ CallState.CALL_CLASSIFICATION_BACKGROUND])
+ .setImsCallType(imsCallTypes[
+ CallState.CALL_CLASSIFICATION_BACKGROUND]);
+ }
+ mCallStateLists.get(phoneId).add(builder.build());
+ }
+ if (ringingCallState != PreciseCallState.PRECISE_CALL_STATE_NOT_VALID
+ && ringingCallState != PreciseCallState.PRECISE_CALL_STATE_IDLE) {
+ CallState.Builder builder = new CallState.Builder(
+ callStates[CallState.CALL_CLASSIFICATION_RINGING])
+ .setNetworkType(mCallNetworkType[phoneId])
+ .setCallQuality(createCallQuality())
+ .setCallClassification(
+ CallState.CALL_CLASSIFICATION_RINGING);
+ if (imsCallIds != null && imsServiceTypes != null && imsCallTypes != null) {
+ builder = builder
+ .setImsCallSessionId(imsCallIds[
+ CallState.CALL_CLASSIFICATION_RINGING])
+ .setImsCallServiceType(imsServiceTypes[
+ CallState.CALL_CLASSIFICATION_RINGING])
+ .setImsCallType(imsCallTypes[
+ CallState.CALL_CLASSIFICATION_RINGING]);
+ }
+ mCallStateLists.get(phoneId).add(builder.build());
+ }
}
for (Record r : mRecords) {
@@ -2213,11 +2288,11 @@
mRemoveList.add(r.binder);
}
}
- if (notifyCallAttributes && r.matchTelephonyCallbackEvent(
+ if (notifyCallState && r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
&& idMatch(r, subId, phoneId)) {
try {
- r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+ r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2515,15 +2590,29 @@
// merge CallQuality with PreciseCallState and network type
mCallQuality[phoneId] = callQuality;
mCallNetworkType[phoneId] = callNetworkType;
- mCallAttributes[phoneId] = new CallAttributes(mPreciseCallState[phoneId],
- callNetworkType, callQuality);
+ if (mCallStateLists.get(phoneId).size() > 0
+ && mCallStateLists.get(phoneId).get(0).getCallState()
+ == PreciseCallState.PRECISE_CALL_STATE_ACTIVE) {
+ CallState prev = mCallStateLists.get(phoneId).remove(0);
+ mCallStateLists.get(phoneId).add(
+ 0, new CallState.Builder(prev.getCallState())
+ .setNetworkType(callNetworkType)
+ .setCallQuality(callQuality)
+ .setCallClassification(prev.getCallClassification())
+ .setImsCallSessionId(prev.getImsCallSessionId())
+ .setImsCallServiceType(prev.getImsCallServiceType())
+ .setImsCallType(prev.getImsCallType()).build());
+ } else {
+ log("There is no active call to report CallQaulity");
+ return;
+ }
for (Record r : mRecords) {
if (r.matchTelephonyCallbackEvent(
TelephonyCallback.EVENT_CALL_ATTRIBUTES_CHANGED)
&& idMatch(r, subId, phoneId)) {
try {
- r.callback.onCallAttributesChanged(mCallAttributes[phoneId]);
+ r.callback.onCallStatesChanged(mCallStateLists.get(phoneId));
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -2991,7 +3080,6 @@
pw.println("mSrvccState=" + mSrvccState[i]);
pw.println("mCallPreciseDisconnectCause=" + mCallPreciseDisconnectCause[i]);
pw.println("mCallQuality=" + mCallQuality[i]);
- pw.println("mCallAttributes=" + mCallAttributes[i]);
pw.println("mCallNetworkType=" + mCallNetworkType[i]);
pw.println("mPreciseDataConnectionStates=" + mPreciseDataConnectionStates.get(i));
pw.println("mOutgoingCallEmergencyNumber=" + mOutgoingCallEmergencyNumber[i]);
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index b92c163..a954164 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -338,7 +338,18 @@
+ " and userId " + userId);
break;
}
+ if (mHandler.hasMessages(CANCEL_GAME_LOADING_MODE)) {
+ mHandler.removeMessages(CANCEL_GAME_LOADING_MODE);
+ }
mPowerManagerInternal.setPowerMode(Mode.GAME_LOADING, isLoading);
+ if (isLoading) {
+ int loadingBoostDuration = getLoadingBoostDuration(packageName, userId);
+ loadingBoostDuration = loadingBoostDuration > 0 ? loadingBoostDuration
+ : LOADING_BOOST_MAX_DURATION;
+ mHandler.sendMessageDelayed(
+ mHandler.obtainMessage(CANCEL_GAME_LOADING_MODE),
+ loadingBoostDuration);
+ }
}
break;
}
diff --git a/services/core/java/com/android/server/display/DisplayDeviceInfo.java b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
index a0cbd7f..8811999 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceInfo.java
@@ -23,6 +23,7 @@
import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
+import android.view.DisplayShape;
import android.view.RoundedCorners;
import android.view.Surface;
@@ -316,6 +317,11 @@
public RoundedCorners roundedCorners;
/**
+ * The {@link RoundedCorners} if present or {@code null} otherwise.
+ */
+ public DisplayShape displayShape;
+
+ /**
* The touch attachment, per {@link DisplayViewport#touch}.
*/
public int touch;
@@ -451,7 +457,8 @@
|| !BrightnessSynchronizer.floatEquals(brightnessDefault,
other.brightnessDefault)
|| !Objects.equals(roundedCorners, other.roundedCorners)
- || installOrientation != other.installOrientation) {
+ || installOrientation != other.installOrientation
+ || !Objects.equals(displayShape, other.displayShape)) {
diff |= DIFF_OTHER;
}
return diff;
@@ -497,6 +504,7 @@
brightnessDefault = other.brightnessDefault;
roundedCorners = other.roundedCorners;
installOrientation = other.installOrientation;
+ displayShape = other.displayShape;
}
// For debugging purposes
@@ -546,6 +554,9 @@
}
sb.append(flagsToString(flags));
sb.append(", installOrientation ").append(installOrientation);
+ if (displayShape != null) {
+ sb.append(", displayShape ").append(displayShape);
+ }
sb.append("}");
return sb.toString();
}
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 5a714f5..4bf1e98 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -38,6 +38,7 @@
import android.view.DisplayAddress;
import android.view.DisplayCutout;
import android.view.DisplayEventReceiver;
+import android.view.DisplayShape;
import android.view.RoundedCorners;
import android.view.SurfaceControl;
@@ -686,6 +687,9 @@
res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
mInfo.installOrientation = mStaticDisplayInfo.installOrientation;
+ mInfo.displayShape = DisplayShape.fromResources(
+ res, mInfo.uniqueId, maxWidth, maxHeight, mInfo.width, mInfo.height);
+
if (mStaticDisplayInfo.isInternal) {
mInfo.type = Display.TYPE_INTERNAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index 26ac528..28bdce3 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -233,6 +233,7 @@
info.displayCutout = mOverrideDisplayInfo.displayCutout;
info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
info.roundedCorners = mOverrideDisplayInfo.roundedCorners;
+ info.displayShape = mOverrideDisplayInfo.displayShape;
}
mInfo.set(info);
}
@@ -437,6 +438,7 @@
mBaseDisplayInfo.brightnessDefault = deviceInfo.brightnessDefault;
mBaseDisplayInfo.roundedCorners = deviceInfo.roundedCorners;
mBaseDisplayInfo.installOrientation = deviceInfo.installOrientation;
+ mBaseDisplayInfo.displayShape = deviceInfo.displayShape;
mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo.set(null);
}
diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
index b0de844..0e11b53 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -29,6 +29,7 @@
import android.util.DisplayMetrics;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayShape;
import android.view.Gravity;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -361,6 +362,8 @@
mInfo.state = mState;
// The display is trusted since it is created by system.
mInfo.flags |= FLAG_TRUSTED;
+ mInfo.displayShape =
+ DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
}
return mInfo;
}
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index a23a073..d0e518b 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -52,6 +52,7 @@
import android.util.ArrayMap;
import android.util.Slog;
import android.view.Display;
+import android.view.DisplayShape;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -524,6 +525,9 @@
mInfo.ownerUid = mOwnerUid;
mInfo.ownerPackageName = mOwnerPackageName;
+
+ mInfo.displayShape =
+ DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
}
return mInfo;
}
diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
index 146b003..c759d98 100644
--- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java
@@ -34,6 +34,7 @@
import android.util.Slog;
import android.view.Display;
import android.view.DisplayAddress;
+import android.view.DisplayShape;
import android.view.Surface;
import android.view.SurfaceControl;
@@ -655,6 +656,8 @@
mInfo.setAssumedDensityForExternalDisplay(mWidth, mHeight);
// The display is trusted since it is created by system.
mInfo.flags |= DisplayDeviceInfo.FLAG_TRUSTED;
+ mInfo.displayShape =
+ DisplayShape.createDefaultDisplayShape(mInfo.width, mInfo.height, false);
}
return mInfo;
}
diff --git a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
index 015e576..c53f1a5 100644
--- a/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
+++ b/services/core/java/com/android/server/inputmethod/IInputMethodInvoker.java
@@ -110,11 +110,10 @@
@AnyThread
void initializeInternal(IBinder token, IInputMethodPrivilegedOperations privilegedOperations,
- int configChanges, @InputMethodNavButtonFlags int navigationBarFlags) {
+ @InputMethodNavButtonFlags int navigationBarFlags) {
final IInputMethod.InitParams params = new IInputMethod.InitParams();
params.token = token;
params.privilegedOperations = privilegedOperations;
- params.configChanges = configChanges;
params.navigationBarFlags = navigationBarFlags;
try {
mTarget.initializeInternal(params);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
index 4d67311..079234c 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodBindingController.java
@@ -296,7 +296,7 @@
if (DEBUG) Slog.v(TAG, "Initiating attach with token: " + mCurToken);
final InputMethodInfo info = mMethodMap.get(mSelectedMethodId);
mSupportsStylusHw = info.supportsStylusHandwriting();
- mService.initializeImeLocked(mCurMethod, mCurToken, info.getConfigChanges());
+ mService.initializeImeLocked(mCurMethod, mCurToken);
mService.scheduleNotifyImeUidToAudioService(mCurMethodUid);
mService.reRequestCurrentClientSessionLocked();
mService.performOnCreateInlineSuggestionsRequestLocked();
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 8b083bd..080d582 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2692,14 +2692,13 @@
}
@GuardedBy("ImfLock.class")
- void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token,
- @android.content.pm.ActivityInfo.Config int configChanges) {
+ void initializeImeLocked(@NonNull IInputMethodInvoker inputMethod, @NonNull IBinder token) {
if (DEBUG) {
Slog.v(TAG, "Sending attach of token: " + token + " for display: "
+ mCurTokenDisplayId);
}
inputMethod.initializeInternal(token, new InputMethodPrivilegedOperationsImpl(this, token),
- configChanges, getInputMethodNavButtonFlagsLocked());
+ getInputMethodNavButtonFlagsLocked());
}
@AnyThread
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 02a57b2..b5c1206 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3358,13 +3358,13 @@
Slogf.wtf(LOG_TAG, "emulateSystemUserModeIfNeeded(): no system user data");
return;
}
+ final int oldMainUserId = getMainUserIdUnchecked();
final int oldFlags = systemUserData.info.flags;
final int newFlags;
final String newUserType;
- // TODO(b/256624031): Also handle FLAG_MAIN
if (newHeadlessSystemUserMode) {
newUserType = UserManager.USER_TYPE_SYSTEM_HEADLESS;
- newFlags = oldFlags & ~UserInfo.FLAG_FULL;
+ newFlags = oldFlags & ~UserInfo.FLAG_FULL & ~UserInfo.FLAG_MAIN;
} else {
newUserType = UserManager.USER_TYPE_FULL_SYSTEM;
newFlags = oldFlags | UserInfo.FLAG_FULL;
@@ -3379,9 +3379,38 @@
+ "%s, flags changed from %s to %s",
systemUserData.info.userType, newUserType,
UserInfo.flagsToString(oldFlags), UserInfo.flagsToString(newFlags));
+
systemUserData.info.userType = newUserType;
systemUserData.info.flags = newFlags;
writeUserLP(systemUserData);
+
+ // Switch the MainUser to a reasonable choice if needed.
+ // (But if there was no MainUser, we deliberately continue to have no MainUser.)
+ final UserData oldMain = getUserDataNoChecks(oldMainUserId);
+ if (newHeadlessSystemUserMode) {
+ if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) != 0) {
+ // System was MainUser. So we need a new choice for Main. Pick the oldest.
+ // If no oldest, don't set any. Let the BootUserInitializer do that later.
+ final UserInfo newMainUser = getEarliestCreatedFullUser();
+ if (newMainUser != null) {
+ Slogf.i(LOG_TAG, "Designating user " + newMainUser.id + " to be Main");
+ newMainUser.flags |= UserInfo.FLAG_MAIN;
+ writeUserLP(getUserDataNoChecks(newMainUser.id));
+ }
+ }
+ } else {
+ // TODO(b/256624031): For now, we demand the Main user (if there is one) is
+ // always the system in non-HSUM. In the future, when we relax this, change how
+ // we handle MAIN.
+ if (oldMain != null && (oldMain.info.flags & UserInfo.FLAG_SYSTEM) == 0) {
+ // Someone else was the MainUser; transfer it to System.
+ Slogf.i(LOG_TAG, "Transferring Main to user 0 from " + oldMain.info.id);
+ oldMain.info.flags &= ~UserInfo.FLAG_MAIN;
+ systemUserData.info.flags |= UserInfo.FLAG_MAIN;
+ writeUserLP(oldMain);
+ writeUserLP(systemUserData);
+ }
+ }
}
}
@@ -3658,8 +3687,10 @@
// Add FLAG_MAIN
if (isHeadlessSystemUserMode()) {
final UserInfo earliestCreatedUser = getEarliestCreatedFullUser();
- earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
- userIdsToWrite.add(earliestCreatedUser.id);
+ if (earliestCreatedUser != null) {
+ earliestCreatedUser.flags |= UserInfo.FLAG_MAIN;
+ userIdsToWrite.add(earliestCreatedUser.id);
+ }
} else {
synchronized (mUsersLock) {
final UserData userData = mUsers.get(UserHandle.USER_SYSTEM);
@@ -3799,9 +3830,10 @@
userInfo.profileBadge = getFreeProfileBadgeLU(userInfo.profileGroupId, userInfo.userType);
}
- private UserInfo getEarliestCreatedFullUser() {
+ /** Returns the oldest Full Admin user, or null is if there none. */
+ private @Nullable UserInfo getEarliestCreatedFullUser() {
final List<UserInfo> users = getUsersInternal(true, true, true);
- UserInfo earliestUser = users.get(0);
+ UserInfo earliestUser = null;
long earliestCreationTime = Long.MAX_VALUE;
for (int i = 0; i < users.size(); i++) {
final UserInfo info = users.get(i);
diff --git a/services/core/java/com/android/server/utils/Slogf.java b/services/core/java/com/android/server/utils/Slogf.java
index e88ac63..6efbd89 100644
--- a/services/core/java/com/android/server/utils/Slogf.java
+++ b/services/core/java/com/android/server/utils/Slogf.java
@@ -162,7 +162,7 @@
}
/**
- * Logs a {@link Log.VEBOSE} message with an exception
+ * Logs a {@link Log.VEBOSE} message with a throwable
*
* <p><strong>Note: </strong>the message will only be formatted if {@link Log#VERBOSE} logging
* is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -170,10 +170,10 @@
* you're calling this method in a critical path, make sure to explicitly do the check before
* calling it.
*/
- public static void v(String tag, Exception exception, String format, @Nullable Object... args) {
+ public static void v(String tag, Throwable throwable, String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.VERBOSE)) return;
- v(tag, getMessage(format, args), exception);
+ v(tag, getMessage(format, args), throwable);
}
/**
@@ -192,7 +192,7 @@
}
/**
- * Logs a {@link Log.DEBUG} message with an exception
+ * Logs a {@link Log.DEBUG} message with a throwable
*
* <p><strong>Note: </strong>the message will only be formatted if {@link Log#DEBUG} logging
* is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -200,10 +200,10 @@
* you're calling this method in a critical path, make sure to explicitly do the check before
* calling it.
*/
- public static void d(String tag, Exception exception, String format, @Nullable Object... args) {
+ public static void d(String tag, Throwable throwable, String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.DEBUG)) return;
- d(tag, getMessage(format, args), exception);
+ d(tag, getMessage(format, args), throwable);
}
/**
@@ -222,7 +222,7 @@
}
/**
- * Logs a {@link Log.INFO} message with an exception
+ * Logs a {@link Log.INFO} message with a throwable
*
* <p><strong>Note: </strong>the message will only be formatted if {@link Log#INFO} logging
* is enabled for the given {@code tag}, but the compiler will still create an intermediate
@@ -230,10 +230,10 @@
* you're calling this method in a critical path, make sure to explicitly do the check before
* calling it.
*/
- public static void i(String tag, Exception exception, String format, @Nullable Object... args) {
+ public static void i(String tag, Throwable throwable, String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.INFO)) return;
- i(tag, getMessage(format, args), exception);
+ i(tag, getMessage(format, args), throwable);
}
/**
@@ -252,7 +252,7 @@
}
/**
- * Logs a {@link Log.WARN} message with an exception
+ * Logs a {@link Log.WARN} message with a throwable
*
* <p><strong>Note: </strong>the message will only be formatted if {@link Log#WARN} logging is
* enabled for the given {@code tag}, but the compiler will still create an intermediate array
@@ -260,10 +260,10 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
- public static void w(String tag, Exception exception, String format, @Nullable Object... args) {
+ public static void w(String tag, Throwable throwable, String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.WARN)) return;
- w(tag, getMessage(format, args), exception);
+ w(tag, getMessage(format, args), throwable);
}
/**
@@ -282,7 +282,7 @@
}
/**
- * Logs a {@link Log.ERROR} message with an exception
+ * Logs a {@link Log.ERROR} message with a throwable
*
* <p><strong>Note: </strong>the message will only be formatted if {@link Log#ERROR} logging is
* enabled for the given {@code tag}, but the compiler will still create an intermediate array
@@ -290,10 +290,10 @@
* calling this method in a critical path, make sure to explicitly do the check before calling
* it.
*/
- public static void e(String tag, Exception exception, String format, @Nullable Object... args) {
+ public static void e(String tag, Throwable throwable, String format, @Nullable Object... args) {
if (!isLoggable(tag, Log.ERROR)) return;
- e(tag, getMessage(format, args), exception);
+ e(tag, getMessage(format, args), throwable);
}
/**
@@ -304,11 +304,11 @@
}
/**
- * Logs a {@code wtf} message with an exception.
+ * Logs a {@code wtf} message with a throwable.
*/
- public static void wtf(String tag, Exception exception, String format,
+ public static void wtf(String tag, Throwable throwable, String format,
@Nullable Object... args) {
- wtf(tag, getMessage(format, args), exception);
+ wtf(tag, getMessage(format, args), throwable);
}
private static String getMessage(String format, @Nullable Object... args) {
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 530fa4d..12424c0 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -3317,9 +3317,17 @@
mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(resultGrants,
resultTo.getUriPermissionsLocked());
}
- if (mForceSendResultForMediaProjection) {
- resultTo.sendResult(this.getUid(), resultWho, requestCode, resultCode,
- resultData, resultGrants, true /* forceSendForMediaProjection */);
+ if (mForceSendResultForMediaProjection || resultTo.isState(RESUMED)) {
+ // Sending the result to the resultTo activity asynchronously to prevent the
+ // resultTo activity getting results before this Activity paused.
+ final ActivityRecord resultToActivity = resultTo;
+ mAtmService.mH.post(() -> {
+ synchronized (mAtmService.mGlobalLock) {
+ resultToActivity.sendResult(this.getUid(), resultWho, requestCode,
+ resultCode, resultData, resultGrants,
+ mForceSendResultForMediaProjection);
+ }
+ });
} else {
resultTo.addResultLocked(this, resultWho, requestCode, resultCode, resultData);
}
@@ -4630,7 +4638,7 @@
false /* forceSendForMediaProjection */);
}
- private void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
+ void sendResult(int callingUid, String resultWho, int requestCode, int resultCode,
Intent data, NeededUriGrants dataGrants, boolean forceSendForMediaProjection) {
if (callingUid > 0) {
mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(dataGrants,
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 5938e7f..0b16a4d 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -78,7 +78,6 @@
import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK;
-import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -2777,11 +2776,6 @@
errMsg = "The app:" + mCallingUid + "is not trusted to " + mStartActivity;
break;
}
- case EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT: {
- errMsg = "Cannot embed activity across TaskFragments for result, resultTo: "
- + mStartActivity.resultTo;
- break;
- }
default:
errMsg = "Unhandled embed result:" + result;
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9c920f53..d1122e1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -207,6 +207,7 @@
import android.view.Display;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.DisplayShape;
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
@@ -391,6 +392,10 @@
mPrivacyIndicatorBoundsCache = new
RotationCache<>(this::calculatePrivacyIndicatorBoundsForRotationUncached);
+ DisplayShape mInitialDisplayShape;
+ private final RotationCache<DisplayShape, DisplayShape> mDisplayShapeCache =
+ new RotationCache<>(this::calculateDisplayShapeForRotationUncached);
+
/**
* Overridden display size. Initialized with {@link #mInitialDisplayWidth}
* and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
@@ -1095,7 +1100,8 @@
mDisplayFrames = new DisplayFrames(mInsetsStateController.getRawInsetsState(),
mDisplayInfo, calculateDisplayCutoutForRotation(mDisplayInfo.rotation),
calculateRoundedCornersForRotation(mDisplayInfo.rotation),
- calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation));
+ calculatePrivacyIndicatorBoundsForRotation(mDisplayInfo.rotation),
+ calculateDisplayShapeForRotation(mDisplayInfo.rotation));
initializeDisplayBaseInfo();
mHoldScreenWakeLock = mWmService.mPowerManager.newWakeLock(
@@ -1969,8 +1975,9 @@
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
final PrivacyIndicatorBounds indicatorBounds =
calculatePrivacyIndicatorBoundsForRotation(rotation);
+ final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(), info,
- cutout, roundedCorners, indicatorBounds);
+ cutout, roundedCorners, indicatorBounds, displayShape);
token.applyFixedRotationTransform(info, displayFrames, mTmpConfiguration);
}
@@ -2178,6 +2185,7 @@
// Update application display metrics.
final DisplayCutout displayCutout = calculateDisplayCutoutForRotation(rotation);
final RoundedCorners roundedCorners = calculateRoundedCornersForRotation(rotation);
+ final DisplayShape displayShape = calculateDisplayShapeForRotation(rotation);
final Rect appFrame = mDisplayPolicy.getDecorInsetsInfo(rotation, dw, dh).mNonDecorFrame;
mDisplayInfo.rotation = rotation;
@@ -2194,6 +2202,7 @@
}
mDisplayInfo.displayCutout = displayCutout.isEmpty() ? null : displayCutout;
mDisplayInfo.roundedCorners = roundedCorners;
+ mDisplayInfo.displayShape = displayShape;
mDisplayInfo.getAppMetrics(mDisplayMetrics);
if (mDisplayScalingDisabled) {
mDisplayInfo.flags |= Display.FLAG_SCALING_DISABLED;
@@ -2280,6 +2289,23 @@
return bounds.rotate(rotation);
}
+ DisplayShape calculateDisplayShapeForRotation(int rotation) {
+ return mDisplayShapeCache.getOrCompute(mInitialDisplayShape, rotation);
+ }
+
+ private DisplayShape calculateDisplayShapeForRotationUncached(
+ DisplayShape displayShape, int rotation) {
+ if (displayShape == null) {
+ return DisplayShape.NONE;
+ }
+
+ if (rotation == ROTATION_0) {
+ return displayShape;
+ }
+
+ return displayShape.setRotation(rotation);
+ }
+
/**
* Compute display info and configuration according to the given rotation without changing
* current display.
@@ -2781,7 +2807,8 @@
return displayFrames.update(rotation, w, h,
calculateDisplayCutoutForRotation(rotation),
calculateRoundedCornersForRotation(rotation),
- calculatePrivacyIndicatorBoundsForRotation(rotation));
+ calculatePrivacyIndicatorBoundsForRotation(rotation),
+ calculateDisplayShapeForRotation(rotation));
}
@Override
@@ -2821,6 +2848,7 @@
mInitialRoundedCorners = mDisplayInfo.roundedCorners;
mCurrentPrivacyIndicatorBounds = new PrivacyIndicatorBounds(new Rect[4],
mDisplayInfo.rotation);
+ mInitialDisplayShape = mDisplayInfo.displayShape;
final Display.Mode maxDisplayMode =
DisplayUtils.getMaximumResolutionDisplayMode(mDisplayInfo.supportedModes);
mPhysicalDisplaySize = new Point(
@@ -2848,6 +2876,7 @@
? DisplayCutout.NO_CUTOUT : mDisplayInfo.displayCutout;
final String newUniqueId = mDisplayInfo.uniqueId;
final RoundedCorners newRoundedCorners = mDisplayInfo.roundedCorners;
+ final DisplayShape newDisplayShape = mDisplayInfo.displayShape;
final boolean displayMetricsChanged = mInitialDisplayWidth != newWidth
|| mInitialDisplayHeight != newHeight
@@ -2855,7 +2884,8 @@
|| mInitialPhysicalXDpi != newXDpi
|| mInitialPhysicalYDpi != newYDpi
|| !Objects.equals(mInitialDisplayCutout, newCutout)
- || !Objects.equals(mInitialRoundedCorners, newRoundedCorners);
+ || !Objects.equals(mInitialRoundedCorners, newRoundedCorners)
+ || !Objects.equals(mInitialDisplayShape, newDisplayShape);
final boolean physicalDisplayChanged = !newUniqueId.equals(mCurrentUniqueDisplayId);
if (displayMetricsChanged || physicalDisplayChanged) {
@@ -2893,6 +2923,7 @@
mInitialPhysicalYDpi = newYDpi;
mInitialDisplayCutout = newCutout;
mInitialRoundedCorners = newRoundedCorners;
+ mInitialDisplayShape = newDisplayShape;
mCurrentUniqueDisplayId = newUniqueId;
reconfigureDisplayLocked();
diff --git a/services/core/java/com/android/server/wm/DisplayFrames.java b/services/core/java/com/android/server/wm/DisplayFrames.java
index 33641f7..e984456 100644
--- a/services/core/java/com/android/server/wm/DisplayFrames.java
+++ b/services/core/java/com/android/server/wm/DisplayFrames.java
@@ -26,6 +26,7 @@
import android.util.proto.ProtoOutputStream;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.DisplayShape;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
import android.view.RoundedCorners;
@@ -56,10 +57,11 @@
public int mRotation;
public DisplayFrames(InsetsState insetsState, DisplayInfo info, DisplayCutout cutout,
- RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds) {
+ RoundedCorners roundedCorners, PrivacyIndicatorBounds indicatorBounds,
+ DisplayShape displayShape) {
mInsetsState = insetsState;
update(info.rotation, info.logicalWidth, info.logicalHeight, cutout, roundedCorners,
- indicatorBounds);
+ indicatorBounds, displayShape);
}
DisplayFrames() {
@@ -73,7 +75,8 @@
*/
public boolean update(int rotation, int w, int h, @NonNull DisplayCutout displayCutout,
@NonNull RoundedCorners roundedCorners,
- @NonNull PrivacyIndicatorBounds indicatorBounds) {
+ @NonNull PrivacyIndicatorBounds indicatorBounds,
+ @NonNull DisplayShape displayShape) {
final InsetsState state = mInsetsState;
final Rect safe = mDisplayCutoutSafe;
if (mRotation == rotation && mWidth == w && mHeight == h
@@ -91,6 +94,7 @@
state.setDisplayCutout(displayCutout);
state.setRoundedCorners(roundedCorners);
state.setPrivacyIndicatorBounds(indicatorBounds);
+ state.setDisplayShape(displayShape);
state.getDisplayCutoutSafe(safe);
if (safe.left > unrestricted.left) {
state.getSource(ITYPE_LEFT_DISPLAY_CUTOUT).setFrame(
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 91cb037..d3a3cf5 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -172,13 +172,6 @@
* indicate that an Activity can't be embedded because the Activity is started on a new task.
*/
static final int EMBEDDING_DISALLOWED_NEW_TASK = 3;
- /**
- * An embedding check result of
- * {@link ActivityStarter#canEmbedActivity(TaskFragment, ActivityRecord, Task)}:
- * indicate that an Activity can't be embedded because the Activity is started on a new
- * TaskFragment, e.g. start an Activity on a new TaskFragment for result.
- */
- static final int EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT = 4;
/**
* Embedding check results of {@link #isAllowedToEmbedActivity(ActivityRecord)} or
@@ -189,7 +182,6 @@
EMBEDDING_DISALLOWED_UNTRUSTED_HOST,
EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
EMBEDDING_DISALLOWED_NEW_TASK,
- EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
})
@interface EmbeddingCheckResult {}
@@ -616,14 +608,6 @@
return EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
}
- // Cannot embed activity across TaskFragments for activity result.
- // If the activity that started for result is finishing, it's likely that this start mode
- // is used to place an activity in the same task. Since the finishing activity won't be
- // able to get the results, so it's OK to embed in a different TaskFragment.
- if (a.resultTo != null && !a.resultTo.finishing && a.resultTo.getTaskFragment() != this) {
- return EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
- }
-
return EMBEDDING_ALLOWED;
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
index 51fa851..e7c384b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/RescuePartyTest.java
@@ -252,6 +252,7 @@
noteBoot(4);
assertTrue(RescueParty.isRebootPropertySet());
+ SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
noteBoot(5);
assertTrue(RescueParty.isFactoryResetPropertySet());
}
@@ -276,6 +277,7 @@
noteAppCrash(4, true);
assertTrue(RescueParty.isRebootPropertySet());
+ SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
noteAppCrash(5, true);
assertTrue(RescueParty.isFactoryResetPropertySet());
}
@@ -429,6 +431,27 @@
for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
noteBoot(i + 1);
}
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+ noteBoot(LEVEL_FACTORY_RESET + 1);
+ assertTrue(RescueParty.isAttemptingFactoryReset());
+ assertTrue(RescueParty.isFactoryResetPropertySet());
+ }
+
+ @Test
+ public void testIsAttemptingFactoryResetOnlyAfterRebootCompleted() {
+ for (int i = 0; i < LEVEL_FACTORY_RESET; i++) {
+ noteBoot(i + 1);
+ }
+ int mitigationCount = LEVEL_FACTORY_RESET + 1;
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ noteBoot(mitigationCount++);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ noteBoot(mitigationCount++);
+ assertFalse(RescueParty.isFactoryResetPropertySet());
+ noteBoot(mitigationCount++);
+ SystemProperties.set(RescueParty.PROP_ATTEMPTING_REBOOT, Boolean.toString(false));
+ noteBoot(mitigationCount + 1);
assertTrue(RescueParty.isAttemptingFactoryReset());
assertTrue(RescueParty.isFactoryResetPropertySet());
}
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index dc77762..8d2e1ec 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -17,6 +17,7 @@
package com.android.server.app;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+import static com.android.server.app.GameManagerService.CANCEL_GAME_LOADING_MODE;
import static com.android.server.app.GameManagerService.WRITE_SETTINGS;
import static org.junit.Assert.assertArrayEquals;
@@ -1454,7 +1455,58 @@
verify(mMockPowerManager, never()).setPowerMode(anyInt(), anyBoolean());
}
- private void setGameState(boolean isLoading) {
+ @Test
+ public void testSetGameStateLoading_withNoDeviceConfig() {
+ mockDeviceConfigNone();
+ mockModifyGameModeGranted();
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ gameManagerService.setGameMode(
+ mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ assertEquals(gameManagerService.getGameMode(mPackageName, USER_ID_1),
+ GameManager.GAME_MODE_PERFORMANCE);
+ int testMode = GameState.MODE_GAMEPLAY_INTERRUPTIBLE;
+ int testLabel = 99;
+ int testQuality = 123;
+ GameState gameState = new GameState(true, testMode, testLabel, testQuality);
+ assertEquals(testMode, gameState.getMode());
+ assertEquals(testLabel, gameState.getLabel());
+ assertEquals(testQuality, gameState.getQuality());
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ mTestLooper.dispatchAll();
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+ reset(mMockPowerManager);
+ assertTrue(
+ gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+ verify(mMockPowerManager, never()).setPowerMode(Mode.GAME_LOADING, false);
+ mTestLooper.moveTimeForward(GameManagerService.LOADING_BOOST_MAX_DURATION);
+ mTestLooper.dispatchAll();
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+ }
+
+ @Test
+ public void testSetGameStateLoading_withDeviceConfig() {
+ String configString = "mode=2,loadingBoost=2000";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configString);
+ mockModifyGameModeGranted();
+ GameManagerService gameManagerService = createServiceAndStartUser(USER_ID_1);
+ gameManagerService.setGameMode(
+ mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ GameState gameState = new GameState(true, GameState.MODE_GAMEPLAY_INTERRUPTIBLE, 99, 123);
+ gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
+ mTestLooper.dispatchAll();
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, true);
+ verify(mMockPowerManager, never()).setPowerMode(Mode.GAME_LOADING, false);
+ reset(mMockPowerManager);
+ assertTrue(
+ gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
+ mTestLooper.moveTimeForward(2000);
+ mTestLooper.dispatchAll();
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+ }
+
+ @Test
+ public void testSetGameStateNotLoading() {
mockDeviceConfigNone();
mockModifyGameModeGranted();
GameManagerService gameManagerService =
@@ -1462,27 +1514,19 @@
startUser(gameManagerService, USER_ID_1);
gameManagerService.setGameMode(
mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
- int testMode = GameState.MODE_NONE;
+ int testMode = GameState.MODE_GAMEPLAY_UNINTERRUPTIBLE;
int testLabel = 99;
int testQuality = 123;
- GameState gameState = new GameState(isLoading, testMode, testLabel, testQuality);
- assertEquals(isLoading, gameState.isLoading());
+ GameState gameState = new GameState(false, testMode, testLabel, testQuality);
+ assertFalse(gameState.isLoading());
assertEquals(testMode, gameState.getMode());
assertEquals(testLabel, gameState.getLabel());
assertEquals(testQuality, gameState.getQuality());
gameManagerService.setGameState(mPackageName, gameState, USER_ID_1);
mTestLooper.dispatchAll();
- verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, isLoading);
- }
-
- @Test
- public void testSetGameStateLoading() {
- setGameState(true);
- }
-
- @Test
- public void testSetGameStateNotLoading() {
- setGameState(false);
+ verify(mMockPowerManager, times(1)).setPowerMode(Mode.GAME_LOADING, false);
+ assertFalse(
+ gameManagerService.mHandler.hasMessages(CANCEL_GAME_LOADING_MODE));
}
private List<String> readGameModeInterventionList() throws Exception {
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index d41ac70..395e6ac 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -161,6 +161,10 @@
when(mMockedResources.getIntArray(
com.android.internal.R.array.config_autoBrightnessLevels))
.thenReturn(new int[]{});
+ when(mMockedResources.obtainTypedArray(R.array.config_displayShapeArray))
+ .thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray))
+ .thenReturn(mockArray);
}
@After
diff --git a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
index ae25c1b..cb59d37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/utils/SlogfTest.java
@@ -44,7 +44,7 @@
private MockitoSession mSession;
- private final Exception mException = new Exception("D'OH!");
+ private final Throwable mThrowable = new Throwable("D'OH!");
@Before
public void setup() {
@@ -78,10 +78,10 @@
}
@Test
- public void testV_msgAndException() {
- Slogf.v(TAG, "msg", mException);
+ public void testV_msgAndThrowable() {
+ Slogf.v(TAG, "msg", mThrowable);
- verify(()-> Slog.v(TAG, "msg", mException));
+ verify(()-> Slog.v(TAG, "msg", mThrowable));
}
@Test
@@ -103,12 +103,12 @@
}
@Test
- public void testV_msgFormattedWithException_enabled() {
+ public void testV_msgFormattedWithThrowable_enabled() {
enableLogging(Log.VERBOSE);
- Slogf.v(TAG, mException, "msg in a %s", "bottle");
+ Slogf.v(TAG, mThrowable, "msg in a %s", "bottle");
- verify(()-> Slog.v(TAG, "msg in a bottle", mException));
+ verify(()-> Slog.v(TAG, "msg in a bottle", mThrowable));
}
@Test
@@ -128,10 +128,10 @@
}
@Test
- public void testD_msgAndException() {
- Slogf.d(TAG, "msg", mException);
+ public void testD_msgAndThrowable() {
+ Slogf.d(TAG, "msg", mThrowable);
- verify(()-> Slog.d(TAG, "msg", mException));
+ verify(()-> Slog.d(TAG, "msg", mThrowable));
}
@Test
@@ -153,19 +153,19 @@
}
@Test
- public void testD_msgFormattedWithException_enabled() {
+ public void testD_msgFormattedWithThrowable_enabled() {
enableLogging(Log.DEBUG);
- Slogf.d(TAG, mException, "msg in a %s", "bottle");
+ Slogf.d(TAG, mThrowable, "msg in a %s", "bottle");
- verify(()-> Slog.d(TAG, "msg in a bottle", mException));
+ verify(()-> Slog.d(TAG, "msg in a bottle", mThrowable));
}
@Test
public void testD_msgFormattedWithException_disabled() {
disableLogging(Log.DEBUG);
- Slogf.d(TAG, mException, "msg in a %s", "bottle");
+ Slogf.d(TAG, mThrowable, "msg in a %s", "bottle");
verify(()-> Slog.d(eq(TAG), any(String.class), any(Throwable.class)), never());
}
@@ -178,10 +178,10 @@
}
@Test
- public void testI_msgAndException() {
- Slogf.i(TAG, "msg", mException);
+ public void testI_msgAndThrowable() {
+ Slogf.i(TAG, "msg", mThrowable);
- verify(()-> Slog.i(TAG, "msg", mException));
+ verify(()-> Slog.i(TAG, "msg", mThrowable));
}
@Test
@@ -203,19 +203,19 @@
}
@Test
- public void testI_msgFormattedWithException_enabled() {
+ public void testI_msgFormattedWithThrowable_enabled() {
enableLogging(Log.INFO);
- Slogf.i(TAG, mException, "msg in a %s", "bottle");
+ Slogf.i(TAG, mThrowable, "msg in a %s", "bottle");
- verify(()-> Slog.i(TAG, "msg in a bottle", mException));
+ verify(()-> Slog.i(TAG, "msg in a bottle", mThrowable));
}
@Test
public void testI_msgFormattedWithException_disabled() {
disableLogging(Log.INFO);
- Slogf.i(TAG, mException, "msg in a %s", "bottle");
+ Slogf.i(TAG, mThrowable, "msg in a %s", "bottle");
verify(()-> Slog.i(eq(TAG), any(String.class), any(Throwable.class)), never());
}
@@ -228,17 +228,17 @@
}
@Test
- public void testW_msgAndException() {
- Slogf.w(TAG, "msg", mException);
+ public void testW_msgAndThrowable() {
+ Slogf.w(TAG, "msg", mThrowable);
- verify(()-> Slog.w(TAG, "msg", mException));
+ verify(()-> Slog.w(TAG, "msg", mThrowable));
}
@Test
- public void testW_exception() {
- Slogf.w(TAG, mException);
+ public void testW_Throwable() {
+ Slogf.w(TAG, mThrowable);
- verify(()-> Slog.w(TAG, mException));
+ verify(()-> Slog.w(TAG, mThrowable));
}
@Test
@@ -260,19 +260,19 @@
}
@Test
- public void testW_msgFormattedWithException_enabled() {
+ public void testW_msgFormattedWithThrowable_enabled() {
enableLogging(Log.WARN);
- Slogf.w(TAG, mException, "msg in a %s", "bottle");
+ Slogf.w(TAG, mThrowable, "msg in a %s", "bottle");
- verify(()-> Slog.w(TAG, "msg in a bottle", mException));
+ verify(()-> Slog.w(TAG, "msg in a bottle", mThrowable));
}
@Test
public void testW_msgFormattedWithException_disabled() {
disableLogging(Log.WARN);
- Slogf.w(TAG, mException, "msg in a %s", "bottle");
+ Slogf.w(TAG, mThrowable, "msg in a %s", "bottle");
verify(()-> Slog.w(eq(TAG), any(String.class), any(Throwable.class)), never());
}
@@ -285,10 +285,10 @@
}
@Test
- public void testE_msgAndException() {
- Slogf.e(TAG, "msg", mException);
+ public void testE_msgAndThrowable() {
+ Slogf.e(TAG, "msg", mThrowable);
- verify(()-> Slog.e(TAG, "msg", mException));
+ verify(()-> Slog.e(TAG, "msg", mThrowable));
}
@Test
@@ -310,19 +310,19 @@
}
@Test
- public void testE_msgFormattedWithException_enabled() {
+ public void testE_msgFormattedWithThrowable_enabled() {
enableLogging(Log.ERROR);
- Slogf.e(TAG, mException, "msg in a %s", "bottle");
+ Slogf.e(TAG, mThrowable, "msg in a %s", "bottle");
- verify(()-> Slog.e(TAG, "msg in a bottle", mException));
+ verify(()-> Slog.e(TAG, "msg in a bottle", mThrowable));
}
@Test
public void testE_msgFormattedWithException_disabled() {
disableLogging(Log.ERROR);
- Slogf.e(TAG, mException, "msg in a %s", "bottle");
+ Slogf.e(TAG, mThrowable, "msg in a %s", "bottle");
verify(()-> Slog.e(eq(TAG), any(String.class), any(Throwable.class)), never());
}
@@ -335,17 +335,17 @@
}
@Test
- public void testWtf_msgAndException() {
- Slogf.wtf(TAG, "msg", mException);
+ public void testWtf_msgAndThrowable() {
+ Slogf.wtf(TAG, "msg", mThrowable);
- verify(()-> Slog.wtf(TAG, "msg", mException));
+ verify(()-> Slog.wtf(TAG, "msg", mThrowable));
}
@Test
- public void testWtf_exception() {
- Slogf.wtf(TAG, mException);
+ public void testWtf_Throwable() {
+ Slogf.wtf(TAG, mThrowable);
- verify(()-> Slog.wtf(TAG, mException));
+ verify(()-> Slog.wtf(TAG, mThrowable));
}
@Test
@@ -377,10 +377,10 @@
}
@Test
- public void testWtf_msgFormattedWithException() {
- Slogf.wtf(TAG, mException, "msg in a %s", "bottle");
+ public void testWtf_msgFormattedWithThrowable() {
+ Slogf.wtf(TAG, mThrowable, "msg in a %s", "bottle");
- verify(()-> Slog.wtf(TAG, "msg in a bottle", mException));
+ verify(()-> Slog.wtf(TAG, "msg in a bottle", mThrowable));
}
private void enableLogging(@Log.Level int level) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 1ab7d7e..a410eed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -1206,6 +1206,25 @@
}
}
+ @Test
+ public void testFinishActivityIfPossible_sendResultImmediatelyIfResumed() {
+ final Task task = new TaskBuilder(mSupervisor).build();
+ final TaskFragment taskFragment1 = createTaskFragmentWithActivity(task);
+ final TaskFragment taskFragment2 = createTaskFragmentWithActivity(task);
+ final ActivityRecord resultToActivity = taskFragment1.getTopMostActivity();
+ final ActivityRecord targetActivity = taskFragment2.getTopMostActivity();
+ resultToActivity.setState(RESUMED, "test");
+ targetActivity.setState(RESUMED, "test");
+ targetActivity.resultTo = resultToActivity;
+
+ clearInvocations(mAtm.getLifecycleManager());
+ targetActivity.finishIfPossible(0, new Intent(), null, "test", false /* oomAdj */);
+ waitUntilHandlersIdle();
+
+ verify(resultToActivity).sendResult(anyInt(), eq(null), anyInt(), anyInt(), any(), eq(null),
+ anyBoolean());
+ }
+
/**
* Verify that complete finish request for non-finishing activity is invalid.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 70b68c7..6733470 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -133,8 +133,8 @@
final RoundedCorners roundedCorners = mHasRoundedCorners
? mDisplayContent.calculateRoundedCornersForRotation(mRotation)
: RoundedCorners.NO_ROUNDED_CORNERS;
- return new DisplayFrames(insetsState, info,
- info.displayCutout, roundedCorners, new PrivacyIndicatorBounds());
+ return new DisplayFrames(insetsState, info, info.displayCutout, roundedCorners,
+ new PrivacyIndicatorBounds(), info.displayShape);
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index d99946f..10f2270 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -58,6 +58,7 @@
import android.graphics.Rect;
import android.platform.test.annotations.Presubmit;
import android.view.DisplayInfo;
+import android.view.DisplayShape;
import android.view.InsetsSource;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
@@ -321,7 +322,8 @@
final InsetsState state = mDisplayContent.getInsetsStateController().getRawInsetsState();
mImeWindow.mAboveInsetsState.set(state);
mDisplayContent.mDisplayFrames = new DisplayFrames(
- state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
+ state, displayInfo, NO_CUTOUT, NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(),
+ DisplayShape.NONE);
mDisplayContent.setInputMethodWindowLocked(mImeWindow);
mImeWindow.mAttrs.setFitInsetsSides(Side.all() & ~Side.BOTTOM);
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
index 4e796c5..8fda191 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java
@@ -24,7 +24,6 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.os.Process.FIRST_APPLICATION_UID;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
@@ -33,9 +32,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
-import static com.android.server.wm.TaskFragment.EMBEDDING_ALLOWED;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION;
-import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT;
import static com.android.server.wm.TaskFragment.EMBEDDING_DISALLOWED_UNTRUSTED_HOST;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
@@ -475,23 +472,6 @@
doReturn(true).when(taskFragment).smallerThanMinDimension(any());
assertEquals(EMBEDDING_DISALLOWED_MIN_DIMENSION_VIOLATION,
taskFragment.isAllowedToEmbedActivity(activity));
-
- // Not allow to start activity across TaskFragments for result.
- final TaskFragment newTaskFragment = new TaskFragmentBuilder(mAtm)
- .setParentTask(taskFragment.getTask())
- .build();
- final ActivityRecord newActivity = new ActivityBuilder(mAtm)
- .setUid(FIRST_APPLICATION_UID)
- .build();
- doReturn(true).when(newTaskFragment).isAllowedToEmbedActivityInTrustedMode(any(), anyInt());
- doReturn(false).when(newTaskFragment).smallerThanMinDimension(any());
- newActivity.resultTo = activity;
- assertEquals(EMBEDDING_DISALLOWED_NEW_TASK_FRAGMENT,
- newTaskFragment.isAllowedToEmbedActivity(newActivity));
-
- // Allow embedding if the resultTo activity is finishing.
- activity.finishing = true;
- assertEquals(EMBEDDING_ALLOWED, newTaskFragment.isAllowedToEmbedActivity(newActivity));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index aab70b5..94b5b93 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -54,6 +54,7 @@
import android.platform.test.annotations.Presubmit;
import android.view.DisplayCutout;
import android.view.DisplayInfo;
+import android.view.DisplayShape;
import android.view.Gravity;
import android.view.InsetsState;
import android.view.PrivacyIndicatorBounds;
@@ -165,7 +166,8 @@
final DisplayInfo info = dc.computeScreenConfiguration(config, Surface.ROTATION_0);
final DisplayCutout cutout = dc.calculateDisplayCutoutForRotation(Surface.ROTATION_0);
final DisplayFrames displayFrames = new DisplayFrames(new InsetsState(),
- info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds());
+ info, cutout, RoundedCorners.NO_ROUNDED_CORNERS, new PrivacyIndicatorBounds(),
+ DisplayShape.NONE);
wallpaperWindow.mToken.applyFixedRotationTransform(info, displayFrames, config);
// Check that the wallpaper has the same frame in landscape than in portrait
diff --git a/services/usb/Android.bp b/services/usb/Android.bp
index 52cfe25..133f924 100644
--- a/services/usb/Android.bp
+++ b/services/usb/Android.bp
@@ -33,5 +33,6 @@
"android.hardware.usb.gadget-V1.0-java",
"android.hardware.usb.gadget-V1.1-java",
"android.hardware.usb.gadget-V1.2-java",
+ "android.hardware.usb.gadget-V1-java",
],
}
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 1c081c1..ffdb07b 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -44,6 +44,7 @@
import android.debug.AdbNotifications;
import android.debug.AdbTransportType;
import android.debug.IAdbTransport;
+import android.hardware.usb.IUsbOperationInternal;
import android.hardware.usb.ParcelableUsbPort;
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbConfiguration;
@@ -54,9 +55,7 @@
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
import android.hardware.usb.gadget.V1_0.GadgetFunction;
-import android.hardware.usb.gadget.V1_0.IUsbGadget;
import android.hardware.usb.gadget.V1_0.Status;
-import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
import android.hardware.usb.gadget.V1_2.UsbSpeed;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
@@ -88,9 +87,12 @@
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.dump.DualDumpOutputStream;
import com.android.server.FgThread;
import com.android.server.LocalServices;
+import com.android.server.usb.hal.gadget.UsbGadgetHal;
+import com.android.server.usb.hal.gadget.UsbGadgetHalInstance;
import com.android.server.utils.EventLogger;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -106,6 +108,7 @@
import java.util.NoSuchElementException;
import java.util.Scanner;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* UsbDeviceManager manages USB state in device mode.
@@ -216,6 +219,13 @@
private static EventLogger sEventLogger;
+ private UsbGadgetHal mUsbGadgetHal;
+
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
static {
sDenyInterfaces = new HashSet<>();
sDenyInterfaces.add(UsbConstants.USB_CLASS_AUDIO);
@@ -298,15 +308,11 @@
mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
initRndisAddress();
+ int operationId = sUsbOperationCount.incrementAndGet();
boolean halNotPresent = false;
- try {
- IUsbGadget.getService(true);
- } catch (RemoteException e) {
- Slog.e(TAG, "USB GADGET HAL present but exception thrown", e);
- } catch (NoSuchElementException e) {
- halNotPresent = true;
- Slog.i(TAG, "USB GADGET HAL not present in the device", e);
- }
+
+ mUsbGadgetHal = UsbGadgetHalInstance.getInstance(this, null);
+ Slog.d(TAG, "getInstance done");
mControlFds = new HashMap<>();
FileDescriptor mtpFd = nativeOpenControl(UsbManager.USB_FUNCTION_MTP);
@@ -320,7 +326,7 @@
}
mControlFds.put(UsbManager.FUNCTION_PTP, ptpFd);
- if (halNotPresent) {
+ if (mUsbGadgetHal == null) {
/**
* Initialze the legacy UsbHandler
*/
@@ -334,6 +340,8 @@
alsaManager, permissionManager);
}
+ mHandler.handlerInitDone(operationId);
+
if (nativeIsStartRequested()) {
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
startAccessoryMode();
@@ -455,6 +463,8 @@
private void startAccessoryMode() {
if (!mHasUsbAccessory) return;
+ int operationId = sUsbOperationCount.incrementAndGet();
+
mAccessoryStrings = nativeGetAccessoryStrings();
boolean enableAudio = (nativeGetAudioMode() == AUDIO_MODE_SOURCE);
// don't start accessory mode if our mandatory strings have not been set
@@ -475,7 +485,7 @@
ACCESSORY_REQUEST_TIMEOUT);
mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSORY_HANDSHAKE_TIMEOUT),
ACCESSORY_HANDSHAKE_TIMEOUT);
- setCurrentFunctions(functions);
+ setCurrentFunctions(functions, operationId);
}
}
@@ -504,6 +514,20 @@
}
}
+ public static void logAndPrint(int priority, IndentingPrintWriter pw, String msg) {
+ Slog.println(priority, TAG, msg);
+ if (pw != null) {
+ pw.println(msg);
+ }
+ }
+
+ public static void logAndPrintException(IndentingPrintWriter pw, String msg, Exception e) {
+ Slog.e(TAG, msg, e);
+ if (pw != null) {
+ pw.println(msg + e);
+ }
+ }
+
abstract static class UsbHandler extends Handler {
// current USB state
@@ -608,6 +632,19 @@
sendMessage(m);
}
+ public boolean sendMessage(int what) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ return sendMessageDelayed(m,0);
+ }
+
+ public void sendMessage(int what, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.arg1 = operationId;
+ sendMessage(m);
+ }
+
public void sendMessage(int what, Object arg) {
removeMessages(what);
Message m = Message.obtain(this, what);
@@ -615,6 +652,22 @@
sendMessage(m);
}
+ public void sendMessage(int what, Object arg, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.obj = arg;
+ m.arg1 = operationId;
+ sendMessage(m);
+ }
+
+ public void sendMessage(int what, boolean arg, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.arg1 = (arg ? 1 : 0);
+ m.arg2 = operationId;
+ sendMessage(m);
+ }
+
public void sendMessage(int what, Object arg, boolean arg1) {
removeMessages(what);
Message m = Message.obtain(this, what);
@@ -623,6 +676,15 @@
sendMessage(m);
}
+ public void sendMessage(int what, long arg, boolean arg1, int operationId) {
+ removeMessages(what);
+ Message m = Message.obtain(this, what);
+ m.obj = arg;
+ m.arg1 = (arg1 ? 1 : 0);
+ m.arg2 = operationId;
+ sendMessage(m);
+ }
+
public void sendMessage(int what, boolean arg1, boolean arg2) {
removeMessages(what);
Message m = Message.obtain(this, what);
@@ -680,7 +742,7 @@
sendMessageDelayed(msg, HOST_STATE_UPDATE_DELAY);
}
- private void setAdbEnabled(boolean enable) {
+ private void setAdbEnabled(boolean enable, int operationId) {
if (DEBUG) Slog.d(TAG, "setAdbEnabled: " + enable);
if (enable) {
@@ -689,7 +751,7 @@
setSystemProperty(USB_PERSISTENT_CONFIG_PROPERTY, "");
}
- setEnabledFunctions(mCurrentFunctions, true);
+ setEnabledFunctions(mCurrentFunctions, true, operationId);
updateAdbNotification(false);
}
@@ -701,6 +763,8 @@
private void updateCurrentAccessory() {
// We are entering accessory mode if we have received a request from the host
// and the request has not timed out yet.
+ int operationId = sUsbOperationCount.incrementAndGet();
+
boolean enteringAccessoryMode = hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT);
if (mConfigured && enteringAccessoryMode) {
@@ -732,18 +796,18 @@
}
} else {
if (!enteringAccessoryMode) {
- notifyAccessoryModeExit();
+ notifyAccessoryModeExit(operationId);
} else if (DEBUG) {
Slog.v(TAG, "Debouncing accessory mode exit");
}
}
}
- private void notifyAccessoryModeExit() {
+ private void notifyAccessoryModeExit(int operationId) {
// make sure accessory mode is off
// and restore default functions
Slog.d(TAG, "exited USB accessory mode");
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
if (mCurrentAccessory != null) {
if (mBootCompleted) {
@@ -869,8 +933,8 @@
mMidiEnabled && mConfigured, mMidiCard, mMidiDevice);
}
- private void setScreenUnlockedFunctions() {
- setEnabledFunctions(mScreenUnlockedFunctions, false);
+ private void setScreenUnlockedFunctions(int operationId) {
+ setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
}
private static class AdbTransport extends IAdbTransport.Stub {
@@ -883,7 +947,8 @@
@Override
public void onAdbEnabled(boolean enabled, byte transportType) {
if (transportType == AdbTransportType.USB) {
- mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+ int operationId = sUsbOperationCount.incrementAndGet();
+ mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
}
}
}
@@ -906,6 +971,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_STATE:
+ int operationId = sUsbOperationCount.incrementAndGet();
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
@@ -923,9 +989,9 @@
// restore defaults when USB is disconnected
if (!mScreenLocked
&& mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
} else {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
}
updateUsbFunctions();
@@ -1036,13 +1102,15 @@
updateUsbNotification(false);
break;
case MSG_ENABLE_ADB:
- setAdbEnabled(msg.arg1 == 1);
+ setAdbEnabled(msg.arg1 == 1, msg.arg2);
break;
case MSG_SET_CURRENT_FUNCTIONS:
long functions = (Long) msg.obj;
- setEnabledFunctions(functions, false);
+ operationId = (int) msg.arg1;
+ setEnabledFunctions(functions, false, operationId);
break;
case MSG_SET_SCREEN_UNLOCKED_FUNCTIONS:
+ operationId = sUsbOperationCount.incrementAndGet();
mScreenUnlockedFunctions = (Long) msg.obj;
if (mSettings != null) {
SharedPreferences.Editor editor = mSettings.edit();
@@ -1053,12 +1121,13 @@
}
if (!mScreenLocked && mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
// If the screen is unlocked, also set current functions.
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
} else {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
break;
case MSG_UPDATE_SCREEN_LOCK:
+ operationId = sUsbOperationCount.incrementAndGet();
if (msg.arg1 == 1 == mScreenLocked) {
break;
}
@@ -1068,23 +1137,25 @@
}
if (mScreenLocked) {
if (!mConnected) {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
} else {
if (mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE
&& mCurrentFunctions == UsbManager.FUNCTION_NONE) {
// Set the screen unlocked functions if current function is charging.
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
}
}
break;
case MSG_UPDATE_USER_RESTRICTIONS:
+ operationId = sUsbOperationCount.incrementAndGet();
// Restart the USB stack if USB transfer is enabled but no longer allowed.
if (isUsbDataTransferActive(mCurrentFunctions) && !isUsbTransferAllowed()) {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, true);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, true, operationId);
}
break;
case MSG_SYSTEM_READY:
+ operationId = sUsbOperationCount.incrementAndGet();
mNotificationManager = (NotificationManager)
mContext.getSystemService(Context.NOTIFICATION_SERVICE);
@@ -1102,17 +1173,19 @@
NotificationManager.IMPORTANCE_HIGH));
}
mSystemReady = true;
- finishBoot();
+ finishBoot(operationId);
break;
case MSG_LOCALE_CHANGED:
updateAdbNotification(true);
updateUsbNotification(true);
break;
case MSG_BOOT_COMPLETED:
+ operationId = sUsbOperationCount.incrementAndGet();
mBootCompleted = true;
- finishBoot();
+ finishBoot(operationId);
break;
case MSG_USER_SWITCHED: {
+ operationId = sUsbOperationCount.incrementAndGet();
if (mCurrentUser != msg.arg1) {
if (DEBUG) {
Slog.v(TAG, "Current user switched to " + msg.arg1);
@@ -1125,16 +1198,18 @@
mSettings.getString(String.format(Locale.ENGLISH,
UNLOCKED_CONFIG_PREF, mCurrentUser), ""));
}
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
break;
}
case MSG_ACCESSORY_MODE_ENTER_TIMEOUT: {
+ operationId = sUsbOperationCount.incrementAndGet();
if (DEBUG) {
- Slog.v(TAG, "Accessory mode enter timeout: " + mConnected);
+ Slog.v(TAG, "Accessory mode enter timeout: " + mConnected
+ + " ,operationId: " + operationId);
}
if (!mConnected || (mCurrentFunctions & UsbManager.FUNCTION_ACCESSORY) == 0) {
- notifyAccessoryModeExit();
+ notifyAccessoryModeExit(operationId);
}
break;
}
@@ -1157,7 +1232,9 @@
}
}
- protected void finishBoot() {
+ public abstract void handlerInitDone(int operationId);
+
+ protected void finishBoot(int operationId) {
if (mBootCompleted && mCurrentUsbFunctionsReceived && mSystemReady) {
if (mPendingBootBroadcast) {
updateUsbStateBroadcastIfNeeded(getAppliedFunctions(mCurrentFunctions));
@@ -1165,9 +1242,9 @@
}
if (!mScreenLocked
&& mScreenUnlockedFunctions != UsbManager.FUNCTION_NONE) {
- setScreenUnlockedFunctions();
+ setScreenUnlockedFunctions(operationId);
} else {
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
}
if (mCurrentAccessory != null) {
mUsbDeviceManager.getCurrentSettings().accessoryAttached(mCurrentAccessory);
@@ -1507,7 +1584,8 @@
/**
* Evaluates USB function policies and applies the change accordingly.
*/
- protected abstract void setEnabledFunctions(long functions, boolean forceRestart);
+ protected abstract void setEnabledFunctions(long functions,
+ boolean forceRestart, int operationId);
public void setAccessoryUEventTime(long accessoryConnectionStartTime) {
mAccessoryConnectionStartTime = accessoryConnectionStartTime;
@@ -1522,6 +1600,11 @@
mSendStringCount = 0;
mStartAccessory = false;
}
+
+ public abstract void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions);
+
+ public abstract void getUsbSpeedCb(int speed);
}
private static final class UsbHandlerLegacy extends UsbHandler {
@@ -1540,6 +1623,11 @@
private String mCurrentFunctionsStr;
private boolean mUsbDataUnlocked;
+ /**
+ * Keeps track of the latest setCurrentUsbFunctions request number.
+ */
+ private int mCurrentRequest = 0;
+
UsbHandlerLegacy(Looper looper, Context context, UsbDeviceManager deviceManager,
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
super(looper, context, deviceManager, alsaManager, permissionManager);
@@ -1573,6 +1661,10 @@
}
}
+ @Override
+ public void handlerInitDone(int operationId) {
+ }
+
private void readOemUsbOverrideConfig(Context context) {
String[] configList = context.getResources().getStringArray(
com.android.internal.R.array.config_oemUsbModeOverride);
@@ -1675,11 +1767,14 @@
}
@Override
- protected void setEnabledFunctions(long usbFunctions, boolean forceRestart) {
+ protected void setEnabledFunctions(long usbFunctions,
+ boolean forceRestart, int operationId) {
boolean usbDataUnlocked = isUsbDataTransferActive(usbFunctions);
if (DEBUG) {
- Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions + ", "
- + "forceRestart=" + forceRestart + ", usbDataUnlocked=" + usbDataUnlocked);
+ Slog.d(TAG, "setEnabledFunctions functions=" + usbFunctions +
+ " ,forceRestart=" + forceRestart +
+ " ,usbDataUnlocked=" + usbDataUnlocked +
+ " ,operationId=" + operationId);
}
if (usbDataUnlocked != mUsbDataUnlocked) {
@@ -1775,7 +1870,6 @@
|| !mCurrentFunctionsStr.equals(functions)
|| !mCurrentFunctionsApplied
|| forceRestart) {
- Slog.i(TAG, "Setting USB config to " + functions);
mCurrentFunctionsStr = functions;
mCurrentOemFunctions = oemFunctions;
mCurrentFunctionsApplied = false;
@@ -1871,15 +1965,18 @@
if (charAfter < functions.length() && functions.charAt(charAfter) != ',') return false;
return true;
}
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed){
+ }
}
- private static final class UsbHandlerHal extends UsbHandler {
-
- /**
- * Proxy object for the usb gadget hal daemon.
- */
- @GuardedBy("mGadgetProxyLock")
- private IUsbGadget mGadgetProxy;
+ private final class UsbHandlerHal extends UsbHandler {
private final Object mGadgetProxyLock = new Object();
@@ -1926,33 +2023,20 @@
UsbHandlerHal(Looper looper, Context context, UsbDeviceManager deviceManager,
UsbAlsaManager alsaManager, UsbPermissionManager permissionManager) {
super(looper, context, deviceManager, alsaManager, permissionManager);
+ int operationId = sUsbOperationCount.incrementAndGet();
try {
- ServiceNotification serviceNotification = new ServiceNotification();
-
- boolean ret = IServiceManager.getService()
- .registerForNotifications(GADGET_HAL_FQ_NAME, "", serviceNotification);
- if (!ret) {
- Slog.e(TAG, "Failed to register usb gadget service start notification");
- return;
- }
synchronized (mGadgetProxyLock) {
- mGadgetProxy = IUsbGadget.getService(true);
- mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
- USB_GADGET_HAL_DEATH_COOKIE);
mCurrentFunctions = UsbManager.FUNCTION_NONE;
mCurrentUsbFunctionsRequested = true;
mUsbSpeed = UsbSpeed.UNKNOWN;
mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
- mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+ updateUsbGadgetHalVersion();
}
String state = FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim();
updateState(state);
- updateUsbGadgetHalVersion();
} catch (NoSuchElementException e) {
Slog.e(TAG, "Usb gadget hal not found", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "Usb Gadget hal not responding", e);
} catch (Exception e) {
Slog.e(TAG, "Error initializing UsbHandler", e);
}
@@ -1965,7 +2049,7 @@
if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
Slog.e(TAG, "Usb Gadget hal service died cookie: " + cookie);
synchronized (mGadgetProxyLock) {
- mGadgetProxy = null;
+ mUsbGadgetHal = null;
}
}
}
@@ -1988,18 +2072,22 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_SET_CHARGING_FUNCTIONS:
- setEnabledFunctions(UsbManager.FUNCTION_NONE, false);
+ int operationId = sUsbOperationCount.incrementAndGet();
+ setEnabledFunctions(UsbManager.FUNCTION_NONE, false, operationId);
break;
case MSG_SET_FUNCTIONS_TIMEOUT:
- Slog.e(TAG, "Set functions timed out! no reply from usb hal");
+ operationId = sUsbOperationCount.incrementAndGet();
+ Slog.e(TAG, "Set functions timed out! no reply from usb hal"
+ + " ,operationId:" + operationId);
if (msg.arg1 != 1) {
// Set this since default function may be selected from Developer options
- setEnabledFunctions(mScreenUnlockedFunctions, false);
+ setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
}
break;
case MSG_GET_CURRENT_USB_FUNCTIONS:
Slog.i(TAG, "processing MSG_GET_CURRENT_USB_FUNCTIONS");
mCurrentUsbFunctionsReceived = true;
+ operationId = msg.arg2;
if (mCurrentUsbFunctionsRequested) {
Slog.i(TAG, "updating mCurrentFunctions");
@@ -2009,91 +2097,71 @@
"mCurrentFunctions:" + mCurrentFunctions + "applied:" + msg.arg1);
mCurrentFunctionsApplied = msg.arg1 == 1;
}
- finishBoot();
+ finishBoot(operationId);
break;
case MSG_FUNCTION_SWITCH_TIMEOUT:
/**
* Dont force to default when the configuration is already set to default.
*/
+ operationId = sUsbOperationCount.incrementAndGet();
if (msg.arg1 != 1) {
// Set this since default function may be selected from Developer options
- setEnabledFunctions(mScreenUnlockedFunctions, false);
+ setEnabledFunctions(mScreenUnlockedFunctions, false, operationId);
}
break;
case MSG_GADGET_HAL_REGISTERED:
boolean preexisting = msg.arg1 == 1;
+ operationId = sUsbOperationCount.incrementAndGet();
synchronized (mGadgetProxyLock) {
try {
- mGadgetProxy = IUsbGadget.getService();
- mGadgetProxy.linkToDeath(new UsbGadgetDeathRecipient(),
- USB_GADGET_HAL_DEATH_COOKIE);
+ mUsbGadgetHal = UsbGadgetHalInstance.getInstance(mUsbDeviceManager,
+ null);
if (!mCurrentFunctionsApplied && !preexisting) {
- setEnabledFunctions(mCurrentFunctions, false);
+ setEnabledFunctions(mCurrentFunctions, false, operationId);
}
} catch (NoSuchElementException e) {
Slog.e(TAG, "Usb gadget hal not found", e);
- } catch (RemoteException e) {
- Slog.e(TAG, "Usb Gadget hal not responding", e);
}
}
break;
case MSG_RESET_USB_GADGET:
synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "reset Usb Gadget mGadgetProxy is null");
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "reset Usb Gadget mUsbGadgetHal is null");
break;
}
try {
- android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxy =
- android.hardware.usb.gadget.V1_1.IUsbGadget
- .castFrom(mGadgetProxy);
- gadgetProxy.reset();
- } catch (RemoteException e) {
+ mUsbGadgetHal.reset();
+ } catch (Exception e) {
Slog.e(TAG, "reset Usb Gadget failed", e);
}
}
break;
case MSG_UPDATE_USB_SPEED:
- synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "mGadgetProxy is null");
- break;
- }
+ operationId = sUsbOperationCount.incrementAndGet();
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "mGadgetHal is null, operationId:" + operationId);
+ break;
+ }
- try {
- android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
- android.hardware.usb.gadget.V1_2.IUsbGadget
- .castFrom(mGadgetProxy);
- if (gadgetProxy != null) {
- gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
- }
- } catch (RemoteException e) {
- Slog.e(TAG, "get UsbSpeed failed", e);
- }
+ try {
+ mUsbGadgetHal.getUsbSpeed(operationId);
+ } catch (Exception e) {
+ Slog.e(TAG, "get UsbSpeed failed", e);
}
break;
case MSG_UPDATE_HAL_VERSION:
- synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "mGadgetProxy is null");
- break;
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "mUsbGadgetHal is null");
+ break;
+ }
+ else {
+ try {
+ mCurrentGadgetHalVersion = mUsbGadgetHal.getGadgetHalVersion();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "update Usb gadget version failed", e);
}
-
- android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
- android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
- if (gadgetProxy == null) {
- android.hardware.usb.gadget.V1_1.IUsbGadget gadgetProxyV1By1 =
- android.hardware.usb.gadget.V1_1.IUsbGadget
- .castFrom(mGadgetProxy);
- if (gadgetProxyV1By1 == null) {
- mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_0;
- break;
- }
- mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_1;
- break;
- }
- mCurrentGadgetHalVersion = UsbManager.GADGET_HAL_V1_2;
}
break;
default:
@@ -2101,56 +2169,31 @@
}
}
- private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
- int mRequest;
- long mFunctions;
- boolean mChargingFunctions;
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
- UsbGadgetCallback() {
+ if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
+ || (mFunctions != functions)) {
+ return;
}
- UsbGadgetCallback(int request, long functions,
- boolean chargingFunctions) {
- mRequest = request;
- mFunctions = functions;
- mChargingFunctions = chargingFunctions;
- }
-
- @Override
- public void setCurrentUsbFunctionsCb(long functions,
- int status) {
- /**
- * Callback called for a previous setCurrenUsbFunction
- */
- if ((mCurrentRequest != mRequest) || !hasMessages(MSG_SET_FUNCTIONS_TIMEOUT)
- || (mFunctions != functions)) {
- return;
- }
-
- removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
- Slog.e(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
- if (status == Status.SUCCESS) {
- mCurrentFunctionsApplied = true;
- } else if (!mChargingFunctions) {
- Slog.e(TAG, "Setting default fuctions");
- sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
- }
- }
-
- @Override
- public void getCurrentUsbFunctionsCb(long functions,
- int status) {
- sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
- status == Status.FUNCTIONS_APPLIED);
- }
-
- @Override
- public void getUsbSpeedCb(int speed) {
- mUsbSpeed = speed;
+ removeMessages(MSG_SET_FUNCTIONS_TIMEOUT);
+ Slog.i(TAG, "notifyCurrentFunction request:" + mRequest + " status:" + status);
+ if (status == Status.SUCCESS) {
+ mCurrentFunctionsApplied = true;
+ } else if (!mChargingFunctions) {
+ Slog.e(TAG, "Setting default fuctions");
+ sendEmptyMessage(MSG_SET_CHARGING_FUNCTIONS);
}
}
- private void setUsbConfig(long config, boolean chargingFunctions) {
+ @Override
+ public void getUsbSpeedCb(int speed) {
+ mUsbSpeed = speed;
+ }
+
+ private void setUsbConfig(long config, boolean chargingFunctions, int operationId) {
if (true) Slog.d(TAG, "setUsbConfig(" + config + ") request:" + ++mCurrentRequest);
/**
* Cancel any ongoing requests, if present.
@@ -2160,8 +2203,8 @@
removeMessages(MSG_SET_CHARGING_FUNCTIONS);
synchronized (mGadgetProxyLock) {
- if (mGadgetProxy == null) {
- Slog.e(TAG, "setUsbConfig mGadgetProxy is null");
+ if (mUsbGadgetHal == null) {
+ Slog.e(TAG, "setUsbConfig mUsbGadgetHal is null");
return;
}
try {
@@ -2178,10 +2221,9 @@
LocalServices.getService(AdbManagerInternal.class)
.stopAdbdForTransport(AdbTransportType.USB);
}
- UsbGadgetCallback usbGadgetCallback = new UsbGadgetCallback(mCurrentRequest,
- config, chargingFunctions);
- mGadgetProxy.setCurrentUsbFunctions(config, usbGadgetCallback,
- SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS);
+ mUsbGadgetHal.setCurrentUsbFunctions(mCurrentRequest,
+ config, chargingFunctions,
+ SET_FUNCTIONS_TIMEOUT_MS - SET_FUNCTIONS_LEEWAY_MS, operationId);
sendMessageDelayed(MSG_SET_FUNCTIONS_TIMEOUT, chargingFunctions,
SET_FUNCTIONS_TIMEOUT_MS);
if (mConnected) {
@@ -2190,17 +2232,19 @@
SET_FUNCTIONS_TIMEOUT_MS + ENUMERATION_TIME_OUT_MS);
}
if (DEBUG) Slog.d(TAG, "timeout message queued");
- } catch (RemoteException e) {
+ } catch (Exception e) {//RemoteException e) {
Slog.e(TAG, "Remoteexception while calling setCurrentUsbFunctions", e);
}
}
}
@Override
- protected void setEnabledFunctions(long functions, boolean forceRestart) {
+ protected void setEnabledFunctions(long functions, boolean forceRestart, int operationId) {
if (DEBUG) {
- Slog.d(TAG, "setEnabledFunctions functions=" + functions + ", "
- + "forceRestart=" + forceRestart);
+ Slog.d(TAG, "setEnabledFunctionsi " +
+ "functions=" + functions +
+ ", forceRestart=" + forceRestart +
+ ", operationId=" + operationId);
}
if (mCurrentGadgetHalVersion < UsbManager.GADGET_HAL_V1_2) {
if ((functions & UsbManager.FUNCTION_NCM) != 0) {
@@ -2221,7 +2265,7 @@
functions = getAppliedFunctions(functions);
// Set the new USB configuration.
- setUsbConfig(functions, chargingFunctions);
+ setUsbConfig(functions, chargingFunctions, operationId);
if (mBootCompleted && isUsbDataTransferActive(functions)) {
// Start up dependent services.
@@ -2229,6 +2273,11 @@
}
}
}
+
+ @Override
+ public void handlerInitDone(int operationId) {
+ mUsbGadgetHal.getCurrentUsbFunctions(operationId);
+ }
}
/* returns the currently attached USB accessory */
@@ -2270,6 +2319,21 @@
return mHandler.getGadgetHalVersion();
}
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions) {
+ mHandler.setCurrentUsbFunctionsCb(functions, status,
+ mRequest, mFunctions, mChargingFunctions);
+ }
+
+ public void getCurrentUsbFunctionsCb(long functions, int status) {
+ mHandler.sendMessage(MSG_GET_CURRENT_USB_FUNCTIONS, functions,
+ status == Status.FUNCTIONS_APPLIED);
+ }
+
+ public void getUsbSpeedCb(int speed) {
+ mHandler.getUsbSpeedCb(speed);
+ }
+
/**
* Returns a dup of the control file descriptor for the given function.
*/
@@ -2295,7 +2359,7 @@
*
* @param functions The functions to set, or empty to set the charging function.
*/
- public void setCurrentFunctions(long functions) {
+ public void setCurrentFunctions(long functions, int operationId) {
if (DEBUG) {
Slog.d(TAG, "setCurrentFunctions(" + UsbManager.usbFunctionsToString(functions) + ")");
}
@@ -2312,7 +2376,7 @@
} else if (functions == UsbManager.FUNCTION_ACCESSORY) {
MetricsLogger.action(mContext, MetricsEvent.ACTION_USB_CONFIG_ACCESSORY);
}
- mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions);
+ mHandler.sendMessage(MSG_SET_CURRENT_FUNCTIONS, functions, operationId);
}
/**
@@ -2340,7 +2404,8 @@
}
private void onAdbEnabled(boolean enabled) {
- mHandler.sendMessage(MSG_ENABLE_ADB, enabled);
+ int operationId = sUsbOperationCount.incrementAndGet();
+ mHandler.sendMessage(MSG_ENABLE_ADB, enabled, operationId);
}
/**
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index d821dee..d09f729 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -622,16 +622,16 @@
}
@Override
- public void setCurrentFunctions(long functions) {
+ public void setCurrentFunctions(long functions, int operationId) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
Preconditions.checkArgument(UsbManager.areSettableFunctions(functions));
Preconditions.checkState(mDeviceManager != null);
- mDeviceManager.setCurrentFunctions(functions);
+ mDeviceManager.setCurrentFunctions(functions, operationId);
}
@Override
- public void setCurrentFunction(String functions, boolean usbDataUnlocked) {
- setCurrentFunctions(UsbManager.usbFunctionsFromString(functions));
+ public void setCurrentFunction(String functions, boolean usbDataUnlocked, int operationId) {
+ setCurrentFunctions(UsbManager.usbFunctionsFromString(functions), operationId);
}
@Override
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
new file mode 100644
index 0000000..bdfe60a
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetAidl.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2022 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.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_V2_0;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.IUsbGadget;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.os.ServiceManager;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+
+/**
+ * Implements the methods to interact with AIDL USB HAL.
+ */
+public final class UsbGadgetAidl implements UsbGadgetHal {
+ private static final String TAG = UsbGadgetAidl.class.getSimpleName();
+ private static final String USB_GADGET_AIDL_SERVICE = IUsbGadget.DESCRIPTOR + "/default";
+ // Proxy object for the usb gadget hal daemon.
+ @GuardedBy("mGadgetProxyLock")
+ private IUsbGadget mGadgetProxy;
+ private final UsbDeviceManager mDeviceManager;
+ public final IndentingPrintWriter mPw;
+ // Mutex for all mutable shared state.
+ private final Object mGadgetProxyLock = new Object();
+ // Callback when the UsbDevice status is changed by the kernel.
+ private UsbGadgetCallback mUsbGadgetCallback;
+
+ public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy == null) {
+ throw new RemoteException("IUsb not initialized yet");
+ }
+ }
+ Slog.i(TAG, "USB Gadget HAL AIDL version: GADGET_HAL_V2_0");
+ return GADGET_HAL_V2_0;
+ }
+
+ @Override
+ public void systemReady() {
+ }
+
+ public void serviceDied() {
+ logAndPrint(Log.ERROR, mPw, "Usb Gadget AIDL hal service died");
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy = null;
+ }
+ connectToProxy(null);
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy != null) {
+ return;
+ }
+
+ try {
+ mGadgetProxy = IUsbGadget.Stub.asInterface(
+ ServiceManager.waitForService(USB_GADGET_AIDL_SERVICE));
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+ + " Did the service fail to start?", e);
+ }
+ }
+ }
+
+ static boolean isServicePresent(IndentingPrintWriter pw) {
+ try {
+ return ServiceManager.isDeclared(USB_GADGET_AIDL_SERVICE);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget Aidl hal service not found.", e);
+ }
+
+ return false;
+ }
+
+ public UsbGadgetAidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+ mDeviceManager = Objects.requireNonNull(deviceManager);
+ mPw = pw;
+ connectToProxy(mPw);
+ }
+
+ @Override
+ public void getCurrentUsbFunctions(long operationId) {
+ synchronized (mGadgetProxyLock) {
+ try {
+ mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback(), operationId);
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getCurrentUsbFunctions"
+ + ", opID:" + operationId, e);
+ return;
+ }
+ }
+ }
+
+ @Override
+ public void getUsbSpeed(long operationId) {
+ try {
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy.getUsbSpeed(new UsbGadgetCallback(), operationId);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getUsbSpeed"
+ + ", opID:" + operationId, e);
+ return;
+ }
+ }
+
+ @Override
+ public void reset() {
+ try {
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy.reset();
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getUsbSpeed", e);
+ return;
+ }
+ }
+
+ @Override
+ public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+ boolean mChargingFunctions, int timeout, long operationId) {
+ try {
+ mUsbGadgetCallback = new UsbGadgetCallback(mRequest,
+ mFunctions, mChargingFunctions);
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback,
+ timeout, operationId);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling setCurrentUsbFunctions: "
+ + "mRequest=" + mRequest
+ + ", mFunctions=" + mFunctions
+ + ", mChargingFunctions=" + mChargingFunctions
+ + ", timeout=" + timeout
+ + ", opID:" + operationId, e);
+ return;
+ }
+ }
+
+ private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+ public int mRequest;
+ public long mFunctions;
+ public boolean mChargingFunctions;
+
+ UsbGadgetCallback() {
+ }
+
+ UsbGadgetCallback(int request, long functions,
+ boolean chargingFunctions) {
+ mRequest = request;
+ mFunctions = functions;
+ mChargingFunctions = chargingFunctions;
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, long transactionId) {
+ mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+ mRequest, mFunctions, mChargingFunctions);
+ }
+
+ @Override
+ public void getCurrentUsbFunctionsCb(long functions,
+ int status, long transactionId) {
+ mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed, long transactionId) {
+ mDeviceManager.getUsbSpeedCb(speed);
+ }
+
+ @Override
+ public String getInterfaceHash() {
+ return IUsbGadgetCallback.HASH;
+ }
+
+ @Override
+ public int getInterfaceVersion() {
+ return IUsbGadgetCallback.VERSION;
+ }
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
new file mode 100644
index 0000000..267247b
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHal.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2022 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.usb.hal.gadget;
+
+import android.annotation.IntDef;
+import android.hardware.usb.gadget.IUsbGadgetCallback;
+import android.hardware.usb.IUsbOperationInternal;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.os.RemoteException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.String;
+
+/**
+ * @hide
+ */
+public interface UsbGadgetHal {
+ /**
+ * Power role: This USB port can act as a source (provide power).
+ * @hide
+ */
+ public static final int HAL_POWER_ROLE_SOURCE = 1;
+
+ /**
+ * Power role: This USB port can act as a sink (receive power).
+ * @hide
+ */
+ public static final int HAL_POWER_ROLE_SINK = 2;
+
+ @IntDef(prefix = { "HAL_POWER_ROLE_" }, value = {
+ HAL_POWER_ROLE_SOURCE,
+ HAL_POWER_ROLE_SINK
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HalUsbPowerRole{}
+
+ /**
+ * Data role: This USB port can act as a host (access data services).
+ * @hide
+ */
+ public static final int HAL_DATA_ROLE_HOST = 1;
+
+ /**
+ * Data role: This USB port can act as a device (offer data services).
+ * @hide
+ */
+ public static final int HAL_DATA_ROLE_DEVICE = 2;
+
+ @IntDef(prefix = { "HAL_DATA_ROLE_" }, value = {
+ HAL_DATA_ROLE_HOST,
+ HAL_DATA_ROLE_DEVICE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HalUsbDataRole{}
+
+ /**
+ * This USB port can act as a downstream facing port (host).
+ *
+ * @hide
+ */
+ public static final int HAL_MODE_DFP = 1;
+
+ /**
+ * This USB port can act as an upstream facing port (device).
+ *
+ * @hide
+ */
+ public static final int HAL_MODE_UFP = 2;
+ @IntDef(prefix = { "HAL_MODE_" }, value = {
+ HAL_MODE_DFP,
+ HAL_MODE_UFP,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface HalUsbPortMode{}
+
+ /**
+ * UsbPortManager would call this when the system is done booting.
+ */
+ public void systemReady();
+
+ /**
+ * This function is used to query the USB functions included in the
+ * current USB configuration.
+ *
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void getCurrentUsbFunctions(long transactionId);
+
+ /**
+ * The function is used to query current USB speed.
+ *
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void getUsbSpeed(long transactionId);
+
+ /**
+ * This function is used to reset USB gadget driver.
+ * Performs USB data connection reset. The connection will disconnect and
+ * reconnect.
+ */
+ public void reset();
+
+ /**
+ * Invoked to query the version of current gadget hal implementation.
+ */
+ public @UsbHalVersion int getGadgetHalVersion() throws RemoteException;
+
+ /**
+ * This function is used to set the current USB gadget configuration.
+ * The USB gadget needs to be torn down if a USB configuration is already
+ * active.
+ *
+ * @param functions list of functions defined by GadgetFunction to be
+ * included in the gadget composition.
+ * @param timeout The maximum time (in milliseconds) within which the
+ * IUsbGadgetCallback needs to be returned.
+ * @param transactionId Used for tracking the current request and is passed down to the HAL
+ * implementation as needed.
+ */
+ public void setCurrentUsbFunctions(int request, long functions,
+ boolean chargingFunctions, int timeout, long transactionId);
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
new file mode 100644
index 0000000..d268315
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHalInstance.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2022 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.usb.hal.gadget;
+
+import static com.android.server.usb.UsbPortManager.logAndPrint;
+
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.hal.gadget.UsbGadgetHidl;
+import com.android.server.usb.hal.gadget.UsbGadgetAidl;
+import com.android.server.usb.UsbDeviceManager;
+
+import android.util.Log;
+/**
+ * Helper class that queries the underlying hal layer to populate UsbPortHal instance.
+ */
+public final class UsbGadgetHalInstance {
+
+ public static UsbGadgetHal getInstance(UsbDeviceManager deviceManager,
+ IndentingPrintWriter pw) {
+
+ logAndPrint(Log.DEBUG, pw, "Querying USB Gadget HAL version");
+ if (UsbGadgetAidl.isServicePresent(null)) {
+ logAndPrint(Log.INFO, pw, "USB Gadget HAL AIDL present");
+ return new UsbGadgetAidl(deviceManager, pw);
+ }
+ if (UsbGadgetHidl.isServicePresent(null)) {
+ logAndPrint(Log.INFO, pw, "USB Gadget HAL HIDL present");
+ return new UsbGadgetHidl(deviceManager, pw);
+ }
+
+ logAndPrint(Log.ERROR, pw, "USB Gadget HAL AIDL/HIDL not present");
+ return null;
+ }
+}
+
diff --git a/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
new file mode 100644
index 0000000..3e5ecc5
--- /dev/null
+++ b/services/usb/java/com/android/server/usb/hal/gadget/UsbGadgetHidl.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2022 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.usb.hal.gadget;
+
+import static android.hardware.usb.UsbManager.GADGET_HAL_NOT_SUPPORTED;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_0;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_1;
+import static android.hardware.usb.UsbManager.GADGET_HAL_V1_2;
+
+import static com.android.server.usb.UsbDeviceManager.logAndPrint;
+import static com.android.server.usb.UsbDeviceManager.logAndPrintException;
+
+import android.annotation.Nullable;
+import android.hardware.usb.gadget.V1_0.Status;
+import android.hardware.usb.gadget.V1_0.IUsbGadget;
+import android.hardware.usb.gadget.V1_2.IUsbGadgetCallback;
+import android.hardware.usb.gadget.V1_2.UsbSpeed;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.hardware.usb.UsbManager.UsbGadgetHalVersion;
+import android.hardware.usb.UsbManager.UsbHalVersion;
+import android.hidl.manager.V1_0.IServiceManager;
+import android.hidl.manager.V1_0.IServiceNotification;
+import android.os.IHwBinder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.usb.UsbDeviceManager;
+
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Objects;
+/**
+ *
+ */
+public final class UsbGadgetHidl implements UsbGadgetHal {
+ // Cookie sent for usb gadget hal death notification.
+ private static final int USB_GADGET_HAL_DEATH_COOKIE = 2000;
+ // Proxy object for the usb gadget hal daemon.
+ @GuardedBy("mGadgetProxyLock")
+ private IUsbGadget mGadgetProxy;
+ private UsbDeviceManager mDeviceManager;
+ private final IndentingPrintWriter mPw;
+ // Mutex for all mutable shared state.
+ private final Object mGadgetProxyLock = new Object();
+ private UsbGadgetCallback mUsbGadgetCallback;
+
+ public @UsbGadgetHalVersion int getGadgetHalVersion() throws RemoteException {
+ int version;
+ synchronized(mGadgetProxyLock) {
+ if (mGadgetProxy == null) {
+ throw new RemoteException("IUsbGadget not initialized yet");
+ }
+ if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ version = UsbManager.GADGET_HAL_V1_2;
+ } else if (android.hardware.usb.gadget.V1_1.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ version = UsbManager.GADGET_HAL_V1_1;
+ } else {
+ version = UsbManager.GADGET_HAL_V1_0;
+ }
+ logAndPrint(Log.INFO, mPw, "USB Gadget HAL HIDL version: " + version);
+ return version;
+ }
+ }
+
+ final class DeathRecipient implements IHwBinder.DeathRecipient {
+ private final IndentingPrintWriter mPw;
+
+ DeathRecipient(IndentingPrintWriter pw) {
+ mPw = pw;
+ }
+
+ @Override
+ public void serviceDied(long cookie) {
+ if (cookie == USB_GADGET_HAL_DEATH_COOKIE) {
+ logAndPrint(Log.ERROR, mPw, "Usb Gadget hal service died cookie: " + cookie);
+ synchronized (mGadgetProxyLock) {
+ mGadgetProxy = null;
+ }
+ }
+ }
+ }
+
+ final class ServiceNotification extends IServiceNotification.Stub {
+ @Override
+ public void onRegistration(String fqName, String name, boolean preexisting) {
+ logAndPrint(Log.INFO, mPw, "Usb gadget hal service started " + fqName + " " + name);
+ connectToProxy(null);
+ }
+ }
+
+ private void connectToProxy(IndentingPrintWriter pw) {
+ synchronized (mGadgetProxyLock) {
+ if (mGadgetProxy != null) {
+ return;
+ }
+
+ try {
+ mGadgetProxy = IUsbGadget.getService();
+ mGadgetProxy.linkToDeath(new DeathRecipient(pw), USB_GADGET_HAL_DEATH_COOKIE);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hal service not found."
+ + " Did the service fail to start?", e);
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hal service not responding"
+ , e);
+ }
+ }
+ }
+
+ @Override
+ public void systemReady() {
+ }
+
+ static boolean isServicePresent(IndentingPrintWriter pw) {
+ try {
+ IUsbGadget.getService(true);
+ } catch (NoSuchElementException e) {
+ logAndPrintException(pw, "connectToProxy: usb gadget hidl hal service not found.", e);
+ return false;
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "IUSBGadget hal service present but failed to get service", e);
+ }
+
+ return true;
+ }
+
+ public UsbGadgetHidl(UsbDeviceManager deviceManager, IndentingPrintWriter pw) {
+ mDeviceManager = Objects.requireNonNull(deviceManager);
+ mPw = pw;
+ try {
+ ServiceNotification serviceNotification = new ServiceNotification();
+
+ boolean ret = IServiceManager.getService()
+ .registerForNotifications("android.hardware.usb.gadget@1.0::IUsbGadget",
+ "", serviceNotification);
+ if (!ret) {
+ logAndPrint(Log.ERROR, pw, "Failed to register service start notification");
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(pw, "Failed to register service start notification", e);
+ return;
+ }
+ connectToProxy(mPw);
+ }
+
+ @Override
+ public void getCurrentUsbFunctions(long transactionId) {
+ try {
+ synchronized(mGadgetProxyLock) {
+ mGadgetProxy.getCurrentUsbFunctions(new UsbGadgetCallback());
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getCurrentUsbFunctions", e);
+ return;
+ }
+ }
+
+ @Override
+ public void getUsbSpeed(long transactionId) {
+ try {
+ synchronized(mGadgetProxyLock) {
+ if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+ android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+ gadgetProxy.getUsbSpeed(new UsbGadgetCallback());
+ }
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw, "get UsbSpeed failed", e);
+ }
+ }
+
+ @Override
+ public void reset() {
+ try {
+ synchronized(mGadgetProxyLock) {
+ if (android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy) != null) {
+ android.hardware.usb.gadget.V1_2.IUsbGadget gadgetProxy =
+ android.hardware.usb.gadget.V1_2.IUsbGadget.castFrom(mGadgetProxy);
+ gadgetProxy.reset();
+ }
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling getUsbSpeed", e);
+ return;
+ }
+ }
+
+ @Override
+ public void setCurrentUsbFunctions(int mRequest, long mFunctions,
+ boolean mChargingFunctions, int timeout, long operationId) {
+ try {
+ mUsbGadgetCallback = new UsbGadgetCallback(null, mRequest,
+ mFunctions, mChargingFunctions);
+ synchronized(mGadgetProxyLock) {
+ mGadgetProxy.setCurrentUsbFunctions(mFunctions, mUsbGadgetCallback, timeout);
+ }
+ } catch (RemoteException e) {
+ logAndPrintException(mPw,
+ "RemoteException while calling setCurrentUsbFunctions"
+ + " mRequest = " + mRequest
+ + ", mFunctions = " + mFunctions
+ + ", timeout = " + timeout
+ + ", mChargingFunctions = " + mChargingFunctions
+ + ", operationId =" + operationId, e);
+ return;
+ }
+ }
+
+ private class UsbGadgetCallback extends IUsbGadgetCallback.Stub {
+ public int mRequest;
+ public long mFunctions;
+ public boolean mChargingFunctions;
+
+ UsbGadgetCallback() {
+ }
+ UsbGadgetCallback(IndentingPrintWriter pw, int request,
+ long functions, boolean chargingFunctions) {
+ mRequest = request;
+ mFunctions = functions;
+ mChargingFunctions = chargingFunctions;
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status) {
+ mDeviceManager.setCurrentUsbFunctionsCb(functions, status,
+ mRequest, mFunctions, mChargingFunctions);
+ }
+
+ @Override
+ public void getCurrentUsbFunctionsCb(long functions,
+ int status) {
+ mDeviceManager.getCurrentUsbFunctionsCb(functions, status);
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed) {
+ mDeviceManager.getUsbSpeedCb(speed);
+ }
+ }
+}
+
diff --git a/telephony/java/android/telephony/Annotation.java b/telephony/java/android/telephony/Annotation.java
index 86b98f1..2435243 100644
--- a/telephony/java/android/telephony/Annotation.java
+++ b/telephony/java/android/telephony/Annotation.java
@@ -5,6 +5,7 @@
import android.net.NetworkCapabilities;
import android.telecom.Connection;
import android.telephony.data.ApnSetting;
+import android.telephony.ims.ImsCallProfile;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -494,7 +495,7 @@
PreciseCallState.PRECISE_CALL_STATE_HOLDING,
PreciseCallState.PRECISE_CALL_STATE_DIALING,
PreciseCallState.PRECISE_CALL_STATE_ALERTING,
- PreciseCallState. PRECISE_CALL_STATE_INCOMING,
+ PreciseCallState.PRECISE_CALL_STATE_INCOMING,
PreciseCallState.PRECISE_CALL_STATE_WAITING,
PreciseCallState.PRECISE_CALL_STATE_DISCONNECTED,
PreciseCallState.PRECISE_CALL_STATE_DISCONNECTING})
@@ -727,6 +728,36 @@
})
public @interface ValidationStatus {}
+ /**
+ * IMS call Service types
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "SERVICE_TYPE_" }, value = {
+ ImsCallProfile.SERVICE_TYPE_NONE,
+ ImsCallProfile.SERVICE_TYPE_NORMAL,
+ ImsCallProfile.SERVICE_TYPE_EMERGENCY,
+ })
+ public @interface ImsCallServiceType {}
+
+ /**
+ * IMS call types
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "CALL_TYPE_" }, value = {
+ ImsCallProfile.CALL_TYPE_NONE,
+ ImsCallProfile.CALL_TYPE_VOICE_N_VIDEO,
+ ImsCallProfile.CALL_TYPE_VOICE,
+ ImsCallProfile.CALL_TYPE_VIDEO_N_VOICE,
+ ImsCallProfile.CALL_TYPE_VT,
+ ImsCallProfile.CALL_TYPE_VT_TX,
+ ImsCallProfile.CALL_TYPE_VT_RX,
+ ImsCallProfile.CALL_TYPE_VT_NODIR,
+ ImsCallProfile.CALL_TYPE_VS,
+ ImsCallProfile.CALL_TYPE_VS_TX,
+ ImsCallProfile.CALL_TYPE_VS_RX,
+ })
+ public @interface ImsCallType {}
+
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = { "NET_CAPABILITY_ENTERPRISE_SUB_LEVEL" }, value = {
diff --git a/telephony/java/android/telephony/CallAttributes.java b/telephony/java/android/telephony/CallAttributes.java
index b7bef39..1dc64a9 100644
--- a/telephony/java/android/telephony/CallAttributes.java
+++ b/telephony/java/android/telephony/CallAttributes.java
@@ -29,8 +29,10 @@
* Contains information about a call's attributes as passed up from the HAL. If there are multiple
* ongoing calls, the CallAttributes will pertain to the call in the foreground.
* @hide
+ * @deprecated use {@link CallState} for call information for each call.
*/
@SystemApi
+@Deprecated
public final class CallAttributes implements Parcelable {
private PreciseCallState mPreciseCallState;
@NetworkType
diff --git a/telephony/java/android/telephony/CallState.aidl b/telephony/java/android/telephony/CallState.aidl
new file mode 100644
index 0000000..dd5af8e
--- /dev/null
+++ b/telephony/java/android/telephony/CallState.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2018 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.telephony;
+
+parcelable CallState;
+
diff --git a/telephony/java/android/telephony/CallState.java b/telephony/java/android/telephony/CallState.java
new file mode 100644
index 0000000..51ecfb0
--- /dev/null
+++ b/telephony/java/android/telephony/CallState.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2022 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.telephony;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.Annotation.ImsCallServiceType;
+import android.telephony.Annotation.ImsCallType;
+import android.telephony.Annotation.NetworkType;
+import android.telephony.Annotation.PreciseCallStates;
+import android.telephony.ims.ImsCallProfile;
+import android.telephony.ims.ImsCallSession;
+
+import java.util.Objects;
+
+/**
+ * Contains information about various states for a call.
+ * @hide
+ */
+@SystemApi
+public final class CallState implements Parcelable {
+
+ /**
+ * Call classifications are just used for backward compatibility of deprecated API {@link
+ * TelephonyCallback#CallAttributesListener#onCallAttributesChanged}, Since these will be
+ * removed when the deprecated API is removed, they should not be opened.
+ */
+ /**
+ * Call classification is not valid. It should not be opened.
+ * @hide
+ */
+ public static final int CALL_CLASSIFICATION_UNKNOWN = -1;
+
+ /**
+ * Call classification indicating foreground call
+ * @hide
+ */
+ public static final int CALL_CLASSIFICATION_RINGING = 0;
+
+ /**
+ * Call classification indicating background call
+ * @hide
+ */
+ public static final int CALL_CLASSIFICATION_FOREGROUND = 1;
+
+ /**
+ * Call classification indicating ringing call
+ * @hide
+ */
+ public static final int CALL_CLASSIFICATION_BACKGROUND = 2;
+
+ /**
+ * Call classification Max value.
+ * @hide
+ */
+ public static final int CALL_CLASSIFICATION_MAX = CALL_CLASSIFICATION_BACKGROUND + 1;
+
+ @PreciseCallStates
+ private final int mPreciseCallState;
+
+ @NetworkType
+ private final int mNetworkType; // TelephonyManager.NETWORK_TYPE_* ints
+ private final CallQuality mCallQuality;
+
+ private final int mCallClassification;
+ /**
+ * IMS call session ID. {@link ImsCallSession#getCallId()}
+ */
+ @Nullable
+ private String mImsCallId;
+
+ /**
+ * IMS call service type of this call
+ */
+ @ImsCallServiceType
+ private int mImsCallServiceType;
+
+ /**
+ * IMS call type of this call.
+ */
+ @ImsCallType
+ private int mImsCallType;
+
+ /**
+ * Constructor of CallAttributes
+ *
+ * @param callState call state defined in {@link PreciseCallState}
+ * @param networkType network type for this call attributes
+ * @param callQuality call quality for this call attributes, only CallState in
+ * {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call
+ * quality.
+ * @param callClassification call classification
+ * @param imsCallId IMS call session ID for this call attributes
+ * @param imsCallServiceType IMS call service type for this call attributes
+ * @param imsCallType IMS call type for this call attributes
+ */
+ private CallState(@PreciseCallStates int callState, @NetworkType int networkType,
+ @NonNull CallQuality callQuality, int callClassification, @Nullable String imsCallId,
+ @ImsCallServiceType int imsCallServiceType, @ImsCallType int imsCallType) {
+ this.mPreciseCallState = callState;
+ this.mNetworkType = networkType;
+ this.mCallQuality = callQuality;
+ this.mCallClassification = callClassification;
+ this.mImsCallId = imsCallId;
+ this.mImsCallServiceType = imsCallServiceType;
+ this.mImsCallType = imsCallType;
+ }
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "mPreciseCallState=" + mPreciseCallState + " mNetworkType=" + mNetworkType
+ + " mCallQuality=" + mCallQuality + " mCallClassification" + mCallClassification
+ + " mImsCallId=" + mImsCallId + " mImsCallServiceType=" + mImsCallServiceType
+ + " mImsCallType=" + mImsCallType;
+ }
+
+ private CallState(Parcel in) {
+ this.mPreciseCallState = in.readInt();
+ this.mNetworkType = in.readInt();
+ this.mCallQuality = in.readParcelable(
+ CallQuality.class.getClassLoader(), CallQuality.class);
+ this.mCallClassification = in.readInt();
+ this.mImsCallId = in.readString();
+ this.mImsCallServiceType = in.readInt();
+ this.mImsCallType = in.readInt();
+ }
+
+ // getters
+ /**
+ * Returns the precise call state of the call.
+ */
+ @PreciseCallStates
+ public int getCallState() {
+ return mPreciseCallState;
+ }
+
+ /**
+ * Returns the {@link TelephonyManager#NetworkType} of the call.
+ *
+ * @see TelephonyManager#NETWORK_TYPE_UNKNOWN
+ * @see TelephonyManager#NETWORK_TYPE_GPRS
+ * @see TelephonyManager#NETWORK_TYPE_EDGE
+ * @see TelephonyManager#NETWORK_TYPE_UMTS
+ * @see TelephonyManager#NETWORK_TYPE_CDMA
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_0
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_A
+ * @see TelephonyManager#NETWORK_TYPE_1xRTT
+ * @see TelephonyManager#NETWORK_TYPE_HSDPA
+ * @see TelephonyManager#NETWORK_TYPE_HSUPA
+ * @see TelephonyManager#NETWORK_TYPE_HSPA
+ * @see TelephonyManager#NETWORK_TYPE_IDEN
+ * @see TelephonyManager#NETWORK_TYPE_EVDO_B
+ * @see TelephonyManager#NETWORK_TYPE_LTE
+ * @see TelephonyManager#NETWORK_TYPE_EHRPD
+ * @see TelephonyManager#NETWORK_TYPE_HSPAP
+ * @see TelephonyManager#NETWORK_TYPE_GSM
+ * @see TelephonyManager#NETWORK_TYPE_TD_SCDMA
+ * @see TelephonyManager#NETWORK_TYPE_IWLAN
+ * @see TelephonyManager#NETWORK_TYPE_LTE_CA
+ * @see TelephonyManager#NETWORK_TYPE_NR
+ */
+ @NetworkType
+ public int getNetworkType() {
+ return mNetworkType;
+ }
+
+ /**
+ * Returns the {#link CallQuality} of the call.
+ * @return call quality for this call attributes, only CallState in {@link
+ * PreciseCallState#PRECISE_CALL_STATE_ACTIVE} will have valid call quality. It will be
+ * null for the call which is not in {@link PreciseCallState#PRECISE_CALL_STATE_ACTIVE}.
+ */
+ @Nullable
+ public CallQuality getCallQuality() {
+ return mCallQuality;
+ }
+
+ /**
+ * Returns the call classification.
+ * @hide
+ */
+ public int getCallClassification() {
+ return mCallClassification;
+ }
+
+ /**
+ * Returns the IMS call session ID.
+ */
+ @Nullable
+ public String getImsCallSessionId() {
+ return mImsCallId;
+ }
+
+ /**
+ * Returns the IMS call service type.
+ */
+ @ImsCallServiceType
+ public int getImsCallServiceType() {
+ return mImsCallServiceType;
+ }
+
+ /**
+ * Returns the IMS call type.
+ */
+ @ImsCallType
+ public int getImsCallType() {
+ return mImsCallType;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPreciseCallState, mNetworkType, mCallQuality, mCallClassification,
+ mImsCallId, mImsCallServiceType, mImsCallType);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object o) {
+ if (o == null || !(o instanceof CallState) || hashCode() != o.hashCode()) {
+ return false;
+ }
+
+ if (this == o) {
+ return true;
+ }
+
+ CallState s = (CallState) o;
+
+ return (mPreciseCallState == s.mPreciseCallState
+ && mNetworkType == s.mNetworkType
+ && Objects.equals(mCallQuality, s.mCallQuality)
+ && mCallClassification == s.mCallClassification
+ && Objects.equals(mImsCallId, s.mImsCallId)
+ && mImsCallType == s.mImsCallType
+ && mImsCallServiceType == s.mImsCallServiceType);
+ }
+
+ /**
+ * {@link Parcelable#describeContents}
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * {@link Parcelable#writeToParcel}
+ */
+ public void writeToParcel(@Nullable Parcel dest, int flags) {
+ dest.writeInt(mPreciseCallState);
+ dest.writeInt(mNetworkType);
+ dest.writeParcelable(mCallQuality, flags);
+ dest.writeInt(mCallClassification);
+ dest.writeString(mImsCallId);
+ dest.writeInt(mImsCallServiceType);
+ dest.writeInt(mImsCallType);
+ }
+
+ public static final @NonNull Creator<CallState> CREATOR = new Creator() {
+ public CallState createFromParcel(Parcel in) {
+ return new CallState(in);
+ }
+
+ public CallState[] newArray(int size) {
+ return new CallState[size];
+ }
+ };
+
+ /**
+ * Builder of {@link CallState}
+ *
+ * <p>The example below shows how you might create a new {@code CallState}:
+ *
+ * <pre><code>
+ *
+ * CallState = new CallState.Builder()
+ * .setCallState(3)
+ * .setNetworkType({@link TelephonyManager#NETWORK_TYPE_LTE})
+ * .setCallQuality({@link CallQuality})
+ * .setImsCallSessionId({@link String})
+ * .setImsCallServiceType({@link ImsCallProfile#SERVICE_TYPE_NORMAL})
+ * .setImsCallType({@link ImsCallProfile#CALL_TYPE_VOICE})
+ * .build();
+ * </code></pre>
+ */
+ public static final class Builder {
+ private @PreciseCallStates int mPreciseCallState;
+ private @NetworkType int mNetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
+ private CallQuality mCallQuality = null;
+ private int mCallClassification = CALL_CLASSIFICATION_UNKNOWN;
+ private String mImsCallId;
+ private @ImsCallServiceType int mImsCallServiceType = ImsCallProfile.SERVICE_TYPE_NONE;
+ private @ImsCallType int mImsCallType = ImsCallProfile.CALL_TYPE_NONE;
+
+
+ /**
+ * Default constructor for the Builder.
+ */
+ public Builder(@PreciseCallStates int preciseCallState) {
+ mPreciseCallState = preciseCallState;
+ }
+
+ /**
+ * Set network type of this call.
+ *
+ * @param networkType the transport type.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public CallState.Builder setNetworkType(@NetworkType int networkType) {
+ this.mNetworkType = networkType;
+ return this;
+ }
+
+ /**
+ * Set the call quality {@link CallQuality} of this call.
+ *
+ * @param callQuality call quality of active call.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public CallState.Builder setCallQuality(@Nullable CallQuality callQuality) {
+ this.mCallQuality = callQuality;
+ return this;
+ }
+
+ /**
+ * Set call classification for this call.
+ *
+ * @param classification call classification type defined in this class.
+ * @return The same instance of the builder.
+ * @hide
+ */
+ @NonNull
+ public CallState.Builder setCallClassification(int classification) {
+ this.mCallClassification = classification;
+ return this;
+ }
+
+ /**
+ * Set IMS call session ID of this call.
+ *
+ * @param imsCallId IMS call session ID.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public CallState.Builder setImsCallSessionId(@Nullable String imsCallId) {
+ this.mImsCallId = imsCallId;
+ return this;
+ }
+
+ /**
+ * Set IMS call service type of this call.
+ *
+ * @param serviceType IMS call service type defined in {@link ImsCallProfile}.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public CallState.Builder setImsCallServiceType(@ImsCallServiceType int serviceType) {
+ this.mImsCallServiceType = serviceType;
+ return this;
+ }
+
+ /**
+ * Set IMS call type of this call.
+ *
+ * @param callType IMS call type defined in {@link ImsCallProfile}.
+ * @return The same instance of the builder.
+ */
+ @NonNull
+ public CallState.Builder setImsCallType(@ImsCallType int callType) {
+ this.mImsCallType = callType;
+ return this;
+ }
+
+ /**
+ * Build the {@link CallState}
+ *
+ * @return the {@link CallState} object
+ */
+ @NonNull
+ public CallState build() {
+ return new CallState(
+ mPreciseCallState,
+ mNetworkType,
+ mCallQuality,
+ mCallClassification,
+ mImsCallId,
+ mImsCallServiceType,
+ mImsCallType);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index e6d7df3..1ea7fdc 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -78,8 +78,9 @@
public static final int SERVICE_TYPE_EMERGENCY = 2;
/**
- * Call types
+ * Call type none
*/
+ public static final int CALL_TYPE_NONE = 0;
/**
* IMSPhone to support IR.92 & IR.94 (voice + video upgrade/downgrade)
*/
diff --git a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
index d133f6f..e2099e6 100644
--- a/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
+++ b/tests/UsbManagerTests/lib/src/com/android/server/usblib/UsbManagerTestLib.java
@@ -24,12 +24,15 @@
import android.content.Context;
import android.hardware.usb.UsbManager;
+import android.os.Binder;
import android.os.RemoteException;
import android.util.Log;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.concurrent.atomic.AtomicInteger;
+
/**
* Unit tests lib for {@link android.hardware.usb.UsbManager}.
*/
@@ -42,6 +45,11 @@
private UsbManager mUsbManagerMock;
@Mock private android.hardware.usb.IUsbManager mMockUsbService;
+ /**
+ * Counter for tracking UsbOperation operations.
+ */
+ private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
+
public UsbManagerTestLib(Context context) {
MockitoAnnotations.initMocks(this);
mContext = context;
@@ -82,10 +90,11 @@
}
private void testSetCurrentFunctionsMock_Matched(long functions) {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
try {
setCurrentFunctions(functions);
- verify(mMockUsbService).setCurrentFunctions(eq(functions));
+ verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
} catch (RemoteException remEx) {
Log.w(TAG, "RemoteException");
}
@@ -106,9 +115,10 @@
}
public void testSetCurrentFunctionsEx(long functions) throws Exception {
+ int operationId = sUsbOperationCount.incrementAndGet() + Binder.getCallingUid();
setCurrentFunctions(functions);
- verify(mMockUsbService).setCurrentFunctions(eq(functions));
+ verify(mMockUsbService).setCurrentFunctions(eq(functions), operationId);
}
public void testGetCurrentFunctions_shouldMatched() {
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
index 86bcb72..4103ca7 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbHandlerTest.java
@@ -98,7 +98,7 @@
}
@Override
- protected void setEnabledFunctions(long functions, boolean force) {
+ protected void setEnabledFunctions(long functions, boolean force, int operationId) {
mCurrentFunctions = functions;
}
@@ -134,6 +134,20 @@
protected void sendStickyBroadcast(Intent intent) {
mBroadcastedIntent = intent;
}
+
+ @Override
+ public void handlerInitDone(int operationId) {
+ }
+
+ @Override
+ public void setCurrentUsbFunctionsCb(long functions,
+ int status, int mRequest, long mFunctions, boolean mChargingFunctions){
+ }
+
+ @Override
+ public void getUsbSpeedCb(int speed){
+ }
+
}
@Before