Merge "Import translations. DO NOT MERGE"
diff --git a/Android.bp b/Android.bp
index 7cc2f30..21054dd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -319,6 +319,7 @@
"core/java/android/service/vr/IVrManager.aidl",
"core/java/android/service/vr/IVrStateCallbacks.aidl",
"core/java/android/service/watchdog/IExplicitHealthCheckService.aidl",
+ "core/java/android/service/watchdog/PackageInfo.aidl",
"core/java/android/print/ILayoutResultCallback.aidl",
"core/java/android/print/IPrinterDiscoveryObserver.aidl",
"core/java/android/print/IPrintDocumentAdapter.aidl",
@@ -1049,6 +1050,35 @@
},
}
+// This library is meant for vendor code that needs to output protobuf. It links
+// against the static version of libprotobuf-cpp-lite, for which we can not guarantee
+// binary compatibility.
+cc_library {
+ name: "libplatformprotos-static",
+ defaults: ["libplatformprotos-defaults"],
+ host_supported: false,
+
+ // This is okay because this library is only built as a static library. The C++
+ // API is not guaranteed. The proto API is guaranteed to be stable via Metrics Council,
+ // but is not authorized to be used outside of debugging.
+ vendor_available: true,
+
+ target: {
+ android: {
+ proto: {
+ type: "lite",
+ },
+ static_libs: [
+ "libprotobuf-cpp-lite",
+ ],
+ shared: {
+ enabled: false,
+ },
+ },
+ },
+}
+
+
// This is the full proto version of libplatformprotos. It may only
// be used by test code that is not shipped on the device.
cc_library {
diff --git a/api/current.txt b/api/current.txt
index 0eb6447..c88ed28 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -22659,7 +22659,7 @@
method public double getDriftNanosPerSecond();
method @FloatRange(from=0.0f) public double getDriftUncertaintyNanosPerSecond();
method public long getElapsedRealtimeNanos();
- method @IntRange(from=0) public long getElapsedRealtimeUncertaintyNanos();
+ method @FloatRange(from=0.0f) public double getElapsedRealtimeUncertaintyNanos();
method public long getFullBiasNanos();
method public int getHardwareClockDiscontinuityCount();
method public int getLeapSecond();
@@ -22863,7 +22863,7 @@
method public float getBearing();
method public float getBearingAccuracyDegrees();
method public long getElapsedRealtimeNanos();
- method public long getElapsedRealtimeUncertaintyNanos();
+ method public double getElapsedRealtimeUncertaintyNanos();
method public android.os.Bundle getExtras();
method public double getLatitude();
method public double getLongitude();
@@ -22892,7 +22892,7 @@
method public void setBearing(float);
method public void setBearingAccuracyDegrees(float);
method public void setElapsedRealtimeNanos(long);
- method public void setElapsedRealtimeUncertaintyNanos(long);
+ method public void setElapsedRealtimeUncertaintyNanos(double);
method public void setExtras(android.os.Bundle);
method public void setLatitude(double);
method public void setLongitude(double);
diff --git a/api/system-current.txt b/api/system-current.txt
index 63d1e73..8ac52f7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6890,12 +6890,21 @@
method @NonNull public final android.os.IBinder onBind(@NonNull android.content.Intent);
method public abstract void onCancelHealthCheck(@NonNull String);
method @NonNull public abstract java.util.List<java.lang.String> onGetRequestedPackages();
- method @NonNull public abstract java.util.List<java.lang.String> onGetSupportedPackages();
+ method @NonNull public abstract java.util.List<android.service.watchdog.PackageInfo> onGetSupportedPackages();
method public abstract void onRequestHealthCheck(@NonNull String);
field public static final String BIND_PERMISSION = "android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE";
field public static final String SERVICE_INTERFACE = "android.service.watchdog.ExplicitHealthCheckService";
}
+ public final class PackageInfo implements android.os.Parcelable {
+ ctor public PackageInfo(@NonNull String, long);
+ method public int describeContents();
+ method public long getHealthCheckTimeoutMillis();
+ method @NonNull public String getPackageName();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.service.watchdog.PackageInfo> CREATOR;
+ }
+
}
package android.telecom {
diff --git a/api/test-current.txt b/api/test-current.txt
index c541b04..242cac3 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -954,7 +954,7 @@
method public void setDriftNanosPerSecond(double);
method public void setDriftUncertaintyNanosPerSecond(@FloatRange(from=0.0f) double);
method public void setElapsedRealtimeNanos(long);
- method public void setElapsedRealtimeUncertaintyNanos(@IntRange(from=0) long);
+ method public void setElapsedRealtimeUncertaintyNanos(@FloatRange(from=0.0f) double);
method public void setFullBiasNanos(long);
method public void setHardwareClockDiscontinuityCount(int);
method public void setLeapSecond(int);
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 25e3573..e16ce24 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -937,7 +937,9 @@
//
// It is NOT ok to call this function from the system_server (for any of the packages it
// loads code from) so we explicitly disallow it there.
- if (needToSetupJitProfiles && !ActivityThread.isSystem()) {
+ //
+ // It is not ok to call this in a zygote context where mActivityThread is null.
+ if (needToSetupJitProfiles && !ActivityThread.isSystem() && mActivityThread != null) {
setupJitProfileSupport();
}
diff --git a/core/java/android/os/CoolingDevice.aidl b/core/java/android/os/CoolingDevice.aidl
new file mode 100644
index 0000000..478e4bd
--- /dev/null
+++ b/core/java/android/os/CoolingDevice.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2019, 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.os;
+
+parcelable CoolingDevice;
diff --git a/core/java/android/os/CoolingDevice.java b/core/java/android/os/CoolingDevice.java
new file mode 100644
index 0000000..0e86a38
--- /dev/null
+++ b/core/java/android/os/CoolingDevice.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2019 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.os;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.hardware.thermal.V2_0.CoolingType;
+
+import com.android.internal.util.Preconditions;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Cooling device values used by IThermalService.
+ *
+ * @hide
+ */
+public final class CoolingDevice implements Parcelable {
+ /**
+ * Current throttle state of the cooling device. The value can any unsigned integer
+ * numbers between 0 and max_state defined in its driver, usually representing the
+ * associated device's power state. 0 means device is not in throttling, higher value
+ * means deeper throttling.
+ */
+ private final long mValue;
+ /** A cooling device type from ThermalHAL */
+ private final int mType;
+ /** Name of this cooling device */
+ private final String mName;
+
+ @IntDef(prefix = { "TYPE_" }, value = {
+ TYPE_FAN,
+ TYPE_BATTERY,
+ TYPE_CPU,
+ TYPE_GPU,
+ TYPE_MODEM,
+ TYPE_NPU,
+ TYPE_COMPONENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ /** Fan for active cooling */
+ public static final int TYPE_FAN = CoolingType.FAN;
+ /** Battery charging cooling deivice */
+ public static final int TYPE_BATTERY = CoolingType.BATTERY;
+ /** CPU cooling deivice */
+ public static final int TYPE_CPU = CoolingType.CPU;
+ /** GPU cooling deivice */
+ public static final int TYPE_GPU = CoolingType.GPU;
+ /** Modem cooling deivice */
+ public static final int TYPE_MODEM = CoolingType.MODEM;
+ /** NPU/TPU cooling deivice */
+ public static final int TYPE_NPU = CoolingType.NPU;
+ /** Generic passive cooling deivice */
+ public static final int TYPE_COMPONENT = CoolingType.COMPONENT;
+
+ /**
+ * Verify a valid cooling device type.
+ *
+ * @return true if a cooling device type is valid otherwise false.
+ */
+ public static boolean isValidType(@Type int type) {
+ return type >= TYPE_FAN && type <= TYPE_COMPONENT;
+ }
+
+ public CoolingDevice(long value, @Type int type, @NonNull String name) {
+ Preconditions.checkArgument(isValidType(type), "Invalid Type");
+ mValue = value;
+ mType = type;
+ mName = Preconditions.checkStringNotEmpty(name);
+ }
+
+ /**
+ * Return the cooling device value.
+ *
+ * @return a cooling device value in int.
+ */
+ public long getValue() {
+ return mValue;
+ }
+
+ /**
+ * Return the cooling device type.
+ *
+ * @return a cooling device type: TYPE_*
+ */
+ public @Type int getType() {
+ return mType;
+ }
+
+ /**
+ * Return the cooling device name.
+ *
+ * @return a cooling device name as String.
+ */
+ public String getName() {
+ return mName;
+ }
+
+ @Override
+ public String toString() {
+ return "CoolingDevice{mValue=" + mValue + ", mType=" + mType + ", mName=" + mName + "}";
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = mName.hashCode();
+ hash = 31 * hash + Long.hashCode(mValue);
+ hash = 31 * hash + mType;
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof CoolingDevice)) {
+ return false;
+ }
+ CoolingDevice other = (CoolingDevice) o;
+ return other.mValue == mValue && other.mType == mType && other.mName.equals(mName);
+ }
+
+ @Override
+ public void writeToParcel(Parcel p, int flags) {
+ p.writeLong(mValue);
+ p.writeInt(mType);
+ p.writeString(mName);
+ }
+
+ public static final @android.annotation.NonNull Parcelable.Creator<CoolingDevice> CREATOR =
+ new Parcelable.Creator<CoolingDevice>() {
+ @Override
+ public CoolingDevice createFromParcel(Parcel p) {
+ long value = p.readLong();
+ int type = p.readInt();
+ String name = p.readString();
+ return new CoolingDevice(value, type, name);
+ }
+
+ @Override
+ public CoolingDevice[] newArray(int size) {
+ return new CoolingDevice[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/core/java/android/os/IThermalService.aidl b/core/java/android/os/IThermalService.aidl
index 9280cb9..8c98960 100644
--- a/core/java/android/os/IThermalService.aidl
+++ b/core/java/android/os/IThermalService.aidl
@@ -16,6 +16,7 @@
package android.os;
+import android.os.CoolingDevice;
import android.os.IThermalEventListener;
import android.os.IThermalStatusListener;
import android.os.Temperature;
@@ -52,7 +53,7 @@
/**
* Get current temperature with its throttling status.
- * @return list of android.os.Temperature
+ * @return list of {@link android.os.Temperature}.
* {@hide}
*/
List<Temperature> getCurrentTemperatures();
@@ -87,4 +88,19 @@
* {@hide}
*/
int getCurrentThermalStatus();
+
+ /**
+ * Get current cooling devices.
+ * @return list of {@link android.os.CoolingDevice}.
+ * {@hide}
+ */
+ List<CoolingDevice> getCurrentCoolingDevices();
+
+ /**
+ * Get current cooling devices on given type.
+ * @param type the cooling device type to query.
+ * @return list of {@link android.os.CoolingDevice}.
+ * {@hide}
+ */
+ List<CoolingDevice> getCurrentCoolingDevicesWithType(in int type);
}
diff --git a/core/java/android/os/Temperature.java b/core/java/android/os/Temperature.java
index be7e824..7caffcd 100644
--- a/core/java/android/os/Temperature.java
+++ b/core/java/android/os/Temperature.java
@@ -17,9 +17,12 @@
package android.os;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.hardware.thermal.V2_0.TemperatureType;
import android.hardware.thermal.V2_0.ThrottlingSeverity;
+import com.android.internal.util.Preconditions;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -30,13 +33,13 @@
*/
public final class Temperature implements Parcelable {
/** Temperature value */
- private float mValue;
- /** A temperature type from ThermalHAL */
- private int mType;
- /** Name of this temperature */
- private String mName;
+ private final float mValue;
+ /** A Temperature type from ThermalHAL */
+ private final int mType;
+ /** Name of this Temperature */
+ private final String mName;
/** The level of the sensor is currently in throttling */
- private int mStatus;
+ private final int mStatus;
@IntDef(prefix = { "THROTTLING_" }, value = {
THROTTLING_NONE,
@@ -75,7 +78,7 @@
@Retention(RetentionPolicy.SOURCE)
public @interface Type {}
- /* Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
+ /** Keep in sync with hardware/interfaces/thermal/2.0/types.hal */
public static final int TYPE_UNKNOWN = TemperatureType.UNKNOWN;
public static final int TYPE_CPU = TemperatureType.CPU;
public static final int TYPE_GPU = TemperatureType.GPU;
@@ -89,9 +92,9 @@
public static final int TYPE_NPU = TemperatureType.NPU;
/**
- * Verify a valid temperature type.
+ * Verify a valid Temperature type.
*
- * @return true if a temperature type is valid otherwise false.
+ * @return true if a Temperature type is valid otherwise false.
*/
public static boolean isValidType(@Type int type) {
return type >= TYPE_UNKNOWN && type <= TYPE_NPU;
@@ -106,67 +109,75 @@
return status >= THROTTLING_NONE && status <= THROTTLING_SHUTDOWN;
}
- public Temperature() {
- this(Float.NaN, TYPE_UNKNOWN, "", THROTTLING_NONE);
- }
-
- public Temperature(float value, @Type int type, String name, @ThrottlingStatus int status) {
+ public Temperature(float value, @Type int type,
+ @NonNull String name, @ThrottlingStatus int status) {
+ Preconditions.checkArgument(isValidType(type), "Invalid Type");
+ Preconditions.checkArgument(isValidStatus(status) , "Invalid Status");
mValue = value;
- mType = isValidType(type) ? type : TYPE_UNKNOWN;
- mName = name;
- mStatus = isValidStatus(status) ? status : THROTTLING_NONE;
+ mType = type;
+ mName = Preconditions.checkStringNotEmpty(name);
+ mStatus = status;
}
/**
- * Return the temperature value.
+ * Return the Temperature value.
*
- * @return a temperature value in floating point could be NaN.
+ * @return a Temperature value in floating point could be NaN.
*/
public float getValue() {
return mValue;
}
/**
- * Return the temperature type.
+ * Return the Temperature type.
*
- * @return a temperature type: TYPE_*
+ * @return a Temperature type: TYPE_*
*/
public @Type int getType() {
return mType;
}
/**
- * Return the temperature name.
+ * Return the Temperature name.
*
- * @return a temperature name as String.
+ * @return a Temperature name as String.
*/
public String getName() {
return mName;
}
/**
- * Return the temperature throttling status.
+ * Return the Temperature throttling status.
*
- * @return a temperature throttling status: THROTTLING_*
+ * @return a Temperature throttling status: THROTTLING_*
*/
public @ThrottlingStatus int getStatus() {
return mStatus;
}
- private Temperature(Parcel p) {
- readFromParcel(p);
+ @Override
+ public String toString() {
+ return "Temperature{mValue=" + mValue + ", mType=" + mType
+ + ", mName=" + mName + ", mStatus=" + mStatus + "}";
}
- /**
- * Fill in Temperature members from a Parcel.
- *
- * @param p the parceled Temperature object.
- */
- public void readFromParcel(Parcel p) {
- mValue = p.readFloat();
- mType = p.readInt();
- mName = p.readString();
- mStatus = p.readInt();
+ @Override
+ public int hashCode() {
+ int hash = mName.hashCode();
+ hash = 31 * hash + Float.hashCode(mValue);
+ hash = 31 * hash + mType;
+ hash = 31 * hash + mStatus;
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof Temperature)) {
+ return false;
+ }
+ Temperature other = (Temperature) o;
+ return other.mValue == mValue && other.mType == mType
+ && other.mName.equals(mName) && other.mStatus == mStatus;
}
@Override
@@ -181,13 +192,18 @@
new Parcelable.Creator<Temperature>() {
@Override
public Temperature createFromParcel(Parcel p) {
- return new Temperature(p);
+ float value = p.readFloat();
+ int type = p.readInt();
+ String name = p.readString();
+ int status = p.readInt();
+ return new Temperature(value, type, name, status);
}
@Override
public Temperature[] newArray(int size) {
return new Temperature[size];
}
+
};
@Override
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 5631282..9ec7723 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -260,6 +260,13 @@
public static final String NAMESPACE_TEXTCLASSIFIER = "textclassifier";
/**
+ * Namespace for contacts provider related features.
+ *
+ * @hide
+ */
+ public static final String NAMESPACE_CONTACTS_PROVIDER = "contacts_provider";
+
+ /**
* List of namespaces which can be read without READ_DEVICE_CONFIG permission
*
* @hide
diff --git a/core/java/android/service/watchdog/ExplicitHealthCheckService.java b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
index 015fba1..682b872 100644
--- a/core/java/android/service/watchdog/ExplicitHealthCheckService.java
+++ b/core/java/android/service/watchdog/ExplicitHealthCheckService.java
@@ -61,7 +61,7 @@
private static final String TAG = "ExplicitHealthCheckService";
/**
- * {@link Bundle} key for a {@link List} of {@link String} value.
+ * {@link Bundle} key for a {@link List} of {@link PackageInfo} value.
*
* {@hide}
*/
@@ -130,7 +130,7 @@
*
* @return all packages supporting explicit health checks
*/
- @NonNull public abstract List<String> onGetSupportedPackages();
+ @NonNull public abstract List<PackageInfo> onGetSupportedPackages();
/**
* Called when the system requests for all the packages that it has currently requested
@@ -187,22 +187,26 @@
@Override
public void getSupportedPackages(RemoteCallback callback) throws RemoteException {
- mHandler.post(() -> sendPackages(callback, EXTRA_SUPPORTED_PACKAGES,
- ExplicitHealthCheckService.this.onGetSupportedPackages()));
+ mHandler.post(() -> {
+ List<PackageInfo> packages =
+ ExplicitHealthCheckService.this.onGetSupportedPackages();
+ Objects.requireNonNull(packages, "Supported package list must be non-null");
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(EXTRA_SUPPORTED_PACKAGES, new ArrayList<>(packages));
+ callback.sendResult(bundle);
+ });
}
@Override
public void getRequestedPackages(RemoteCallback callback) throws RemoteException {
- mHandler.post(() -> sendPackages(callback, EXTRA_REQUESTED_PACKAGES,
- ExplicitHealthCheckService.this.onGetRequestedPackages()));
- }
-
- private void sendPackages(RemoteCallback callback, String key, List<String> packages) {
- Objects.requireNonNull(packages,
- "Supported and requested package list must be non-null");
- Bundle bundle = new Bundle();
- bundle.putStringArrayList(key, new ArrayList<>(packages));
- callback.sendResult(bundle);
+ mHandler.post(() -> {
+ List<String> packages =
+ ExplicitHealthCheckService.this.onGetRequestedPackages();
+ Objects.requireNonNull(packages, "Requested package list must be non-null");
+ Bundle bundle = new Bundle();
+ bundle.putStringArrayList(EXTRA_REQUESTED_PACKAGES, new ArrayList<>(packages));
+ callback.sendResult(bundle);
+ });
}
}
}
diff --git a/core/java/android/service/watchdog/PackageInfo.aidl b/core/java/android/service/watchdog/PackageInfo.aidl
new file mode 100644
index 0000000..5605aec
--- /dev/null
+++ b/core/java/android/service/watchdog/PackageInfo.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2019 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.service.watchdog;
+
+/**
+ * @hide
+ */
+parcelable PackageInfo;
diff --git a/core/java/android/service/watchdog/PackageInfo.java b/core/java/android/service/watchdog/PackageInfo.java
new file mode 100644
index 0000000..cee9b6d
--- /dev/null
+++ b/core/java/android/service/watchdog/PackageInfo.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2019 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.service.watchdog;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A PackageInfo contains a package supporting explicit health checks and the
+ * timeout in {@link System#uptimeMillis} across reboots after which health
+ * check requests from clients are failed.
+ *
+ * @hide
+ */
+@SystemApi
+public final class PackageInfo implements Parcelable {
+ // TODO: Receive from DeviceConfig flag
+ private static final long DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS = TimeUnit.HOURS.toMillis(1);
+
+ private final String mPackageName;
+ private final long mHealthCheckTimeoutMillis;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param packageName the package name
+ * @param durationMillis the duration in milliseconds, must be greater than or
+ * equal to 0. If it is 0, it will use a system default value.
+ */
+ public PackageInfo(@NonNull String packageName, long healthCheckTimeoutMillis) {
+ mPackageName = Preconditions.checkNotNull(packageName);
+ if (healthCheckTimeoutMillis == 0) {
+ mHealthCheckTimeoutMillis = DEFAULT_HEALTH_CHECK_TIMEOUT_MILLIS;
+ } else {
+ mHealthCheckTimeoutMillis = Preconditions.checkArgumentNonnegative(
+ healthCheckTimeoutMillis);
+ }
+ }
+
+ private PackageInfo(Parcel parcel) {
+ mPackageName = parcel.readString();
+ mHealthCheckTimeoutMillis = parcel.readLong();
+ }
+
+ /**
+ * Gets the package name.
+ *
+ * @return the package name
+ */
+ public @NonNull String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Gets the timeout in milliseconds to evaluate an explicit health check result after a request.
+ *
+ * @return the duration in {@link System#uptimeMillis} across reboots
+ */
+ public long getHealthCheckTimeoutMillis() {
+ return mHealthCheckTimeoutMillis;
+ }
+
+ @Override
+ public String toString() {
+ return "PackageInfo{" + mPackageName + ", " + mHealthCheckTimeoutMillis + "}";
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (other == this) {
+ return true;
+ }
+ if (!(other instanceof PackageInfo)) {
+ return false;
+ }
+
+ PackageInfo otherInfo = (PackageInfo) other;
+ return Objects.equals(otherInfo.getHealthCheckTimeoutMillis(), mHealthCheckTimeoutMillis)
+ && Objects.equals(otherInfo.getPackageName(), mPackageName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPackageName, mHealthCheckTimeoutMillis);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mPackageName);
+ parcel.writeLong(mHealthCheckTimeoutMillis);
+ }
+
+ public static final @NonNull Creator<PackageInfo> CREATOR = new Creator<PackageInfo>() {
+ @Override
+ public PackageInfo createFromParcel(Parcel source) {
+ return new PackageInfo(source);
+ }
+
+ @Override
+ public PackageInfo[] newArray(int size) {
+ return new PackageInfo[size];
+ }
+ };
+}
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 336c2e5..04046fe 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -53,7 +53,6 @@
DEFAULT_FLAGS.put("settings_network_and_internet_v2", "true");
DEFAULT_FLAGS.put("settings_slice_injection", "true");
DEFAULT_FLAGS.put("settings_systemui_theme", "true");
- DEFAULT_FLAGS.put("settings_mainline_module", "true");
DEFAULT_FLAGS.put(DYNAMIC_SYSTEM, "false");
DEFAULT_FLAGS.put(SEAMLESS_TRANSFER, "false");
DEFAULT_FLAGS.put(HEARING_AID_SETTINGS, "false");
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index afa6a6a..94be25f 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -788,7 +788,7 @@
} else {
ImageView fileIconView = parent.findViewById(R.id.content_preview_file_icon);
fileIconView.setVisibility(View.VISIBLE);
- fileIconView.setImageResource(R.drawable.ic_doc_generic);
+ fileIconView.setImageResource(R.drawable.chooser_file_generic);
}
}
@@ -837,12 +837,14 @@
}
for (Uri uri : uris) {
- if (findPreferredContentPreview(uri, resolver) == CONTENT_PREVIEW_IMAGE) {
- return CONTENT_PREVIEW_IMAGE;
+ // Defaulting to file preview when there are mixed image/file types is
+ // preferable, as it shows the user the correct number of items being shared
+ if (findPreferredContentPreview(uri, resolver) == CONTENT_PREVIEW_FILE) {
+ return CONTENT_PREVIEW_FILE;
}
}
- return CONTENT_PREVIEW_FILE;
+ return CONTENT_PREVIEW_IMAGE;
}
return CONTENT_PREVIEW_TEXT;
diff --git a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
index b47ef12..ff94264 100644
--- a/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
+++ b/core/java/com/android/internal/statusbar/RegisterStatusBarResult.java
@@ -78,8 +78,8 @@
dest.writeInt(mFullscreenStackSysUiVisibility);
dest.writeInt(mDockedStackSysUiVisibility);
dest.writeStrongBinder(mImeToken);
- dest.writeParcelable(mFullscreenStackBounds, flags);
- dest.writeParcelable(mDockedStackBounds, flags);
+ dest.writeTypedObject(mFullscreenStackBounds, flags);
+ dest.writeTypedObject(mDockedStackBounds, flags);
}
/**
@@ -101,8 +101,8 @@
final int fullscreenStackSysUiVisibility = source.readInt();
final int dockedStackSysUiVisibility = source.readInt();
final IBinder imeToken = source.readStrongBinder();
- final Rect fullscreenStackBounds = Rect.CREATOR.createFromParcel(source);
- final Rect dockedStackBounds = Rect.CREATOR.createFromParcel(source);
+ final Rect fullscreenStackBounds = source.readTypedObject(Rect.CREATOR);
+ final Rect dockedStackBounds = source.readTypedObject(Rect.CREATOR);
return new RegisterStatusBarResult(icons, disabledFlags1, systemUiVisibility,
menuVisible, imeWindowVis, imeBackDisposition, showImeSwitcher,
disabledFlags2, fullscreenStackSysUiVisibility,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c7a60cf..c7d8432 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -618,6 +618,7 @@
<!-- Added in Q -->
<protected-broadcast android:name="android.content.pm.action.SESSION_UPDATED" />
+ <protected-broadcast android:name="android.settings.action.GRAYSCALE_CHANGED" />
<!-- For CarIdlenessTracker -->
<protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_ON" />
diff --git a/core/res/res/drawable/chooser_file_generic.xml b/core/res/res/drawable/chooser_file_generic.xml
new file mode 100644
index 0000000..006dfba
--- /dev/null
+++ b/core/res/res/drawable/chooser_file_generic.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:fillColor="#FF737373"
+ android:pathData="M6 2c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6H6zm7 7V3.5L18.5 9H13z"/>
+</vector>
diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml
index 7cfbb1b..6abf57a 100644
--- a/core/res/res/layout/chooser_grid_preview_text.xml
+++ b/core/res/res/layout/chooser_grid_preview_text.xml
@@ -51,7 +51,9 @@
android:layout_height="24dp"
android:gravity="center"
android:layout_gravity="center_vertical"
- android:background="@drawable/ic_content_copy_gm2"/>
+ android:foreground="@drawable/ic_content_copy_gm2"
+ android:clickable="true"
+ android:background="?attr/selectableItemBackgroundBorderless"/>
</LinearLayout>
<!-- Required sub-layout so we can get the nice rounded corners-->
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 21f5acb..e8cc96c 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3558,6 +3558,12 @@
-->
<string name="config_defaultSystemCaptionsService" translatable="false"></string>
+ <!-- The component name for the system-wide captions manager service.
+ This service must be trusted, as the system binds to it and keeps it running.
+ Example: "com.android.captions/.SystemCaptionsManagerService"
+ -->
+ <string name="config_defaultSystemCaptionsManagerService" translatable="false"></string>
+
<!-- The package name for the incident report approver app.
This app is usually PermissionController or an app that replaces it. When
a bugreport or incident report with EXPLICT-level sharing flags is going to be
diff --git a/core/res/res/values/styles_device_defaults.xml b/core/res/res/values/styles_device_defaults.xml
index 3c7b36d..d253f00 100644
--- a/core/res/res/values/styles_device_defaults.xml
+++ b/core/res/res/values/styles_device_defaults.xml
@@ -98,7 +98,11 @@
<style name="Widget.DeviceDefault.ActionBar.TabView" parent="Widget.Material.ActionBar.TabView"/>
<style name="Widget.DeviceDefault.ActionBar.TabText" parent="Widget.Material.ActionBar.TabText"/>
<style name="Widget.DeviceDefault.ActionBar.TabBar" parent="Widget.Material.ActionBar.TabBar"/>
- <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Material.ActionBar.Solid"/>
+ <style name="Widget.DeviceDefault.ActionBar.Solid" parent="Widget.Material.ActionBar.Solid">
+ <item name="background">?attr/colorPrimaryDark</item>
+ <item name="backgroundStacked">?attr/colorPrimaryDark</item>
+ <item name="backgroundSplit">?attr/colorPrimaryDark</item>
+ </style>
<style name="Widget.DeviceDefault.Button.Borderless.Small" parent="Widget.Material.Button.Borderless.Small"/>
<style name="Widget.DeviceDefault.AbsListView" parent="Widget.Material.AbsListView"/>
<style name="Widget.DeviceDefault.Spinner.DropDown.ActionBar" parent="Widget.Material.Spinner.DropDown.ActionBar"/>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fb7be77..664059a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3409,6 +3409,7 @@
<java-symbol type="string" name="config_defaultContentSuggestionsService" />
<java-symbol type="string" name="config_defaultAttentionService" />
<java-symbol type="string" name="config_defaultSystemCaptionsService" />
+ <java-symbol type="string" name="config_defaultSystemCaptionsManagerService" />
<java-symbol type="string" name="notification_channel_foreground_service" />
<java-symbol type="string" name="foreground_service_app_in_background" />
@@ -3477,6 +3478,7 @@
<java-symbol type="layout" name="shutdown_dialog" />
<java-symbol type="dimen" name="chooser_service_spacing" />
<java-symbol type="bool" name="config_showSysuiShutdown" />
+ <java-symbol type="drawable" name="chooser_file_generic" />
<java-symbol type="layout" name="notification_template_messaging_text_message" />
<java-symbol type="layout" name="notification_template_messaging_image_message" />
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
new file mode 100644
index 0000000..3cb1e18
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/statusbar/RegisterStatusBarResultTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Parcel;
+import android.os.UserHandle;
+import android.util.ArrayMap;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class RegisterStatusBarResultTest {
+
+ /**
+ * Test {@link RegisterStatusBarResult} can be stored then restored with {@link Parcel}.
+ */
+ @Test
+ public void testParcelable() {
+ final String dumyIconKey = "dummyIcon1";
+ final ArrayMap<String, StatusBarIcon> iconMap = new ArrayMap<>();
+ iconMap.put(dumyIconKey, new StatusBarIcon("com.android.internal.statusbar.test",
+ UserHandle.of(100), 123, 1, 2, "dummyIconDescription"));
+
+ final RegisterStatusBarResult original = new RegisterStatusBarResult(iconMap,
+ 0x2 /* disabledFlags1 */,
+ 0x4 /* systemUiVisibility */,
+ true /* menuVisible */,
+ 0x8 /* imeWindowVis */,
+ 0x10 /* imeBackDisposition */,
+ false /* showImeSwitcher */,
+ 0x20 /* disabledFlags2 */,
+ 0x40 /* fullscreenStackSysUiVisibility */,
+ 0x80 /* dockedStackSysUiVisibility */,
+ new Binder() /* imeToken */,
+ new Rect(0x100, 0x200, 0x400, 0x800) /* fullscreenStackBounds */,
+ new Rect(0x1000, 0x2000, 0x4000, 0x8000) /* dockedStackBounds */);
+
+ final RegisterStatusBarResult copy = clone(original);
+
+ assertThat(copy.mIcons).hasSize(original.mIcons.size());
+ // We already test that StatusBarIcon is Parcelable. Only check StatusBarIcon.user here.
+ assertThat(copy.mIcons.get(dumyIconKey).user)
+ .isEqualTo(original.mIcons.get(dumyIconKey).user);
+
+ assertThat(copy.mDisabledFlags1).isEqualTo(original.mDisabledFlags1);
+ assertThat(copy.mSystemUiVisibility).isEqualTo(original.mSystemUiVisibility);
+ assertThat(copy.mMenuVisible).isEqualTo(original.mMenuVisible);
+ assertThat(copy.mImeWindowVis).isEqualTo(original.mImeWindowVis);
+ assertThat(copy.mImeBackDisposition).isEqualTo(original.mImeBackDisposition);
+ assertThat(copy.mShowImeSwitcher).isEqualTo(original.mShowImeSwitcher);
+ assertThat(copy.mDisabledFlags2).isEqualTo(original.mDisabledFlags2);
+ assertThat(copy.mFullscreenStackSysUiVisibility)
+ .isEqualTo(original.mFullscreenStackSysUiVisibility);
+ assertThat(copy.mDockedStackSysUiVisibility)
+ .isEqualTo(original.mDockedStackSysUiVisibility);
+ assertThat(copy.mImeToken).isSameAs(original.mImeToken);
+ assertThat(copy.mFullscreenStackBounds).isEqualTo(original.mFullscreenStackBounds);
+ assertThat(copy.mDockedStackBounds).isEqualTo(original.mDockedStackBounds);
+ }
+
+ private RegisterStatusBarResult clone(RegisterStatusBarResult original) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return RegisterStatusBarResult.CREATOR.createFromParcel(parcel);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+}
diff --git a/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java b/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java
new file mode 100644
index 0000000..fe552a0
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/statusbar/StatusBarIconTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.os.UserHandle;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class StatusBarIconTest {
+
+ /**
+ * Test {@link StatusBarIcon} can be stored then restored with {@link Parcel}.
+ */
+ @Test
+ public void testParcelable() {
+ final UserHandle dummyUserHandle = UserHandle.of(100);
+ final String dummyIconPackageName = "com.android.internal.statusbar.test";
+ final int dummyIconId = 123;
+ final int dummyIconLevel = 1;
+ final int dummyIconNumber = 2;
+ final CharSequence dummyIconContentDescription = "dummyIcon";
+ final StatusBarIcon original = new StatusBarIcon(dummyIconPackageName, dummyUserHandle,
+ dummyIconId, dummyIconLevel, dummyIconNumber, dummyIconContentDescription);
+
+ final StatusBarIcon copy = clone(original);
+
+ assertThat(copy.user).isEqualTo(original.user);
+ assertThat(copy.pkg).isEqualTo(original.pkg);
+ assertThat(copy.icon.sameAs(original.icon)).isTrue();
+ assertThat(copy.iconLevel).isEqualTo(original.iconLevel);
+ assertThat(copy.visible).isEqualTo(original.visible);
+ assertThat(copy.number).isEqualTo(original.number);
+ assertThat(copy.contentDescription).isEqualTo(original.contentDescription);
+ }
+
+ private StatusBarIcon clone(StatusBarIcon original) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return StatusBarIcon.CREATOR.createFromParcel(parcel);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+}
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 9519704..1b515ad 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -1319,7 +1319,7 @@
typedef std::map<int, int> SourceToDestinationRuntimePackageMap;
std::map<ApkAssetsCookie, SourceToDestinationRuntimePackageMap> src_asset_cookie_id_map;
- // Determine which ApkAssets are loaded in both theme AssetManagers
+ // Determine which ApkAssets are loaded in both theme AssetManagers.
std::vector<const ApkAssets*> src_assets = o.asset_manager_->GetApkAssets();
for (size_t i = 0; i < src_assets.size(); i++) {
const ApkAssets* src_asset = src_assets[i];
@@ -1328,7 +1328,7 @@
for (size_t j = 0; j < dest_assets.size(); j++) {
const ApkAssets* dest_asset = dest_assets[j];
- // Map the runtime package of the source apk asset to the destination apk asset
+ // Map the runtime package of the source apk asset to the destination apk asset.
if (src_asset->GetPath() == dest_asset->GetPath()) {
const std::vector<std::unique_ptr<const LoadedPackage>>& src_packages =
src_asset->GetLoadedArsc()->GetPackages();
@@ -1353,15 +1353,14 @@
package_map[src_package_id] = dest_package_id;
}
- src_to_dest_asset_cookies.insert(std::pair<ApkAssetsCookie, ApkAssetsCookie>(i, j));
- src_asset_cookie_id_map.insert(
- std::pair<ApkAssetsCookie, SourceToDestinationRuntimePackageMap>(i, package_map));
+ src_to_dest_asset_cookies.insert(std::make_pair(i, j));
+ src_asset_cookie_id_map.insert(std::make_pair(i, package_map));
break;
}
}
}
- // Reset the data in the destination theme
+ // Reset the data in the destination theme.
for (size_t p = 0; p < packages_.size(); p++) {
if (packages_[p] != nullptr) {
packages_[p].reset();
@@ -1387,16 +1386,17 @@
continue;
}
- // If the attribute value represents an attribute or reference, the package id of the
- // value needs to be rewritten to the package id of the value in the destination
- uint32_t attribue_data = entry.value.data;
- if ((entry.value.dataType == Res_value::TYPE_ATTRIBUTE
- || entry.value.dataType == Res_value::TYPE_REFERENCE
- || entry.value.dataType == Res_value::TYPE_DYNAMIC_ATTRIBUTE
- || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
- && attribue_data != 0x0) {
+ 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
+ || entry.value.dataType == Res_value::TYPE_DYNAMIC_REFERENCE)
+ && entry.value.data != 0x0;
- // Determine the package id of the reference in the destination AssetManager
+ // If the attribute value represents an attribute or reference, the package id of the
+ // value needs to be rewritten to the package id of the value in the destination.
+ uint32_t attribute_data = entry.value.data;
+ if (is_reference) {
+ // Determine the package id of the reference in the destination AssetManager.
auto value_package_map = src_asset_cookie_id_map.find(entry.cookie);
if (value_package_map == src_asset_cookie_id_map.end()) {
continue;
@@ -1408,14 +1408,28 @@
continue;
}
- attribue_data = fix_package_id(entry.value.data, value_dest_package->second);
+ attribute_data = fix_package_id(entry.value.data, value_dest_package->second);
+ }
+
+ // Find the cookie of the value in the destination. If the source apk is not loaded in the
+ // destination, only copy resources that do not reference resources in the source.
+ ApkAssetsCookie data_dest_cookie;
+ auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
+ if (value_dest_cookie != src_to_dest_asset_cookies.end()) {
+ data_dest_cookie = value_dest_cookie->second;
+ } else {
+ if (is_reference || entry.value.dataType == Res_value::TYPE_STRING) {
+ continue;
+ } else {
+ data_dest_cookie = 0x0;
+ }
}
// The package id of the attribute needs to be rewritten to the package id of the
- // attribute in the destination
+ // attribute in the destination.
int attribute_dest_package_id = p;
if (attribute_dest_package_id != 0x01) {
- // Find the cookie of the attribute resource id
+ // Find the cookie of the attribute resource id in the source AssetManager
FindEntryResult attribute_entry_result;
ApkAssetsCookie attribute_cookie =
o.asset_manager_->FindEntry(make_resid(p, t, e), 0 /* density_override */ ,
@@ -1423,7 +1437,7 @@
true /* ignore_configuration */,
&attribute_entry_result);
- // Determine the package id of the attribute in the destination AssetManager
+ // Determine the package id of the attribute in the destination AssetManager.
auto attribute_package_map = src_asset_cookie_id_map.find(attribute_cookie);
if (attribute_package_map == src_asset_cookie_id_map.end()) {
continue;
@@ -1436,13 +1450,13 @@
attribute_dest_package_id = attribute_dest_package->second;
}
- // Lazily instantiate the destination package
+ // Lazily instantiate the destination package.
std::unique_ptr<Package>& dest_package = packages_[attribute_dest_package_id];
if (dest_package == nullptr) {
dest_package.reset(new Package());
}
- // Lazily instantiate and resize the destination type
+ // Lazily instantiate and resize the destination type.
util::unique_cptr<ThemeType>& dest_type = dest_package->types[t];
if (dest_type == nullptr || dest_type->entry_count < type->entry_count) {
const size_t type_alloc_size = sizeof(ThemeType)
@@ -1450,7 +1464,7 @@
void* dest_data = malloc(type_alloc_size);
memset(dest_data, 0, type->entry_count * sizeof(ThemeEntry));
- // Copy the existing destination type values if the type is resized
+ // Copy the existing destination type values if the type is resized.
if (dest_type != nullptr) {
memcpy(dest_data, type, sizeof(ThemeType)
+ (dest_type->entry_count * sizeof(ThemeEntry)));
@@ -1460,15 +1474,9 @@
dest_type->entry_count = type->entry_count;
}
- // Find the cookie of the value in the destination
- auto value_dest_cookie = src_to_dest_asset_cookies.find(entry.cookie);
- if (value_dest_cookie == src_to_dest_asset_cookies.end()) {
- continue;
- }
-
- dest_type->entries[e].cookie = value_dest_cookie->second;
+ dest_type->entries[e].cookie = data_dest_cookie;
dest_type->entries[e].value.dataType = entry.value.dataType;
- dest_type->entries[e].value.data = attribue_data;
+ dest_type->entries[e].value.data = attribute_data;
dest_type->entries[e].type_spec_flags = entry.type_spec_flags;
}
}
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 2c39cee..be5ecd9 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -282,48 +282,81 @@
}
TEST_F(ThemeTest, OnlyCopySameAssetsThemeWhenAssetManagersDiffer) {
- AssetManager2 assetmanager_one;
- assetmanager_one.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
+ AssetManager2 assetmanager_dst;
+ assetmanager_dst.SetApkAssets({system_assets_.get(), lib_one_assets_.get(), style_assets_.get(),
libclient_assets_.get()});
- AssetManager2 assetmanager_two;
- assetmanager_two.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
+ AssetManager2 assetmanager_src;
+ assetmanager_src.SetApkAssets({system_assets_.get(), lib_two_assets_.get(), lib_one_assets_.get(),
style_assets_.get()});
- auto theme_one = assetmanager_one.NewTheme();
- ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
+ auto theme_dst = assetmanager_dst.NewTheme();
+ ASSERT_TRUE(theme_dst->ApplyStyle(app::R::style::StyleOne));
- auto theme_two = assetmanager_two.NewTheme();
- ASSERT_TRUE(theme_two->ApplyStyle(R::style::Theme_One));
- ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
- ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
+ auto theme_src = assetmanager_src.NewTheme();
+ ASSERT_TRUE(theme_src->ApplyStyle(R::style::Theme_One));
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleTwo));
+ ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_one::R::style::Theme, 0x03),
false /*force*/));
- ASSERT_TRUE(theme_two->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
+ ASSERT_TRUE(theme_src->ApplyStyle(fix_package_id(lib_two::R::style::Theme, 0x02),
false /*force*/));
- theme_one->SetTo(*theme_two);
+ theme_dst->SetTo(*theme_src);
Res_value value;
uint32_t flags;
- // System resources (present in destination asset manager)
- EXPECT_EQ(0, theme_one->GetAttribute(R::attr::foreground, &value, &flags));
+ // System resources (present in destination asset manager).
+ EXPECT_EQ(0, theme_dst->GetAttribute(R::attr::foreground, &value, &flags));
// The cookie of the style asset is 3 in the source and 2 in the destination.
- // Check that the cookie has been rewritten to the destination values
- EXPECT_EQ(2, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+ // Check that the cookie has been rewritten to the destination values.
+ EXPECT_EQ(2, theme_dst->GetAttribute(app::R::attr::attr_one, &value, &flags));
// The cookie of the lib_one asset is 2 in the source and 1 in the destination.
// The package id of the lib_one package is 0x03 in the source and 0x02 in the destination
- // Check that the cookie and packages have been rewritten to the destination values
- EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
+ // Check that the cookie and packages have been rewritten to the destination values.
+ EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr1, 0x02), &value,
&flags));
- EXPECT_EQ(1, theme_one->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
+ EXPECT_EQ(1, theme_dst->GetAttribute(fix_package_id(lib_one::R::attr::attr2, 0x02), &value,
&flags));
// attr2 references an attribute in lib_one. Check that the resolution of the attribute value is
- // correct after the value of attr2 had its package id rewritten to the destination package id
+ // correct after the value of attr2 had its package id rewritten to the destination package id.
EXPECT_EQ(700, value.data);
}
+TEST_F(ThemeTest, CopyNonReferencesWhenPackagesDiffer) {
+ AssetManager2 assetmanager_dst;
+ assetmanager_dst.SetApkAssets({system_assets_.get()});
+
+ AssetManager2 assetmanager_src;
+ assetmanager_src.SetApkAssets({system_assets_.get(), style_assets_.get()});
+
+ auto theme_dst = assetmanager_dst.NewTheme();
+ auto theme_src = assetmanager_src.NewTheme();
+ ASSERT_TRUE(theme_src->ApplyStyle(app::R::style::StyleSeven));
+ theme_dst->SetTo(*theme_src);
+
+ Res_value value;
+ uint32_t flags;
+
+ // Allow inline resource values to be copied even if the source apk asset is not present in the
+ // destination.
+ EXPECT_EQ(0, theme_dst->GetAttribute(0x0101021b /* android:versionCode */, &value, &flags));
+
+ // Do not copy strings since the data is an index into the values string pool of the source apk
+ // asset.
+ EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010001 /* android:label */, &value, &flags));
+
+ // Do not copy values that reference another resource if the resource is not present in the
+ // destination.
+ EXPECT_EQ(-1, theme_dst->GetAttribute(0x01010002 /* android:icon */, &value, &flags));
+ EXPECT_EQ(-1, theme_dst->GetAttribute(0x010100d1 /* android:tag */, &value, &flags));
+
+ // Allow @empty to and @null to be copied.
+ EXPECT_EQ(0, theme_dst->GetAttribute(0x010100d0 /* android:id */, &value, &flags));
+ EXPECT_EQ(0, theme_dst->GetAttribute(0x01010000 /* android:theme */, &value, &flags));
+}
+
} // namespace android
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 538a847..f11486f 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -51,6 +51,7 @@
StyleFour = 0x7f020003u,
StyleFive = 0x7f020004u,
StyleSix = 0x7f020005u,
+ StyleSeven = 0x7f020006u,
};
};
};
diff --git a/libs/androidfw/tests/data/styles/build b/libs/androidfw/tests/data/styles/build
index 1ef8e6e..7b7c1f7 100755
--- a/libs/androidfw/tests/data/styles/build
+++ b/libs/androidfw/tests/data/styles/build
@@ -2,5 +2,7 @@
set -e
+PATH_TO_FRAMEWORK_RES=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
aapt2 compile -o compiled.flata --dir res
-aapt2 link -o styles.apk --manifest AndroidManifest.xml compiled.flata
+aapt2 link -o styles.apk --manifest AndroidManifest.xml -I $PATH_TO_FRAMEWORK_RES compiled.flata
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index 1a23176..06774a8 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -79,4 +79,14 @@
<item name="attr_three">3</item>
</style>
+ <public type="style" name="StyleSeven" id="0x7f020006" />
+ <style name="StyleSeven" >
+ <item name="android:versionCode">3</item>
+ <item name="android:label">"string"</item>
+ <item name="android:icon">?attr/attr_one</item>
+ <item name="android:tag">@string/string_one</item>
+ <item name="android:id">@null</item>
+ <item name="android:theme">@empty</item>
+ </style>
+
</resources>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index cd5c7a1..92e9bf9 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/libs/protoutil/src/ProtoFileReader.cpp b/libs/protoutil/src/ProtoFileReader.cpp
index 074170a..4017979 100644
--- a/libs/protoutil/src/ProtoFileReader.cpp
+++ b/libs/protoutil/src/ProtoFileReader.cpp
@@ -55,6 +55,7 @@
mSize(get_file_size(fd)),
mPos(0),
mOffset(0),
+ mMaxOffset(0),
mChunkSize(sizeof(mBuffer)) {
}
diff --git a/location/java/android/location/GnssClock.java b/location/java/android/location/GnssClock.java
index 5384061..8a7878b 100644
--- a/location/java/android/location/GnssClock.java
+++ b/location/java/android/location/GnssClock.java
@@ -17,7 +17,6 @@
package android.location;
import android.annotation.FloatRange;
-import android.annotation.IntRange;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -54,7 +53,7 @@
private double mDriftUncertaintyNanosPerSecond;
private int mHardwareClockDiscontinuityCount;
private long mElapsedRealtimeNanos;
- private long mElapsedRealtimeUncertaintyNanos;
+ private double mElapsedRealtimeUncertaintyNanos;
/**
* @hide
@@ -469,8 +468,8 @@
* <p>The value is only available if {@link #hasElapsedRealtimeUncertaintyNanos()} is
* {@code true}.
*/
- @IntRange(from = 0)
- public long getElapsedRealtimeUncertaintyNanos() {
+ @FloatRange(from = 0.0f)
+ public double getElapsedRealtimeUncertaintyNanos() {
return mElapsedRealtimeUncertaintyNanos;
}
@@ -482,7 +481,7 @@
*/
@TestApi
public void setElapsedRealtimeUncertaintyNanos(
- @IntRange(from = 0) long elapsedRealtimeUncertaintyNanos) {
+ @FloatRange(from = 0.0f) double elapsedRealtimeUncertaintyNanos) {
setFlag(HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS);
mElapsedRealtimeUncertaintyNanos = elapsedRealtimeUncertaintyNanos;
}
@@ -496,7 +495,7 @@
@TestApi
public void resetElapsedRealtimeUncertaintyNanos() {
resetFlag(HAS_ELAPSED_REALTIME_UNCERTAINTY_NANOS);
- mElapsedRealtimeUncertaintyNanos = Long.MAX_VALUE;
+ mElapsedRealtimeUncertaintyNanos = Double.NaN;
}
/**
@@ -543,7 +542,7 @@
gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
gpsClock.mElapsedRealtimeNanos = parcel.readLong();
- gpsClock.mElapsedRealtimeUncertaintyNanos = parcel.readLong();
+ gpsClock.mElapsedRealtimeUncertaintyNanos = parcel.readDouble();
return gpsClock;
}
@@ -567,7 +566,7 @@
parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
parcel.writeInt(mHardwareClockDiscontinuityCount);
parcel.writeLong(mElapsedRealtimeNanos);
- parcel.writeLong(mElapsedRealtimeUncertaintyNanos);
+ parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
}
@Override
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 673b411..9c36d76 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -136,7 +136,7 @@
private long mElapsedRealtimeNanos = 0;
// Estimate of the relative precision of the alignment of this SystemClock
// timestamp, with the reported measurements in nanoseconds (68% confidence).
- private long mElapsedRealtimeUncertaintyNanos = 0;
+ private double mElapsedRealtimeUncertaintyNanos = 0.0f;
private double mLatitude = 0.0;
private double mLongitude = 0.0;
private double mAltitude = 0.0f;
@@ -199,7 +199,7 @@
mProvider = null;
mTime = 0;
mElapsedRealtimeNanos = 0;
- mElapsedRealtimeUncertaintyNanos = 0;
+ mElapsedRealtimeUncertaintyNanos = 0.0;
mFieldsMask = 0;
mLatitude = 0;
mLongitude = 0;
@@ -599,9 +599,17 @@
* ElapsedRealtimeNanos timestamp, with the reported measurements in
* nanoseconds (68% confidence).
*
+ * This means that we have 68% confidence that the true timestamp of the
+ * event is within ElapsedReatimeNanos +/- uncertainty.
+ *
+ * Example :
+ * - getElapsedRealtimeNanos() returns 10000000
+ * - getElapsedRealtimeUncertaintyNanos() returns 1000000 (equivalent to 1millisecond)
+ * This means that the event most likely happened between 9000000 and 11000000.
+ *
* @return uncertainty of elapsed real-time of fix, in nanoseconds.
*/
- public long getElapsedRealtimeUncertaintyNanos() {
+ public double getElapsedRealtimeUncertaintyNanos() {
return mElapsedRealtimeUncertaintyNanos;
}
@@ -612,7 +620,7 @@
*
* @param time uncertainty of the elapsed real-time of fix, in nanoseconds.
*/
- public void setElapsedRealtimeUncertaintyNanos(long time) {
+ public void setElapsedRealtimeUncertaintyNanos(double time) {
mElapsedRealtimeUncertaintyNanos = time;
mFieldsMask |= HAS_ELAPSED_REALTIME_UNCERTAINTY_MASK;
}
@@ -1104,7 +1112,7 @@
}
if (hasElapsedRealtimeUncertaintyNanos()) {
s.append(" etAcc=");
- TimeUtils.formatDuration(mElapsedRealtimeUncertaintyNanos / 1000000L, s);
+ TimeUtils.formatDuration((long) (mElapsedRealtimeUncertaintyNanos / 1000000), s);
}
if (hasAltitude()) s.append(" alt=").append(mAltitude);
if (hasSpeed()) s.append(" vel=").append(mSpeed);
@@ -1136,7 +1144,7 @@
Location l = new Location(provider);
l.mTime = in.readLong();
l.mElapsedRealtimeNanos = in.readLong();
- l.mElapsedRealtimeUncertaintyNanos = in.readLong();
+ l.mElapsedRealtimeUncertaintyNanos = in.readDouble();
l.mFieldsMask = in.readInt();
l.mLatitude = in.readDouble();
l.mLongitude = in.readDouble();
@@ -1167,7 +1175,7 @@
parcel.writeString(mProvider);
parcel.writeLong(mTime);
parcel.writeLong(mElapsedRealtimeNanos);
- parcel.writeLong(mElapsedRealtimeUncertaintyNanos);
+ parcel.writeDouble(mElapsedRealtimeUncertaintyNanos);
parcel.writeInt(mFieldsMask);
parcel.writeDouble(mLatitude);
parcel.writeDouble(mLongitude);
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 512210b..267d9f5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -112,17 +112,22 @@
// zoneId
VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
int value = getSeekbarValue(mCarAudioManager, groupId);
+ // find if the group id for which the volume changed is currently being
+ // displayed.
+ boolean isShowing = mCarVolumeLineItems.stream().anyMatch(
+ item -> item.getGroupId() == groupId);
// Do not update the progress if it is the same as before. When car audio
// manager sets
// its group volume caused by the seekbar progress changed, it also triggers
// this
// callback. Updating the seekbar at the same time could block the continuous
// seeking.
- if (value != volumeItem.progress) {
+ if (value != volumeItem.progress && isShowing) {
volumeItem.carVolumeItem.setProgress(value);
volumeItem.progress = value;
}
if ((flags & AudioManager.FLAG_SHOW_UI) != 0) {
+ mCurrentlyDisplayingGroupId = groupId;
mHandler.obtainMessage(H.SHOW,
Events.SHOW_REASON_VOLUME_CHANGED).sendToTarget();
}
@@ -134,10 +139,10 @@
}
};
private boolean mHovering;
+ private int mCurrentlyDisplayingGroupId;
private boolean mShowing;
private boolean mExpanded;
private View mExpandIcon;
- private VolumeItem mDefaultVolumeItem;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
@@ -152,8 +157,7 @@
mAvailableVolumeItems.add(volumeItem);
// The first one is the default item.
if (groupId == 0) {
- mDefaultVolumeItem = volumeItem;
- setupDefaultCarVolumeItem();
+ setuptListItem(0);
}
}
@@ -177,9 +181,11 @@
}
};
- private void setupDefaultCarVolumeItem() {
- mDefaultVolumeItem.defaultItem = true;
- addCarVolumeListItem(mDefaultVolumeItem, /* volumeGroupId = */0,
+ private void setuptListItem(int groupId) {
+ mCarVolumeLineItems.clear();
+ VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
+ volumeItem.defaultItem = true;
+ addCarVolumeListItem(volumeItem, /* volumeGroupId = */ groupId,
R.drawable.car_ic_keyboard_arrow_down, new ExpandIconListener()
);
}
@@ -299,9 +305,7 @@
return;
}
mShowing = true;
- if (mCarVolumeLineItems.isEmpty()) {
- setupDefaultCarVolumeItem();
- }
+ setuptListItem(mCurrentlyDisplayingGroupId);
mDialog.show();
Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked());
}
@@ -437,7 +441,7 @@
carVolumeItem.setSupplementalIcon(/* drawable= */ null,
/* showSupplementalIconDivider= */ false);
}
-
+ carVolumeItem.setGroupId(volumeGroupId);
mCarVolumeLineItems.add(carVolumeItem);
volumeItem.carVolumeItem = carVolumeItem;
volumeItem.progress = progress;
@@ -545,11 +549,8 @@
Animator inAnimator;
if (mExpanded) {
for (int groupId = 0; groupId < mAvailableVolumeItems.size(); ++groupId) {
- // Adding the items which are not coming from the default item.
- VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
- if (volumeItem.defaultItem) {
- updateDefaultVolumeItem(volumeItem.carVolumeItem);
- } else {
+ if (groupId != mCurrentlyDisplayingGroupId) {
+ VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
addCarVolumeListItem(volumeItem, groupId, 0, null);
}
}
@@ -561,11 +562,8 @@
Iterator itr = mCarVolumeLineItems.iterator();
while (itr.hasNext()) {
CarVolumeItem carVolumeItem = (CarVolumeItem) itr.next();
- VolumeItem volumeItem = findVolumeItem(carVolumeItem);
- if (!volumeItem.defaultItem) {
+ if (carVolumeItem.getGroupId() != mCurrentlyDisplayingGroupId) {
itr.remove();
- } else {
- updateDefaultVolumeItem(carVolumeItem);
}
}
inAnimator = AnimatorInflater.loadAnimator(
@@ -587,21 +585,6 @@
mVolumeItemsAdapter.notifyDataSetChanged();
}
- private void updateDefaultVolumeItem(CarVolumeItem carVolumeItem) {
- VolumeItem volumeItem = findVolumeItem(carVolumeItem);
-
- // When volume dialog is expanded or collapsed the default list item is never
- // reset. Whereas all other list items are removed when the dialog is collapsed and then
- // added when the dialog is expanded using {@link CarVolumeDialogImpl#addCarVolumeListItem}.
- // This sets the progressbar and the tint color of icons for all items other than default
- // if they were changed. For default list item it should be done manually here.
- int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
- Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
- primaryIcon.mutate().setTint(color);
- volumeItem.carVolumeItem.setPrimaryIcon(primaryIcon);
- volumeItem.carVolumeItem.setProgress(volumeItem.progress);
- }
-
private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
private final int mVolumeGroupId;
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
index 9613de1..e1ea6f6 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeItem.java
@@ -35,6 +35,7 @@
private Drawable mSupplementalIcon;
private View.OnClickListener mSupplementalIconOnClickListener;
private boolean mShowSupplementalIconDivider;
+ private int mGroupId;
private int mMax;
private int mProgress;
@@ -85,6 +86,20 @@
mIsDirty = true;
}
+ /**
+ * Gets the group id associated.
+ */
+ public int getGroupId() {
+ return mGroupId;
+ }
+
+ /**
+ * Sets the group id associated.
+ */
+ public void setGroupId(int groupId) {
+ this.mGroupId = groupId;
+ }
+
/** Sets {@code OnClickListener} for the supplemental icon. */
public void setSupplementalIconListener(View.OnClickListener listener) {
mSupplementalIconOnClickListener = listener;
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
index 040e2ab..52e54f9 100644
--- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
@@ -19,6 +19,7 @@
import android.content.ComponentName;
import android.content.Intent;
import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.PackageInfo;
import android.util.Log;
import java.util.ArrayList;
@@ -67,8 +68,12 @@
}
@Override
- public List<String> onGetSupportedPackages() {
- return new ArrayList<>(mSupportedCheckers.keySet());
+ public List<PackageInfo> onGetSupportedPackages() {
+ List<PackageInfo> packages = new ArrayList<>();
+ for (ExplicitHealthChecker checker : mSupportedCheckers.values()) {
+ packages.add(checker.getSupportedPackage());
+ }
+ return packages;
}
@Override
@@ -82,7 +87,7 @@
while (it.hasNext()) {
ExplicitHealthChecker checker = it.next();
if (checker.isPending()) {
- packages.add(checker.getPackageName());
+ packages.add(checker.getSupportedPackage().getPackageName());
}
}
return packages;
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
index 650878e..c51be88 100644
--- a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
@@ -16,6 +16,8 @@
package android.ext.services.watchdog;
+import android.service.watchdog.PackageInfo;
+
/**
* A type of explicit health check that can be performed on a device, e.g network health check
*/
@@ -38,7 +40,7 @@
boolean isPending();
/**
- * Returns the package name this checker can make requests for.
+ * Returns the {@link PackageInfo} object this checker can make requests for.
*/
- String getPackageName();
+ PackageInfo getSupportedPackage();
}
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
index 32375e6..09b319e 100644
--- a/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
+++ b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
@@ -21,6 +21,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.service.watchdog.ExplicitHealthCheckService;
+import android.service.watchdog.PackageInfo;
import com.android.internal.annotations.GuardedBy;
@@ -34,6 +35,8 @@
private final Object mLock = new Object();
private final ExplicitHealthCheckService mService;
private final String mPackageName;
+ // TODO: Receive from DeviceConfig flag
+ private final long mRequestDurationMillis = 0;
@GuardedBy("mLock")
private boolean mIsPending;
@@ -73,8 +76,8 @@
}
@Override
- public String getPackageName() {
- return mPackageName;
+ public PackageInfo getSupportedPackage() {
+ return new PackageInfo(mPackageName, mRequestDurationMillis);
}
// TODO(b/120598832): Also monitor NetworkCallback#onAvailable to see if we have any
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index bdc4ebd..65ede3d 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -28,7 +28,7 @@
/>
<FrameLayout
- android:id="@+id/header_permission_wrapper"
+ android:id="@+id/permission_or_settings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animateLayoutChanges="true">
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 56b231b..a4870d4 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -222,14 +222,14 @@
@Override
public void onUiModeChanged() {
if (mStackView != null) {
- mStackView.onConfigChanged();
+ mStackView.onThemeChanged();
}
}
@Override
public void onOverlayChanged() {
if (mStackView != null) {
- mStackView.onConfigChanged();
+ mStackView.onThemeChanged();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index e8b1122..6b21526 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -69,7 +69,7 @@
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
/**
- * Container for the expanded bubble view, handles rendering the caret and header of the view.
+ * Container for the expanded bubble view, handles rendering the caret and settings icon.
*/
public class BubbleExpandedView extends LinearLayout implements View.OnClickListener {
private static final String TAG = "BubbleExpandedView";
@@ -82,6 +82,7 @@
// Permission view
private View mPermissionView;
+ private TextView mPermissionPrompt;
// Views for expanded state
private ExpandableNotificationRow mNotifRow;
@@ -94,9 +95,13 @@
private boolean mNeedsNewHeight;
private int mMinHeight;
- private int mHeaderHeight;
+ private int mSettingsIconHeight;
private int mBubbleHeight;
private int mPermissionHeight;
+ private int mIconInset;
+ private Drawable mSettingsIconDrawable;
+ private int mPointerWidth;
+ private int mPointerHeight;
private NotificationEntry mEntry;
private PackageManager mPm;
@@ -173,20 +178,21 @@
Resources res = getResources();
mPointerView = findViewById(R.id.pointer_view);
- int width = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
- int height = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
+ mPointerWidth = res.getDimensionPixelSize(R.dimen.bubble_pointer_width);
+ mPointerHeight = res.getDimensionPixelSize(R.dimen.bubble_pointer_height);
TypedArray ta = getContext().obtainStyledAttributes(
new int[] {android.R.attr.colorBackgroundFloating});
int bgColor = ta.getColor(0, Color.WHITE);
ta.recycle();
- ShapeDrawable triangleDrawable = new ShapeDrawable(
- TriangleShape.create(width, height, false /* pointUp */));
+ ShapeDrawable triangleDrawable = new ShapeDrawable(TriangleShape.create(
+ mPointerWidth, mPointerHeight, false /* pointUp */));
+
triangleDrawable.setTint(bgColor);
mPointerView.setBackground(triangleDrawable);
- FrameLayout viewWrapper = findViewById(R.id.header_permission_wrapper);
+ FrameLayout permissionOrSettings = findViewById(R.id.permission_or_settings);
LayoutTransition transition = new LayoutTransition();
transition.setDuration(200);
@@ -200,18 +206,21 @@
transition.setInterpolator(LayoutTransition.DISAPPEARING, Interpolators.ALPHA_OUT);
transition.setAnimateParentHierarchy(false);
- viewWrapper.setLayoutTransition(transition);
- viewWrapper.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
+ permissionOrSettings.setLayoutTransition(transition);
+ permissionOrSettings.getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
- mHeaderHeight = getContext().getResources().getDimensionPixelSize(
+ mSettingsIconHeight = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_expanded_header_height);
+ mSettingsIcon = findViewById(R.id.settings_button);
+ mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
+ mSettingsIcon.setOnClickListener(this);
+ // Save initial drawable to create adaptive icons that will take its place.
+ mSettingsIconDrawable = mSettingsIcon.getDrawable();
+
mPermissionHeight = getContext().getResources().getDimensionPixelSize(
R.dimen.bubble_permission_height);
-
mPermissionView = findViewById(R.id.permission_layout);
- mSettingsIcon = findViewById(R.id.settings_button);
- mSettingsIcon.setOnClickListener(this);
- updateHeaderColor();
+ mPermissionPrompt = mPermissionView.findViewById(R.id.prompt);
findViewById(R.id.no_bubbles_button).setOnClickListener(this);
findViewById(R.id.yes_bubbles_button).setOnClickListener(this);
@@ -264,7 +273,7 @@
/**
* Creates a background with corners rounded based on how the view is configured to display
*/
- private Drawable createHeaderPermissionBackground(int bgColor) {
+ private Drawable createPermissionBackground(int bgColor) {
TypedArray ta2 = getContext().obtainStyledAttributes(
new int[] {android.R.attr.dialogCornerRadius});
final float cr = ta2.getDimension(0, 0f);
@@ -311,8 +320,8 @@
if (mAppIcon == null) {
mAppIcon = mPm.getDefaultActivityIcon();
}
- updateHeaderView();
- updatePermissionView();
+ updateTheme();
+ togglePermissionOrSettings();
updateExpandedView();
}
@@ -338,12 +347,12 @@
/**
* Updates the entry backing this view. This will not re-populate ActivityView, it will
- * only update the deep-links in the header, the title, and the height of the view.
+ * only update the deep-links in the title, and the height of the view.
*/
public void update(NotificationEntry entry) {
if (entry.key.equals(mEntry.key)) {
mEntry = entry;
- updateHeaderView();
+ updateSettingsContentDescription();
updateHeight();
} else {
Log.w(TAG, "Trying to update entry with different key, new entry: "
@@ -351,35 +360,36 @@
}
}
- /**
- * Update header color and icon shape when theme changes.
- */
- void updateHeaderColor() {
+ void updateTheme() {
+ // Get new colors.
TypedArray ta = mContext.obtainStyledAttributes(
- new int[] {android.R.attr.colorBackgroundFloating, android.R.attr.colorForeground});
+ new int[]{android.R.attr.colorBackgroundFloating, android.R.attr.colorForeground});
int backgroundColor = ta.getColor(0, Color.WHITE /* default */);
int foregroundColor = ta.getColor(1, Color.BLACK /* default */);
ta.recycle();
- mPermissionView.setBackground(createHeaderPermissionBackground(backgroundColor));
+ // Must clear tint first - otherwise tint updates inconsistently.
+ mSettingsIconDrawable.setTintList(null);
+ mSettingsIconDrawable.setTint(foregroundColor);
- Drawable settingsIcon = mSettingsIcon.getDrawable();
- settingsIcon.setTint(foregroundColor);
-
- int mIconInset = getResources().getDimensionPixelSize(R.dimen.bubble_icon_inset);
- InsetDrawable foreground = new InsetDrawable(settingsIcon, mIconInset);
+ InsetDrawable foreground = new InsetDrawable(mSettingsIconDrawable, mIconInset);
ColorDrawable background = new ColorDrawable(backgroundColor);
AdaptiveIconDrawable adaptiveIcon = new AdaptiveIconDrawable(background,
foreground);
mSettingsIcon.setImageDrawable(adaptiveIcon);
+
+ // Update permission prompt color.
+ mPermissionView.setBackground(createPermissionBackground(backgroundColor));
+ mPermissionPrompt.setTextColor(foregroundColor);
+
+ // Update triangle color.
+ ShapeDrawable triangleDrawable = new ShapeDrawable(
+ TriangleShape.create(mPointerWidth, mPointerHeight, false /* pointUp */));
+ triangleDrawable.setTint(backgroundColor);
+ mPointerView.setBackground(triangleDrawable);
}
- private void updateHeaderView() {
- mSettingsIcon.setContentDescription(getResources().getString(
- R.string.bubbles_settings_button_description, mAppName));
- }
-
- private void updatePermissionView() {
+ void togglePermissionOrSettings() {
boolean hasUserApprovedBubblesForPackage = false;
try {
hasUserApprovedBubblesForPackage =
@@ -392,12 +402,6 @@
showSettingsIcon();
} else {
showPermissionView();
- ((ImageView) mPermissionView.findViewById(R.id.pkgicon)).setImageDrawable(mAppIcon);
- ((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName);
- ((TextView) mPermissionView.findViewById(R.id.prompt)).setText(
- getResources().getString(R.string.bubbles_prompt, mAppName));
- logBubbleClickEvent(mEntry,
- StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_DIALOG_SHOWN);
}
}
@@ -432,7 +436,7 @@
*/
int getExpandedSize() {
int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
- ? mHeaderHeight
+ ? mSettingsIconHeight
: mPermissionHeight;
return mBubbleHeight + mPointerView.getHeight() + mPointerMargin
+ chromeHeight;
@@ -460,7 +464,7 @@
desiredHeight = desiredPx > 0 ? desiredPx : mMinHeight;
}
int chromeHeight = mPermissionView.getVisibility() != View.VISIBLE
- ? mHeaderHeight
+ ? mSettingsIconHeight
: mPermissionHeight;
int max = mStackView.getMaxExpandedHeight() - chromeHeight - mPointerView.getHeight()
- mPointerMargin;
@@ -523,15 +527,28 @@
}
}
+ private void updateSettingsContentDescription() {
+ mSettingsIcon.setContentDescription(getResources().getString(
+ R.string.bubbles_settings_button_description, mAppName));
+ }
+
void showSettingsIcon() {
+ updateSettingsContentDescription();
+
mPermissionView.setVisibility(GONE);
mSettingsIcon.setVisibility(VISIBLE);
}
void showPermissionView() {
+ ((ImageView) mPermissionView.findViewById(R.id.pkgicon)).setImageDrawable(mAppIcon);
+ ((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName);
+ mPermissionPrompt.setText(
+ getResources().getString(R.string.bubbles_prompt, mAppName));
+ logBubbleClickEvent(mEntry,
+ StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_DIALOG_SHOWN);
+
mSettingsIcon.setVisibility(GONE);
mPermissionView.setVisibility(VISIBLE);
-
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 00b1c9e..a4e1ad7 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -309,12 +309,12 @@
}
/**
- * Handle config changes.
+ * Handle theme changes.
*/
- public void onConfigChanged() {
+ public void onThemeChanged() {
for (Bubble b: mBubbleData.getBubbles()) {
b.iconView.updateViews();
- b.expandedView.updateHeaderColor();
+ b.expandedView.updateTheme();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index 0f659c3..4606526 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -202,13 +202,21 @@
// add a multiple property end listener to the layout that will call the end action
// provided to startAll() once all animations on the animated properties complete.
return (endActions) -> {
+ final Runnable runAllEndActions = () -> {
+ for (Runnable action : endActions) {
+ action.run();
+ }
+ };
+
+ // If there aren't any children to animate, just run the end actions.
+ if (mLayout.getChildCount() == 0) {
+ runAllEndActions.run();
+ return;
+ }
+
if (endActions != null) {
mLayout.setEndActionForMultipleProperties(
- () -> {
- for (Runnable action : endActions) {
- action.run();
- }
- },
+ runAllEndActions,
allAnimatedProperties.toArray(
new DynamicAnimation.ViewProperty[0]));
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index cff3855..0e9264b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -477,6 +477,15 @@
}
mThemeResId = themeResId;
+ reInflateViews();
+ }
+
+ @Override
+ public void onOverlayChanged() {
+ reInflateViews();
+ }
+
+ private void reInflateViews() {
updateShowEmptyShadeView();
// Re-inflate the status view group.
@@ -484,9 +493,9 @@
removeView(mKeyguardStatusView);
mKeyguardStatusView = (KeyguardStatusView) mInjectionInflationController
.injectable(LayoutInflater.from(mContext)).inflate(
- R.layout.keyguard_status_view,
- this,
- false);
+ R.layout.keyguard_status_view,
+ this,
+ false);
addView(mKeyguardStatusView, index);
// Re-associate the clock container with the keyguard clock switch.
@@ -500,9 +509,9 @@
KeyguardBottomAreaView oldBottomArea = mKeyguardBottomArea;
mKeyguardBottomArea = (KeyguardBottomAreaView) mInjectionInflationController
.injectable(LayoutInflater.from(mContext)).inflate(
- R.layout.keyguard_bottom_area,
- this,
- false);
+ R.layout.keyguard_bottom_area,
+ this,
+ false);
mKeyguardBottomArea.initFrom(oldBottomArea);
addView(mKeyguardBottomArea, index);
initBottomArea();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
index 38a90f7..eef6ddc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayoutTest.java
@@ -25,6 +25,7 @@
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
import android.os.SystemClock;
import android.testing.AndroidTestingRunner;
@@ -449,6 +450,18 @@
Mockito.verify(allEnd, times(1)).run();
}
+ @Test
+ public void testAnimationsForChildrenFromIndex_noChildren() {
+ mLayout.setController(mTestableController);
+
+ final Runnable after = Mockito.mock(Runnable.class);
+ mTestableController
+ .animationsForChildrenFromIndex(0, (index, animation) -> { })
+ .startAll(after);
+
+ verify(after, Mockito.times(1)).run();
+ }
+
/**
* Animation controller with configuration methods whose return values can be set by individual
* tests.
diff --git a/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml
index 5648f91..c73cbba 100644
--- a/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml
+++ b/packages/overlays/AccentColorBlackOverlay/res/values/colors_device_defaults.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
- * Copyright (c) 2018, The Android Open Source Project
+ * Copyright (c) 2019, 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.
@@ -18,5 +18,5 @@
-->
<resources>
<color name="accent_device_default_light">#202020</color>
- <color name="accent_device_default_dark">#FFFFFF</color>
+ <color name="accent_device_default_dark">#D7DEE6</color>
</resources>
diff --git a/packages/overlays/AccentColorCinnamonOverlay/Android.mk b/packages/overlays/AccentColorCinnamonOverlay/Android.mk
new file mode 100644
index 0000000..d53c114
--- /dev/null
+++ b/packages/overlays/AccentColorCinnamonOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2019, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorCinnamon
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorCinnamonOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorCinnamonOverlay/AndroidManifest.xml b/packages/overlays/AccentColorCinnamonOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..bcb6c4f
--- /dev/null
+++ b/packages/overlays/AccentColorCinnamonOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2019, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.cinnamon"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_cinnamon_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 0000000..c420ab6
--- /dev/null
+++ b/packages/overlays/AccentColorCinnamonOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#AF6050</color>
+ <color name="accent_device_default_dark">#9D6962</color>
+</resources>
diff --git a/packages/overlays/AccentColorCinnamonOverlay/res/values/strings.xml b/packages/overlays/AccentColorCinnamonOverlay/res/values/strings.xml
new file mode 100644
index 0000000..ac8ca7d
--- /dev/null
+++ b/packages/overlays/AccentColorCinnamonOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Cinnamon accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_cinnamon_overlay" translatable="false">Cinnamon</string>
+</resources>
+
diff --git a/packages/overlays/AccentColorOceanOverlay/Android.mk b/packages/overlays/AccentColorOceanOverlay/Android.mk
new file mode 100644
index 0000000..a28fc72
--- /dev/null
+++ b/packages/overlays/AccentColorOceanOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2019, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorOcean
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorOceanOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorOceanOverlay/AndroidManifest.xml b/packages/overlays/AccentColorOceanOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..bbee10d
--- /dev/null
+++ b/packages/overlays/AccentColorOceanOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2019, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.ocean"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_ocean_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 0000000..6aec805
--- /dev/null
+++ b/packages/overlays/AccentColorOceanOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#0C80A7</color>
+ <color name="accent_device_default_dark">#347D98</color>
+</resources>
diff --git a/packages/overlays/AccentColorOceanOverlay/res/values/strings.xml b/packages/overlays/AccentColorOceanOverlay/res/values/strings.xml
new file mode 100644
index 0000000..9342d48
--- /dev/null
+++ b/packages/overlays/AccentColorOceanOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Ocean accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_ocean_overlay" translatable="false">Ocean</string>
+</resources>
+
diff --git a/packages/overlays/AccentColorOrchidOverlay/Android.mk b/packages/overlays/AccentColorOrchidOverlay/Android.mk
new file mode 100644
index 0000000..c635890
--- /dev/null
+++ b/packages/overlays/AccentColorOrchidOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2019, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorOrchid
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorOrchidOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorOrchidOverlay/AndroidManifest.xml b/packages/overlays/AccentColorOrchidOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..0290b68
--- /dev/null
+++ b/packages/overlays/AccentColorOrchidOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2019, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.orchid"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_orchid_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 0000000..049f8b8
--- /dev/null
+++ b/packages/overlays/AccentColorOrchidOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#C42CC9</color>
+ <color name="accent_device_default_dark">#C42CC9</color>
+</resources>
diff --git a/packages/overlays/AccentColorOrchidOverlay/res/values/strings.xml b/packages/overlays/AccentColorOrchidOverlay/res/values/strings.xml
new file mode 100644
index 0000000..4e7ec48
--- /dev/null
+++ b/packages/overlays/AccentColorOrchidOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Orchid accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_orchid_overlay" translatable="false">Orchid</string>
+</resources>
+
diff --git a/packages/overlays/AccentColorSpaceOverlay/Android.mk b/packages/overlays/AccentColorSpaceOverlay/Android.mk
new file mode 100644
index 0000000..a0edb96
--- /dev/null
+++ b/packages/overlays/AccentColorSpaceOverlay/Android.mk
@@ -0,0 +1,31 @@
+#
+# Copyright 2019, 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_RRO_THEME := AccentColorSpace
+LOCAL_CERTIFICATE := platform
+LOCAL_PRODUCT_MODULE := true
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+
+LOCAL_PACKAGE_NAME := AccentColorSpaceOverlay
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_RRO_PACKAGE)
diff --git a/packages/overlays/AccentColorSpaceOverlay/AndroidManifest.xml b/packages/overlays/AccentColorSpaceOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..b9f1fa9
--- /dev/null
+++ b/packages/overlays/AccentColorSpaceOverlay/AndroidManifest.xml
@@ -0,0 +1,25 @@
+<!--
+/**
+ * Copyright (c) 2019, 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.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.theme.color.space"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay android:targetPackage="android" android:category="android.theme.customization.accent_color" android:priority="1"/>
+
+ <application android:label="@string/accent_color_space_overlay" android:hasCode="false"/>
+</manifest>
diff --git a/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml b/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml
new file mode 100644
index 0000000..b6f757c
--- /dev/null
+++ b/packages/overlays/AccentColorSpaceOverlay/res/values/colors_device_defaults.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <color name="accent_device_default_light">#47618A</color>
+ <color name="accent_device_default_dark">#5D7A92</color>
+</resources>
diff --git a/packages/overlays/AccentColorSpaceOverlay/res/values/strings.xml b/packages/overlays/AccentColorSpaceOverlay/res/values/strings.xml
new file mode 100644
index 0000000..55cd5ae
--- /dev/null
+++ b/packages/overlays/AccentColorSpaceOverlay/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Space accent color name application label. [CHAR LIMIT=50] -->
+ <string name="accent_color_space_overlay" translatable="false">Space</string>
+</resources>
+
diff --git a/packages/overlays/IconShapeSquareOverlay/res/values/config.xml b/packages/overlays/IconShapeSquareOverlay/res/values/config.xml
index 54623f5..7b65555 100644
--- a/packages/overlays/IconShapeSquareOverlay/res/values/config.xml
+++ b/packages/overlays/IconShapeSquareOverlay/res/values/config.xml
@@ -21,6 +21,8 @@
<string name="config_icon_mask" translatable="false">"M50,0L100,0 100,100 0,100 0,0z"</string>
<!-- Flag indicating whether round icons should be parsed from the application manifest. -->
<bool name="config_useRoundIcon">false</bool>
+ <!-- Corner radius of system dialogs -->
+ <dimen name="config_dialogCornerRadius">0dp</dimen>
</resources>
diff --git a/services/Android.bp b/services/Android.bp
index 567efac..b08d1a8 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -31,6 +31,7 @@
"services.print",
"services.restrictions",
"services.startop",
+ "services.systemcaptions",
"services.usage",
"services.usb",
"services.voiceinteraction",
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9b02c4e..757c2dc 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -129,7 +129,8 @@
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
com.android.internal.R.string.config_defaultContentCaptureService),
- UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate= */ false);
+ UserManager.DISALLOW_CONTENT_CAPTURE,
+ /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_NO_REFRESH);
DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
ActivityThread.currentApplication().getMainExecutor(),
(namespace, key, value) -> onDeviceConfigChange(key, value));
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0f39029..47c85683 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1697,6 +1697,8 @@
return;
}
+ type = fixTypeIfAuto(type);
+
// Sanity check the window length. This will catch people mistakenly
// trying to pass an end-of-window timestamp rather than a duration.
if (windowLength > AlarmManager.INTERVAL_HALF_DAY) {
@@ -1812,6 +1814,21 @@
}
/**
+ * In case of cars, we need to avoid scheduling wakeup alarms, since we don't want the system
+ * to wake up from suspend arbitrarily to perform app work.
+ */
+ private int fixTypeIfAuto(int type) {
+ if (mInjector.isAutomotive()) {
+ if (type == AlarmManager.ELAPSED_REALTIME_WAKEUP) {
+ type = AlarmManager.ELAPSED_REALTIME;
+ } else if (type == AlarmManager.RTC_WAKEUP) {
+ type = AlarmManager.RTC;
+ }
+ }
+ return type;
+ }
+
+ /**
* Return the minimum time that should elapse before an app in the specified bucket
* can receive alarms again
*/
@@ -2214,6 +2231,7 @@
pw.print(" mLastTickSet="); pw.println(sdf.format(new Date(mLastTickSet)));
pw.print(" mLastTickAdded="); pw.println(sdf.format(new Date(mLastTickAdded)));
pw.print(" mLastTickRemoved="); pw.println(sdf.format(new Date(mLastTickRemoved)));
+ pw.print(" mIsAutomotive="); pw.println(mInjector.isAutomotive());
if (RECORD_ALARMS_IN_HISTORY) {
pw.println();
@@ -3838,9 +3856,12 @@
static class Injector {
private long mNativeData;
private Context mContext;
+ private final boolean mIsAutomotive;
Injector(Context context) {
mContext = context;
+ mIsAutomotive = context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
}
void init() {
@@ -3929,6 +3950,10 @@
ClockReceiver getClockReceiver(AlarmManagerService service) {
return service.new ClockReceiver();
}
+
+ boolean isAutomotive() {
+ return mIsAutomotive;
+ }
}
private class AlarmThread extends Thread
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 3079192..0786b18 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -929,20 +929,13 @@
private void initIfBootedAndConnected() {
Slog.d(TAG, "Thinking about init, mBootCompleted=" + mBootCompleted
+ ", mDaemonConnected=" + mDaemonConnected);
- if (mBootCompleted && mDaemonConnected) {
- // Tell vold to lock or unlock the user directories based on the
- // current file-based encryption status.
- final boolean initLocked;
- if (StorageManager.isFileEncryptedNativeOrEmulated()) {
- // For native FBE this is a no-op after reboot, but this is
- // still needed in case of framework restarts.
- Slog.d(TAG, "FBE is enabled; ensuring all user directories are locked.");
- initLocked = true;
- } else {
- // This is in case FBE emulation was turned off.
- Slog.d(TAG, "FBE is disabled; ensuring the FBE emulation state is cleared.");
- initLocked = false;
- }
+ if (mBootCompleted && mDaemonConnected
+ && !StorageManager.isFileEncryptedNativeOnly()) {
+ // When booting a device without native support, make sure that our
+ // user directories are locked or unlocked based on the current
+ // emulation status.
+ final boolean initLocked = StorageManager.isFileEncryptedEmulatedOnly();
+ Slog.d(TAG, "Setting up emulation state, initlocked=" + initLocked);
final List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers();
for (UserInfo user : users) {
try {
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index d67853a..aa52621 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -44,6 +44,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.os.SELinux;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.service.restricted_image.RestrictedImageProto;
@@ -1091,6 +1092,13 @@
return;
}
+ // Additionally, this flag allows turning off face for a device
+ // (either permanently through the build or on an individual device).
+ if (SystemProperties.getBoolean("ro.face.disable_debug_data", false)
+ || SystemProperties.getBoolean("persist.face.disable_debug_data", false)) {
+ return;
+ }
+
final ProtoOutputStream proto = new ProtoOutputStream(fd);
final long setToken = proto.start(RestrictedImagesDumpProto.SETS);
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 098b0e9..9782f30 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -15,6 +15,7 @@
*/
package com.android.server.infra;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
@@ -45,6 +46,8 @@
import com.android.server.SystemService;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.List;
/**
@@ -75,6 +78,30 @@
public abstract class AbstractMasterSystemService<M extends AbstractMasterSystemService<M, S>,
S extends AbstractPerUserSystemService<S, M>> extends SystemService {
+ /** On a package update, does not refresh the per-user service in the cache. */
+ public static final int PACKAGE_UPDATE_POLICY_NO_REFRESH = 0;
+
+ /**
+ * On a package update, removes any existing per-user services in the cache.
+ *
+ * <p>This does not immediately recreate these services. It is assumed they will be recreated
+ * for the next user request.
+ */
+ public static final int PACKAGE_UPDATE_POLICY_REFRESH_LAZY = 1;
+
+ /**
+ * On a package update, removes and recreates any existing per-user services in the cache.
+ */
+ public static final int PACKAGE_UPDATE_POLICY_REFRESH_EAGER = 2;
+
+ @IntDef(flag = true, prefix = { "PACKAGE_UPDATE_POLICY_" }, value = {
+ PACKAGE_UPDATE_POLICY_NO_REFRESH,
+ PACKAGE_UPDATE_POLICY_REFRESH_LAZY,
+ PACKAGE_UPDATE_POLICY_REFRESH_EAGER
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface PackageUpdatePolicy {}
+
/**
* Log tag
*/
@@ -127,8 +154,11 @@
/**
* Whether the per-user service should be removed from the cache when its apk is updated.
+ *
+ * <p>One of {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH},
+ * {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY} or {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}.
*/
- private final boolean mRefreshServiceOnPackageUpdate;
+ private final @PackageUpdatePolicy int mPackageUpdatePolicy;
/**
* Name of the service packages whose APK are being updated, keyed by user id.
@@ -154,7 +184,7 @@
@Nullable ServiceNameResolver serviceNameResolver,
@Nullable String disallowProperty) {
this(context, serviceNameResolver, disallowProperty,
- /* refreshServiceOnPackageUpdate=*/ true);
+ /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_LAZY);
}
/**
@@ -167,17 +197,19 @@
* @param disallowProperty when not {@code null}, defines a {@link UserManager} restriction that
* disables the service. <b>NOTE: </b> you'll also need to add it to
* {@code UserRestrictionsUtils.USER_RESTRICTIONS}.
- * @param refreshServiceOnPackageUpdate when {@code true}, the
- * {@link AbstractPerUserSystemService} is removed from the cache (and re-added) when the
- * service package is updated; when {@code false}, the service is untouched during the
- * update.
+ * @param packageUpdatePolicy when {@link #PACKAGE_UPDATE_POLICY_REFRESH_LAZY}, the
+ * {@link AbstractPerUserSystemService} is removed from the cache when the service
+ * package is updated; when {@link #PACKAGE_UPDATE_POLICY_REFRESH_EAGER}, the
+ * {@link AbstractPerUserSystemService} is removed from the cache and immediately
+ * re-added when the service package is updated; when
+ * {@link #PACKAGE_UPDATE_POLICY_NO_REFRESH}, the service is untouched during the update.
*/
protected AbstractMasterSystemService(@NonNull Context context,
@Nullable ServiceNameResolver serviceNameResolver,
- @Nullable String disallowProperty, boolean refreshServiceOnPackageUpdate) {
+ @Nullable String disallowProperty, @PackageUpdatePolicy int packageUpdatePolicy) {
super(context);
- mRefreshServiceOnPackageUpdate = refreshServiceOnPackageUpdate;
+ mPackageUpdatePolicy = packageUpdatePolicy;
mServiceNameResolver = serviceNameResolver;
if (mServiceNameResolver != null) {
@@ -645,7 +677,7 @@
final int size = mServicesCache.size();
pw.print(prefix); pw.print("Debug: "); pw.print(realDebug);
pw.print(" Verbose: "); pw.println(realVerbose);
- pw.print("Refresh on package update: "); pw.println(mRefreshServiceOnPackageUpdate);
+ pw.print("Refresh on package update: "); pw.println(mPackageUpdatePolicy);
if (mUpdatingPackageNames != null) {
pw.print("Packages being updated: "); pw.println(mUpdatingPackageNames);
}
@@ -701,12 +733,21 @@
}
mUpdatingPackageNames.put(userId, packageName);
onServicePackageUpdatingLocked(userId);
- if (mRefreshServiceOnPackageUpdate) {
+ if (mPackageUpdatePolicy != PACKAGE_UPDATE_POLICY_NO_REFRESH) {
if (debug) {
- Slog.d(mTag, "Removing service for user " + userId + " because package "
- + activePackageName + " is being updated");
+ Slog.d(mTag, "Removing service for user " + userId
+ + " because package " + activePackageName
+ + " is being updated");
}
removeCachedServiceLocked(userId);
+
+ if (mPackageUpdatePolicy == PACKAGE_UPDATE_POLICY_REFRESH_EAGER) {
+ if (debug) {
+ Slog.d(mTag, "Eagerly recreating service for user "
+ + userId);
+ }
+ getServiceForUserLocked(userId);
+ }
} else {
if (debug) {
Slog.d(mTag, "Holding service for user " + userId + " while package "
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 06db8b8..48f21e4 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -104,6 +104,9 @@
| CONSTRAINT_TIMING_DELAY
| CONSTRAINT_WITHIN_QUOTA;
+ // TODO(b/129954980)
+ private static final boolean STATS_LOG_ENABLED = false;
+
// Soft override: ignore constraints like time that don't affect API availability
public static final int OVERRIDE_SOFT = 1;
// Full override: ignore all constraints including API-affecting like connectivity
@@ -1000,7 +1003,7 @@
}
satisfiedConstraints = (satisfiedConstraints&~constraint) | (state ? constraint : 0);
mSatisfiedConstraintsOfInterest = satisfiedConstraints & CONSTRAINTS_OF_INTEREST;
- if ((STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
+ if (STATS_LOG_ENABLED && (STATSD_CONSTRAINTS_TO_LOG & constraint) != 0) {
StatsLog.write_non_chained(StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED,
sourceUid, null, getBatteryName(), getProtoConstraint(constraint),
state ? StatsLog.SCHEDULED_JOB_CONSTRAINT_CHANGED__STATE__SATISFIED
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4504b2e..e28f89c 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -786,7 +786,7 @@
| (location.hasElapsedRealtimeUncertaintyNanos()
? ELAPSED_REALTIME_HAS_TIME_UNCERTAINTY_NS : 0);
long elapsedRealtimeNanos = location.getElapsedRealtimeNanos();
- long elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
+ double elapsedRealtimeUncertaintyNanos = location.getElapsedRealtimeUncertaintyNanos();
native_inject_best_location(
gnssLocationFlags, latitudeDegrees, longitudeDegrees,
@@ -2215,7 +2215,7 @@
float horizontalAccuracyMeters, float verticalAccuracyMeters,
float speedAccuracyMetersPerSecond, float bearingAccuracyDegrees,
long timestamp, int elapsedRealtimeFlags, long elapsedRealtimeNanos,
- long elapsedRealtimeUncertaintyNanos);
+ double elapsedRealtimeUncertaintyNanos);
private native void native_inject_location(double latitude, double longitude, float accuracy);
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 16d11ef..0381445 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -24,6 +24,7 @@
import android.hardware.thermal.V2_0.IThermalChangedCallback;
import android.hardware.thermal.V2_0.ThrottlingSeverity;
import android.os.Binder;
+import android.os.CoolingDevice;
import android.os.HwBinder;
import android.os.IThermalEventListener;
import android.os.IThermalService;
@@ -49,8 +50,10 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* This is a system service that listens to HAL thermal events and dispatch those to listeners.
@@ -93,8 +96,7 @@
private ThermalHalWrapper mHalWrapper;
/** Hal ready. */
- @GuardedBy("mLock")
- private boolean mHalReady;
+ private final AtomicBoolean mHalReady = new AtomicBoolean();
/** Invalid throttling status */
private static final int INVALID_THROTTLING = Integer.MIN_VALUE;
@@ -150,7 +152,7 @@
onTemperatureChanged(temperatures.get(i), false);
}
onTemperatureMapChangedLocked();
- mHalReady = halConnected /* true */;
+ mHalReady.set(true);
}
}
@@ -298,20 +300,6 @@
}
}
- private void dumpTemperaturesLocked(PrintWriter pw, String prefix,
- Collection<Temperature> temperatures) {
- for (Temperature t : temperatures) {
- pw.print(prefix);
- String out = String.format("Name: %s, Type: %d, Status: %d, Value: %f",
- t.getName(),
- t.getType(),
- t.getStatus(),
- t.getValue()
- );
- pw.println(out);
- }
- }
-
@VisibleForTesting
final IThermalService.Stub mService = new IThermalService.Stub() {
@Override
@@ -324,7 +312,7 @@
if (!mThermalEventListeners.register(listener, null)) {
return false;
}
- if (mHalReady) {
+ if (mHalReady.get()) {
// Notify its callback after new client registered.
postEventListenerCurrentTemperatures(listener, null);
}
@@ -346,7 +334,7 @@
if (!mThermalEventListeners.register(listener, new Integer(type))) {
return false;
}
- if (mHalReady) {
+ if (mHalReady.get()) {
// Notify its callback after new client registered.
postEventListenerCurrentTemperatures(listener, new Integer(type));
}
@@ -377,7 +365,7 @@
android.Manifest.permission.DEVICE_POWER, null);
final long token = Binder.clearCallingIdentity();
try {
- if (!mHalReady) {
+ if (!mHalReady.get()) {
return new ArrayList<>();
}
return mHalWrapper.getCurrentTemperatures(false, 0 /* not used */);
@@ -392,7 +380,7 @@
android.Manifest.permission.DEVICE_POWER, null);
final long token = Binder.clearCallingIdentity();
try {
- if (!mHalReady) {
+ if (!mHalReady.get()) {
return new ArrayList<>();
}
return mHalWrapper.getCurrentTemperatures(true, type);
@@ -410,7 +398,7 @@
if (!mThermalStatusListeners.register(listener)) {
return false;
}
- if (mHalReady) {
+ if (mHalReady.get()) {
// Notify its callback after new client registered.
postStatusListener(listener);
}
@@ -447,6 +435,43 @@
}
@Override
+ public List<CoolingDevice> getCurrentCoolingDevices() {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mHalReady.get()) {
+ return new ArrayList<>();
+ }
+ return mHalWrapper.getCurrentCoolingDevices(false, 0);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public List<CoolingDevice> getCurrentCoolingDevicesWithType(int type) {
+ getContext().enforceCallingOrSelfPermission(
+ android.Manifest.permission.DEVICE_POWER, null);
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!mHalReady.get()) {
+ return new ArrayList<>();
+ }
+ return mHalWrapper.getCurrentCoolingDevices(true, type);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private void dumpItemsLocked(PrintWriter pw, String prefix,
+ Collection<?> items) {
+ for (Iterator iterator = items.iterator(); iterator.hasNext();) {
+ pw.println(prefix + iterator.next().toString());
+ }
+ }
+
+ @Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) {
return;
@@ -461,17 +486,19 @@
mThermalStatusListeners.dump(pw, "\t");
pw.println("Thermal Status: " + mStatus);
pw.println("Cached temperatures:");
- dumpTemperaturesLocked(pw, "\t", mTemperatureMap.values());
- pw.println("HAL Ready: " + mHalReady);
- if (mHalReady) {
+ dumpItemsLocked(pw, "\t", mTemperatureMap.values());
+ pw.println("HAL Ready: " + mHalReady.get());
+ if (mHalReady.get()) {
pw.println("HAL connection:");
mHalWrapper.dump(pw, "\t");
pw.println("Current temperatures from HAL:");
- dumpTemperaturesLocked(pw, "\t",
+ dumpItemsLocked(pw, "\t",
mHalWrapper.getCurrentTemperatures(false, 0));
+ pw.println("Current cooling devices from HAL:");
+ dumpItemsLocked(pw, "\t",
+ mHalWrapper.getCurrentCoolingDevices(false, 0));
}
}
-
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -588,6 +615,9 @@
protected abstract List<Temperature> getCurrentTemperatures(boolean shouldFilter,
int type);
+ protected abstract List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+ int type);
+
protected abstract boolean connectToHal();
protected abstract void dump(PrintWriter pw, String prefix);
@@ -664,6 +694,42 @@
}
@Override
+ protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ List<CoolingDevice> ret = new ArrayList<>();
+ if (mThermalHal10 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal10.getCoolingDevices((status, coolingDevices) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ for (android.hardware.thermal.V1_0.CoolingDevice
+ coolingDevice : coolingDevices) {
+ if (shouldFilter && type != coolingDevice.type) {
+ continue;
+ }
+ ret.add(new CoolingDevice(
+ (long) coolingDevice.currentValue,
+ coolingDevice.type,
+ coolingDevice.name));
+ }
+ } else {
+ Slog.e(TAG,
+ "Couldn't get cooling device because of HAL error: "
+ + status.debugMessage);
+ }
+
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
@@ -757,6 +823,42 @@
}
@Override
+ protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ List<CoolingDevice> ret = new ArrayList<>();
+ if (mThermalHal11 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal11.getCoolingDevices((status, coolingDevices) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ for (android.hardware.thermal.V1_0.CoolingDevice
+ coolingDevice : coolingDevices) {
+ if (shouldFilter && type != coolingDevice.type) {
+ continue;
+ }
+ ret.add(new CoolingDevice(
+ (long) coolingDevice.currentValue,
+ coolingDevice.type,
+ coolingDevice.name));
+ }
+ } else {
+ Slog.e(TAG,
+ "Couldn't get cooling device because of HAL error: "
+ + status.debugMessage);
+ }
+
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
@@ -817,9 +919,7 @@
}
try {
mThermalHal20.getCurrentTemperatures(shouldFilter, type,
- (ThermalStatus status,
- ArrayList<android.hardware.thermal.V2_0.Temperature>
- temperatures) -> {
+ (status, temperatures) -> {
if (ThermalStatusCode.SUCCESS == status.code) {
for (android.hardware.thermal.V2_0.Temperature
temperature : temperatures) {
@@ -844,6 +944,39 @@
}
@Override
+ protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter,
+ int type) {
+ synchronized (mHalLock) {
+ List<CoolingDevice> ret = new ArrayList<>();
+ if (mThermalHal20 == null) {
+ return ret;
+ }
+ try {
+ mThermalHal20.getCurrentCoolingDevices(shouldFilter, type,
+ (status, coolingDevices) -> {
+ if (ThermalStatusCode.SUCCESS == status.code) {
+ for (android.hardware.thermal.V2_0.CoolingDevice
+ coolingDevice : coolingDevices) {
+ ret.add(new CoolingDevice(
+ coolingDevice.value, coolingDevice.type,
+ coolingDevice.name));
+ }
+ } else {
+ Slog.e(TAG,
+ "Couldn't get cooling device because of HAL error: "
+ + status.debugMessage);
+ }
+
+ });
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Couldn't getCurrentCoolingDevices, reconnecting...", e);
+ connectToHal();
+ }
+ return ret;
+ }
+ }
+
+ @Override
protected boolean connectToHal() {
synchronized (mHalLock) {
try {
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index f4e10ed..6d9e097 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -41,6 +41,7 @@
import android.database.ContentObserver;
import android.database.CursorWindow;
import android.net.Uri;
+import android.os.AsyncTask;
import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
@@ -195,7 +196,13 @@
Slog.i(LOG_TAG, "Packages changed - re-running initial grants for user "
+ userId);
}
- performInitialGrantsIfNecessary(userId);
+ if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())
+ && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ // Package is being upgraded - we're about to get ACTION_PACKAGE_ADDED
+ return;
+ }
+ AsyncTask.THREAD_POOL_EXECUTOR.execute(
+ () -> performInitialGrantsIfNecessaryAsync(userId));
}
}, UserHandle.ALL, intentFilter, null, null);
@@ -222,8 +229,7 @@
performInitialGrantsIfNecessary(userId);
}
- @MainThread
- private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
+ private CompletableFuture<Void> performInitialGrantsIfNecessaryAsync(@UserIdInt int userId) {
RoleUserState userState;
userState = getOrCreateUserState(userId);
@@ -247,20 +253,27 @@
getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(),
successful -> {
if (successful) {
+ userState.setPackagesHash(packagesHash);
result.complete(null);
} else {
result.completeExceptionally(new RuntimeException());
}
});
- try {
- result.get(30, TimeUnit.SECONDS);
- userState.setPackagesHash(packagesHash);
- } catch (InterruptedException | ExecutionException | TimeoutException e) {
- Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
- }
+ return result;
} else if (DEBUG) {
Slog.i(LOG_TAG, "Already ran grants for package state " + packagesHash);
}
+ return CompletableFuture.completedFuture(null);
+ }
+
+ @MainThread
+ private void performInitialGrantsIfNecessary(@UserIdInt int userId) {
+ CompletableFuture<Void> result = performInitialGrantsIfNecessaryAsync(userId);
+ try {
+ result.get(30, TimeUnit.SECONDS);
+ } catch (InterruptedException | ExecutionException | TimeoutException e) {
+ Slog.e(LOG_TAG, "Failed to grant defaults for user " + userId, e);
+ }
}
private void migrateRoleIfNecessary(String role, @UserIdInt int userId) {
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 019cb31..73e9bf0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -499,7 +499,7 @@
}
if (flags & ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) {
- SET(ElapsedRealtimeUncertaintyNanos, location.elapsedRealtime.timeUncertaintyNs);
+ SET(ElapsedRealtimeUncertaintyNanos, static_cast<double>(location.elapsedRealtime.timeUncertaintyNs));
}
return object.get();
@@ -533,7 +533,7 @@
jfloat horizontalAccuracyMeters, jfloat verticalAccuracyMeters,
jfloat speedAccuracyMetersPerSecond, jfloat bearingAccuracyDegrees,
jlong timestamp, jint elapsedRealtimeFlags, jlong elapsedRealtimeNanos,
- jlong elapsedRealtimeUncertaintyNanos) {
+ jdouble elapsedRealtimeUncertaintyNanos) {
GnssLocation_V2_0 location;
location.v1_0 = createGnssLocation_V1_0(
gnssLocationFlags, latitudeDegrees, longitudeDegrees, altitudeMeters,
@@ -1162,7 +1162,7 @@
SET(ElapsedRealtimeNanos, static_cast<uint64_t>(elapsedRealtime.timestampNs));
}
if (flags & ElapsedRealtimeFlags::HAS_TIME_UNCERTAINTY_NS) {
- SET(ElapsedRealtimeUncertaintyNanos, static_cast<uint64_t>(elapsedRealtime.timeUncertaintyNs));
+ SET(ElapsedRealtimeUncertaintyNanos, static_cast<double>(elapsedRealtime.timeUncertaintyNs));
}
translateGnssClock(object, data.clock);
}
@@ -2076,7 +2076,7 @@
jlong timestamp,
jint elapsedRealtimeFlags,
jlong elapsedRealtimeNanos,
- jlong elapsedRealtimeUncertaintyNanos) {
+ jdouble elapsedRealtimeUncertaintyNanos) {
if (gnssHal_V2_0 != nullptr) {
GnssLocation_V2_0 location = createGnssLocation_V2_0(
gnssLocationFlags,
@@ -2988,7 +2988,7 @@
android_location_GnssLocationProvider_read_nmea)},
{"native_inject_time", "(JJI)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_time)},
- {"native_inject_best_location", "(IDDDFFFFFFJIJJ)V", reinterpret_cast<void *>(
+ {"native_inject_best_location", "(IDDDFFFFFFJIJD)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_best_location)},
{"native_inject_location", "(DDF)V", reinterpret_cast<void *>(
android_location_GnssLocationProvider_inject_location)},
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9d09c4c..106e642 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -254,6 +254,8 @@
"com.android.server.autofill.AutofillManagerService";
private static final String CONTENT_CAPTURE_MANAGER_SERVICE_CLASS =
"com.android.server.contentcapture.ContentCaptureManagerService";
+ private static final String SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS =
+ "com.android.server.systemcaptions.SystemCaptionsManagerService";
private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
"com.android.server.timezone.RulesManagerService$Lifecycle";
private static final String IOT_SERVICE_CLASS =
@@ -1232,6 +1234,8 @@
startContentCaptureService(context);
startAttentionService(context);
+ startSystemCaptionsManagerService(context);
+
// App prediction manager service
traceBeginAndSlog("StartAppPredictionService");
mSystemServiceManager.startService(APP_PREDICTION_MANAGER_SERVICE_CLASS);
@@ -2225,6 +2229,19 @@
}, BOOT_TIMINGS_TRACE_LOG);
}
+ private void startSystemCaptionsManagerService(@NonNull Context context) {
+ String serviceName = context.getString(
+ com.android.internal.R.string.config_defaultSystemCaptionsManagerService);
+ if (TextUtils.isEmpty(serviceName)) {
+ Slog.d(TAG, "SystemCaptionsManagerService disabled because resource is not overlaid");
+ return;
+ }
+
+ traceBeginAndSlog("StartSystemCaptionsManagerService");
+ mSystemServiceManager.startService(SYSTEM_CAPTIONS_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
+
private void startContentCaptureService(@NonNull Context context) {
// First check if it was explicitly enabled by DeviceConfig
boolean explicitlyEnabled = false;
@@ -2273,7 +2290,7 @@
traceEnd();
}
- static final void startSystemUi(Context context, WindowManagerService windowManager) {
+ private static void startSystemUi(Context context, WindowManagerService windowManager) {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.android.systemui",
"com.android.systemui.SystemUIService"));
diff --git a/services/systemcaptions/Android.bp b/services/systemcaptions/Android.bp
new file mode 100644
index 0000000..4e190b6
--- /dev/null
+++ b/services/systemcaptions/Android.bp
@@ -0,0 +1,5 @@
+java_library_static {
+ name: "services.systemcaptions",
+ srcs: ["java/**/*.java"],
+ libs: ["services.core"],
+}
diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java
new file mode 100644
index 0000000..5480b6c
--- /dev/null
+++ b/services/systemcaptions/java/com/android/server/systemcaptions/RemoteSystemCaptionsManagerService.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2019 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.systemcaptions;
+
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.UserHandle;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+
+/** Manages the connection to the remote system captions manager service. */
+final class RemoteSystemCaptionsManagerService {
+
+ private static final String TAG = RemoteSystemCaptionsManagerService.class.getSimpleName();
+
+ private static final String SERVICE_INTERFACE =
+ "android.service.systemcaptions.SystemCaptionsManagerService";
+
+ private final Object mLock = new Object();
+
+ private final Context mContext;
+ private final Intent mIntent;
+ private final ComponentName mComponentName;
+ private final int mUserId;
+ private final boolean mVerbose;
+ private final Handler mHandler;
+
+ private final RemoteServiceConnection mServiceConnection = new RemoteServiceConnection();
+
+ @GuardedBy("mLock")
+ @Nullable private IBinder mService;
+
+ @GuardedBy("mLock")
+ private boolean mBinding = false;
+
+ @GuardedBy("mLock")
+ private boolean mDestroyed = false;
+
+ RemoteSystemCaptionsManagerService(
+ Context context, ComponentName componentName, int userId, boolean verbose) {
+ mContext = context;
+ mComponentName = componentName;
+ mUserId = userId;
+ mVerbose = verbose;
+ mIntent = new Intent(SERVICE_INTERFACE).setComponent(componentName);
+ mHandler = new Handler(Looper.getMainLooper());
+ }
+
+ void initialize() {
+ if (mVerbose) {
+ Slog.v(TAG, "initialize()");
+ }
+ ensureBound();
+ }
+
+ void destroy() {
+ if (mVerbose) {
+ Slog.v(TAG, "destroy()");
+ }
+
+ synchronized (mLock) {
+ if (mDestroyed) {
+ if (mVerbose) {
+ Slog.v(TAG, "destroy(): Already destroyed");
+ }
+ return;
+ }
+ mDestroyed = true;
+ ensureUnboundLocked();
+ }
+ }
+
+ boolean isDestroyed() {
+ synchronized (mLock) {
+ return mDestroyed;
+ }
+ }
+
+ private void ensureBound() {
+ synchronized (mLock) {
+ if (mService != null || mBinding) {
+ return;
+ }
+
+ if (mVerbose) {
+ Slog.v(TAG, "ensureBound(): binding");
+ }
+ mBinding = true;
+
+ int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+ boolean willBind = mContext.bindServiceAsUser(mIntent, mServiceConnection, flags,
+ mHandler, new UserHandle(mUserId));
+ if (!willBind) {
+ Slog.w(TAG, "Could not bind to " + mIntent + " with flags " + flags);
+ mBinding = false;
+ mService = null;
+ }
+ }
+ }
+
+ @GuardedBy("mLock")
+ private void ensureUnboundLocked() {
+ if (mService == null && !mBinding) {
+ return;
+ }
+
+ mBinding = false;
+ mService = null;
+
+ if (mVerbose) {
+ Slog.v(TAG, "ensureUnbound(): unbinding");
+ }
+ mContext.unbindService(mServiceConnection);
+ }
+
+ private class RemoteServiceConnection implements ServiceConnection {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (mLock) {
+ if (mVerbose) {
+ Slog.v(TAG, "onServiceConnected()");
+ }
+ if (mDestroyed || !mBinding) {
+ Slog.wtf(TAG, "onServiceConnected() dispatched after unbindService");
+ return;
+ }
+ mBinding = false;
+ mService = service;
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ synchronized (mLock) {
+ if (mVerbose) {
+ Slog.v(TAG, "onServiceDisconnected()");
+ }
+ mBinding = true;
+ mService = null;
+ }
+ }
+ }
+}
diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerPerUserService.java b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerPerUserService.java
new file mode 100644
index 0000000..b503670
--- /dev/null
+++ b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerPerUserService.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2019 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.systemcaptions;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.app.AppGlobals;
+import android.content.ComponentName;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.server.infra.AbstractPerUserSystemService;
+
+/** Manages the captions manager service on a per-user basis. */
+final class SystemCaptionsManagerPerUserService extends
+ AbstractPerUserSystemService<SystemCaptionsManagerPerUserService,
+ SystemCaptionsManagerService> {
+
+ private static final String TAG = SystemCaptionsManagerPerUserService.class.getSimpleName();
+
+ @Nullable
+ @GuardedBy("mLock")
+ private RemoteSystemCaptionsManagerService mRemoteService;
+
+ SystemCaptionsManagerPerUserService(
+ @NonNull SystemCaptionsManagerService master,
+ @NonNull Object lock, boolean disabled, @UserIdInt int userId) {
+ super(master, lock, userId);
+ }
+
+ @Override
+ @NonNull
+ protected ServiceInfo newServiceInfoLocked(
+ @SuppressWarnings("unused") @NonNull ComponentName serviceComponent)
+ throws PackageManager.NameNotFoundException {
+ try {
+ return AppGlobals.getPackageManager().getServiceInfo(serviceComponent,
+ PackageManager.GET_META_DATA, mUserId);
+ } catch (RemoteException e) {
+ throw new PackageManager.NameNotFoundException(
+ "Could not get service for " + serviceComponent);
+ }
+ }
+
+ @GuardedBy("mLock")
+ void initializeLocked() {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "initialize()");
+ }
+
+ RemoteSystemCaptionsManagerService service = getRemoteServiceLocked();
+ if (service == null && mMaster.verbose) {
+ Slog.v(TAG, "initialize(): Failed to init remote server");
+ }
+ }
+
+ @GuardedBy("mLock")
+ void destroyLocked() {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "destroyLocked()");
+ }
+
+ if (mRemoteService != null) {
+ mRemoteService.destroy();
+ mRemoteService = null;
+ }
+ }
+
+ @GuardedBy("mLock")
+ @Nullable
+ private RemoteSystemCaptionsManagerService getRemoteServiceLocked() {
+ if (mRemoteService == null) {
+ String serviceName = getComponentNameLocked();
+ if (serviceName == null) {
+ if (mMaster.verbose) {
+ Slog.v(TAG, "getRemoteServiceLocked(): Not set");
+ }
+ return null;
+ }
+
+ ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
+ mRemoteService = new RemoteSystemCaptionsManagerService(
+ getContext(),
+ serviceComponent,
+ mUserId,
+ mMaster.verbose);
+ if (mMaster.verbose) {
+ Slog.v(TAG, "getRemoteServiceLocked(): initialize for user " + mUserId);
+ }
+ mRemoteService.initialize();
+ }
+
+ return mRemoteService;
+ }
+}
diff --git a/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java
new file mode 100644
index 0000000..27a116c
--- /dev/null
+++ b/services/systemcaptions/java/com/android/server/systemcaptions/SystemCaptionsManagerService.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 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.systemcaptions;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.content.Context;
+
+import com.android.server.infra.AbstractMasterSystemService;
+import com.android.server.infra.FrameworkResourcesServiceNameResolver;
+
+/** A system service to bind to a remote system captions manager service. */
+public final class SystemCaptionsManagerService extends
+ AbstractMasterSystemService<SystemCaptionsManagerService,
+ SystemCaptionsManagerPerUserService> {
+
+ public SystemCaptionsManagerService(@NonNull Context context) {
+ super(context,
+ new FrameworkResourcesServiceNameResolver(
+ context,
+ com.android.internal.R.string.config_defaultSystemCaptionsManagerService),
+ /*disallowProperty=*/ null,
+ /*packageUpdatePolicy=*/ PACKAGE_UPDATE_POLICY_REFRESH_EAGER);
+ }
+
+ @Override
+ public void onStart() {
+ // Do nothing. This service does not publish any local or system services.
+ }
+
+ @Override
+ protected SystemCaptionsManagerPerUserService newServiceLocked(
+ @UserIdInt int resolvedUserId, boolean disabled) {
+ SystemCaptionsManagerPerUserService perUserService =
+ new SystemCaptionsManagerPerUserService(this, mLock, disabled, resolvedUserId);
+ perUserService.initializeLocked();
+ return perUserService;
+ }
+
+ @Override
+ protected void onServiceRemoved(
+ SystemCaptionsManagerPerUserService service, @UserIdInt int userId) {
+ synchronized (mLock) {
+ service.destroyLocked();
+ }
+ }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 7a40e44..7a68e92 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -66,6 +66,7 @@
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -118,6 +119,8 @@
private AlarmManagerService.ClockReceiver mClockReceiver;
@Mock
private PowerManager.WakeLock mWakeLock;
+ @Mock
+ private PackageManager mMockPackageManager;
private MockitoSession mMockingSession;
private Injector mInjector;
@@ -128,15 +131,21 @@
static class TestTimer {
private long mElapsed;
boolean mExpired;
+ int mType;
synchronized long getElapsed() {
return mElapsed;
}
- synchronized void set(long millisElapsed) {
+ synchronized void set(int type, long millisElapsed) {
+ mType = type;
mElapsed = millisElapsed;
}
+ synchronized int getType() {
+ return mType;
+ }
+
synchronized void expire() throws InterruptedException {
mExpired = true;
notifyAll();
@@ -146,6 +155,8 @@
}
public class Injector extends AlarmManagerService.Injector {
+ boolean mIsAutomotiveOverride;
+
Injector(Context context) {
super(context);
}
@@ -179,7 +190,7 @@
@Override
void setAlarm(int type, long millis) {
- mTestTimer.set(millis);
+ mTestTimer.set(type, millis);
}
@Override
@@ -211,6 +222,11 @@
PowerManager.WakeLock getAlarmWakeLock() {
return mWakeLock;
}
+
+ @Override
+ boolean isAutomotive() {
+ return mIsAutomotiveOverride;
+ }
}
@Before
@@ -237,6 +253,8 @@
when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
doReturn("min_futurity=0,min_interval=0").when(() ->
Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+
mInjector = new Injector(mMockContext);
mService = new AlarmManagerService(mMockContext, mInjector);
spyOn(mService);
@@ -933,6 +951,37 @@
}
@Test
+ public void alarmTypes() throws Exception {
+ final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC};
+ final int[] typesExpected = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME,
+ ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
+ assertAlarmTypeConversion(typesToSet, typesExpected);
+ }
+
+ /**
+ * Confirm that wakeup alarms are never set for automotive.
+ */
+ @Test
+ public void alarmTypesForAuto() throws Exception {
+ mInjector.mIsAutomotiveOverride = true;
+ final int[] typesToSet = {ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME, RTC_WAKEUP, RTC};
+ final int[] typesExpected = {ELAPSED_REALTIME, ELAPSED_REALTIME, ELAPSED_REALTIME,
+ ELAPSED_REALTIME};
+ assertAlarmTypeConversion(typesToSet, typesExpected);
+ }
+
+ private void assertAlarmTypeConversion(int[] typesToSet, int[] typesExpected) throws Exception {
+ for (int i = 0; i < typesToSet.length; i++) {
+ setTestAlarm(typesToSet[i], 1234, getNewMockPendingIntent());
+ final int typeSet = mTestTimer.getType();
+ assertEquals("Alarm of type " + typesToSet[i] + " was set to type " + typeSet,
+ typesExpected[i], typeSet);
+ mNowElapsedTest = mTestTimer.getElapsed();
+ mTestTimer.expire();
+ }
+ }
+
+ @Test
public void alarmCountOnInvalidSet() {
setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 12345, null);
assertEquals(-1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, -1));
diff --git a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
index 94d293e..27d5296 100644
--- a/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/ThermalManagerServiceTest.java
@@ -28,6 +28,7 @@
import static org.mockito.Mockito.when;
import android.content.Context;
+import android.os.CoolingDevice;
import android.os.IBinder;
import android.os.IPowerManager;
import android.os.IThermalEventListener;
@@ -85,6 +86,8 @@
private class ThermalHalFake extends ThermalHalWrapper {
private static final int INIT_STATUS = Temperature.THROTTLING_NONE;
private ArrayList<Temperature> mTemperatureList = new ArrayList<>();
+ private ArrayList<CoolingDevice> mCoolingDeviceList = new ArrayList<>();
+
private Temperature mSkin1 = new Temperature(0, Temperature.TYPE_SKIN, "skin1",
INIT_STATUS);
private Temperature mSkin2 = new Temperature(0, Temperature.TYPE_SKIN, "skin2",
@@ -93,17 +96,40 @@
INIT_STATUS);
private Temperature mUsbPort = new Temperature(0, Temperature.TYPE_USB_PORT, "usbport",
INIT_STATUS);
+ private CoolingDevice mCpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "cpu");
+ private CoolingDevice mGpu = new CoolingDevice(0, CoolingDevice.TYPE_BATTERY, "gpu");
ThermalHalFake() {
mTemperatureList.add(mSkin1);
mTemperatureList.add(mSkin2);
mTemperatureList.add(mBattery);
mTemperatureList.add(mUsbPort);
+ mCoolingDeviceList.add(mCpu);
+ mCoolingDeviceList.add(mGpu);
}
@Override
protected List<Temperature> getCurrentTemperatures(boolean shouldFilter, int type) {
- return mTemperatureList;
+ List<Temperature> ret = new ArrayList<>();
+ for (Temperature temperature : mTemperatureList) {
+ if (shouldFilter && type != temperature.getType()) {
+ continue;
+ }
+ ret.add(temperature);
+ }
+ return ret;
+ }
+
+ @Override
+ protected List<CoolingDevice> getCurrentCoolingDevices(boolean shouldFilter, int type) {
+ List<CoolingDevice> ret = new ArrayList<>();
+ for (CoolingDevice cdev : mCoolingDeviceList) {
+ if (shouldFilter && type != cdev.getType()) {
+ continue;
+ }
+ ret.add(cdev);
+ }
+ return ret;
}
@Override
@@ -117,8 +143,10 @@
}
}
- private void assertTemperatureEquals(List<Temperature> expected, List<Temperature> value) {
- assertEquals(new HashSet<>(expected), new HashSet<>(value));
+ private void assertListEqualsIgnoringOrder(List<?> actual, List<?> expected) {
+ HashSet<?> actualSet = new HashSet<>(actual);
+ HashSet<?> expectedSet = new HashSet<>(expected);
+ assertEquals(expectedSet, actualSet);
}
@Before
@@ -148,13 +176,14 @@
ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(4)).notifyThrottling(captor.capture());
- assertTemperatureEquals(mFakeHal.mTemperatureList, captor.getAllValues());
+ assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues());
verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(1)).onStatusChange(Temperature.THROTTLING_NONE);
captor = ArgumentCaptor.forClass(Temperature.class);
verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(2)).notifyThrottling(captor.capture());
- assertTemperatureEquals(new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
+ assertListEqualsIgnoringOrder(
+ new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
captor.getAllValues());
verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(1)).onStatusChange(Temperature.THROTTLING_NONE);
@@ -185,7 +214,7 @@
ArgumentCaptor<Temperature> captor = ArgumentCaptor.forClass(Temperature.class);
verify(mEventListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(4)).notifyThrottling(captor.capture());
- assertTemperatureEquals(mFakeHal.mTemperatureList, captor.getAllValues());
+ assertListEqualsIgnoringOrder(mFakeHal.mTemperatureList, captor.getAllValues());
verify(mStatusListener1, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(1)).onStatusChange(Temperature.THROTTLING_NONE);
// Register new callbacks and verify old ones are not called (remained same) while new
@@ -200,7 +229,8 @@
captor = ArgumentCaptor.forClass(Temperature.class);
verify(mEventListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(2)).notifyThrottling(captor.capture());
- assertTemperatureEquals(new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
+ assertListEqualsIgnoringOrder(
+ new ArrayList<>(Arrays.asList(mFakeHal.mSkin1, mFakeHal.mSkin2)),
captor.getAllValues());
verify(mStatusListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
.times(1)).onStatusChange(Temperature.THROTTLING_NONE);
@@ -260,9 +290,9 @@
@Test
public void testGetCurrentTemperatures() throws RemoteException {
- assertTemperatureEquals(mFakeHal.getCurrentTemperatures(false, 0),
+ assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(false, 0),
mService.mService.getCurrentTemperatures());
- assertTemperatureEquals(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
+ assertListEqualsIgnoringOrder(mFakeHal.getCurrentTemperatures(true, Temperature.TYPE_SKIN),
mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN));
}
@@ -300,4 +330,16 @@
mService.mService.getCurrentTemperaturesWithType(Temperature.TYPE_SKIN).size());
assertEquals(Temperature.THROTTLING_NONE, mService.mService.getCurrentThermalStatus());
}
+
+ @Test
+ public void testGetCurrentCoolingDevices() throws RemoteException {
+ assertListEqualsIgnoringOrder(mFakeHal.getCurrentCoolingDevices(false, 0),
+ mService.mService.getCurrentCoolingDevices());
+ assertListEqualsIgnoringOrder(
+ mFakeHal.getCurrentCoolingDevices(false, CoolingDevice.TYPE_BATTERY),
+ mService.mService.getCurrentCoolingDevices());
+ assertListEqualsIgnoringOrder(
+ mFakeHal.getCurrentCoolingDevices(true, CoolingDevice.TYPE_CPU),
+ mService.mService.getCurrentCoolingDevicesWithType(CoolingDevice.TYPE_CPU));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index de4fb98..23bae88 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -37,7 +37,6 @@
import android.platform.test.annotations.Presubmit;
import android.util.SparseIntArray;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.server.wm.ActivityMetricsLaunchObserver.ActivityRecordProto;
@@ -119,7 +118,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnIntentStarted() throws Exception {
Intent intent = new Intent("action 1");
@@ -130,7 +128,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnIntentFailed() throws Exception {
testOnIntentStarted();
@@ -146,7 +143,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnActivityLaunched() throws Exception {
testOnIntentStarted();
@@ -158,7 +154,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnActivityLaunchFinished() throws Exception {
testOnActivityLaunched();
@@ -173,7 +168,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnActivityLaunchCancelled() throws Exception {
testOnActivityLaunched();
@@ -187,7 +181,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnActivityLaunchedTrampoline() throws Exception {
testOnIntentStarted();
@@ -204,7 +197,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnActivityLaunchFinishedTrampoline() throws Exception {
testOnActivityLaunchedTrampoline();
@@ -219,7 +211,6 @@
}
@Test
- @FlakyTest(bugId = 129138370)
public void testOnActivityLaunchCancelledTrampoline() throws Exception {
testOnActivityLaunchedTrampoline();
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
index 7cfe71e..c9263eb 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositioningControllerTests.java
@@ -32,7 +32,6 @@
import android.platform.test.annotations.Presubmit;
import android.view.InputChannel;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import org.junit.Before;
@@ -88,7 +87,6 @@
assertNull(mTarget.getDragWindowHandleLocked());
}
- @FlakyTest(bugId = 129331490)
@Test
public void testHandleTapOutsideTask() {
synchronized (mWm.mGlobalLock) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
index d8a01b9..1eb716a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskStackChangedListenerTest.java
@@ -39,7 +39,6 @@
import android.support.test.uiautomator.UiDevice;
import android.text.TextUtils;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.MediumTest;
import com.android.internal.annotations.GuardedBy;
@@ -159,6 +158,7 @@
* Tests for onTaskCreated, onTaskMovedToFront, onTaskRemoved and onTaskRemovalStarted.
*/
@Test
+ @Presubmit
public void testTaskChangeCallBacks() throws Exception {
final Object[] params = new Object[2];
final CountDownLatch taskCreatedLaunchLatch = new CountDownLatch(1);
diff --git a/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index d01c889..37fab09 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -121,8 +121,6 @@
*
* @param handle the new phone number to dial
* @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
- * If {@code null}, no change will be made to the
- * {@link PhoneAccountHandle} used to place the call.
* @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
* if the confirmFirst is true, and if the redirection request of this
* response was sent with a true flag of allowInteractiveResponse via
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index a567d03..0f8f873 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2762,6 +2762,48 @@
public static final String KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION =
"carrier_auto_cancel_cs_notification";
+ /**
+ * Passing this value as {@link KEY_SUBSCRIPTION_GROUP_UUID_STRING} will remove the
+ * subscription from a group instead of adding it to a group.
+ *
+ * TODO: Expose in a future release.
+ *
+ * @hide
+ */
+ public static final String REMOVE_GROUP_UUID_STRING = "00000000-0000-0000-0000-000000000000";
+
+ /**
+ * The UUID of a Group of related subscriptions in which to place the current subscription.
+ *
+ * A grouped subscription will behave for billing purposes and other UI purposes as though it
+ * is a transparent extension of other subscriptions in the group.
+ *
+ * <p>If set to {@link #REMOVE_GROUP_UUID_STRING}, then the subscription will be removed from
+ * its current group.
+ *
+ * TODO: unhide this key.
+ *
+ * @hide
+ */
+ public static final String KEY_SUBSCRIPTION_GROUP_UUID_STRING =
+ "key_subscription_group_uuid_string";
+
+ /**
+ * A boolean property indicating whether this subscription should be managed as an opportunistic
+ * subscription.
+ *
+ * If true, then this subscription will be selected based on available coverage and will not be
+ * available for a user in settings menus for selecting macro network providers. If unset,
+ * defaults to “false”.
+ *
+ * TODO: unhide this key.
+ *
+ * @hide
+ */
+ public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL =
+ "key_is_opportunistic_subscription_bool";
+
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -3160,6 +3202,8 @@
sDefaults.putString(KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING, "");
sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
false);
+ sDefaults.putString(KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
+ sDefaults.putBoolean(KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
}
/**
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index e66ead7..373adca 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -226,6 +226,14 @@
errorCount++;
continue;
}
+
+ // Doubles are not supported yet.
+ if (javaType == JAVA_TYPE_DOUBLE) {
+ print_error(field, "Doubles are not supported in atoms. Please change field %s to float\n",
+ field->name().c_str());
+ errorCount++;
+ continue;
+ }
}
// Check that if there's an attribution chain, it's at position 1.
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index a5b56a4..4e6d073 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -25,6 +25,11 @@
const string DEFAULT_MODULE_NAME = "DEFAULT";
const string DEFAULT_CPP_NAMESPACE = "android,util";
const string DEFAULT_CPP_HEADER_IMPORT = "statslog.h";
+const string DEFAULT_JAVA_PACKAGE = "android.util";
+const string DEFAULT_JAVA_CLASS = "StatsLogInternal";
+
+const int JAVA_MODULE_REQUIRES_FLOAT = 0x01;
+const int JAVA_MODULE_REQUIRES_ATTRIBUTION = 0x02;
using android::os::statsd::Atom;
@@ -921,11 +926,350 @@
}
}
+static void write_java_helpers_for_module(
+ FILE * out,
+ const AtomDecl &attributionDecl,
+ const int requiredHelpers) {
+ fprintf(out, " private static void copyInt(byte[] buff, int pos, int val) {\n");
+ fprintf(out, " buff[pos] = (byte) (val);\n");
+ fprintf(out, " buff[pos + 1] = (byte) (val >> 8);\n");
+ fprintf(out, " buff[pos + 2] = (byte) (val >> 16);\n");
+ fprintf(out, " buff[pos + 3] = (byte) (val >> 24);\n");
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+ fprintf(out, "\n");
+
+ fprintf(out, " private static void copyLong(byte[] buff, int pos, long val) {\n");
+ fprintf(out, " buff[pos] = (byte) (val);\n");
+ fprintf(out, " buff[pos + 1] = (byte) (val >> 8);\n");
+ fprintf(out, " buff[pos + 2] = (byte) (val >> 16);\n");
+ fprintf(out, " buff[pos + 3] = (byte) (val >> 24);\n");
+ fprintf(out, " buff[pos + 4] = (byte) (val >> 32);\n");
+ fprintf(out, " buff[pos + 5] = (byte) (val >> 40);\n");
+ fprintf(out, " buff[pos + 6] = (byte) (val >> 48);\n");
+ fprintf(out, " buff[pos + 7] = (byte) (val >> 56);\n");
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+ fprintf(out, "\n");
+
+ if (requiredHelpers & JAVA_MODULE_REQUIRES_FLOAT) {
+ fprintf(out, " private static void copyFloat(byte[] buff, int pos, float val) {\n");
+ fprintf(out, " copyInt(buff, pos, Float.floatToIntBits(val));\n");
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+ fprintf(out, "\n");
+ }
+
+ if (requiredHelpers & JAVA_MODULE_REQUIRES_ATTRIBUTION) {
+ fprintf(out, " private static void writeAttributionChain(byte[] buff, int pos");
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s[] %s",
+ java_type_name(chainField.javaType), chainField.name.c_str());
+ }
+ fprintf(out, ") {\n");
+
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+
+ // Write the first list begin.
+ fprintf(out, " buff[pos] = LIST_TYPE;\n");
+ fprintf(out, " buff[pos + 1] = (byte) (%s.length);\n", tagName);
+ fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n");
+
+ // Iterate through the attribution chain and write the nodes.
+ fprintf(out, " for (int i = 0; i < %s.length; i++) {\n", tagName);
+ // Write the list begin.
+ fprintf(out, " buff[pos] = LIST_TYPE;\n");
+ fprintf(out, " buff[pos + 1] = %lu;\n", attributionDecl.fields.size());
+ fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n");
+
+ // Write the uid.
+ fprintf(out, " buff[pos] = INT_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, %s[i]);\n", uidName);
+ fprintf(out, " pos += INT_TYPE_SIZE;\n");
+
+ // Write the tag.
+ fprintf(out, " String %sStr = (%s[i] == null) ? \"\" : %s[i];\n",
+ tagName, tagName, tagName);
+ fprintf(out, " byte[] %sByte = %sStr.getBytes(UTF_8);\n", tagName, tagName);
+ fprintf(out, " buff[pos] = STRING_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, %sByte.length);\n", tagName);
+ fprintf(out, " System.arraycopy("
+ "%sByte, 0, buff, pos + STRING_TYPE_OVERHEAD, %sByte.length);\n",
+ tagName, tagName);
+ fprintf(out, " pos += STRING_TYPE_OVERHEAD + %sByte.length;\n", tagName);
+ fprintf(out, " }\n");
+ fprintf(out, " }\n");
+ fprintf(out, "\n");
+ }
+}
+
+
+static int write_java_non_chained_method_for_module(
+ FILE* out,
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const string& moduleName
+ ) {
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ // Skip if this signature is not needed for the module.
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+
+ // Print method signature.
+ vector<java_type_t> signature = signature_to_modules_it->first;
+ fprintf(out, " public static void write_non_chained(int code");
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ // Non chained signatures should not have attribution chains.
+ return 1;
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ // Module logging does not yet support key value pair.
+ return 1;
+ } else {
+ fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+ }
+ argIndex++;
+ }
+ fprintf(out, ") {\n");
+
+ fprintf(out, " write(code");
+ argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ // First two args are uid and tag of attribution chain.
+ if (argIndex == 1) {
+ fprintf(out, ", new int[] {arg%d}", argIndex);
+ } else if (argIndex == 2) {
+ fprintf(out, ", new java.lang.String[] {arg%d}", argIndex);
+ } else {
+ fprintf(out, ", arg%d", argIndex);
+ }
+ argIndex++;
+ }
+ fprintf(out, ");\n");
+ fprintf(out, " }\n");
+ fprintf(out, "\n");
+ }
+ return 0;
+}
+
+static int write_java_method_for_module(
+ FILE* out,
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const AtomDecl &attributionDecl,
+ const string& moduleName,
+ int* requiredHelpers
+ ) {
+
+ for (auto signature_to_modules_it = signatures_to_modules.begin();
+ signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ // Skip if this signature is not needed for the module.
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
+
+ // Print method signature.
+ vector<java_type_t> signature = signature_to_modules_it->first;
+ fprintf(out, " public static void write(int code");
+ int argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ if (*arg == JAVA_TYPE_ATTRIBUTION_CHAIN) {
+ for (auto chainField : attributionDecl.fields) {
+ fprintf(out, ", %s[] %s",
+ java_type_name(chainField.javaType), chainField.name.c_str());
+ }
+ } else if (*arg == JAVA_TYPE_KEY_VALUE_PAIR) {
+ // Module logging does not yet support key value pair.
+ return 1;
+ } else {
+ fprintf(out, ", %s arg%d", java_type_name(*arg), argIndex);
+ }
+ argIndex++;
+ }
+ fprintf(out, ") {\n");
+
+ // Calculate the size of the buffer.
+ fprintf(out, " // Initial overhead of the list, timestamp, and atom tag.\n");
+ fprintf(out, " int needed = LIST_TYPE_OVERHEAD + LONG_TYPE_SIZE + INT_TYPE_SIZE;\n");
+ argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_BOOLEAN:
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_FLOAT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " needed += INT_TYPE_SIZE;\n");
+ break;
+ case JAVA_TYPE_LONG:
+ // Longs take 9 bytes, 1 for the type and 8 for the value.
+ fprintf(out, " needed += LONG_TYPE_SIZE;\n");
+ break;
+ case JAVA_TYPE_STRING:
+ // Strings take 5 metadata bytes + length of byte encoded string.
+ fprintf(out, " if (arg%d == null) {\n", argIndex);
+ fprintf(out, " arg%d = \"\";\n", argIndex);
+ fprintf(out, " }\n");
+ fprintf(out, " byte[] arg%dBytes= arg%d.getBytes(UTF_8);\n",
+ argIndex, argIndex);
+ fprintf(out, " needed += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+ argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ // Byte arrays take 5 metadata bytes + length of byte array.
+ fprintf(out, " if (arg%d == null) {\n", argIndex);
+ fprintf(out, " arg%d = new byte[0];\n", argIndex);
+ fprintf(out, " }\n");
+ fprintf(out, " needed += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN:
+ {
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+ // Null checks on the params.
+ fprintf(out, " if (%s == null) {\n", uidName);
+ fprintf(out, " %s = new %s[0];\n", uidName,
+ java_type_name(attributionDecl.fields.front().javaType));
+ fprintf(out, " }\n");
+ fprintf(out, " if (%s == null) {\n", tagName);
+ fprintf(out, " %s = new %s[0];\n", tagName,
+ java_type_name(attributionDecl.fields.back().javaType));
+ fprintf(out, " }\n");
+
+ // First check that the lengths of the uid and tag arrays are the same.
+ fprintf(out, " if (%s.length != %s.length) {\n", uidName, tagName);
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+ fprintf(out, " int attrSize = LIST_TYPE_OVERHEAD;\n");
+ fprintf(out, " for (int i = 0; i < %s.length; i++) {\n", tagName);
+ fprintf(out, " String str%d = (%s[i] == null) ? \"\" : %s[i];\n",
+ argIndex, tagName, tagName);
+ fprintf(out, " int str%dlen = str%d.getBytes(UTF_8).length;\n",
+ argIndex, argIndex);
+ fprintf(out,
+ " attrSize += "
+ "LIST_TYPE_OVERHEAD + INT_TYPE_SIZE + STRING_TYPE_OVERHEAD + str%dlen;\n",
+ argIndex);
+ fprintf(out, " }\n");
+ fprintf(out, " needed += attrSize;\n");
+ break;
+ }
+ default:
+ // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR.
+ return 1;
+ }
+ argIndex++;
+ }
+
+ // Now we have the size that is needed. Check for overflow and return if needed.
+ fprintf(out, " if (needed > MAX_EVENT_PAYLOAD) {\n");
+ fprintf(out, " return;\n");
+ fprintf(out, " }\n");
+
+ // Create new buffer, and associated data types.
+ fprintf(out, " byte[] buff = new byte[needed];\n");
+ fprintf(out, " int pos = 0;\n");
+
+ // Initialize the buffer with list data type.
+ fprintf(out, " buff[pos] = LIST_TYPE;\n");
+ fprintf(out, " buff[pos + 1] = %lu;\n", signature.size() + 2);
+ fprintf(out, " pos += LIST_TYPE_OVERHEAD;\n");
+
+ // Write timestamp.
+ fprintf(out, " long elapsedRealtime = SystemClock.elapsedRealtimeNanos();\n");
+ fprintf(out, " buff[pos] = LONG_TYPE;\n");
+ fprintf(out, " copyLong(buff, pos + 1, elapsedRealtime);\n");
+ fprintf(out, " pos += LONG_TYPE_SIZE;\n");
+
+ // Write atom code.
+ fprintf(out, " buff[pos] = INT_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, code);\n");
+ fprintf(out, " pos += INT_TYPE_SIZE;\n");
+
+ // Write the args.
+ argIndex = 1;
+ for (vector<java_type_t>::const_iterator arg = signature.begin();
+ arg != signature.end(); arg++) {
+ switch (*arg) {
+ case JAVA_TYPE_BOOLEAN:
+ fprintf(out, " buff[pos] = INT_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, arg%d? 1 : 0);\n", argIndex);
+ fprintf(out, " pos += INT_TYPE_SIZE;\n");
+ break;
+ case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
+ fprintf(out, " buff[pos] = INT_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, arg%d);\n", argIndex);
+ fprintf(out, " pos += INT_TYPE_SIZE;\n");
+ break;
+ case JAVA_TYPE_FLOAT:
+ *requiredHelpers |= JAVA_MODULE_REQUIRES_FLOAT;
+ fprintf(out, " buff[pos] = FLOAT_TYPE;\n");
+ fprintf(out, " copyFloat(buff, pos + 1, arg%d);\n", argIndex);
+ fprintf(out, " pos += FLOAT_TYPE_SIZE;\n");
+ break;
+ case JAVA_TYPE_LONG:
+ fprintf(out, " buff[pos] = LONG_TYPE;\n");
+ fprintf(out, " copyLong(buff, pos + 1, arg%d);\n", argIndex);
+ fprintf(out, " pos += LONG_TYPE_SIZE;\n");
+ break;
+ case JAVA_TYPE_STRING:
+ fprintf(out, " buff[pos] = STRING_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, arg%dBytes.length);\n", argIndex);
+ fprintf(out, " System.arraycopy("
+ "arg%dBytes, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%dBytes.length);\n",
+ argIndex, argIndex);
+ fprintf(out, " pos += STRING_TYPE_OVERHEAD + arg%dBytes.length;\n",
+ argIndex);
+ break;
+ case JAVA_TYPE_BYTE_ARRAY:
+ fprintf(out, " buff[pos] = STRING_TYPE;\n");
+ fprintf(out, " copyInt(buff, pos + 1, arg%d.length);\n", argIndex);
+ fprintf(out, " System.arraycopy("
+ "arg%d, 0, buff, pos + STRING_TYPE_OVERHEAD, arg%d.length);\n",
+ argIndex, argIndex);
+ fprintf(out, " pos += STRING_TYPE_OVERHEAD + arg%d.length;\n", argIndex);
+ break;
+ case JAVA_TYPE_ATTRIBUTION_CHAIN:
+ {
+ *requiredHelpers |= JAVA_MODULE_REQUIRES_ATTRIBUTION;
+ const char* uidName = attributionDecl.fields.front().name.c_str();
+ const char* tagName = attributionDecl.fields.back().name.c_str();
+
+ fprintf(out, " writeAttributionChain(buff, pos, %s, %s);\n",
+ uidName, tagName);
+ fprintf(out, " pos += attrSize;\n");
+ break;
+ }
+ default:
+ // Unsupported types: OBJECT, DOUBLE, KEY_VALUE_PAIR.
+ return 1;
+ }
+ argIndex++;
+ }
+
+ fprintf(out, " StatsLog.writeRaw(buff, pos);\n");
+ fprintf(out, " }\n");
+ fprintf(out, "\n");
+ }
+ return 0;
+}
+
static void write_java_work_source_method(FILE* out,
- const map<vector<java_type_t>, set<string>>& signatures_to_modules) {
+ const map<vector<java_type_t>, set<string>>& signatures_to_modules,
+ const string& moduleName) {
fprintf(out, "\n // WorkSource methods.\n");
for (auto signature_to_modules_it = signatures_to_modules.begin();
signature_to_modules_it != signatures_to_modules.end(); signature_to_modules_it++) {
+ // Skip if this signature is not needed for the module.
+ if (!signature_needed_for_module(signature_to_modules_it->second, moduleName)) {
+ continue;
+ }
vector<java_type_t> signature = signature_to_modules_it->first;
// Determine if there is Attribution in this signature.
int attributionArg = -1;
@@ -948,7 +1292,9 @@
}
// Method header (signature)
- fprintf(out, " /** @hide */\n");
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ fprintf(out, " /** @hide */\n");
+ }
fprintf(out, " public static void write(int code");
int argIndex = 1;
for (vector<java_type_t>::const_iterator arg = signature.begin();
@@ -973,7 +1319,7 @@
}
}
fprintf(out, ");\n");
- fprintf(out, " }\n"); // close flor-loop
+ fprintf(out, " }\n"); // close for-loop
// write() component.
fprintf(out, " ArrayList<WorkSource.WorkChain> workChains = ws.getWorkChains();\n");
@@ -994,6 +1340,67 @@
}
}
+static void write_java_atom_codes(FILE* out, const Atoms& atoms, const string& moduleName) {
+ fprintf(out, " // Constants for atom codes.\n");
+
+ std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
+ build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
+
+ // Print constants for the atom codes.
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ // Skip if the atom is not needed for the module.
+ if (!atom_needed_for_module(*atom, moduleName)) {
+ continue;
+ }
+ string constant = make_constant_name(atom->name);
+ fprintf(out, "\n");
+ fprintf(out, " /**\n");
+ fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
+ write_java_usage(out, "write", constant, *atom);
+ auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
+ if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
+ write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
+ }
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ fprintf(out, " * @hide\n");
+ }
+ fprintf(out, " */\n");
+ fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
+ }
+ fprintf(out, "\n");
+}
+
+static void write_java_enum_values(FILE* out, const Atoms& atoms, const string& moduleName) {
+ fprintf(out, " // Constants for enum values.\n\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ // Skip if the atom is not needed for the module.
+ if (!atom_needed_for_module(*atom, moduleName)) {
+ continue;
+ }
+ for (vector<AtomField>::const_iterator field = atom->fields.begin();
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ENUM) {
+ fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
+ field->name.c_str());
+ for (map<int, string>::const_iterator value = field->enumValues.begin();
+ value != field->enumValues.end(); value++) {
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ fprintf(out, " /** @hide */\n");
+ }
+ fprintf(out, " public static final int %s__%s__%s = %d;\n",
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(),
+ value->first);
+ }
+ fprintf(out, "\n");
+ }
+ }
+ }
+}
+
static int
write_stats_log_java(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl)
{
@@ -1012,64 +1419,87 @@
fprintf(out, " * @hide\n");
fprintf(out, " */\n");
fprintf(out, "public class StatsLogInternal {\n");
- fprintf(out, " // Constants for atom codes.\n");
+ write_java_atom_codes(out, atoms, DEFAULT_MODULE_NAME);
- std::map<int, set<AtomDecl>::const_iterator> atom_code_to_non_chained_decl_map;
- build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
-
- // Print constants for the atom codes.
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- string constant = make_constant_name(atom->name);
- fprintf(out, "\n");
- fprintf(out, " /**\n");
- fprintf(out, " * %s %s<br>\n", atom->message.c_str(), atom->name.c_str());
- write_java_usage(out, "write", constant, *atom);
- auto non_chained_decl = atom_code_to_non_chained_decl_map.find(atom->code);
- if (non_chained_decl != atom_code_to_non_chained_decl_map.end()) {
- write_java_usage(out, "write_non_chained", constant, *non_chained_decl->second);
- }
- fprintf(out, " * @hide\n");
- fprintf(out, " */\n");
- fprintf(out, " public static final int %s = %d;\n", constant.c_str(), atom->code);
- }
- fprintf(out, "\n");
-
- // Print constants for the enum values.
- fprintf(out, " // Constants for enum values.\n\n");
- for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
- atom != atoms.decls.end(); atom++) {
- for (vector<AtomField>::const_iterator field = atom->fields.begin();
- field != atom->fields.end(); field++) {
- if (field->javaType == JAVA_TYPE_ENUM) {
- fprintf(out, " // Values for %s.%s\n", atom->message.c_str(),
- field->name.c_str());
- for (map<int, string>::const_iterator value = field->enumValues.begin();
- value != field->enumValues.end(); value++) {
- fprintf(out, " /** @hide */\n");
- fprintf(out, " public static final int %s__%s__%s = %d;\n",
- make_constant_name(atom->message).c_str(),
- make_constant_name(field->name).c_str(),
- make_constant_name(value->second).c_str(),
- value->first);
- }
- fprintf(out, "\n");
- }
- }
- }
+ write_java_enum_values(out, atoms, DEFAULT_MODULE_NAME);
// Print write methods
fprintf(out, " // Write methods\n");
write_java_method(out, "write", atoms.signatures_to_modules, attributionDecl);
write_java_method(out, "write_non_chained", atoms.non_chained_signatures_to_modules,
attributionDecl);
- write_java_work_source_method(out, atoms.signatures_to_modules);
+ write_java_work_source_method(out, atoms.signatures_to_modules, DEFAULT_MODULE_NAME);
fprintf(out, "}\n");
return 0;
}
+// TODO: Merge this with write_stats_log_java so that we can get rid of StatsLogInternal JNI.
+static int
+write_stats_log_java_for_module(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const string& moduleName, const string& javaClass, const string& javaPackage)
+{
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+ fprintf(out, "package %s;\n", javaPackage.c_str());
+ fprintf(out, "\n");
+ fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
+ fprintf(out, "\n");
+ fprintf(out, "import android.util.StatsLog;\n");
+ fprintf(out, "import android.os.SystemClock;\n");
+ fprintf(out, "\n");
+ fprintf(out, "import java.util.ArrayList;\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "/**\n");
+ fprintf(out, " * Utility class for logging statistics events.\n");
+ fprintf(out, " */\n");
+ fprintf(out, "public class %s {\n", javaClass.c_str());
+
+ // TODO: ideally these match with the native values (and automatically change if they change).
+ fprintf(out, " private static final int LOGGER_ENTRY_MAX_PAYLOAD = 4068;\n");
+ fprintf(out,
+ " private static final int MAX_EVENT_PAYLOAD = LOGGER_ENTRY_MAX_PAYLOAD - 4;\n");
+ // Value types. Must match with EventLog.java and log.h.
+ fprintf(out, " private static final byte INT_TYPE = 0;\n");
+ fprintf(out, " private static final byte LONG_TYPE = 1;\n");
+ fprintf(out, " private static final byte STRING_TYPE = 2;\n");
+ fprintf(out, " private static final byte LIST_TYPE = 3;\n");
+ fprintf(out, " private static final byte FLOAT_TYPE = 4;\n");
+
+ // Size of each value type.
+ // Booleans, ints, floats, and enums take 5 bytes, 1 for the type and 4 for the value.
+ fprintf(out, " private static final int INT_TYPE_SIZE = 5;\n");
+ fprintf(out, " private static final int FLOAT_TYPE_SIZE = 5;\n");
+ // Longs take 9 bytes, 1 for the type and 8 for the value.
+ fprintf(out, " private static final int LONG_TYPE_SIZE = 9;\n");
+ // Strings take 5 metadata bytes: 1 byte is for the type, 4 are for the length.
+ fprintf(out, " private static final int STRING_TYPE_OVERHEAD = 5;\n");
+ fprintf(out, " private static final int LIST_TYPE_OVERHEAD = 2;\n");
+
+ write_java_atom_codes(out, atoms, moduleName);
+
+ write_java_enum_values(out, atoms, moduleName);
+
+ int errors = 0;
+ int requiredHelpers = 0;
+ // Print write methods
+ fprintf(out, " // Write methods\n");
+ errors += write_java_method_for_module(out, atoms.signatures_to_modules, attributionDecl,
+ moduleName, &requiredHelpers);
+ errors += write_java_non_chained_method_for_module(out, atoms.non_chained_signatures_to_modules,
+ moduleName);
+
+ fprintf(out, " // Helper methods for copying primitives\n");
+ write_java_helpers_for_module(out, attributionDecl, requiredHelpers);
+
+ fprintf(out, "}\n");
+
+ return errors;
+}
+
static const char*
jni_type_name(java_type_t type)
{
@@ -1521,7 +1951,11 @@
fprintf(stderr, " --namespace COMMA,SEP,NAMESPACE required for cpp/header with module\n");
fprintf(stderr, " comma separated namespace of the files\n");
fprintf(stderr, " --importHeader NAME required for cpp/jni to say which header to import\n");
-}
+ fprintf(stderr, " --javaPackage PACKAGE the package for the java file.\n");
+ fprintf(stderr, " required for java with module\n");
+ fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
+ fprintf(stderr, " Optional for Java with module.\n");
+ fprintf(stderr, " Default is \"StatsLogInternal\"\n");}
/**
* Do the argument parsing and execute the tasks.
@@ -1537,6 +1971,8 @@
string moduleName = DEFAULT_MODULE_NAME;
string cppNamespace = DEFAULT_CPP_NAMESPACE;
string cppHeaderImport = DEFAULT_CPP_HEADER_IMPORT;
+ string javaPackage = DEFAULT_JAVA_PACKAGE;
+ string javaClass = DEFAULT_JAVA_CLASS;
int index = 1;
while (index < argc) {
@@ -1592,6 +2028,20 @@
return 1;
}
cppHeaderImport = argv[index];
+ } else if (0 == strcmp("--javaPackage", argv[index])) {
+ index++;
+ if (index >= argc) {
+ print_usage();
+ return 1;
+ }
+ javaPackage = argv[index];
+ } else if (0 == strcmp("--javaClass", argv[index])) {
+ index++;
+ if (index >= argc) {
+ print_usage();
+ return 1;
+ }
+ javaClass = argv[index];
}
index++;
}
@@ -1661,8 +2111,18 @@
fprintf(stderr, "Unable to open file for write: %s\n", javaFilename.c_str());
return 1;
}
- errorCount = android::stats_log_api_gen::write_stats_log_java(
- out, atoms, attributionDecl);
+ // If this is for a specific module, the java package must also be provided.
+ if (moduleName != DEFAULT_MODULE_NAME && javaPackage== DEFAULT_JAVA_PACKAGE) {
+ fprintf(stderr, "Must supply --javaPackage if supplying a specific module\n");
+ return 1;
+ }
+ if (moduleName == DEFAULT_MODULE_NAME) {
+ errorCount = android::stats_log_api_gen::write_stats_log_java(
+ out, atoms, attributionDecl);
+ } else {
+ errorCount = android::stats_log_api_gen::write_stats_log_java_for_module(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage);
+ }
fclose(out);
}
@@ -1678,7 +2138,7 @@
fclose(out);
}
- return 0;
+ return errorCount;
}
}