Merge "add page fragmentation info into procstats"
diff --git a/api/current.txt b/api/current.txt
index cea404f..b5b47b0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -12290,6 +12290,7 @@
method public void parseBundleExtra(java.lang.String, android.util.AttributeSet, android.os.Bundle) throws org.xmlpull.v1.XmlPullParserException;
method public void parseBundleExtras(android.content.res.XmlResourceParser, android.os.Bundle) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public deprecated void updateConfiguration(android.content.res.Configuration, android.util.DisplayMetrics);
+ field public static final int ID_NULL = 0; // 0x0
}
public static class Resources.NotFoundException extends java.lang.RuntimeException {
@@ -24146,6 +24147,7 @@
method public int dequeueOutputBuffer(android.media.MediaCodec.BufferInfo, long);
method protected void finalize();
method public void flush();
+ method public java.lang.String getCanonicalName();
method public android.media.MediaCodecInfo getCodecInfo();
method public java.nio.ByteBuffer getInputBuffer(int);
method public deprecated java.nio.ByteBuffer[] getInputBuffers();
@@ -24272,10 +24274,15 @@
}
public final class MediaCodecInfo {
+ method public java.lang.String getCanonicalName();
method public android.media.MediaCodecInfo.CodecCapabilities getCapabilitiesForType(java.lang.String);
method public java.lang.String getName();
method public java.lang.String[] getSupportedTypes();
+ method public boolean isAlias();
method public boolean isEncoder();
+ method public boolean isHardwareAccelerated();
+ method public boolean isSoftwareOnly();
+ method public boolean isVendor();
}
public static final class MediaCodecInfo.AudioCapabilities {
@@ -24351,7 +24358,10 @@
field public static final deprecated int COLOR_QCOM_FormatYUV420SemiPlanar = 2141391872; // 0x7fa30c00
field public static final deprecated int COLOR_TI_FormatYUV420PackedSemiPlanar = 2130706688; // 0x7f000100
field public static final java.lang.String FEATURE_AdaptivePlayback = "adaptive-playback";
+ field public static final java.lang.String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+ field public static final java.lang.String FEATURE_FrameParsing = "frame-parsing";
field public static final java.lang.String FEATURE_IntraRefresh = "intra-refresh";
+ field public static final java.lang.String FEATURE_MultipleFrames = "multiple-frames";
field public static final java.lang.String FEATURE_PartialFrame = "partial-frame";
field public static final java.lang.String FEATURE_SecurePlayback = "secure-playback";
field public static final java.lang.String FEATURE_TunneledPlayback = "tunneled-playback";
@@ -24582,12 +24592,53 @@
method public android.util.Range<java.lang.Double> getSupportedFrameRatesFor(int, int);
method public android.util.Range<java.lang.Integer> getSupportedHeights();
method public android.util.Range<java.lang.Integer> getSupportedHeightsFor(int);
+ method public java.util.List<android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint> getSupportedPerformancePoints();
method public android.util.Range<java.lang.Integer> getSupportedWidths();
method public android.util.Range<java.lang.Integer> getSupportedWidthsFor(int);
method public int getWidthAlignment();
method public boolean isSizeSupported(int, int);
}
+ public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+ method public boolean covers(android.media.MediaFormat);
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_24;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_240;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_25;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_30;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_50;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_60;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_100;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_120;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_200;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_24;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_240;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_25;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_30;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_50;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint HD_60;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_24;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_25;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_30;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_48;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_50;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint SD_60;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_100;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_120;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_200;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_24;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_240;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_25;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_30;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
+ field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
+ field public final int frameRate;
+ field public final int height;
+ field public final int width;
+ }
+
public final class MediaCodecList {
ctor public MediaCodecList(int);
method public java.lang.String findDecoderForFormat(android.media.MediaFormat);
@@ -29862,7 +29913,7 @@
method public android.net.wifi.WifiInfo getConnectionInfo();
method public android.net.DhcpInfo getDhcpInfo();
method public int getMaxNumberOfNetworkSuggestionsPerApp();
- method public java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
+ method public deprecated java.util.List<android.net.wifi.hotspot2.PasspointConfiguration> getPasspointConfigurations();
method public java.util.List<android.net.wifi.ScanResult> getScanResults();
method public int getWifiState();
method public boolean is5GHzBandSupported();
@@ -29882,7 +29933,7 @@
method public deprecated boolean reconnect();
method public deprecated boolean removeNetwork(int);
method public int removeNetworkSuggestions(java.util.List<android.net.wifi.WifiNetworkSuggestion>);
- method public void removePasspointConfiguration(java.lang.String);
+ method public deprecated void removePasspointConfiguration(java.lang.String);
method public deprecated boolean saveConfiguration();
method public void setTdlsEnabled(java.net.InetAddress, boolean);
method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7ea7afb..dc5d266 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -197,6 +197,7 @@
}
public static final class R.array {
+ field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
}
@@ -4143,12 +4144,19 @@
field public static final int WPA2_PSK = 4; // 0x4
}
+ public class WifiInfo implements android.os.Parcelable {
+ method public boolean isOsuAp();
+ }
+
public class WifiManager {
method public void connect(android.net.wifi.WifiConfiguration, android.net.wifi.WifiManager.ActionListener);
method public void connect(int, android.net.wifi.WifiManager.ActionListener);
method public void disable(int, android.net.wifi.WifiManager.ActionListener);
method public void disableEphemeralNetwork(java.lang.String);
method public void forget(int, android.net.wifi.WifiManager.ActionListener);
+ method public java.util.List<android.util.Pair<android.net.wifi.WifiConfiguration, java.util.Map<java.lang.Integer, java.util.List<android.net.wifi.ScanResult>>>> getAllMatchingWifiConfigs(java.util.List<android.net.wifi.ScanResult>);
+ method public java.util.Map<android.net.wifi.hotspot2.OsuProvider, java.util.List<android.net.wifi.ScanResult>> getMatchingOsuProviders(java.util.List<android.net.wifi.ScanResult>);
+ method public java.util.Map<android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(java.util.Set<android.net.wifi.hotspot2.OsuProvider>);
method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
method public android.net.wifi.WifiConfiguration getWifiApConfiguration();
method public int getWifiApState();
@@ -4163,6 +4171,7 @@
method public void startEasyConnectAsConfiguratorInitiator(java.lang.String, int, int, android.os.Handler, android.net.wifi.EasyConnectStatusCallback);
method public void startEasyConnectAsEnrolleeInitiator(java.lang.String, android.os.Handler, android.net.wifi.EasyConnectStatusCallback);
method public boolean startScan(android.os.WorkSource);
+ method public void startSubscriptionProvisioning(android.net.wifi.hotspot2.OsuProvider, android.net.wifi.hotspot2.ProvisioningCallback, android.os.Handler);
method public void stopEasyConnectSession();
method public void unregisterNetworkRequestMatchCallback(android.net.wifi.WifiManager.NetworkRequestMatchCallback);
field public static final int CHANGE_REASON_ADDED = 0; // 0x0
@@ -4182,6 +4191,8 @@
field public static final java.lang.String EXTRA_WIFI_CONFIGURATION = "wifiConfiguration";
field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_EVENT_TYPE = "et";
field public static final java.lang.String EXTRA_WIFI_CREDENTIAL_SSID = "ssid";
+ field public static final int PASSPOINT_HOME_NETWORK = 0; // 0x0
+ field public static final int PASSPOINT_ROAMING_NETWORK = 1; // 0x1
field public static final java.lang.String WIFI_AP_STATE_CHANGED_ACTION = "android.net.wifi.WIFI_AP_STATE_CHANGED";
field public static final int WIFI_AP_STATE_DISABLED = 11; // 0xb
field public static final int WIFI_AP_STATE_DISABLING = 10; // 0xa
@@ -4358,6 +4369,59 @@
}
+package android.net.wifi.hotspot2 {
+
+ public final class OsuProvider implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.String getFriendlyName();
+ method public android.net.Uri getServerUri();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.wifi.hotspot2.OsuProvider> CREATOR;
+ }
+
+ public abstract class ProvisioningCallback {
+ ctor public ProvisioningCallback();
+ method public abstract void onProvisioningComplete();
+ method public abstract void onProvisioningFailure(int);
+ method public abstract void onProvisioningStatus(int);
+ field public static final int OSU_FAILURE_ADD_PASSPOINT_CONFIGURATION = 22; // 0x16
+ field public static final int OSU_FAILURE_AP_CONNECTION = 1; // 0x1
+ field public static final int OSU_FAILURE_INVALID_SERVER_URL = 8; // 0x8
+ field public static final int OSU_FAILURE_NO_AAA_SERVER_TRUST_ROOT_NODE = 17; // 0x11
+ field public static final int OSU_FAILURE_NO_AAA_TRUST_ROOT_CERTIFICATE = 21; // 0x15
+ field public static final int OSU_FAILURE_NO_OSU_ACTIVITY_FOUND = 14; // 0xe
+ field public static final int OSU_FAILURE_NO_POLICY_SERVER_TRUST_ROOT_NODE = 19; // 0x13
+ field public static final int OSU_FAILURE_NO_PPS_MO = 16; // 0x10
+ field public static final int OSU_FAILURE_NO_REMEDIATION_SERVER_TRUST_ROOT_NODE = 18; // 0x12
+ field public static final int OSU_FAILURE_OSU_PROVIDER_NOT_FOUND = 23; // 0x17
+ field public static final int OSU_FAILURE_PROVISIONING_ABORTED = 6; // 0x6
+ field public static final int OSU_FAILURE_PROVISIONING_NOT_AVAILABLE = 7; // 0x7
+ field public static final int OSU_FAILURE_RETRIEVE_TRUST_ROOT_CERTIFICATES = 20; // 0x14
+ field public static final int OSU_FAILURE_SERVER_CONNECTION = 3; // 0x3
+ field public static final int OSU_FAILURE_SERVER_URL_INVALID = 2; // 0x2
+ field public static final int OSU_FAILURE_SERVER_VALIDATION = 4; // 0x4
+ field public static final int OSU_FAILURE_SERVICE_PROVIDER_VERIFICATION = 5; // 0x5
+ field public static final int OSU_FAILURE_SOAP_MESSAGE_EXCHANGE = 11; // 0xb
+ field public static final int OSU_FAILURE_START_REDIRECT_LISTENER = 12; // 0xc
+ field public static final int OSU_FAILURE_TIMED_OUT_REDIRECT_LISTENER = 13; // 0xd
+ field public static final int OSU_FAILURE_UNEXPECTED_COMMAND_TYPE = 9; // 0x9
+ field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_STATUS = 15; // 0xf
+ field public static final int OSU_FAILURE_UNEXPECTED_SOAP_MESSAGE_TYPE = 10; // 0xa
+ field public static final int OSU_STATUS_AP_CONNECTED = 2; // 0x2
+ field public static final int OSU_STATUS_AP_CONNECTING = 1; // 0x1
+ field public static final int OSU_STATUS_INIT_SOAP_EXCHANGE = 6; // 0x6
+ field public static final int OSU_STATUS_REDIRECT_RESPONSE_RECEIVED = 8; // 0x8
+ field public static final int OSU_STATUS_RETRIEVING_TRUST_ROOT_CERTS = 11; // 0xb
+ field public static final int OSU_STATUS_SECOND_SOAP_EXCHANGE = 9; // 0x9
+ field public static final int OSU_STATUS_SERVER_CONNECTED = 5; // 0x5
+ field public static final int OSU_STATUS_SERVER_CONNECTING = 3; // 0x3
+ field public static final int OSU_STATUS_SERVER_VALIDATED = 4; // 0x4
+ field public static final int OSU_STATUS_THIRD_SOAP_EXCHANGE = 10; // 0xa
+ field public static final int OSU_STATUS_WAITING_FOR_REDIRECT_RESPONSE = 7; // 0x7
+ }
+
+}
+
package android.net.wifi.rtt {
public static final class RangingRequest.Builder {
@@ -5028,6 +5092,7 @@
method public static void removeOnPropertyChangedListener(android.provider.DeviceConfig.OnPropertyChangedListener);
method public static void resetToDefaults(int, java.lang.String);
method public static boolean setProperty(java.lang.String, java.lang.String, java.lang.String, boolean);
+ field public static final java.lang.String NAMESPACE_GAME_DRIVER = "game_driver";
field public static final java.lang.String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
}
@@ -7190,6 +7255,7 @@
method public int getServiceType();
method public static int getVideoStateFromCallType(int);
method public static int getVideoStateFromImsCallProfile(android.telephony.ims.ImsCallProfile);
+ method public boolean isEmergencyCallTesting();
method public boolean isVideoCall();
method public boolean isVideoPaused();
method public static int presentationToOir(int);
@@ -7198,6 +7264,7 @@
method public void setCallExtraInt(java.lang.String, int);
method public void setCallRestrictCause(int);
method public void setEmergencyCallRouting(int);
+ method public void setEmergencyCallTesting(boolean);
method public void setEmergencyServiceCategories(int);
method public void setEmergencyUrns(java.util.List<java.lang.String>);
method public void updateCallExtras(android.telephony.ims.ImsCallProfile);
diff --git a/api/test-current.txt b/api/test-current.txt
index 5fcbb5e..e0e0f35 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1118,6 +1118,24 @@
field public static final android.os.Parcelable.Creator<android.os.VibrationEffect.Waveform> CREATOR;
}
+ public class VintfObject {
+ method public static java.lang.String[] getHalNamesAndVersions();
+ method public static java.lang.String getSepolicyVersion();
+ method public static java.lang.Long getTargetFrameworkCompatibilityMatrixVersion();
+ method public static java.util.Map<java.lang.String, java.lang.String[]> getVndkSnapshots();
+ method public static java.lang.String[] report();
+ }
+
+ public class VintfRuntimeInfo {
+ method public static java.lang.String getCpuInfo();
+ method public static java.lang.String getHardwareId();
+ method public static java.lang.String getKernelVersion();
+ method public static java.lang.String getNodeName();
+ method public static java.lang.String getOsName();
+ method public static java.lang.String getOsRelease();
+ method public static java.lang.String getOsVersion();
+ }
+
public class WorkSource implements android.os.Parcelable {
ctor public WorkSource(int);
method public boolean add(int);
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index abe18ba..803f83c 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -20,6 +20,7 @@
"misc-*",
"modernize-*",
"readability-*",
+ "-modernize-avoid-c-arrays",
],
tidy_flags: [
"-system-headers",
@@ -38,6 +39,7 @@
"libidmap2/CommandLineOptions.cpp",
"libidmap2/FileUtils.cpp",
"libidmap2/Idmap.cpp",
+ "libidmap2/Policies.cpp",
"libidmap2/PrettyPrintVisitor.cpp",
"libidmap2/RawPrintVisitor.cpp",
"libidmap2/ResourceUtils.cpp",
@@ -87,6 +89,7 @@
"tests/Idmap2BinaryTests.cpp",
"tests/IdmapTests.cpp",
"tests/Main.cpp",
+ "tests/PoliciesTests.cpp",
"tests/PrettyPrintVisitorTests.cpp",
"tests/RawPrintVisitorTests.cpp",
"tests/ResourceUtilsTests.cpp",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index b075673..c455ac0 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -27,17 +27,25 @@
#include "idmap2/CommandLineOptions.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
using android::ApkAssets;
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::CommandLineOptions;
using android::idmap2::Idmap;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
using android::idmap2::utils::kIdmapFilePermissionMask;
bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
std::string target_apk_path;
std::string overlay_apk_path;
std::string idmap_path;
+ std::vector<std::string> policies;
+ bool ignore_overlayable;
const CommandLineOptions opts =
CommandLineOptions("idmap2 create")
@@ -47,12 +55,28 @@
.MandatoryOption("--overlay-apk-path",
"input: path to apk which contains the new resource values",
&overlay_apk_path)
- .MandatoryOption("--idmap-path", "output: path to where to write idmap file",
- &idmap_path);
+ .MandatoryOption("--idmap-path", "output: path to where to write idmap file", &idmap_path)
+ .OptionalOption("--policy",
+ "input: an overlayable policy this overlay fulfills "
+ "(if none or supplied, the overlay policy will default to \"public\")",
+ &policies)
+ .OptionalFlag("--ignore-overlayable", "disables overlayable and policy checks",
+ &ignore_overlayable);
if (!opts.Parse(args, out_error)) {
return false;
}
+ PolicyBitmask fulfilled_policies = 0;
+ if (auto result = PoliciesToBitmask(policies, out_error)) {
+ fulfilled_policies |= *result;
+ } else {
+ return false;
+ }
+
+ if (fulfilled_policies == 0) {
+ fulfilled_policies |= PolicyFlags::POLICY_PUBLIC;
+ }
+
const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
if (!target_apk) {
out_error << "error: failed to load apk " << target_apk_path << std::endl;
@@ -66,7 +90,8 @@
}
const std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, out_error);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ fulfilled_policies, !ignore_overlayable, out_error);
if (!idmap) {
return false;
}
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index 4f88127..a269ee9 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -21,8 +21,11 @@
#include <set>
#include <sstream>
#include <string>
+#include <utility>
#include <vector>
+#include "android-base/properties.h"
+
#include "idmap2/CommandLineOptions.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
@@ -34,6 +37,10 @@
using android::idmap2::CommandLineOptions;
using android::idmap2::Idmap;
using android::idmap2::MemoryChunk;
+using android::idmap2::PoliciesToBitmask;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+using android::idmap2::Result;
using android::idmap2::Xml;
using android::idmap2::ZipFile;
using android::idmap2::utils::FindFiles;
@@ -45,11 +52,19 @@
return priority < rhs.priority || (priority == rhs.priority && apk_path < rhs.apk_path);
}
- std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes)
- std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes)
- int priority; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string apk_path; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::string idmap_path; // NOLINT(misc-non-private-member-variables-in-classes)
+ int priority; // NOLINT(misc-non-private-member-variables-in-classes)
+ std::vector<std::string> policies; // NOLINT(misc-non-private-member-variables-in-classes)
+ bool ignore_overlayable; // NOLINT(misc-non-private-member-variables-in-classes)
};
+bool VendorIsQOrLater() {
+ // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+ std::string version = android::base::GetProperty("ro.vndk.version", "Q");
+ return version == "Q" || version == "q";
+}
+
std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
bool recursive, std::ostream& out_error) {
const auto predicate = [](unsigned char type, const std::string& path) -> bool {
@@ -70,6 +85,22 @@
return std::make_unique<std::vector<std::string>>(paths.cbegin(), paths.cend());
}
+PolicyBitmask PolicyForPath(const std::string& apk_path) {
+ static const std::vector<std::pair<std::string, PolicyBitmask>> values = {
+ {"/product/", PolicyFlags::POLICY_PRODUCT_PARTITION},
+ {"/system/", PolicyFlags::POLICY_SYSTEM_PARTITION},
+ {"/vendor/", PolicyFlags::POLICY_VENDOR_PARTITION},
+ };
+
+ for (auto const& pair : values) {
+ if (apk_path.compare(0, pair.first.size(), pair.first) == 0) {
+ return pair.second | PolicyFlags::POLICY_PUBLIC;
+ }
+ }
+
+ return PolicyFlags::POLICY_PUBLIC;
+}
+
} // namespace
bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
@@ -77,6 +108,7 @@
std::string target_package_name;
std::string target_apk_path;
std::string output_directory;
+ std::vector<std::string> override_policies;
bool recursive = false;
const CommandLineOptions opts =
@@ -89,7 +121,12 @@
.MandatoryOption("--target-apk-path", "path to target apk", &target_apk_path)
.MandatoryOption("--output-directory",
"directory in which to write artifacts (idmap files and overlays.list)",
- &output_directory);
+ &output_directory)
+ .OptionalOption(
+ "--override-policy",
+ "input: an overlayable policy this overlay fulfills "
+ "(if none or supplied, the overlays will not have their policies overriden",
+ &override_policies);
if (!opts.Parse(args, out_error)) {
return false;
}
@@ -144,29 +181,63 @@
continue;
}
- // Sort the static overlays in ascending priority order
+ PolicyBitmask fulfilled_policies;
+ if (!override_policies.empty()) {
+ if (Result<PolicyBitmask> result = PoliciesToBitmask(override_policies, out_error)) {
+ fulfilled_policies = *result;
+ } else {
+ return false;
+ }
+ } else {
+ fulfilled_policies = PolicyForPath(path);
+ }
+
+ bool ignore_overlayable = false;
+ if ((fulfilled_policies & PolicyFlags::POLICY_VENDOR_PARTITION) != 0 && !VendorIsQOrLater()) {
+ // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+ // restrictions on this overlay because the pre-Q platform has no understanding of
+ // overlayable.
+ ignore_overlayable = true;
+ }
+
std::string idmap_path = Idmap::CanonicalIdmapPathFor(output_directory, path);
- InputOverlay input{path, idmap_path, priority};
+
+ // Sort the static overlays in ascending priority order
+ InputOverlay input{path, idmap_path, priority, override_policies, ignore_overlayable};
interesting_apks.insert(
std::lower_bound(interesting_apks.begin(), interesting_apks.end(), input), input);
}
std::stringstream stream;
for (const auto& overlay : interesting_apks) {
+ // Create the idmap for the overlay if it currently does not exist or if it is not up to date.
std::stringstream dev_null;
- if (!Verify(std::vector<std::string>({"--idmap-path", overlay.idmap_path}), dev_null) &&
- !Create(std::vector<std::string>({
- "--target-apk-path",
- target_apk_path,
- "--overlay-apk-path",
- overlay.apk_path,
- "--idmap-path",
- overlay.idmap_path,
- }),
- out_error)) {
- return false;
+
+ std::vector<std::string> verify_args = {"--idmap-path", overlay.idmap_path};
+ for (const std::string& policy : overlay.policies) {
+ verify_args.emplace_back("--policy");
+ verify_args.emplace_back(policy);
}
- stream << overlay.idmap_path << std::endl;
+
+ if (!Verify(std::vector<std::string>(verify_args), dev_null)) {
+ std::vector<std::string> create_args = {"--target-apk-path", target_apk_path,
+ "--overlay-apk-path", overlay.apk_path,
+ "--idmap-path", overlay.idmap_path};
+ if (overlay.ignore_overlayable) {
+ create_args.emplace_back("--ignore-overlayable");
+ }
+
+ for (const std::string& policy : overlay.policies) {
+ verify_args.emplace_back("--policy");
+ verify_args.emplace_back(policy);
+ }
+
+ if (!Create(create_args, out_error)) {
+ return false;
+ }
+ }
+
+ stream << overlay.idmap_path << std::endl;
}
std::cout << stream.str();
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index d2e46e1..a3c7527 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -26,12 +26,15 @@
#include <string>
#include "android-base/macros.h"
+#include "android-base/stringprintf.h"
#include "utils/String8.h"
#include "utils/Trace.h"
#include "idmap2/BinaryStreamVisitor.h"
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
#include "idmap2d/Idmap2Service.h"
@@ -39,6 +42,8 @@
using android::idmap2::BinaryStreamVisitor;
using android::idmap2::Idmap;
using android::idmap2::IdmapHeader;
+using android::idmap2::PolicyBitmask;
+using android::idmap2::Result;
using android::idmap2::utils::kIdmapFilePermissionMask;
namespace {
@@ -54,6 +59,10 @@
return Status::fromExceptionCode(Status::EX_NONE, msg.c_str());
}
+PolicyBitmask ConvertAidlArgToPolicyBitmask(int32_t arg) {
+ return static_cast<PolicyBitmask>(arg);
+}
+
} // namespace
namespace android::os {
@@ -78,6 +87,8 @@
}
Status Idmap2Service::verifyIdmap(const std::string& overlay_apk_path,
+ int32_t fulfilled_policies ATTRIBUTE_UNUSED,
+ bool enforce_overlayable ATTRIBUTE_UNUSED,
int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
assert(_aidl_return);
const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
@@ -86,11 +97,15 @@
fin.close();
std::stringstream dev_null;
*_aidl_return = header && header->IsUpToDate(dev_null);
+
+ // TODO(b/119328308): Check that the set of fulfilled policies of the overlay has not changed
+
return ok();
}
Status Idmap2Service::createIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path, int32_t user_id,
+ const std::string& overlay_apk_path, int32_t fulfilled_policies,
+ bool enforce_overlayable, int32_t user_id,
std::unique_ptr<std::string>* _aidl_return) {
assert(_aidl_return);
std::stringstream trace;
@@ -101,6 +116,8 @@
_aidl_return->reset(nullptr);
+ const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
+
const std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
if (!target_apk) {
return error("failed to load apk " + target_apk_path);
@@ -113,7 +130,8 @@
std::stringstream err;
const std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, err);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ policy_bitmask, enforce_overlayable, err);
if (!idmap) {
return error(err.str());
}
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.h b/cmds/idmap2/idmap2d/Idmap2Service.h
index e0bc22e..1aab059 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.h
+++ b/cmds/idmap2/idmap2d/Idmap2Service.h
@@ -39,11 +39,12 @@
binder::Status removeIdmap(const std::string& overlay_apk_path, int32_t user_id,
bool* _aidl_return);
- binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t user_id,
- bool* _aidl_return);
+ binder::Status verifyIdmap(const std::string& overlay_apk_path, int32_t fulfilled_policies,
+ bool enforce_overlayable, int32_t user_id, bool* _aidl_return);
binder::Status createIdmap(const std::string& target_apk_path,
- const std::string& overlay_apk_path, int32_t user_id,
+ const std::string& overlay_apk_path, int32_t fulfilled_policies,
+ bool enforce_overlayable, int32_t user_id,
std::unique_ptr<std::string>* _aidl_return);
};
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
index d475417..ea7274f 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/IIdmap2.aidl
@@ -20,9 +20,18 @@
* @hide
*/
interface IIdmap2 {
+ const int POLICY_PUBLIC = 0x00000001;
+ const int POLICY_SYSTEM_PARTITION = 0x00000002;
+ const int POLICY_VENDOR_PARTITION = 0x00000004;
+ const int POLICY_PRODUCT_PARTITION = 0x00000008;
+
@utf8InCpp String getIdmapPath(@utf8InCpp String overlayApkPath, int userId);
boolean removeIdmap(@utf8InCpp String overlayApkPath, int userId);
- boolean verifyIdmap(@utf8InCpp String overlayApkPath, int userId);
+ boolean verifyIdmap(@utf8InCpp String overlayApkPath, int fulfilledPolicies,
+ boolean enforceOverlayable, int userId);
@nullable @utf8InCpp String createIdmap(@utf8InCpp String targetApkPath,
- @utf8InCpp String overlayApkPath, int userId);
+ @utf8InCpp String overlayApkPath,
+ int fulfilledPolicies,
+ boolean enforceOverlayable,
+ int userId);
}
diff --git a/cmds/idmap2/include/idmap2/CommandLineOptions.h b/cmds/idmap2/include/idmap2/CommandLineOptions.h
index b93e716..6db6bf9 100644
--- a/cmds/idmap2/include/idmap2/CommandLineOptions.h
+++ b/cmds/idmap2/include/idmap2/CommandLineOptions.h
@@ -44,6 +44,8 @@
std::vector<std::string>* value);
CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
std::string* value);
+ CommandLineOptions& OptionalOption(const std::string& name, const std::string& description,
+ std::vector<std::string>* value);
bool Parse(const std::vector<std::string>& argv, std::ostream& outError) const;
void Usage(std::ostream& out) const;
@@ -56,6 +58,7 @@
COUNT_OPTIONAL,
COUNT_EXACTLY_ONCE,
COUNT_ONCE_OR_MORE,
+ COUNT_OPTIONAL_ONCE_OR_MORE,
} count;
bool argument;
};
diff --git a/cmds/idmap2/include/idmap2/Idmap.h b/cmds/idmap2/include/idmap2/Idmap.h
index b989e4c..1666dc8 100644
--- a/cmds/idmap2/include/idmap2/Idmap.h
+++ b/cmds/idmap2/include/idmap2/Idmap.h
@@ -57,6 +57,8 @@
#include "androidfw/ResourceTypes.h"
#include "androidfw/StringPiece.h"
+#include "idmap2/Policies.h"
+
namespace android::idmap2 {
class Idmap;
@@ -233,11 +235,10 @@
// file is used; change this in the next version of idmap to use a named
// package instead; also update FromApkAssets to take additional parameters:
// the target and overlay package names
- static std::unique_ptr<const Idmap> FromApkAssets(const std::string& target_apk_path,
- const ApkAssets& target_apk_assets,
- const std::string& overlay_apk_path,
- const ApkAssets& overlay_apk_assets,
- std::ostream& out_error);
+ static std::unique_ptr<const Idmap> FromApkAssets(
+ const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+ const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+ const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error);
inline const std::unique_ptr<const IdmapHeader>& GetHeader() const {
return header_;
diff --git a/cmds/idmap2/include/idmap2/Policies.h b/cmds/idmap2/include/idmap2/Policies.h
new file mode 100644
index 0000000..eecee25
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/Policies.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <ostream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/StringPiece.h"
+
+#include "Result.h"
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+#define IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
+
+namespace android::idmap2 {
+
+using PolicyFlags = ResTable_overlayable_policy_header::PolicyFlags;
+using PolicyBitmask = uint32_t;
+
+// Parses a the string representation of a set of policies into a bitmask. The format of the string
+// is the same as for the <policy> element.
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+ std::ostream& err);
+
+} // namespace android::idmap2
+
+#endif // IDMAP2_INCLUDE_IDMAP2_POLICIES_H_
diff --git a/cmds/idmap2/libidmap2/CommandLineOptions.cpp b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
index cabc8f3..a49a607 100644
--- a/cmds/idmap2/libidmap2/CommandLineOptions.cpp
+++ b/cmds/idmap2/libidmap2/CommandLineOptions.cpp
@@ -68,9 +68,18 @@
return *this;
}
+CommandLineOptions& CommandLineOptions::OptionalOption(const std::string& name,
+ const std::string& description,
+ std::vector<std::string>* value) {
+ assert(value != nullptr);
+ auto func = [value](const std::string& arg) -> void { value->push_back(arg); };
+ options_.push_back(Option{name, description, func, Option::COUNT_OPTIONAL_ONCE_OR_MORE, true});
+ return *this;
+}
+
bool CommandLineOptions::Parse(const std::vector<std::string>& argv, std::ostream& outError) const {
const auto pivot = std::partition(options_.begin(), options_.end(), [](const Option& opt) {
- return opt.count != Option::COUNT_OPTIONAL;
+ return opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
});
std::set<std::string> mandatory_opts;
std::transform(options_.begin(), pivot, std::inserter(mandatory_opts, mandatory_opts.end()),
@@ -122,7 +131,8 @@
size_t maxLength = 0;
out << "usage: " << name_;
for (const Option& opt : options_) {
- const bool mandatory = opt.count != Option::COUNT_OPTIONAL;
+ const bool mandatory =
+ opt.count != Option::COUNT_OPTIONAL && opt.count != Option::COUNT_OPTIONAL_ONCE_OR_MORE;
out << " ";
if (!mandatory) {
out << "[";
@@ -134,9 +144,15 @@
out << opt.name;
maxLength = std::max(maxLength, opt.name.size());
}
+
+ if (opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
+ out << " [..]";
+ }
+
if (!mandatory) {
out << "]";
}
+
if (opt.count == Option::COUNT_ONCE_OR_MORE) {
out << " [" << opt.name << " arg [..]]";
}
@@ -150,7 +166,8 @@
out << opt.name;
}
out << " " << opt.description;
- if (opt.count == Option::COUNT_ONCE_OR_MORE) {
+ if (opt.count == Option::COUNT_ONCE_OR_MORE ||
+ opt.count == Option::COUNT_OPTIONAL_ONCE_OR_MORE) {
out << " (can be provided multiple times)";
}
out << std::endl;
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index 37d6af8..2890ae1 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -274,11 +274,23 @@
return std::move(idmap);
}
-std::unique_ptr<const Idmap> Idmap::FromApkAssets(const std::string& target_apk_path,
- const ApkAssets& target_apk_assets,
- const std::string& overlay_apk_path,
- const ApkAssets& overlay_apk_assets,
- std::ostream& out_error) {
+bool CheckOverlayable(const LoadedPackage& target_package, PolicyBitmask fulfilled_polices,
+ ResourceId resid) {
+ const OverlayableInfo* info = target_package.GetOverlayableInfo(resid);
+ if (info == nullptr) {
+ // If the resource does not have an overlayable definition, allow the resource to be overlaid.
+ // Once overlayable enforcement is turned on, this check will return false.
+ return true;
+ }
+
+ // Enforce policy restrictions if the resource is declared as overlayable.
+ return (info->policy_flags & fulfilled_polices) != 0;
+}
+
+std::unique_ptr<const Idmap> Idmap::FromApkAssets(
+ const std::string& target_apk_path, const ApkAssets& target_apk_assets,
+ const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
+ const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
AssetManager2 target_asset_manager;
if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
out_error << "error: failed to create target asset manager" << std::endl;
@@ -380,6 +392,15 @@
if (target_resid == 0) {
continue;
}
+
+ if (enforce_overlayable && !CheckOverlayable(*target_pkg, fulfilled_policies, target_resid)) {
+ // The resources must be defined as overlayable and the overlay must fulfill at least one
+ // policy enforced on the overlayable resource
+ LOG(WARNING) << "overlay \"" << overlay_apk_path << "\" is not allowed to overlay resource \""
+ << full_name << "\"" << std::endl;
+ continue;
+ }
+
matching_resources.Add(target_resid, overlay_resid);
}
diff --git a/cmds/idmap2/libidmap2/Policies.cpp b/cmds/idmap2/libidmap2/Policies.cpp
new file mode 100644
index 0000000..0f87ef0
--- /dev/null
+++ b/cmds/idmap2/libidmap2/Policies.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+#include <iterator>
+#include <map>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "androidfw/ResourceTypes.h"
+
+#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+namespace {
+
+const std::map<android::StringPiece, PolicyFlags> kStringToFlag = {
+ {"public", PolicyFlags::POLICY_PUBLIC},
+ {"product", PolicyFlags::POLICY_PRODUCT_PARTITION},
+ {"system", PolicyFlags::POLICY_SYSTEM_PARTITION},
+ {"vendor", PolicyFlags::POLICY_VENDOR_PARTITION},
+};
+} // namespace
+
+Result<PolicyBitmask> PoliciesToBitmask(const std::vector<std::string>& policies,
+ std::ostream& err) {
+ PolicyBitmask bitmask = 0;
+ for (const std::string& policy : policies) {
+ const auto iter = kStringToFlag.find(policy);
+ if (iter != kStringToFlag.end()) {
+ bitmask |= iter->second;
+ } else {
+ err << "error: unknown policy \"" << policy << "\"";
+ return kResultError;
+ }
+ }
+
+ return Result<PolicyBitmask>(bitmask);
+}
+
+} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
index 2698ac0..35ec1ff 100644
--- a/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
+++ b/cmds/idmap2/tests/BinaryStreamVisitorTests.cpp
@@ -78,7 +78,8 @@
std::stringstream error;
std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
ASSERT_THAT(idmap, NotNull());
std::stringstream stream;
@@ -101,25 +102,52 @@
header = loaded_idmap->GetEntryMapForType(0x02);
ASSERT_THAT(header, NotNull());
- success = LoadedIdmap::Lookup(header, 0x0002, &entry);
+ success = LoadedIdmap::Lookup(header, 0x0000, &entry); // string/a
ASSERT_FALSE(success);
- success = LoadedIdmap::Lookup(header, 0x0003, &entry);
+ success = LoadedIdmap::Lookup(header, 0x0001, &entry); // string/b
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0002, &entry); // string/c
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0003, &entry); // string/not_overlayable
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0004, &entry); // string/policy_product
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0005, &entry); // string/policy_public
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0006, &entry); // string/policy_system
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0007, &entry); // string/policy_system_vendor
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x0008, &entry); // string/str1
ASSERT_TRUE(success);
ASSERT_EQ(entry, 0x0000);
- success = LoadedIdmap::Lookup(header, 0x0004, &entry);
+ success = LoadedIdmap::Lookup(header, 0x0009, &entry); // string/str2
ASSERT_FALSE(success);
- success = LoadedIdmap::Lookup(header, 0x0005, &entry);
+ success = LoadedIdmap::Lookup(header, 0x000a, &entry); // string/str3
ASSERT_TRUE(success);
ASSERT_EQ(entry, 0x0001);
- success = LoadedIdmap::Lookup(header, 0x0006, &entry);
+ success = LoadedIdmap::Lookup(header, 0x000b, &entry); // string/str4
ASSERT_TRUE(success);
ASSERT_EQ(entry, 0x0002);
- success = LoadedIdmap::Lookup(header, 0x0007, &entry);
+ success = LoadedIdmap::Lookup(header, 0x000c, &entry); // string/x
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x000d, &entry); // string/y
+ ASSERT_FALSE(success);
+
+ success = LoadedIdmap::Lookup(header, 0x000e, &entry); // string/z
ASSERT_FALSE(success);
}
diff --git a/cmds/idmap2/tests/CommandLineOptionsTests.cpp b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
index c27d27a..39f18d3 100644
--- a/cmds/idmap2/tests/CommandLineOptionsTests.cpp
+++ b/cmds/idmap2/tests/CommandLineOptionsTests.cpp
@@ -121,6 +121,56 @@
ASSERT_FALSE(success);
}
+TEST(CommandLineOptionsTests, OptionalOptionList) {
+ std::vector<std::string> foo;
+ std::vector<std::string> bar;
+ CommandLineOptions opts = CommandLineOptions("test")
+ .OptionalOption("--foo", "", &foo)
+ .OptionalOption("--bar", "", &bar);
+ std::ostream fakeStdErr(nullptr);
+ bool success = opts.Parse({"--foo", "FOO", "--bar", "BAR"}, fakeStdErr);
+ ASSERT_TRUE(success);
+ ASSERT_EQ(foo.size(), 1U);
+ ASSERT_EQ(foo[0], "FOO");
+ ASSERT_EQ(bar.size(), 1U);
+ ASSERT_EQ(bar[0], "BAR");
+
+ foo.clear();
+ bar.clear();
+ success = opts.Parse({"--foo", "BAZ"}, fakeStdErr);
+ ASSERT_TRUE(success);
+ ASSERT_EQ(foo.size(), 1U);
+ ASSERT_EQ(foo[0], "BAZ");
+ ASSERT_EQ(bar.size(), 0U);
+
+ foo.clear();
+ bar.clear();
+ success =
+ opts.Parse({"--foo", "BAZ", "--foo", "BIZ", "--bar", "FIZ", "--bar", "FUZZ"}, fakeStdErr);
+ ASSERT_TRUE(success);
+ ASSERT_EQ(foo.size(), 2U);
+ ASSERT_EQ(foo[0], "BAZ");
+ ASSERT_EQ(foo[1], "BIZ");
+ ASSERT_EQ(bar.size(), 2U);
+ ASSERT_EQ(bar[0], "FIZ");
+ ASSERT_EQ(bar[1], "FUZZ");
+
+ foo.clear();
+ bar.clear();
+ success = opts.Parse({"--foo"}, fakeStdErr);
+ ASSERT_FALSE(success);
+
+ foo.clear();
+ bar.clear();
+ success = opts.Parse({"--foo", "--bar", "BAR"}, fakeStdErr);
+ ASSERT_FALSE(success);
+
+ foo.clear();
+ bar.clear();
+ success = opts.Parse({"--foo", "FOO", "--bar"}, fakeStdErr);
+ ASSERT_FALSE(success);
+}
+
TEST(CommandLineOptionsTests, CornerCases) {
std::string foo;
std::string bar;
@@ -172,6 +222,7 @@
bool arg5 = false;
bool arg6 = false;
std::vector<std::string> arg7;
+ std::vector<std::string> arg8;
CommandLineOptions opts = CommandLineOptions("test")
.MandatoryOption("--aa", "description-aa", &arg1)
.OptionalFlag("--bb", "description-bb", &arg5)
@@ -179,12 +230,13 @@
.OptionalOption("--dd", "description-dd", &arg3)
.MandatoryOption("--ee", "description-ee", &arg4)
.OptionalFlag("--ff", "description-ff", &arg6)
- .MandatoryOption("--gg", "description-gg", &arg7);
+ .MandatoryOption("--gg", "description-gg", &arg7)
+ .OptionalOption("--hh", "description-hh", &arg8);
std::stringstream stream;
opts.Usage(stream);
const std::string s = stream.str();
ASSERT_NE(s.find("usage: test --aa arg [--bb] [--cc arg] [--dd arg] --ee arg [--ff] --gg arg "
- "[--gg arg [..]]"),
+ "[--gg arg [..]] [--hh arg [..]]"),
std::string::npos);
ASSERT_NE(s.find("--aa arg description-aa"), std::string::npos);
ASSERT_NE(s.find("--ff description-ff"), std::string::npos);
diff --git a/cmds/idmap2/tests/FileUtilsTests.cpp b/cmds/idmap2/tests/FileUtilsTests.cpp
index 4bf832a..d9d9a7f 100644
--- a/cmds/idmap2/tests/FileUtilsTests.cpp
+++ b/cmds/idmap2/tests/FileUtilsTests.cpp
@@ -37,10 +37,10 @@
[](unsigned char type ATTRIBUTE_UNUSED,
const std::string& path ATTRIBUTE_UNUSED) -> bool { return true; });
ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 4U);
- ASSERT_EQ(
- std::set<std::string>(v->begin(), v->end()),
- std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target"}));
+ ASSERT_EQ(v->size(), 6U);
+ ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
+ std::set<std::string>({root + "/.", root + "/..", root + "/overlay", root + "/target",
+ root + "/system-overlay", root + "/system-overlay-invalid"}));
}
TEST(FileUtilsTests, FindFilesFindApkFilesRecursive) {
@@ -49,11 +49,13 @@
return type == DT_REG && path.size() > 4 && path.compare(path.size() - 4, 4, ".apk") == 0;
});
ASSERT_THAT(v, NotNull());
- ASSERT_EQ(v->size(), 4U);
+ ASSERT_EQ(v->size(), 6U);
ASSERT_EQ(std::set<std::string>(v->begin(), v->end()),
std::set<std::string>({root + "/target/target.apk", root + "/overlay/overlay.apk",
root + "/overlay/overlay-static-1.apk",
- root + "/overlay/overlay-static-2.apk"}));
+ root + "/overlay/overlay-static-2.apk",
+ root + "/system-overlay/system-overlay.apk",
+ root + "/system-overlay-invalid/system-overlay-invalid.apk"}));
}
TEST(FileUtilsTests, ReadFile) {
diff --git a/cmds/idmap2/tests/Idmap2BinaryTests.cpp b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
index 22f48e9..0c8f164 100644
--- a/cmds/idmap2/tests/Idmap2BinaryTests.cpp
+++ b/cmds/idmap2/tests/Idmap2BinaryTests.cpp
@@ -38,6 +38,7 @@
#include "gtest/gtest.h"
#include "androidfw/PosixUtils.h"
+
#include "idmap2/FileUtils.h"
#include "idmap2/Idmap.h"
@@ -114,8 +115,9 @@
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
ASSERT_NE(result->stdout.find("0x7f010000 -> 0x7f010000 integer/int1"), std::string::npos);
- ASSERT_NE(result->stdout.find("0x7f020003 -> 0x7f020000 string/str1"), std::string::npos);
- ASSERT_NE(result->stdout.find("0x7f020005 -> 0x7f020001 string/str3"), std::string::npos);
+ ASSERT_NE(result->stdout.find("0x7f020008 -> 0x7f020000 string/str1"), std::string::npos);
+ ASSERT_NE(result->stdout.find("0x7f02000a -> 0x7f020001 string/str3"), std::string::npos);
+ ASSERT_NE(result->stdout.find("0x7f02000b -> 0x7f020002 string/str4"), std::string::npos);
ASSERT_EQ(result->stdout.find("00000210: 007f target package id"), std::string::npos);
// clang-format off
@@ -157,7 +159,8 @@
"--recursive",
"--target-package-name", "test.target",
"--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath()});
+ "--output-directory", GetTempDirPath(),
+ "--override-policy", "public"});
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -190,7 +193,8 @@
"--input-directory", GetTestDataPath() + "/overlay",
"--target-package-name", "test.target",
"--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath()});
+ "--output-directory", GetTempDirPath(),
+ "--override-policy", "public"});
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -207,7 +211,8 @@
"--recursive",
"--target-package-name", "test.target",
"--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath()});
+ "--output-directory", GetTempDirPath(),
+ "--override-policy", "public"});
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -222,7 +227,8 @@
"--input-directory", GetTempDirPath(),
"--target-package-name", "test.target",
"--target-apk-path", GetTargetApkPath(),
- "--output-directory", GetTempDirPath()});
+ "--output-directory", GetTempDirPath(),
+ "--override-policy", "public"});
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -245,7 +251,7 @@
"lookup",
"--idmap-path", GetIdmapPath(),
"--config", "",
- "--resid", "0x7f020003"}); // string/str1
+ "--resid", "0x7f020008"}); // string/str1
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_EQ(result->status, EXIT_SUCCESS) << result->stderr;
@@ -310,6 +316,18 @@
// clang-format on
ASSERT_THAT(result, NotNull());
ASSERT_NE(result->status, EXIT_SUCCESS);
+
+ // unknown policy
+ // clang-format off
+ result = ExecuteBinary({"idmap2",
+ "create",
+ "--target-apk-path", GetTargetApkPath(),
+ "--overlay-apk-path", GetOverlayApkPath(),
+ "--idmap-path", GetIdmapPath(),
+ "--policy", "this-does-not-exist"});
+ // clang-format on
+ ASSERT_THAT(result, NotNull());
+ ASSERT_NE(result->status, EXIT_SUCCESS);
}
} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 963f22e..c6eb71c 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -184,13 +184,14 @@
std::stringstream error;
std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
ASSERT_THAT(idmap, NotNull());
ASSERT_THAT(idmap->GetHeader(), NotNull());
ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
- ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xf5ad1d1d);
+ ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xca2093da);
ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b);
ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
@@ -216,13 +217,127 @@
ASSERT_EQ(types[1]->GetTargetTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetOverlayTypeId(), 0x02U);
ASSERT_EQ(types[1]->GetEntryCount(), 4U);
- ASSERT_EQ(types[1]->GetEntryOffset(), 3U);
+ ASSERT_EQ(types[1]->GetEntryOffset(), 8U);
ASSERT_EQ(types[1]->GetEntry(0), 0x0000U);
ASSERT_EQ(types[1]->GetEntry(1), kNoEntry);
ASSERT_EQ(types[1]->GetEntry(2), 0x0001U);
ASSERT_EQ(types[1]->GetEntry(3), 0x0002U);
}
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublic) {
+ const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ ASSERT_THAT(target_apk, NotNull());
+
+ const std::string overlay_apk_path(GetTestDataPath() + "/system-overlay/system-overlay.apk");
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ ASSERT_THAT(overlay_apk, NotNull());
+
+ std::stringstream error;
+ std::unique_ptr<const Idmap> idmap =
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, error);
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+ ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+ ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+ const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+ ASSERT_EQ(types.size(), 1U);
+
+ ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+ ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 3U);
+ ASSERT_EQ(types[0]->GetEntryOffset(), 5U);
+ ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/policy_public
+ ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalid) {
+ const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ ASSERT_THAT(target_apk, NotNull());
+
+ const std::string overlay_apk_path(GetTestDataPath() +
+ "/system-overlay-invalid/system-overlay-invalid.apk");
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ ASSERT_THAT(overlay_apk, NotNull());
+
+ std::stringstream error;
+ std::unique_ptr<const Idmap> idmap =
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, error);
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+ ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+ ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+ const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+ ASSERT_EQ(types.size(), 1U);
+
+ ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+ ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 5U);
+ ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+ ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
+ ASSERT_EQ(types[0]->GetEntry(1), kNoEntry); // string/policy_product
+ ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_public
+ ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system_vendor
+}
+
+TEST(IdmapTests, CreateIdmapFromApkAssetsPolicySystemPublicInvalidIgnoreOverlayable) {
+ const std::string target_apk_path(GetTestDataPath() + "/target/target.apk");
+ std::unique_ptr<const ApkAssets> target_apk = ApkAssets::Load(target_apk_path);
+ ASSERT_THAT(target_apk, NotNull());
+
+ const std::string overlay_apk_path(GetTestDataPath() +
+ "/system-overlay-invalid/system-overlay-invalid.apk");
+ std::unique_ptr<const ApkAssets> overlay_apk = ApkAssets::Load(overlay_apk_path);
+ ASSERT_THAT(overlay_apk, NotNull());
+
+ std::stringstream error;
+ std::unique_ptr<const Idmap> idmap =
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ false, error);
+ ASSERT_THAT(idmap, NotNull());
+
+ const std::vector<std::unique_ptr<const IdmapData>>& dataBlocks = idmap->GetData();
+ ASSERT_EQ(dataBlocks.size(), 1U);
+
+ const std::unique_ptr<const IdmapData>& data = dataBlocks[0];
+
+ ASSERT_EQ(data->GetHeader()->GetTargetPackageId(), 0x7fU);
+ ASSERT_EQ(data->GetHeader()->GetTypeCount(), 1U);
+
+ const std::vector<std::unique_ptr<const IdmapData::TypeEntry>>& types = data->GetTypeEntries();
+ ASSERT_EQ(types.size(), 1U);
+
+ ASSERT_EQ(types[0]->GetTargetTypeId(), 0x02U);
+ ASSERT_EQ(types[0]->GetOverlayTypeId(), 0x01U);
+ ASSERT_EQ(types[0]->GetEntryCount(), 5U);
+ ASSERT_EQ(types[0]->GetEntryOffset(), 3U);
+ ASSERT_EQ(types[0]->GetEntry(0), 0x0000U); // string/not_overlayable
+ ASSERT_EQ(types[0]->GetEntry(1), 0x0001U); // string/policy_product
+ ASSERT_EQ(types[0]->GetEntry(2), 0x0002U); // string/policy_public
+ ASSERT_EQ(types[0]->GetEntry(3), 0x0003U); // string/policy_system
+ ASSERT_EQ(types[0]->GetEntry(4), 0x0004U); // string/policy_system_vendor
+}
+
TEST(IdmapTests, FailToCreateIdmapFromApkAssetsIfPathTooLong) {
std::string target_apk_path(GetTestDataPath());
for (int i = 0; i < 32; i++) {
@@ -239,7 +354,8 @@
std::stringstream error;
std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
ASSERT_THAT(idmap, IsNull());
}
@@ -255,8 +371,9 @@
ASSERT_THAT(overlay_apk, NotNull());
std::stringstream error;
- std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+ std::unique_ptr<const Idmap> idmap = Idmap::FromApkAssets(
+ target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, PolicyFlags::POLICY_PUBLIC,
+ /* enforce_overlayable */ true, error);
ASSERT_THAT(idmap, NotNull());
std::stringstream stream;
diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp
new file mode 100644
index 0000000..ab567ad
--- /dev/null
+++ b/cmds/idmap2/tests/PoliciesTests.cpp
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#include <string>
+
+#include "gtest/gtest.h"
+
+#include "TestHelpers.h"
+#include "idmap2/Policies.h"
+
+using android::idmap2::PolicyBitmask;
+using android::idmap2::PolicyFlags;
+
+namespace android::idmap2 {
+
+TEST(PoliciesTests, PoliciesToBitmasks) {
+ const Result<PolicyBitmask> bitmask1 = PoliciesToBitmask({"system"}, std::cerr);
+ ASSERT_NE(bitmask1, kResultError);
+ ASSERT_EQ(bitmask1, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+ const Result<PolicyBitmask> bitmask2 = PoliciesToBitmask({"system", "vendor"}, std::cerr);
+ ASSERT_NE(bitmask2, kResultError);
+ ASSERT_EQ(bitmask2, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+ const Result<PolicyBitmask> bitmask3 = PoliciesToBitmask({"vendor", "system"}, std::cerr);
+ ASSERT_NE(bitmask3, kResultError);
+ ASSERT_EQ(bitmask3, PolicyFlags::POLICY_SYSTEM_PARTITION | PolicyFlags::POLICY_VENDOR_PARTITION);
+
+ const Result<PolicyBitmask> bitmask4 =
+ PoliciesToBitmask({"public", "product", "system", "vendor"}, std::cerr);
+ ASSERT_NE(bitmask4, kResultError);
+ ASSERT_EQ(bitmask4, PolicyFlags::POLICY_PUBLIC | PolicyFlags::POLICY_PRODUCT_PARTITION |
+ PolicyFlags::POLICY_SYSTEM_PARTITION |
+ PolicyFlags::POLICY_VENDOR_PARTITION);
+
+ const Result<PolicyBitmask> bitmask5 =
+ PoliciesToBitmask({"system", "system", "system"}, std::cerr);
+ ASSERT_NE(bitmask5, kResultError);
+ ASSERT_EQ(bitmask5, PolicyFlags::POLICY_SYSTEM_PARTITION);
+
+ const Result<PolicyBitmask> bitmask6 = PoliciesToBitmask({""}, std::cerr);
+ ASSERT_EQ(bitmask6, kResultError);
+
+ const Result<PolicyBitmask> bitmask7 = PoliciesToBitmask({"foo"}, std::cerr);
+ ASSERT_EQ(bitmask7, kResultError);
+
+ const Result<PolicyBitmask> bitmask8 = PoliciesToBitmask({"system", "foo"}, std::cerr);
+ ASSERT_EQ(bitmask8, kResultError);
+
+ const Result<PolicyBitmask> bitmask9 = PoliciesToBitmask({"system", ""}, std::cerr);
+ ASSERT_EQ(bitmask9, kResultError);
+
+ const Result<PolicyBitmask> bitmask10 = PoliciesToBitmask({"system "}, std::cerr);
+ ASSERT_EQ(bitmask10, kResultError);
+}
+
+} // namespace android::idmap2
diff --git a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
index 7736bc0..eaa47cd 100644
--- a/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/PrettyPrintVisitorTests.cpp
@@ -25,6 +25,7 @@
#include "androidfw/Idmap.h"
#include "idmap2/Idmap.h"
+#include "idmap2/Policies.h"
#include "idmap2/PrettyPrintVisitor.h"
#include "TestHelpers.h"
@@ -32,6 +33,7 @@
using ::testing::NotNull;
using android::ApkAssets;
+using android::idmap2::PolicyBitmask;
namespace android::idmap2 {
@@ -46,7 +48,8 @@
std::stringstream error;
std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
ASSERT_THAT(idmap, NotNull());
std::stringstream stream;
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index 0318cd2..b58c61a 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -42,7 +42,8 @@
std::stringstream error;
std::unique_ptr<const Idmap> idmap =
- Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk, error);
+ Idmap::FromApkAssets(target_apk_path, *target_apk, overlay_apk_path, *overlay_apk,
+ PolicyFlags::POLICY_PUBLIC, /* enforce_overlayable */ true, error);
ASSERT_THAT(idmap, NotNull());
std::stringstream stream;
@@ -51,7 +52,7 @@
ASSERT_NE(stream.str().find("00000000: 504d4449 magic\n"), std::string::npos);
ASSERT_NE(stream.str().find("00000004: 00000001 version\n"), std::string::npos);
- ASSERT_NE(stream.str().find("00000008: f5ad1d1d target crc\n"), std::string::npos);
+ ASSERT_NE(stream.str().find("00000008: ca2093da target crc\n"), std::string::npos);
ASSERT_NE(stream.str().find("0000000c: d470336b overlay crc\n"), std::string::npos);
ASSERT_NE(stream.str().find("0000021c: 00000000 0x7f010000 -> 0x7f010000 integer/int1\n"),
std::string::npos);
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
new file mode 100644
index 0000000..977cd97
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="test.overlay.system.invalid">
+ <overlay
+ android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/build b/cmds/idmap2/tests/data/system-overlay-invalid/build
new file mode 100644
index 0000000..920e1f8
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/build
@@ -0,0 +1,26 @@
+# 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+ --no-resource-removal \
+ -I "$FRAMEWORK_RES_APK" \
+ --manifest AndroidManifest.xml \
+ -o system-overlay-invalid.apk \
+ compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
new file mode 100644
index 0000000..5127707
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml
@@ -0,0 +1,29 @@
+<?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>
+ <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+ following resources. -->
+ <string name="policy_system">policy_system</string>
+ <string name="policy_system_vendor">policy_system_vendor</string>
+ <string name="policy_public">policy_public</string>
+
+ <!-- It also requests to overlay a resource that belongs to a policy the overlay does not
+ fulfill.-->
+ <string name="policy_product">policy_product</string>
+
+ <!-- It also requests to overlay a resource that is not declared as overlayable.-->
+ <string name="not_overlayable">not_overlayable</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
new file mode 100644
index 0000000..c367f82
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
new file mode 100644
index 0000000..8af9064
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/AndroidManifest.xml
@@ -0,0 +1,21 @@
+<?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.
+-->
+<manifest
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ package="test.overlay.system">
+ <overlay
+ android:targetPackage="test.target" />
+</manifest>
diff --git a/cmds/idmap2/tests/data/system-overlay/build b/cmds/idmap2/tests/data/system-overlay/build
new file mode 100644
index 0000000..be0d239
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/build
@@ -0,0 +1,26 @@
+# 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.
+
+FRAMEWORK_RES_APK=${ANDROID_BUILD_TOP}/prebuilts/sdk/current/public/android.jar
+
+aapt2 compile --dir res -o compiled.flata
+
+aapt2 link \
+ --no-resource-removal \
+ -I "$FRAMEWORK_RES_APK" \
+ --manifest AndroidManifest.xml \
+ -o system-overlay.apk \
+ compiled.flata
+
+rm compiled.flata
diff --git a/cmds/idmap2/tests/data/system-overlay/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay/res/values/values.xml
new file mode 100644
index 0000000..6aaa0b0
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/res/values/values.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>
+ <!-- This overlay will fulfill the policies "public|system". This allows it overlay the
+ following resources. -->
+ <string name="policy_system">policy_system</string>
+ <string name="policy_system_vendor">policy_system_vendor</string>
+ <string name="policy_public">policy_public</string>
+</resources>
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
new file mode 100644
index 0000000..90f30eb
--- /dev/null
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
new file mode 100644
index 0000000..de19e6f
--- /dev/null
+++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
@@ -0,0 +1,48 @@
+<?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>
+<overlayable name="TestResources">
+ <!-- Publicly overlayable resources -->
+ <item type="string" name="a" />
+ <item type="string" name="b" />
+ <item type="string" name="c" />
+ <item type="string" name="str1" />
+ <item type="string" name="str2" />
+ <item type="string" name="str3" />
+ <item type="string" name="str4" />
+ <item type="string" name="x" />
+ <item type="string" name="y" />
+ <item type="string" name="z" />
+ <item type="integer" name="int1" />
+
+ <!-- Resources with partition restrictins -->
+ <policy type="system">
+ <item type="string" name="policy_system" />
+ </policy>
+
+ <policy type="system|vendor">
+ <item type="string" name="policy_system_vendor" />
+ </policy>
+
+ <policy type="product">
+ <item type="string" name="policy_product" />
+ </policy>
+
+ <policy type="public">
+ <item type="string" name="policy_public" />
+ </policy>
+</overlayable>
+</resources>
\ No newline at end of file
diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml
index 56bf0d6..ef9012e 100644
--- a/cmds/idmap2/tests/data/target/res/values/values.xml
+++ b/cmds/idmap2/tests/data/target/res/values/values.xml
@@ -25,4 +25,12 @@
<string name="y">y</string>
<string name="z">z</string>
<integer name="int1">1</integer>
+
+ <!-- This resources is not marked as overlayable -->
+ <string name="not_overlayable">not_overlayable</string>
+
+ <string name="policy_system">policy_system</string>
+ <string name="policy_system_vendor">policy_system_vendor</string>
+ <string name="policy_product">policy_product</string>
+ <string name="policy_public">policy_public</string>
</resources>
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index 18ecc27..9a6220d 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 5392a3c..02eff0b6 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -1108,18 +1108,6 @@
Landroid/os/UserManager;->mService:Landroid/os/IUserManager;
Landroid/os/UserManager;->removeUser(I)Z
Landroid/os/Vibrator;-><init>()V
-Landroid/os/VintfObject;->getHalNamesAndVersions()[Ljava/lang/String;
-Landroid/os/VintfObject;->getSepolicyVersion()Ljava/lang/String;
-Landroid/os/VintfObject;->getTargetFrameworkCompatibilityMatrixVersion()Ljava/lang/Long;
-Landroid/os/VintfObject;->getVndkSnapshots()Ljava/util/Map;
-Landroid/os/VintfObject;->report()[Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getCpuInfo()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getHardwareId()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getKernelVersion()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getNodeName()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsName()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsRelease()Ljava/lang/String;
-Landroid/os/VintfRuntimeInfo;->getOsVersion()Ljava/lang/String;
Landroid/os/WorkSource;-><init>(Landroid/os/Parcel;)V
Landroid/os/WorkSource;->mNames:[Ljava/lang/String;
Landroid/os/WorkSource;->mNum:I
@@ -1824,22 +1812,10 @@
Lcom/android/internal/os/RuntimeInit;->initialized:Z
Lcom/android/internal/os/RuntimeInit;->main([Ljava/lang/String;)V
Lcom/android/internal/os/RuntimeInit;->mApplicationObject:Landroid/os/IBinder;
-Lcom/android/internal/os/ZygoteConnection$Arguments;-><init>([Ljava/lang/String;)V
-Lcom/android/internal/os/ZygoteConnection$Arguments;->effectiveCapabilities:J
-Lcom/android/internal/os/ZygoteConnection$Arguments;->gid:I
-Lcom/android/internal/os/ZygoteConnection$Arguments;->gids:[I
-Lcom/android/internal/os/ZygoteConnection$Arguments;->permittedCapabilities:J
-Lcom/android/internal/os/ZygoteConnection$Arguments;->remainingArgs:[Ljava/lang/String;
-Lcom/android/internal/os/ZygoteConnection$Arguments;->rlimits:Ljava/util/ArrayList;
-Lcom/android/internal/os/ZygoteConnection$Arguments;->uid:I
-Lcom/android/internal/os/ZygoteConnection;->applyUidSecurityPolicy(Lcom/android/internal/os/ZygoteConnection$Arguments;Landroid/net/Credentials;)V
Lcom/android/internal/os/ZygoteConnection;->closeSocket()V
-Lcom/android/internal/os/ZygoteConnection;->getFileDesciptor()Ljava/io/FileDescriptor;
-Lcom/android/internal/os/ZygoteConnection;->intArray2d:[[I
Lcom/android/internal/os/ZygoteConnection;->mSocket:Landroid/net/LocalSocket;
Lcom/android/internal/os/ZygoteConnection;->mSocketOutStream:Ljava/io/DataOutputStream;
Lcom/android/internal/os/ZygoteConnection;->peer:Landroid/net/Credentials;
-Lcom/android/internal/os/ZygoteConnection;->readArgumentList()[Ljava/lang/String;
Lcom/android/internal/os/ZygoteInit;->main([Ljava/lang/String;)V
Lcom/android/internal/os/ZygoteInit;->mResources:Landroid/content/res/Resources;
Lcom/android/internal/os/ZygoteSecurityException;-><init>(Ljava/lang/String;)V
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index d374f1c..836627e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -124,6 +124,7 @@
import android.view.autofill.IAutofillWindowPresenter;
import android.view.contentcapture.ContentCaptureContext;
import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.ContentCaptureSession;
import android.widget.AdapterView;
import android.widget.Toast;
import android.widget.Toolbar;
@@ -1034,13 +1035,15 @@
}
/** @hide */ private static final int CONTENT_CAPTURE_START = 1;
- /** @hide */ private static final int CONTENT_CAPTURE_FLUSH = 2;
- /** @hide */ private static final int CONTENT_CAPTURE_STOP = 3;
+ /** @hide */ private static final int CONTENT_CAPTURE_PAUSE = 2;
+ /** @hide */ private static final int CONTENT_CAPTURE_RESUME = 3;
+ /** @hide */ private static final int CONTENT_CAPTURE_STOP = 4;
/** @hide */
@IntDef(prefix = { "CONTENT_CAPTURE_" }, value = {
CONTENT_CAPTURE_START,
- CONTENT_CAPTURE_FLUSH,
+ CONTENT_CAPTURE_PAUSE,
+ CONTENT_CAPTURE_RESUME,
CONTENT_CAPTURE_STOP
})
@Retention(RetentionPolicy.SOURCE)
@@ -1062,8 +1065,11 @@
}
cm.onActivityStarted(mToken, getComponentName(), flags);
break;
- case CONTENT_CAPTURE_FLUSH:
- cm.flush();
+ case CONTENT_CAPTURE_PAUSE:
+ cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_PAUSED);
+ break;
+ case CONTENT_CAPTURE_RESUME:
+ cm.flush(ContentCaptureSession.FLUSH_REASON_ACTIVITY_RESUMED);
break;
case CONTENT_CAPTURE_STOP:
cm.onActivityStopped();
@@ -1755,7 +1761,7 @@
}
}
mCalled = true;
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_RESUME);
}
/**
@@ -2149,7 +2155,7 @@
}
}
mCalled = true;
- notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_FLUSH);
+ notifyContentCaptureManagerIfNeeded(CONTENT_CAPTURE_PAUSE);
}
/**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index c4b315e..dcd6e2e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -98,6 +98,12 @@
* href="{@docRoot}guide/topics/resources/index.html">Application Resources</a>.</p>
*/
public class Resources {
+ /**
+ * The {@code null} resource ID. This denotes an invalid resource ID that is returned by the
+ * system when a resource is not found or the value is set to {@code @null} in XML.
+ */
+ public static final @AnyRes int ID_NULL = 0;
+
static final String TAG = "Resources";
private static final Object sSync = new Object();
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index fb22194..23c54f4 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -16,23 +16,27 @@
package android.os;
-import java.util.Map;
+import android.annotation.TestApi;
+import java.util.Map;
/**
* Java API for libvintf.
+ *
* @hide
*/
+@TestApi
public class VintfObject {
- /// ---------- OTA
-
/**
* Slurps all device information (both manifests and both matrices)
* and report them.
* If any error in getting one of the manifests, it is not included in
* the list.
+ *
+ * @hide
*/
+ @TestApi
public static native String[] report();
/**
@@ -44,6 +48,8 @@
* @return = 0 if success (compatible)
* > 0 if incompatible
* < 0 if any error (mount partition fails, illformed XML, etc.)
+ *
+ * @hide
*/
public static native int verify(String[] packageInfo);
@@ -55,22 +61,28 @@
* @return = 0 if success (compatible)
* > 0 if incompatible
* < 0 if any error (mount partition fails, illformed XML, etc.)
+ *
+ * @hide
*/
public static native int verifyWithoutAvb();
- /// ---------- CTS Device Info
-
/**
* @return a list of HAL names and versions that is supported by this
* device as stated in device and framework manifests. For example,
* ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
* "android.hardware.camera.device@3.2"]. There are no duplicates.
+ *
+ * @hide
*/
+ @TestApi
public static native String[] getHalNamesAndVersions();
/**
* @return the BOARD_SEPOLICY_VERS build flag available in device manifest.
+ *
+ * @hide
*/
+ @TestApi
public static native String getSepolicyVersion();
/**
@@ -78,13 +90,22 @@
* specified in framework manifest. For example,
* [("27", ["libjpeg.so", "libbase.so"]),
* ("28", ["libjpeg.so", "libbase.so"])]
+ *
+ * @hide
*/
+ @TestApi
public static native Map<String, String[]> getVndkSnapshots();
/**
- * @return target FCM version, a number specified in the device manifest
- * indicating the FCM version that the device manifest implements. Null if
- * device manifest doesn't specify this number (for legacy devices).
+ * @return Target Framework Compatibility Matrix (FCM) version, a number
+ * specified in the device manifest indicating the FCM version that the
+ * device manifest implements. Null if device manifest doesn't specify this
+ * number (for legacy devices).
+ *
+ * @hide
*/
+ @TestApi
public static native Long getTargetFrameworkCompatibilityMatrixVersion();
+
+ private VintfObject() {}
}
diff --git a/core/java/android/os/VintfRuntimeInfo.java b/core/java/android/os/VintfRuntimeInfo.java
index 29698b9..f17039b 100644
--- a/core/java/android/os/VintfRuntimeInfo.java
+++ b/core/java/android/os/VintfRuntimeInfo.java
@@ -16,55 +16,84 @@
package android.os;
+import android.annotation.TestApi;
+
/**
* Java API for ::android::vintf::RuntimeInfo. Methods return null / 0 on any error.
*
* @hide
*/
+@TestApi
public class VintfRuntimeInfo {
private VintfRuntimeInfo() {}
/**
* @return /sys/fs/selinux/policyvers, via security_policyvers() native call
+ *
+ * @hide
*/
public static native long getKernelSepolicyVersion();
/**
* @return content of /proc/cpuinfo
+ *
+ * @hide
*/
+ @TestApi
public static native String getCpuInfo();
/**
* @return os name extracted from uname() native call
+ *
+ * @hide
*/
+ @TestApi
public static native String getOsName();
/**
* @return node name extracted from uname() native call
+ *
+ * @hide
*/
+ @TestApi
public static native String getNodeName();
/**
* @return os release extracted from uname() native call
+ *
+ * @hide
*/
+ @TestApi
public static native String getOsRelease();
/**
* @return os version extracted from uname() native call
+ *
+ * @hide
*/
+ @TestApi
public static native String getOsVersion();
/**
* @return hardware id extracted from uname() native call
+ *
+ * @hide
*/
+ @TestApi
public static native String getHardwareId();
/**
* @return kernel version extracted from uname() native call. Format is
* {@code x.y.z}.
+ *
+ * @hide
*/
+ @TestApi
public static native String getKernelVersion();
/**
* @return libavb version in OS. Format is {@code x.y}.
+ *
+ * @hide
*/
public static native String getBootAvbVersion();
/**
* @return libavb version in bootloader. Format is {@code x.y}.
+ *
+ * @hide
*/
public static native String getBootVbmetaAvbVersion();
-
}
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 44cb221..af8146e 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -53,6 +53,13 @@
public static final Uri CONTENT_URI = Uri.parse("content://" + Settings.AUTHORITY + "/config");
/**
+ * Namespace for all Game Driver features.
+ * @hide
+ */
+ @SystemApi
+ public static final String NAMESPACE_GAME_DRIVER = "game_driver";
+
+ /**
* Namespace for all input-related features that are used at the native level.
* These features are applied at reboot.
*
diff --git a/core/java/android/provider/FontsContract.java b/core/java/android/provider/FontsContract.java
index 8e37559..e931826 100644
--- a/core/java/android/provider/FontsContract.java
+++ b/core/java/android/provider/FontsContract.java
@@ -34,6 +34,7 @@
import android.graphics.fonts.FontStyle;
import android.graphics.fonts.FontVariationAxis;
import android.net.Uri;
+import android.os.Build.VERSION_CODES;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.HandlerThread;
@@ -651,7 +652,16 @@
if (familyBuilder == null) {
familyBuilder = new FontFamily.Builder(font);
} else {
- familyBuilder.addFont(font);
+ try {
+ familyBuilder.addFont(font);
+ } catch (IllegalArgumentException e) {
+ if (context.getApplicationInfo().targetSdkVersion <= VERSION_CODES.P) {
+ // Surpress the IllegalArgumentException for keeping the backward
+ // compatibility.
+ continue;
+ }
+ throw e;
+ }
}
} catch (IOException e) {
continue;
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index ffd4156..dc7c343 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -22,6 +22,7 @@
import android.annotation.SystemService;
import android.annotation.UnsupportedAppUsage;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
@@ -29,6 +30,7 @@
import android.os.Build;
import android.os.Handler;
import android.os.Message;
+import android.os.SystemProperties;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
@@ -38,6 +40,9 @@
import com.android.internal.R;
+import dalvik.system.PathClassLoader;
+import java.io.File;
+import java.lang.reflect.Method;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -72,6 +77,10 @@
private static final String TAG = LayoutInflater.class.getSimpleName();
private static final boolean DEBUG = false;
+ private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+ = "view.precompiled_layout_enabled";
+ private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
+
/** Empty stack trace used to avoid log spam in re-throw exceptions. */
private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
@@ -93,6 +102,13 @@
private Factory2 mPrivateFactory;
private Filter mFilter;
+ // Indicates whether we should try to inflate layouts using a precompiled layout instead of
+ // inflating from the XML resource.
+ private boolean mUseCompiledView;
+ // This variable holds the classloader that will be used to look for precompiled layouts. The
+ // The classloader includes the generated compiled_view.dex file.
+ private ClassLoader mPrecompiledClassLoader;
+
@UnsupportedAppUsage
final Object[] mConstructorArgs = new Object[2];
@@ -223,6 +239,7 @@
*/
protected LayoutInflater(Context context) {
mContext = context;
+ initPrecompiledViews();
}
/**
@@ -239,6 +256,7 @@
mFactory2 = original.mFactory2;
mPrivateFactory = original.mPrivateFactory;
setFilter(original.mFilter);
+ initPrecompiledViews();
}
/**
@@ -380,6 +398,41 @@
}
}
+ private void initPrecompiledViews() {
+ // Check if precompiled layouts are enabled by a system property.
+ mUseCompiledView =
+ SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false);
+ if (!mUseCompiledView) {
+ return;
+ }
+
+ // Make sure the application allows code generation
+ ApplicationInfo appInfo = mContext.getApplicationInfo();
+ if ((appInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_PREFER_CODE_INTEGRITY) != 0
+ || appInfo.isPrivilegedApp()) {
+ mUseCompiledView = false;
+ return;
+ }
+
+ // Try to load the precompiled layout file.
+ try {
+ mPrecompiledClassLoader = mContext.getClassLoader();
+ String dexFile = mContext.getCodeCacheDir() + COMPILED_VIEW_DEX_FILE_NAME;
+ if (new File(dexFile).exists()) {
+ mPrecompiledClassLoader = new PathClassLoader(dexFile, mPrecompiledClassLoader);
+ } else {
+ // If the precompiled layout file doesn't exist, then disable precompiled
+ // layouts.
+ mUseCompiledView = false;
+ }
+ } catch (Throwable e) {
+ if (DEBUG) {
+ Log.e(TAG, "Failed to initialized precompiled views layouts", e);
+ }
+ mUseCompiledView = false;
+ }
+ }
+
/**
* Inflate a new view hierarchy from the specified xml resource. Throws
* {@link InflateException} if there is an error.
@@ -436,10 +489,14 @@
final Resources res = getContext().getResources();
if (DEBUG) {
Log.d(TAG, "INFLATING from resource: \"" + res.getResourceName(resource) + "\" ("
- + Integer.toHexString(resource) + ")");
+ + Integer.toHexString(resource) + ")");
}
- final XmlResourceParser parser = res.getLayout(resource);
+ View view = tryInflatePrecompiled(resource, res, root, attachToRoot);
+ if (view != null) {
+ return view;
+ }
+ XmlResourceParser parser = res.getLayout(resource);
try {
return inflate(parser, root, attachToRoot);
} finally {
@@ -447,6 +504,73 @@
}
}
+ private @Nullable
+ View tryInflatePrecompiled(@LayoutRes int resource, Resources res, @Nullable ViewGroup root,
+ boolean attachToRoot) {
+ if (!mUseCompiledView) {
+ return null;
+ }
+
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "inflate (precompiled)");
+
+ // Try to inflate using a precompiled layout.
+ String pkg = res.getResourcePackageName(resource);
+ String layout = res.getResourceEntryName(resource);
+
+ try {
+ Class clazz = mPrecompiledClassLoader.loadClass("" + pkg + ".CompiledView");
+ Method inflater = clazz.getMethod(layout, Context.class, int.class);
+ View view = (View) inflater.invoke(null, mContext, resource);
+
+ if (view != null && root != null) {
+ // We were able to use the precompiled inflater, but now we need to do some work to
+ // attach the view to the root correctly.
+ XmlResourceParser parser = res.getLayout(resource);
+ try {
+ AttributeSet attrs = Xml.asAttributeSet(parser);
+ advanceToRootNode(parser);
+ ViewGroup.LayoutParams params = root.generateLayoutParams(attrs);
+
+ if (attachToRoot) {
+ root.addView(view, params);
+ } else {
+ view.setLayoutParams(params);
+ }
+ } finally {
+ parser.close();
+ }
+ }
+
+ return view;
+ } catch (Throwable e) {
+ if (DEBUG) {
+ Log.e(TAG, "Failed to use precompiled view", e);
+ }
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ return null;
+ }
+
+ /**
+ * Advances the given parser to the first START_TAG. Throws InflateException if no start tag is
+ * found.
+ */
+ private void advanceToRootNode(XmlPullParser parser)
+ throws InflateException, IOException, XmlPullParserException {
+ // Look for the root node.
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(parser.getPositionDescription()
+ + ": No start tag found!");
+ }
+ }
+
/**
* Inflate a new view hierarchy from the specified XML node. Throws
* {@link InflateException} if there is an error.
@@ -480,18 +604,7 @@
View result = root;
try {
- // Look for the root node.
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty
- }
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(parser.getPositionDescription()
- + ": No start tag found!");
- }
-
+ advanceToRootNode(parser);
final String name = parser.getName();
if (DEBUG) {
@@ -994,82 +1107,85 @@
+ "reference. The layout ID " + value + " is not valid.");
}
- final XmlResourceParser childParser = context.getResources().getLayout(layout);
+ final View precompiled = tryInflatePrecompiled(layout, context.getResources(),
+ (ViewGroup) parent, /*attachToRoot=*/true);
+ if (precompiled == null) {
+ final XmlResourceParser childParser = context.getResources().getLayout(layout);
- try {
- final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+ try {
+ final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
- while ((type = childParser.next()) != XmlPullParser.START_TAG &&
- type != XmlPullParser.END_DOCUMENT) {
- // Empty.
+ while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(childParser.getPositionDescription() +
+ ": No start tag found!");
+ }
+
+ final String childName = childParser.getName();
+
+ if (TAG_MERGE.equals(childName)) {
+ // The <merge> tag doesn't support android:theme, so
+ // nothing special to do here.
+ rInflate(childParser, parent, context, childAttrs, false);
+ } else {
+ final View view = createViewFromTag(parent, childName,
+ context, childAttrs, hasThemeOverride);
+ final ViewGroup group = (ViewGroup) parent;
+
+ final TypedArray a = context.obtainStyledAttributes(
+ attrs, R.styleable.Include);
+ final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
+ final int visibility = a.getInt(R.styleable.Include_visibility, -1);
+ a.recycle();
+
+ // We try to load the layout params set in the <include /> tag.
+ // If the parent can't generate layout params (ex. missing width
+ // or height for the framework ViewGroups, though this is not
+ // necessarily true of all ViewGroups) then we expect it to throw
+ // a runtime exception.
+ // We catch this exception and set localParams accordingly: true
+ // means we successfully loaded layout params from the <include>
+ // tag, false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ params = group.generateLayoutParams(attrs);
+ } catch (RuntimeException e) {
+ // Ignore, just fail over to child attrs.
+ }
+ if (params == null) {
+ params = group.generateLayoutParams(childAttrs);
+ }
+ view.setLayoutParams(params);
+
+ // Inflate all children.
+ rInflateChildren(childParser, view, childAttrs, true);
+
+ if (id != View.NO_ID) {
+ view.setId(id);
+ }
+
+ switch (visibility) {
+ case 0:
+ view.setVisibility(View.VISIBLE);
+ break;
+ case 1:
+ view.setVisibility(View.INVISIBLE);
+ break;
+ case 2:
+ view.setVisibility(View.GONE);
+ break;
+ }
+
+ group.addView(view);
+ }
+ } finally {
+ childParser.close();
}
-
- if (type != XmlPullParser.START_TAG) {
- throw new InflateException(childParser.getPositionDescription() +
- ": No start tag found!");
- }
-
- final String childName = childParser.getName();
-
- if (TAG_MERGE.equals(childName)) {
- // The <merge> tag doesn't support android:theme, so
- // nothing special to do here.
- rInflate(childParser, parent, context, childAttrs, false);
- } else {
- final View view = createViewFromTag(parent, childName,
- context, childAttrs, hasThemeOverride);
- final ViewGroup group = (ViewGroup) parent;
-
- final TypedArray a = context.obtainStyledAttributes(
- attrs, R.styleable.Include);
- final int id = a.getResourceId(R.styleable.Include_id, View.NO_ID);
- final int visibility = a.getInt(R.styleable.Include_visibility, -1);
- a.recycle();
-
- // We try to load the layout params set in the <include /> tag.
- // If the parent can't generate layout params (ex. missing width
- // or height for the framework ViewGroups, though this is not
- // necessarily true of all ViewGroups) then we expect it to throw
- // a runtime exception.
- // We catch this exception and set localParams accordingly: true
- // means we successfully loaded layout params from the <include>
- // tag, false means we need to rely on the included layout params.
- ViewGroup.LayoutParams params = null;
- try {
- params = group.generateLayoutParams(attrs);
- } catch (RuntimeException e) {
- // Ignore, just fail over to child attrs.
- }
- if (params == null) {
- params = group.generateLayoutParams(childAttrs);
- }
- view.setLayoutParams(params);
-
- // Inflate all children.
- rInflateChildren(childParser, view, childAttrs, true);
-
- if (id != View.NO_ID) {
- view.setId(id);
- }
-
- switch (visibility) {
- case 0:
- view.setVisibility(View.VISIBLE);
- break;
- case 1:
- view.setVisibility(View.INVISIBLE);
- break;
- case 2:
- view.setVisibility(View.GONE);
- break;
- }
-
- group.addView(view);
- }
- } finally {
- childParser.close();
}
-
LayoutInflater.consumeChildElements(parser);
}
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index ff5120d..273d89c 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -167,6 +167,7 @@
InputWindowHandle handle);
private static native void nativeTransferTouchFocus(long transactionObj, IBinder fromToken,
IBinder toToken);
+ private static native boolean nativeGetProtectedContentSupport();
private final CloseGuard mCloseGuard = CloseGuard.get();
private String mName;
@@ -1730,6 +1731,14 @@
}
/**
+ * Returns whether protected content is supported in GPU composition.
+ * @hide
+ */
+ public static boolean getProtectedContentSupport() {
+ return nativeGetProtectedContentSupport();
+ }
+
+ /**
* @hide
*/
public static class Transaction implements Closeable {
diff --git a/core/java/android/view/contentcapture/ChildContentCaptureSession.java b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
index 04e725e..cb4c4b4 100644
--- a/core/java/android/view/contentcapture/ChildContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ChildContentCaptureSession.java
@@ -68,8 +68,8 @@
}
@Override
- void flush() {
- mParent.flush();
+ void flush(@FlushReason int reason) {
+ mParent.flush(reason);
}
@Override
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 81b2e01..413f1a5 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -24,10 +24,11 @@
import android.content.ComponentName;
import android.content.Context;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.view.contentcapture.ContentCaptureSession.FlushReason;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.os.IResultReceiver;
@@ -51,8 +52,6 @@
private static final String TAG = ContentCaptureManager.class.getSimpleName();
- private static final String BG_THREAD_NAME = "intel_svc_streamer_thread";
-
/**
* Timeout for calls to system_server.
*/
@@ -89,24 +88,13 @@
public ContentCaptureManager(@NonNull Context context,
@Nullable IContentCaptureManager service) {
mContext = Preconditions.checkNotNull(context, "context cannot be null");
- if (VERBOSE) {
- Log.v(TAG, "Constructor for " + context.getPackageName());
- }
- mService = service;
- // TODO(b/119220549): use an existing bg thread instead...
- final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
- bgThread.start();
- mHandler = Handler.createAsync(bgThread.getLooper());
- }
+ if (VERBOSE) Log.v(TAG, "Constructor for " + context.getPackageName());
- @NonNull
- private static Handler newHandler() {
- // TODO(b/119220549): use an existing bg thread instead...
- // TODO(b/119220549): use UI Thread directly (as calls are one-way) or an existing bgThread
- // or a shared thread / handler held at the Application level
- final HandlerThread bgThread = new HandlerThread(BG_THREAD_NAME);
- bgThread.start();
- return Handler.createAsync(bgThread.getLooper());
+ mService = service;
+ // TODO(b/119220549): we might not even need a handler, as the IPCs are oneway. But if we
+ // do, then we should optimize it to run the tests after the Choreographer finishes the most
+ // important steps of the frame.
+ mHandler = Handler.createAsync(Looper.getMainLooper());
}
/**
@@ -154,8 +142,8 @@
*
* @hide
*/
- public void flush() {
- getMainContentCaptureSession().flush();
+ public void flush(@FlushReason int reason) {
+ getMainContentCaptureSession().flush(reason);
}
/**
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index 7bfc5b4..a9e7b5e 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -19,6 +19,7 @@
import static android.view.contentcapture.ContentCaptureManager.VERBOSE;
import android.annotation.CallSuper;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.DebugUtils;
@@ -35,6 +36,8 @@
import dalvik.system.CloseGuard;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.UUID;
@@ -125,6 +128,32 @@
private static final int INITIAL_CHILDREN_CAPACITY = 5;
+ /** @hide */
+ public static final int FLUSH_REASON_FULL = 1;
+ /** @hide */
+ public static final int FLUSH_REASON_ACTIVITY_PAUSED = 2;
+ /** @hide */
+ public static final int FLUSH_REASON_ACTIVITY_RESUMED = 3;
+ /** @hide */
+ public static final int FLUSH_REASON_SESSION_STARTED = 4;
+ /** @hide */
+ public static final int FLUSH_REASON_SESSION_FINISHED = 5;
+ /** @hide */
+ public static final int FLUSH_REASON_IDLE_TIMEOUT = 6;
+
+ /** @hide */
+ @IntDef(prefix = { "FLUSH_REASON_" }, value = {
+ FLUSH_REASON_FULL,
+ FLUSH_REASON_ACTIVITY_PAUSED,
+ FLUSH_REASON_ACTIVITY_RESUMED,
+ FLUSH_REASON_SESSION_STARTED,
+ FLUSH_REASON_SESSION_FINISHED,
+ FLUSH_REASON_IDLE_TIMEOUT
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface FlushReason{}
+
+
private final CloseGuard mCloseGuard = CloseGuard.get();
private final Object mLock = new Object();
@@ -212,7 +241,7 @@
/**
* Flushes the buffered events to the service.
*/
- abstract void flush();
+ abstract void flush(@FlushReason int reason);
/**
* Destroys this session, flushing out all pending notifications to the service.
@@ -250,7 +279,7 @@
}
try {
- flush();
+ flush(FLUSH_REASON_SESSION_FINISHED);
} finally {
onDestroy();
}
@@ -407,12 +436,31 @@
return mId;
}
- /**
- * @hide
- */
+ /** @hide */
@NonNull
protected static String getStateAsString(int state) {
return state + " (" + (state == UNKNWON_STATE ? "UNKNOWN"
: DebugUtils.flagsToString(ContentCaptureSession.class, "STATE_", state)) + ")";
}
+
+ /** @hide */
+ @NonNull
+ static String getflushReasonAsString(@FlushReason int reason) {
+ switch (reason) {
+ case FLUSH_REASON_FULL:
+ return "FULL";
+ case FLUSH_REASON_ACTIVITY_PAUSED:
+ return "PAUSED";
+ case FLUSH_REASON_ACTIVITY_RESUMED:
+ return "RESUMED";
+ case FLUSH_REASON_SESSION_STARTED:
+ return "STARTED";
+ case FLUSH_REASON_SESSION_FINISHED:
+ return "FINISHED";
+ case FLUSH_REASON_IDLE_TIMEOUT:
+ return "IDLE";
+ default:
+ return "UNKOWN-" + reason;
+ }
+ }
}
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index a3ff8c0..f0778fa 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -35,7 +35,7 @@
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.RemoteException;
-import android.os.SystemClock;
+import android.util.LocalLog;
import android.util.Log;
import android.util.TimeUtils;
import android.view.autofill.AutofillId;
@@ -131,6 +131,9 @@
// Used just for debugging purposes (on dump)
private long mNextFlush;
+ // TODO(b/121044064): use settings to set size
+ private final LocalLog mFlushHistory = new LocalLog(10);
+
/** @hide */
protected MainContentCaptureSession(@NonNull Context context, @NonNull Handler handler,
@Nullable IContentCaptureManager systemServerInterface,
@@ -172,8 +175,9 @@
}
@Override
- void flush() {
- mHandler.sendMessage(obtainMessage(MainContentCaptureSession::handleForceFlush, this));
+ void flush(@FlushReason int reason) {
+ mHandler.sendMessage(
+ obtainMessage(MainContentCaptureSession::handleForceFlush, this, reason));
}
@Override
@@ -264,24 +268,25 @@
}
private void handleSendEvent(@NonNull ContentCaptureEvent event, boolean forceFlush) {
- if (!handleHasStarted()
- && event.getType() != ContentCaptureEvent.TYPE_SESSION_STARTED) {
+ final int eventType = event.getType();
+ if (!handleHasStarted() && eventType != ContentCaptureEvent.TYPE_SESSION_STARTED) {
// TODO(b/120494182): comment when this could happen (dialogs?)
Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
- + ContentCaptureEvent.getTypeAsString(event.getType())
+ + ContentCaptureEvent.getTypeAsString(eventType)
+ "): session not started yet");
return;
}
+ if (VERBOSE) Log.v(TAG, "handleSendEvent(" + getDebugState() + "): " + event);
if (mEvents == null) {
if (VERBOSE) {
Log.v(TAG, "handleSendEvent(" + getDebugState() + ", "
- + ContentCaptureEvent.getTypeAsString(event.getType())
- + "): cCreating buffer for " + MAX_BUFFER_SIZE + " events");
+ + ContentCaptureEvent.getTypeAsString(eventType)
+ + "): creating buffer for " + MAX_BUFFER_SIZE + " events");
}
mEvents = new ArrayList<>(MAX_BUFFER_SIZE);
}
- if (!mEvents.isEmpty() && event.getType() == TYPE_VIEW_TEXT_CHANGED) {
+ if (!mEvents.isEmpty() && eventType == TYPE_VIEW_TEXT_CHANGED) {
final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
// TODO(b/121045053): check if flags match
@@ -304,7 +309,7 @@
final boolean bufferEvent = numberEvents < MAX_BUFFER_SIZE;
if (bufferEvent && !forceFlush) {
- handleScheduleFlush(/* checkExisting= */ true);
+ handleScheduleFlush(FLUSH_REASON_IDLE_TIMEOUT, /* checkExisting= */ true);
return;
}
@@ -323,15 +328,26 @@
// when it's launched again
return;
}
+ final int flushReason;
+ switch (eventType) {
+ case ContentCaptureEvent.TYPE_SESSION_STARTED:
+ flushReason = FLUSH_REASON_SESSION_STARTED;
+ break;
+ case ContentCaptureEvent.TYPE_SESSION_FINISHED:
+ flushReason = FLUSH_REASON_SESSION_FINISHED;
+ break;
+ default:
+ flushReason = FLUSH_REASON_FULL;
+ }
- handleForceFlush();
+ handleForceFlush(flushReason);
}
private boolean handleHasStarted() {
return mState != UNKNWON_STATE;
}
- private void handleScheduleFlush(boolean checkExisting) {
+ private void handleScheduleFlush(@FlushReason int reason, boolean checkExisting) {
if (!handleHasStarted()) {
Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): session not started yet");
return;
@@ -340,43 +356,51 @@
// "Renew" the flush message by removing the previous one
mHandler.removeMessages(MSG_FLUSH);
}
- mNextFlush = SystemClock.elapsedRealtime() + FLUSHING_FREQUENCY_MS;
+ mNextFlush = System.currentTimeMillis() + FLUSHING_FREQUENCY_MS;
if (VERBOSE) {
- Log.v(TAG, "handleScheduleFlush(" + getDebugState() + "): scheduled to flush in "
- + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.formatUptime(mNextFlush));
+ Log.v(TAG, "handleScheduleFlush(" + getDebugState()
+ + ", reason=" + getflushReasonAsString(reason) + "): scheduled to flush in "
+ + FLUSHING_FREQUENCY_MS + "ms: " + TimeUtils.logTimeOfDay(mNextFlush));
}
mHandler.sendMessageDelayed(
- obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this)
+ obtainMessage(MainContentCaptureSession::handleFlushIfNeeded, this, reason)
.setWhat(MSG_FLUSH), FLUSHING_FREQUENCY_MS);
}
- private void handleFlushIfNeeded() {
+ private void handleFlushIfNeeded(@FlushReason int reason) {
if (mEvents.isEmpty()) {
if (VERBOSE) Log.v(TAG, "Nothing to flush");
return;
}
- handleForceFlush();
+ handleForceFlush(reason);
}
- private void handleForceFlush() {
+ private void handleForceFlush(@FlushReason int reason) {
if (mEvents == null) return;
if (mDirectServiceInterface == null) {
if (VERBOSE) {
Log.v(TAG, "handleForceFlush(" + getDebugState()
+ + ", reason=" + getflushReasonAsString(reason)
+ "): hold your horses, client not ready: " + mEvents);
}
if (!mHandler.hasMessages(MSG_FLUSH)) {
- handleScheduleFlush(/* checkExisting= */ false);
+ handleScheduleFlush(reason, /* checkExisting= */ false);
}
return;
}
final int numberEvents = mEvents.size();
+ final String reasonString = getflushReasonAsString(reason);
+ if (DEBUG) {
+ Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState()
+ + ". Reason: " + reasonString);
+ }
+ // Logs reason, size, max size, idle timeout
+ final String logRecord = "r=" + reasonString + " s=" + numberEvents
+ + " m=" + MAX_BUFFER_SIZE + " i=" + FLUSHING_FREQUENCY_MS;
try {
- if (DEBUG) {
- Log.d(TAG, "Flushing " + numberEvents + " event(s) for " + getDebugState());
- }
+ mFlushHistory.log(logRecord);
mHandler.removeMessages(MSG_FLUSH);
final ParceledListSlice<ContentCaptureEvent> events = handleClearEvents();
@@ -500,7 +524,6 @@
@Override
void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
- pw.print(prefix); pw.print("id: "); pw.println(mId);
pw.print(prefix); pw.print("mContext: "); pw.println(mContext);
pw.print(prefix); pw.print("user: "); pw.println(mContext.getUserId());
if (mSystemServerInterface != null) {
@@ -535,8 +558,12 @@
}
pw.print(prefix); pw.print("flush frequency: "); pw.println(FLUSHING_FREQUENCY_MS);
pw.print(prefix); pw.print("next flush: ");
- TimeUtils.formatDuration(mNextFlush - SystemClock.elapsedRealtime(), pw); pw.println();
+ TimeUtils.formatDuration(mNextFlush - System.currentTimeMillis(), pw);
+ pw.print(" ("); pw.print(TimeUtils.logTimeOfDay(mNextFlush)); pw.println(")");
}
+ pw.print(prefix); pw.println("flush history:");
+ mFlushHistory.reverseDump(/* fd= */ null, pw, /* args= */ null); pw.println();
+
super.dump(prefix, pw);
}
diff --git a/core/java/com/android/internal/infra/AbstractRemoteService.java b/core/java/com/android/internal/infra/AbstractRemoteService.java
index 5945958..72c67d7 100644
--- a/core/java/com/android/internal/infra/AbstractRemoteService.java
+++ b/core/java/com/android/internal/infra/AbstractRemoteService.java
@@ -139,6 +139,14 @@
return mDestroyed;
}
+ /**
+ * Gets the name of the service.
+ */
+ @NonNull
+ public final ComponentName getComponentName() {
+ return mComponentName;
+ }
+
private void handleOnConnectedStateChangedInternal(boolean connected) {
if (connected) {
handlePendingRequests();
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 12a8343b4..67c3064 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -841,6 +841,43 @@
return jStatus;
}
+static int android_media_AudioRecord_set_microphone_direction(JNIEnv *env, jobject thiz,
+ jint direction) {
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for setMicrophoneDirection()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ jint jStatus = AUDIO_JAVA_SUCCESS;
+ status_t status =
+ lpRecorder->setMicrophoneDirection(static_cast<audio_microphone_direction_t>(direction));
+ if (status != NO_ERROR) {
+ jStatus = nativeToJavaStatus(status);
+ }
+
+ return jStatus;
+}
+
+static int android_media_AudioRecord_set_microphone_field_dimension(JNIEnv *env, jobject thiz,
+ jfloat zoom) {
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioRecord pointer for setMicrophoneFieldDimension()");
+ return (jint)AUDIO_JAVA_ERROR;
+ }
+
+ jint jStatus = AUDIO_JAVA_SUCCESS;
+ status_t status = lpRecorder->setMicrophoneFieldDimension(zoom);
+ if (status != NO_ERROR) {
+ jStatus = nativeToJavaStatus(status);
+ }
+
+ return jStatus;
+}
+
// ----------------------------------------------------------------------------
static jint android_media_AudioRecord_get_port_id(JNIEnv *env, jobject thiz) {
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
@@ -896,6 +933,10 @@
{"native_get_active_microphones", "(Ljava/util/ArrayList;)I",
(void *)android_media_AudioRecord_get_active_microphones},
{"native_getPortId", "()I", (void *)android_media_AudioRecord_get_port_id},
+ {"native_set_microphone_direction", "(I)I",
+ (void *)android_media_AudioRecord_set_microphone_direction},
+ {"native_set_microphone_field_dimension", "(F)I",
+ (void *)android_media_AudioRecord_set_microphone_field_dimension},
};
// field names found in android/media/AudioRecord.java
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index 10da892..aa10a2f 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -138,6 +138,7 @@
event->getDeviceId(), event->getSource(), event->getDisplayId(),
event->getAction(), event->getActionButton(), event->getFlags(),
event->getEdgeFlags(), event->getMetaState(), event->getButtonState(),
+ event->getClassification(),
event->getXOffset(), event->getYOffset(),
event->getXPrecision(), event->getYPrecision(),
event->getDownTime(), event->getHistoricalEventTime(i),
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 9ce6df1..ac13025 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -660,6 +660,10 @@
if (t.duration() > 100ms) ALOGD("Excessive delay in setPowerMode()");
}
+static jboolean nativeGetProtectedContentSupport(JNIEnv* env, jclass) {
+ return static_cast<jboolean>(SurfaceComposerClient::getProtectedContentSupport());
+}
+
static jboolean nativeClearContentFrameStats(JNIEnv* env, jclass clazz, jlong nativeObject) {
SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
status_t err = ctrl->clearLayerFrameStats();
@@ -1028,6 +1032,8 @@
(void*)nativeGetAnimationFrameStats },
{"nativeSetDisplayPowerMode", "(Landroid/os/IBinder;I)V",
(void*)nativeSetDisplayPowerMode },
+ {"nativeGetProtectedContentSupport", "()Z",
+ (void*)nativeGetProtectedContentSupport },
{"nativeDeferTransactionUntil", "(JJLandroid/os/IBinder;J)V",
(void*)nativeDeferTransactionUntil },
{"nativeDeferTransactionUntilSurface", "(JJJJ)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cf1f7bb..f3e3241 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1186,6 +1186,7 @@
<!-- Used for permissions that are associated with activity recognition.
TODO(zezeozue). STOPSHIP: Add icon -->
<permission-group android:name="android.permission-group.ACTIVITY_RECOGNITION"
+ android:icon="@drawable/perm_group_activity_recognition"
android:label="@string/permgrouplab_activityRecognition"
android:description="@string/permgroupdesc_activityRecognition"
android:request="@string/permgrouprequest_activityRecognition"
diff --git a/core/res/res/drawable/perm_group_activity_recognition.xml b/core/res/res/drawable/perm_group_activity_recognition.xml
new file mode 100644
index 0000000..0ade6c6
--- /dev/null
+++ b/core/res/res/drawable/perm_group_activity_recognition.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1
+2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9
+0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2
+2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" />
+</vector>
diff --git a/core/res/res/drawable/perm_group_sensors.xml b/core/res/res/drawable/perm_group_sensors.xml
index ce36c13..e4663d7 100644
--- a/core/res/res/drawable/perm_group_sensors.xml
+++ b/core/res/res/drawable/perm_group_sensors.xml
@@ -19,11 +19,11 @@
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
-
- <path
- android:fillColor="#000000"
- android:pathData="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1
-2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9
-0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5 .1 -.8 .1 l-5.2
-2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z" />
-</vector>
\ No newline at end of file
+ <path
+ android:fillColor="#000000"
+ android:pathData="M16.5,3c-1.74,0 -3.41,0.81 -4.5,2.09C10.91,3.81 9.24,3 7.5,3C4.42,3 2,5.42 2,
+ 8.5c0,3.78 3.4,6.86 8.55,11.54L12,21.35l1.45,-1.32C18.6,15.36 22,12.28 22,8.5C22,
+ 5.42 19.58,3 16.5,3zM12.1,18.55l-0.1,0.1l-0.1,-0.1C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5,
+ 5 7.5,5c1.54,0 3.04,0.99 3.57,2.36h1.87C13.46,5.99 14.96,5 16.5,5c2,0 3.5,1.5 3.5,3.5C20,
+ 11.39 16.86,14.24 12.1,18.55z"/>
+</vector>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aa1364f..64fdc02 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -618,15 +618,6 @@
<!-- Integer indicating wpa_supplicant scan interval when p2p is connected in milliseconds -->
<integer translatable="false" name="config_wifi_scan_interval_p2p_connected">60000</integer>
- <!-- Integer indicating the framework scan interval in milliseconds. This is used in the scenario
- where the chipset does not support background scanning (config_wifi_background_scan_suport
- is false) to set up a periodic wake up scan so that the device can connect to a new access
- point on the move. A value of 0 means no periodic scans will be used in the framework. -->
- <integer translatable="false" name="config_wifi_framework_scan_interval">300000</integer>
-
- <!-- Integer indicating the framework no networks periodic scan interval in milliseconds. -->
- <integer translatable="false" name="config_wifi_no_network_periodic_scan_interval">300000</integer>
-
<!-- Integer indicating disconnect mode short scan interval in milliseconds -->
<integer translatable="false" name="config_wifi_disconnected_short_scan_interval">15000</integer>
@@ -692,6 +683,11 @@
<!-- Wifi driver supports Automatic channel selection (ACS) for softap -->
<bool translatable="false" name="config_wifi_softap_acs_supported">false</bool>
+ <!-- Channel list restriction to Automatic channel selection (ACS) for softap. If the device
+ doesn't want to restrict channels this should be empty. Value is a comma separated channel
+ string and/or channel range string like '1-6,11' -->
+ <string translatable="false" name="config_wifi_softap_acs_supported_channel_list"></string>
+
<!-- Wifi driver supports IEEE80211AC for softap -->
<bool translatable="false" name="config_wifi_softap_ieee80211ac_supported">false</bool>
@@ -699,6 +695,9 @@
for automotive builds only (the one that have PackageManager#FEATURE_AUTOMOTIVE) -->
<bool translatable="false" name="config_wifi_local_only_hotspot_5ghz">false</bool>
+ <!-- Indicates that connected MAC randomization is supported on this device -->
+ <bool translatable="false" name="config_wifi_connected_mac_randomization_supported">false</bool>
+
<!-- Flag indicating whether we should enable the automatic brightness.
Software implementation will be used if config_hardware_auto_brightness_available is not set -->
<bool name="config_automatic_brightness_available">false</bool>
@@ -1892,6 +1891,8 @@
cell broadcasting sms, and MMS. -->
<bool name="config_sms_capable">true</bool>
+ <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use
+ config_defaultRoleHolders now. -->
<!-- Default SMS Application. This will be the default SMS application when
the phone first boots. The user can then change the default app to one
of their choosing.
@@ -1910,6 +1911,12 @@
the behavior will be as though no app was named as an explicit default. -->
<string name="default_browser" translatable="false"></string>
+ <!-- Default role holders. This will be an array of roles and package names of their default
+ holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". -->
+ <string-array name="config_defaultRoleHolders" translatable="false">
+ <item>android.app.role.SMS: com.android.messaging</item>
+ </string-array>
+
<!-- Enable/disable default bluetooth profiles:
HSP_AG, ObexObjectPush, Audio, NAP -->
<bool name="config_bluetooth_default_profiles">true</bool>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b3b30e9..777886a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2985,6 +2985,11 @@
<public name="system_notification_accent_color" />
</public-group>
+ <public-group type="array" first-id="0x01070006">
+ <!-- @hide @SystemApi -->
+ <public name="config_defaultRoleHolders" />
+ </public-group>
+
<!-- ===============================================================
DO NOT ADD UN-GROUPED ITEMS HERE
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index eb0a7a1..9317cff 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -325,6 +325,7 @@
<java-symbol type="bool" name="config_forceDefaultOrientation" />
<java-symbol type="bool" name="config_wifi_batched_scan_supported" />
<java-symbol type="bool" name="config_wifi_softap_acs_supported" />
+ <java-symbol type="string" name="config_wifi_softap_acs_supported_channel_list" />
<java-symbol type="bool" name="config_wifi_softap_ieee80211ac_supported" />
<java-symbol type="bool" name="config_enableMultiUserUI"/>
<java-symbol type="bool" name="config_enableNewAutoSelectNetworkUI"/>
@@ -458,9 +459,7 @@
<java-symbol type="integer" name="config_toastDefaultGravity" />
<java-symbol type="integer" name="config_triplePressOnPowerBehavior" />
<java-symbol type="integer" name="config_shortPressOnSleepBehavior" />
- <java-symbol type="integer" name="config_wifi_framework_scan_interval" />
<java-symbol type="integer" name="config_wifi_supplicant_scan_interval" />
- <java-symbol type="integer" name="config_wifi_no_network_periodic_scan_interval" />
<java-symbol type="integer" name="config_wifi_scan_interval_p2p_connected" />
<java-symbol type="integer" name="config_windowOutsetBottom" />
<java-symbol type="integer" name="db_connection_pool_size" />
@@ -1880,6 +1879,7 @@
<java-symbol type="bool" name="config_wifi_dual_band_support" />
<java-symbol type="bool" name="config_wifi_convert_apband_5ghz_to_any" />
<java-symbol type="bool" name="config_wifi_local_only_hotspot_5ghz" />
+ <java-symbol type="bool" name="config_wifi_connected_mac_randomization_supported" />
<java-symbol type="bool" name="config_wifi_fast_bss_transition_enabled" />
<java-symbol type="bool" name="config_wimaxEnabled" />
<java-symbol type="bool" name="show_ongoing_ime_switcher" />
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index a2f0eba..6ecb63a 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -115,7 +115,7 @@
}
@Override
- void flush() {
+ void flush(int reason) {
throw new UnsupportedOperationException("should not have been called");
}
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 6b9ebd3..1655e89 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1643,10 +1643,6 @@
// The overlay must reside of the product partition or must have existed on the product
// partition before an upgrade to overlay these resources.
POLICY_PRODUCT_PARTITION = 0x00000008,
-
- // The overlay must reside of the product services partition or must have existed on the product
- // services partition before an upgrade to overlay these resources.
- POLICY_PRODUCT_SERVICES_PARTITION = 0x00000010,
};
uint32_t policy_flags;
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index 2e386a0..b8d3c6b 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -312,7 +312,6 @@
EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable"));
EXPECT_THAT(info->policy_flags,
Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION
- | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION
| ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION));
info = package->GetOverlayableInfo(overlayable::R::string::overlayable4);
diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk
index 8634747..047e6af 100644
--- a/libs/androidfw/tests/data/overlayable/overlayable.apk
+++ b/libs/androidfw/tests/data/overlayable/overlayable.apk
Binary files differ
diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
index dba7b08..fcdbe94 100644
--- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
+++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml
@@ -32,9 +32,9 @@
</overlayable>
<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable">
- <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of
+ <!-- Any overlay on the vendor or product partition can overlay the value of
@string/overlayable3 -->
- <policy type="product_services|vendor|product">
+ <policy type="vendor|product">
<item type="string" name="overlayable3" />
</policy>
</overlayable>
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 33f81f1..92afe7e 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -61,7 +61,8 @@
* been read yet. Data should be read from the audio hardware in chunks of sizes inferior to
* the total recording buffer size.
*/
-public class AudioRecord implements AudioRouting, AudioRecordingMonitor, AudioRecordingMonitorClient
+public class AudioRecord implements AudioRouting, MicrophoneDirection,
+ AudioRecordingMonitor, AudioRecordingMonitorClient
{
//---------------------------------------------------------
// Constants
@@ -1657,7 +1658,6 @@
return activeMicrophones;
}
-
//--------------------------------------------------------------------------
// Implementation of AudioRecordingMonitor interface
//--------------------
@@ -1707,6 +1707,33 @@
return native_getPortId();
}
+ //--------------------------------------------------------------------------
+ // MicrophoneDirection
+ //--------------------
+ /**
+ * Specifies the logical microphone (for processing).
+ *
+ * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+ * @return retval OK if the call is successful, an error code otherwise.
+ * @hide
+ */
+ public int setMicrophoneDirection(int direction) {
+ return native_set_microphone_direction(direction);
+ }
+
+ /**
+ * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+ * (for processing). The selected microphone is determined by the use-case for the stream.
+ *
+ * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+ * though 0 (no zoom) to 1 (maximum zoom).
+ * @return retval OK if the call is successful, an error code otherwise.
+ * @hide
+ */
+ public int setMicrophoneFieldDimension(float zoom) {
+ return native_set_microphone_field_dimension(zoom);
+ }
+
//---------------------------------------------------------
// Interface definitions
//--------------------
@@ -1860,6 +1887,9 @@
private native int native_getPortId();
+ private native int native_set_microphone_direction(int direction);
+ private native int native_set_microphone_field_dimension(float zoom);
+
//---------------------------------------------------------
// Utility methods
//------------------
diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java
index bc9500d..f756658 100644
--- a/media/java/android/media/MediaCodec.java
+++ b/media/java/android/media/MediaCodec.java
@@ -1829,9 +1829,14 @@
mBufferLock = new Object();
+ // save name used at creation
+ mNameAtCreation = nameIsType ? null : name;
+
native_setup(name, nameIsType, encoder);
}
+ private String mNameAtCreation;
+
@Override
protected void finalize() {
native_finalize();
@@ -3317,12 +3322,36 @@
private native void native_setAudioPresentation(int presentationId, int programId);
/**
- * Get the component name. If the codec was created by createDecoderByType
- * or createEncoderByType, what component is chosen is not known beforehand.
+ * Retrieve the codec name.
+ *
+ * If the codec was created by createDecoderByType or createEncoderByType, what component is
+ * chosen is not known beforehand. This method returns the name of the codec that was
+ * selected by the platform.
+ *
+ * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+ * names) for the same underlying codec, any of which can be used to instantiate the same
+ * underlying codec in {@link MediaCodec#createByCodecName}. This method returns the
+ * name used to create the codec in this case.
+ *
* @throws IllegalStateException if in the Released state.
*/
@NonNull
- public native final String getName();
+ public final String getName() {
+ // get canonical name to handle exception
+ String canonicalName = getCanonicalName();
+ return mNameAtCreation != null ? mNameAtCreation : canonicalName;
+ }
+
+ /**
+ * Retrieve the underlying codec name.
+ *
+ * This method is similar to {@link #getName}, except that it returns the underlying component
+ * name even if an alias was used to create this MediaCodec object by name,
+ *
+ * @throws IllegalStateException if in the Released state.
+ */
+ @NonNull
+ public native final String getCanonicalName();
/**
* Return Metrics data about the current codec instance.
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 01def96..751d57b 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -32,8 +32,10 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.Vector;
/**
* Provides information about a given media codec available on the device. You can
@@ -61,15 +63,25 @@
*
*/
public final class MediaCodecInfo {
- private boolean mIsEncoder;
+ private static final String TAG = "MediaCodecInfo";
+
+ private static final int FLAG_IS_ENCODER = (1 << 0);
+ private static final int FLAG_IS_VENDOR = (1 << 1);
+ private static final int FLAG_IS_SOFTWARE_ONLY = (1 << 2);
+ private static final int FLAG_IS_HARDWARE_ACCELERATED = (1 << 3);
+
+ private int mFlags;
private String mName;
+ private String mCanonicalName;
private Map<String, CodecCapabilities> mCaps;
/* package private */ MediaCodecInfo(
- String name, boolean isEncoder, CodecCapabilities[] caps) {
+ String name, String canonicalName, int flags, CodecCapabilities[] caps) {
mName = name;
- mIsEncoder = isEncoder;
+ mCanonicalName = canonicalName;
+ mFlags = flags;
mCaps = new HashMap<String, CodecCapabilities>();
+
for (CodecCapabilities c: caps) {
mCaps.put(c.getMimeType(), c);
}
@@ -77,16 +89,69 @@
/**
* Retrieve the codec name.
+ *
+ * <strong>Note:</strong> Implementations may provide multiple aliases (codec
+ * names) for the same underlying codec, any of which can be used to instantiate the same
+ * underlying codec in {@link MediaCodec#createByCodecName}.
+ *
+ * Applications targeting SDK < {@link android.os.Build.VERSION_CODES#Q}, cannot determine if
+ * the multiple codec names listed in MediaCodecList are in-fact for the same codec.
*/
+ @NonNull
public final String getName() {
return mName;
}
/**
+ * Retrieve the underlying codec name.
+ *
+ * Device implementations may provide multiple aliases (codec names) for the same underlying
+ * codec to maintain backward app compatibility. This method returns the name of the underlying
+ * codec name, which must not be another alias. For non-aliases this is always the name of the
+ * codec.
+ */
+ @NonNull
+ public final String getCanonicalName() {
+ return mCanonicalName;
+ }
+
+ /**
+ * Query if the codec is an alias for another underlying codec.
+ */
+ public final boolean isAlias() {
+ return !mName.equals(mCanonicalName);
+ }
+
+ /**
* Query if the codec is an encoder.
*/
public final boolean isEncoder() {
- return mIsEncoder;
+ return (mFlags & FLAG_IS_ENCODER) != 0;
+ }
+
+ /**
+ * Query if the codec is provided by the Android platform (false) or the device manufacturer
+ * (true).
+ */
+ public final boolean isVendor() {
+ return (mFlags & FLAG_IS_VENDOR) != 0;
+ }
+
+ /**
+ * Query if the codec is software only. Software-only codecs are more secure as they run in
+ * a tighter security sandbox. On the other hand, software-only codecs do not provide any
+ * performance guarantees.
+ */
+ public final boolean isSoftwareOnly() {
+ return (mFlags & FLAG_IS_SOFTWARE_ONLY) != 0;
+ }
+
+ /**
+ * Query if the codec is hardware accelerated. This attribute is provided by the device
+ * manufacturer. Note that it cannot be tested for correctness.
+ */
+ public final boolean isHardwareAccelerated() {
+ return (mFlags & FLAG_IS_HARDWARE_ACCELERATED) != 0;
}
/**
@@ -461,6 +526,26 @@
public static final String FEATURE_TunneledPlayback = "tunneled-playback";
/**
+ * If true, the timestamp of each output buffer is derived from the timestamp of the input
+ * buffer that produced the output. If false, the timestamp of each output buffer is
+ * derived from the timestamp of the first input buffer.
+ */
+ public static final String FEATURE_DynamicTimestamp = "dynamic-timestamp";
+
+ /**
+ * <b>decoder only</b>If true, the codec supports partial (including multiple) access units
+ * per input buffer.
+ */
+ public static final String FEATURE_FrameParsing = "frame-parsing";
+
+ /**
+ * If true, the codec supports multiple access units (for decoding, or to output for
+ * encoders). If false, the codec only supports single access units. Producing multiple
+ * access units for output is an optional feature.
+ */
+ public static final String FEATURE_MultipleFrames = "multiple-frames";
+
+ /**
* <b>video decoder only</b>: codec supports queuing partial frames.
*/
public static final String FEATURE_PartialFrame = "partial-frame";
@@ -496,10 +581,15 @@
new Feature(FEATURE_SecurePlayback, (1 << 1), false),
new Feature(FEATURE_TunneledPlayback, (1 << 2), false),
new Feature(FEATURE_PartialFrame, (1 << 3), false),
+ new Feature(FEATURE_FrameParsing, (1 << 4), false),
+ new Feature(FEATURE_MultipleFrames, (1 << 5), false),
+ new Feature(FEATURE_DynamicTimestamp, (1 << 6), false),
};
private static final Feature[] encoderFeatures = {
new Feature(FEATURE_IntraRefresh, (1 << 0), false),
+ new Feature(FEATURE_MultipleFrames, (1 << 1), false),
+ new Feature(FEATURE_DynamicTimestamp, (1 << 2), false),
};
/** @hide */
@@ -868,7 +958,7 @@
CodecCapabilities ret = new CodecCapabilities(
new CodecProfileLevel[] { pl }, new int[0], true /* encoder */,
- 0 /* flags */, defaultFormat, new MediaFormat() /* info */);
+ defaultFormat, new MediaFormat() /* info */);
if (ret.mError != 0) {
return null;
}
@@ -877,10 +967,10 @@
/* package private */ CodecCapabilities(
CodecProfileLevel[] profLevs, int[] colFmts,
- boolean encoder, int flags,
+ boolean encoder,
Map<String, Object>defaultFormatMap,
Map<String, Object>capabilitiesMap) {
- this(profLevs, colFmts, encoder, flags,
+ this(profLevs, colFmts, encoder,
new MediaFormat(defaultFormatMap),
new MediaFormat(capabilitiesMap));
}
@@ -888,11 +978,11 @@
private MediaFormat mCapabilitiesInfo;
/* package private */ CodecCapabilities(
- CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder, int flags,
+ CodecProfileLevel[] profLevs, int[] colFmts, boolean encoder,
MediaFormat defaultFormat, MediaFormat info) {
final Map<String, Object> map = info.getMap();
colorFormats = colFmts;
- mFlagsVerified = flags;
+ mFlagsVerified = 0; // TODO: remove as it is unused
mDefaultFormat = defaultFormat;
mCapabilitiesInfo = info;
mMime = mDefaultFormat.getString(MediaFormat.KEY_MIME);
@@ -1242,6 +1332,7 @@
private Range<Rational> mBlockAspectRatioRange;
private Range<Long> mBlocksPerSecondRange;
private Map<Size, Range<Long>> mMeasuredFrameRates;
+ private Vector<PerformancePoint> mPerformancePoints;
private Range<Integer> mFrameRateRange;
private int mBlockWidth;
@@ -1523,6 +1614,158 @@
}
/**
+ * Video performance points are a set of standard performance points defined by pixel rate.
+ */
+ public static final class PerformancePoint {
+ /**
+ * Frame width in pixels.
+ */
+ public final int width;
+
+ /**
+ * Frame height in pixels.
+ */
+ public final int height;
+
+ /**
+ * Frame rate in frames per second.
+ */
+ public final int frameRate;
+
+ /* package private */
+ PerformancePoint(int width_, int height_, int frameRate_) {
+ width = width_;
+ height = height_;
+ frameRate = frameRate_;
+ }
+
+ /**
+ * Checks whether the performance point covers a media format.
+ *
+ * @param format Stream format considered
+ *
+ * @return {@code true} if the performance point covers the format.
+ */
+ public boolean covers(@NonNull MediaFormat format) {
+ // for simplicity, this code assumes a 16x16 block size.
+ long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16);
+ long mbps = macroBlocks * frameRate;
+
+ long formatMacroBlocks =
+ (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16)
+ * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16);
+ double formatMbps =
+ Math.ceil(formatMacroBlocks
+ * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue());
+ return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks
+ && formatMbps <= mbps;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof PerformancePoint) {
+ PerformancePoint other = (PerformancePoint)o;
+ return ((long)width * height) == ((long)other.width * other.height)
+ && frameRate == other.frameRate;
+ }
+ return false;
+ }
+
+ /** 480p 24fps */
+ public static final PerformancePoint SD_24 = new PerformancePoint(720, 480, 24);
+ /** 576p 25fps */
+ public static final PerformancePoint SD_25 = new PerformancePoint(720, 576, 25);
+ /** 480p 30fps */
+ public static final PerformancePoint SD_30 = new PerformancePoint(720, 480, 30);
+ /** 480p 48fps */
+ public static final PerformancePoint SD_48 = new PerformancePoint(720, 480, 48);
+ /** 576p 50fps */
+ public static final PerformancePoint SD_50 = new PerformancePoint(720, 576, 50);
+ /** 480p 60fps */
+ public static final PerformancePoint SD_60 = new PerformancePoint(720, 480, 60);
+
+ /** 720p 24fps */
+ public static final PerformancePoint HD_24 = new PerformancePoint(1280, 720, 24);
+ /** 720p 25fps */
+ public static final PerformancePoint HD_25 = new PerformancePoint(1280, 720, 25);
+ /** 720p 30fps */
+ public static final PerformancePoint HD_30 = new PerformancePoint(1280, 720, 30);
+ /** 720p 50fps */
+ public static final PerformancePoint HD_50 = new PerformancePoint(1280, 720, 50);
+ /** 720p 60fps */
+ public static final PerformancePoint HD_60 = new PerformancePoint(1280, 720, 60);
+ /** 720p 100fps */
+ public static final PerformancePoint HD_100 = new PerformancePoint(1280, 720, 100);
+ /** 720p 120fps */
+ public static final PerformancePoint HD_120 = new PerformancePoint(1280, 720, 120);
+ /** 720p 200fps */
+ public static final PerformancePoint HD_200 = new PerformancePoint(1280, 720, 200);
+ /** 720p 240fps */
+ public static final PerformancePoint HD_240 = new PerformancePoint(1280, 720, 240);
+
+ /** 1080p 24fps */
+ public static final PerformancePoint FHD_24 = new PerformancePoint(1920, 1080, 24);
+ /** 1080p 25fps */
+ public static final PerformancePoint FHD_25 = new PerformancePoint(1920, 1080, 25);
+ /** 1080p 30fps */
+ public static final PerformancePoint FHD_30 = new PerformancePoint(1920, 1080, 30);
+ /** 1080p 50fps */
+ public static final PerformancePoint FHD_50 = new PerformancePoint(1920, 1080, 50);
+ /** 1080p 60fps */
+ public static final PerformancePoint FHD_60 = new PerformancePoint(1920, 1080, 60);
+ /** 1080p 100fps */
+ public static final PerformancePoint FHD_100 = new PerformancePoint(1920, 1080, 100);
+ /** 1080p 120fps */
+ public static final PerformancePoint FHD_120 = new PerformancePoint(1920, 1080, 120);
+ /** 1080p 200fps */
+ public static final PerformancePoint FHD_200 = new PerformancePoint(1920, 1080, 200);
+ /** 1080p 240fps */
+ public static final PerformancePoint FHD_240 = new PerformancePoint(1920, 1080, 240);
+
+ /** 2160p 24fps */
+ public static final PerformancePoint UHD_24 = new PerformancePoint(3840, 2160, 24);
+ /** 2160p 25fps */
+ public static final PerformancePoint UHD_25 = new PerformancePoint(3840, 2160, 25);
+ /** 2160p 30fps */
+ public static final PerformancePoint UHD_30 = new PerformancePoint(3840, 2160, 30);
+ /** 2160p 50fps */
+ public static final PerformancePoint UHD_50 = new PerformancePoint(3840, 2160, 50);
+ /** 2160p 60fps */
+ public static final PerformancePoint UHD_60 = new PerformancePoint(3840, 2160, 60);
+ /** 2160p 100fps */
+ public static final PerformancePoint UHD_100 = new PerformancePoint(3840, 2160, 100);
+ /** 2160p 120fps */
+ public static final PerformancePoint UHD_120 = new PerformancePoint(3840, 2160, 120);
+ /** 2160p 200fps */
+ public static final PerformancePoint UHD_200 = new PerformancePoint(3840, 2160, 200);
+ /** 2160p 240fps */
+ public static final PerformancePoint UHD_240 = new PerformancePoint(3840, 2160, 240);
+ }
+
+ /**
+ * Returns the supported performance points. May return {@code null} if the codec did not
+ * publish any performance point information (e.g. the vendor codecs have not been updated
+ * to the latest android release). May return an empty list if the codec published that
+ * if does not guarantee any performance points.
+ * <p>
+ * This is a performance guarantee provided by the device manufacturer for hardware codecs
+ * based on hardware capabilities of the device.
+ * <p>
+ * The returned list is sorted first by decreasing number of pixels, then by decreasing
+ * width, and finally by decreasing frame rate.
+ * Performance points assume a single active codec. For use cases where multiple
+ * codecs are active, should use that highest pixel count, and add the frame rates of
+ * each individual codec.
+ */
+ @Nullable
+ public List<PerformancePoint> getSupportedPerformancePoints() {
+ if (mPerformancePoints == null) {
+ return null;
+ }
+ return new ArrayList<PerformancePoint>(mPerformancePoints);
+ }
+
+ /**
* Returns whether a given video size ({@code width} and
* {@code height}) and {@code frameRate} combination is supported.
*/
@@ -1658,6 +1901,50 @@
mSmallerDimensionUpperLimit = SIZE_RANGE.getUpper();
}
+ private @Nullable Vector<PerformancePoint> getPerformancePoints(Map<String, Object> map) {
+ Vector<PerformancePoint> ret = new Vector<>();
+ final String prefix = "performance-point-";
+ Set<String> keys = map.keySet();
+ for (String key : keys) {
+ // looking for: performance-point-WIDTHxHEIGHT-range
+ if (!key.startsWith(prefix)) {
+ continue;
+ }
+ String subKey = key.substring(prefix.length());
+ if (subKey.equals("none") && ret.size() == 0) {
+ // This means that component knowingly did not publish performance points.
+ // This is different from when the component forgot to publish performance
+ // points.
+ return ret;
+ }
+ String[] temp = key.split("-");
+ if (temp.length != 4) {
+ continue;
+ }
+ String sizeStr = temp[2];
+ Size size = Utils.parseSize(sizeStr, null);
+ if (size == null || size.getWidth() * size.getHeight() <= 0) {
+ continue;
+ }
+ Range<Long> range = Utils.parseLongRange(map.get(key), null);
+ if (range == null || range.getLower() < 0 || range.getUpper() < 0) {
+ continue;
+ }
+ ret.add(new PerformancePoint(
+ size.getWidth(), size.getHeight(), range.getLower().intValue()));
+ }
+ // check if the component specified no performance point indication
+ if (ret.size() == 0) {
+ return null;
+ }
+
+ // sort reversed by area first, then by frame rate
+ ret.sort((a, b) -> (a.width * a.height != b.width * b.height ?
+ (b.width * b.height - a.width * a.height) :
+ (b.frameRate - a.frameRate)));
+ return ret;
+ }
+
private Map<Size, Range<Long>> getMeasuredFrameRates(Map<String, Object> map) {
Map<Size, Range<Long>> ret = new HashMap<Size, Range<Long>>();
final String prefix = "measured-frame-rate-";
@@ -1769,6 +2056,7 @@
blockRates =
Utils.parseLongRange(map.get("blocks-per-second-range"), null);
mMeasuredFrameRates = getMeasuredFrameRates(map);
+ mPerformancePoints = getPerformancePoints(map);
Pair<Range<Integer>, Range<Integer>> sizeRanges =
parseWidthHeightRanges(map.get("size-range"));
if (sizeRanges != null) {
@@ -3172,7 +3460,7 @@
}
return new MediaCodecInfo(
- mName, mIsEncoder,
+ mName, mCanonicalName, mFlags,
caps.toArray(new CodecCapabilities[caps.size()]));
}
}
diff --git a/media/java/android/media/MediaCodecList.java b/media/java/android/media/MediaCodecList.java
index 2e47865..a460954 100644
--- a/media/java/android/media/MediaCodecList.java
+++ b/media/java/android/media/MediaCodecList.java
@@ -111,12 +111,14 @@
caps[typeIx++] = getCodecCapabilities(index, type);
}
return new MediaCodecInfo(
- getCodecName(index), isEncoder(index), caps);
+ getCodecName(index), getCanonicalName(index), getAttributes(index), caps);
}
/* package private */ static native final String getCodecName(int index);
- /* package private */ static native final boolean isEncoder(int index);
+ /* package private */ static native final String getCanonicalName(int index);
+
+ /* package private */ static native final int getAttributes(int index);
/* package private */ static native final String[] getSupportedTypes(int index);
diff --git a/media/java/android/media/MicrophoneDirection.java b/media/java/android/media/MicrophoneDirection.java
new file mode 100644
index 0000000..99201c0
--- /dev/null
+++ b/media/java/android/media/MicrophoneDirection.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * @hide
+ */
+public interface MicrophoneDirection {
+ /**
+ * @hide
+ */
+ int MIC_DIRECTION_UNSPECIFIED = 0;
+
+ /**
+ * @hide
+ */
+ int MIC_DIRECTION_FRONT = 1;
+
+ /**
+ * @hide
+ */
+ int MIC_DIRECTION_BACK = 2;
+
+ /**
+ * @hide
+ */
+ int MIC_DIRECTION_EXTERNAL = 3;
+
+ /**
+ * Specifies the logical microphone (for processing).
+ *
+ * @param direction Direction constant (MicrophoneDirection.MIC_DIRECTION_*)
+ * @return retval OK if the call is successful, an error code otherwise.
+ * @hide
+ */
+ int setMicrophoneDirection(int direction);
+
+ /**
+ * Specifies the zoom factor (i.e. the field dimension) for the selected microphone
+ * (for processing). The selected microphone is determined by the use-case for the stream.
+ *
+ * @param zoom the desired field dimension of microphone capture. Range is from -1 (wide angle),
+ * though 0 (no zoom) to 1 (maximum zoom).
+ * @return retval OK if the call is successful, an error code otherwise.
+ * @hide
+ */
+ int setMicrophoneFieldDimension(float zoom);
+}
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 7b07bea3..9c51996 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -648,7 +648,6 @@
capabilities->getSupportedColorFormats(&colorFormats);
capabilities->getSupportedProfileLevels(&profileLevels);
- uint32_t flags = capabilities->getFlags();
sp<AMessage> details = capabilities->getDetails();
jobject defaultFormatObj = NULL;
@@ -687,7 +686,7 @@
return env->NewObject(
gCodecInfo.capsClazz, gCodecInfo.capsCtorId,
- profileLevelArray.get(), colorFormatsArray.get(), isEncoder, flags,
+ profileLevelArray.get(), colorFormatsArray.get(), isEncoder,
defaultFormatRef.get(), detailsRef.get());
}
@@ -700,23 +699,28 @@
return err;
}
+ // TODO: get alias
ScopedLocalRef<jstring> nameObject(env,
env->NewStringUTF(codecInfo->getCodecName()));
+ ScopedLocalRef<jstring> canonicalNameObject(env,
+ env->NewStringUTF(codecInfo->getCodecName()));
+
+ MediaCodecInfo::Attributes attributes = codecInfo->getAttributes();
bool isEncoder = codecInfo->isEncoder();
- Vector<AString> mimes;
- codecInfo->getSupportedMimes(&mimes);
+ Vector<AString> mediaTypes;
+ codecInfo->getSupportedMediaTypes(&mediaTypes);
ScopedLocalRef<jobjectArray> capsArrayObj(env,
- env->NewObjectArray(mimes.size(), gCodecInfo.capsClazz, NULL));
+ env->NewObjectArray(mediaTypes.size(), gCodecInfo.capsClazz, NULL));
- for (size_t i = 0; i < mimes.size(); i++) {
+ for (size_t i = 0; i < mediaTypes.size(); i++) {
const sp<MediaCodecInfo::Capabilities> caps =
- codecInfo->getCapabilitiesFor(mimes[i].c_str());
+ codecInfo->getCapabilitiesFor(mediaTypes[i].c_str());
ScopedLocalRef<jobject> capsObj(env, getCodecCapabilitiesObject(
- env, mimes[i].c_str(), isEncoder, caps));
+ env, mediaTypes[i].c_str(), isEncoder, caps));
env->SetObjectArrayElement(capsArrayObj.get(), i, capsObj.get());
}
@@ -729,7 +733,7 @@
"(Ljava/lang/String;Z[Landroid/media/MediaCodecInfo$CodecCapabilities;)V");
*codecInfoObject = env->NewObject(codecInfoClazz.get(), codecInfoCtorID,
- nameObject.get(), isEncoder, capsArrayObj.get());
+ nameObject.get(), canonicalNameObject.get(), attributes, capsArrayObj.get());
return OK;
}
@@ -2079,7 +2083,7 @@
gCodecInfo.capsClazz = (jclass)env->NewGlobalRef(clazz.get());
method = env->GetMethodID(clazz.get(), "<init>",
- "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+ "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
"Ljava/util/Map;Ljava/util/Map;)V");
CHECK(method != NULL);
gCodecInfo.capsCtorId = method;
@@ -2217,7 +2221,7 @@
{ "getImage", "(ZI)Landroid/media/Image;",
(void *)android_media_MediaCodec_getImage },
- { "getName", "()Ljava/lang/String;",
+ { "getCanonicalName", "()Ljava/lang/String;",
(void *)android_media_MediaCodec_getName },
{ "getOwnCodecInfo", "()Landroid/media/MediaCodecInfo;",
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 8de11ca..cf14942 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -41,6 +41,21 @@
return mcl;
}
+static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) {
+ sp<IMediaCodecList> mcl = getCodecList(env);
+ if (mcl == NULL) {
+ // Runtime exception already pending.
+ return NULL;
+ }
+
+ sp<MediaCodecInfo> info = mcl->getCodecInfo(index);
+ if (info == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ }
+
+ return info;
+}
+
static jint android_media_MediaCodecList_getCodecCount(
JNIEnv *env, jobject /* thiz */) {
sp<IMediaCodecList> mcl = getCodecList(env);
@@ -53,15 +68,22 @@
static jstring android_media_MediaCodecList_getCodecName(
JNIEnv *env, jobject /* thiz */, jint index) {
- sp<IMediaCodecList> mcl = getCodecList(env);
- if (mcl == NULL) {
+ sp<MediaCodecInfo> info = getCodecInfo(env, index);
+ if (info == NULL) {
// Runtime exception already pending.
return NULL;
}
- const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+ // TODO: support aliases
+ const char *name = info->getCodecName();
+ return env->NewStringUTF(name);
+}
+
+static jstring android_media_MediaCodecList_getCanonicalName(
+ JNIEnv *env, jobject /* thiz */, jint index) {
+ sp<MediaCodecInfo> info = getCodecInfo(env, index);
if (info == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ // Runtime exception already pending.
return NULL;
}
@@ -94,39 +116,27 @@
return ret;
}
-static jboolean android_media_MediaCodecList_isEncoder(
+static jboolean android_media_MediaCodecList_getAttributes(
JNIEnv *env, jobject /* thiz */, jint index) {
- sp<IMediaCodecList> mcl = getCodecList(env);
- if (mcl == NULL) {
- // Runtime exception already pending.
- return false;
- }
-
- const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
+ sp<MediaCodecInfo> info = getCodecInfo(env, index);
if (info == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return false;
+ // Runtime exception already pending.
+ return 0;
}
- return info->isEncoder();
+ return info->getAttributes();
}
static jarray android_media_MediaCodecList_getSupportedTypes(
JNIEnv *env, jobject /* thiz */, jint index) {
- sp<IMediaCodecList> mcl = getCodecList(env);
- if (mcl == NULL) {
+ sp<MediaCodecInfo> info = getCodecInfo(env, index);
+ if (info == NULL) {
// Runtime exception already pending.
return NULL;
}
- const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
- if (info == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return NULL;
- }
-
Vector<AString> types;
- info->getSupportedMimes(&types);
+ info->getSupportedMediaTypes(&types);
jclass clazz = env->FindClass("java/lang/String");
CHECK(clazz != NULL);
@@ -150,17 +160,12 @@
return NULL;
}
- sp<IMediaCodecList> mcl = getCodecList(env);
- if (mcl == NULL) {
+ sp<MediaCodecInfo> info = getCodecInfo(env, index);
+ if (info == NULL) {
// Runtime exception already pending.
return NULL;
}
- const sp<MediaCodecInfo> &info = mcl->getCodecInfo(index);
- if (info == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
- return NULL;
- }
const char *typeStr = env->GetStringUTFChars(type, NULL);
if (typeStr == NULL) {
@@ -186,7 +191,6 @@
capabilities->getSupportedColorFormats(&colorFormats);
capabilities->getSupportedProfileLevels(&profileLevels);
- uint32_t flags = capabilities->getFlags();
sp<AMessage> details = capabilities->getDetails();
bool isEncoder = info->isEncoder();
@@ -240,11 +244,11 @@
}
jmethodID capsConstructID = env->GetMethodID(capsClazz, "<init>",
- "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZI"
+ "([Landroid/media/MediaCodecInfo$CodecProfileLevel;[IZ"
"Ljava/util/Map;Ljava/util/Map;)V");
jobject caps = env->NewObject(capsClazz, capsConstructID,
- profileLevelArray, colorFormatsArray, isEncoder, flags,
+ profileLevelArray, colorFormatsArray, isEncoder,
defaultFormatObj, infoObj);
env->DeleteLocalRef(profileLevelArray);
@@ -288,9 +292,15 @@
static const JNINativeMethod gMethods[] = {
{ "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
+
+ { "getCanonicalName", "(I)Ljava/lang/String;",
+ (void *)android_media_MediaCodecList_getCanonicalName },
+
{ "getCodecName", "(I)Ljava/lang/String;",
(void *)android_media_MediaCodecList_getCodecName },
- { "isEncoder", "(I)Z", (void *)android_media_MediaCodecList_isEncoder },
+
+ { "getAttributes", "(I)I", (void *)android_media_MediaCodecList_getAttributes },
+
{ "getSupportedTypes", "(I)[Ljava/lang/String;",
(void *)android_media_MediaCodecList_getSupportedTypes },
diff --git a/packages/SystemUI/res-keyguard/layout/type_clock.xml b/packages/SystemUI/res-keyguard/layout/type_clock.xml
new file mode 100644
index 0000000..21c64e9
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/type_clock.xml
@@ -0,0 +1,55 @@
+<?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.
+ -->
+<com.android.keyguard.clock.ClockLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <com.android.keyguard.clock.TypographicClock
+ android:id="@+id/type_clock"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ >
+ <TextView
+ android:id="@+id/header"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="50dp"
+ style="@style/widget_big"
+ android:textColor="@color/typeClockAccentColor"
+ android:text="@string/type_clock_header"
+ android:textSize="40dp"
+ />
+ <TextView
+ android:id="@+id/hour"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="50dp"
+ style="@style/widget_big"
+ android:textSize="40dp"
+ />
+ <TextView
+ android:id="@+id/minute"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="50dp"
+ style="@style/widget_big"
+ android:textSize="40dp"
+ />
+ </com.android.keyguard.clock.TypographicClock>
+</com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/values/colors.xml b/packages/SystemUI/res-keyguard/values/colors.xml
index 7a849eb..74ee7ff 100644
--- a/packages/SystemUI/res-keyguard/values/colors.xml
+++ b/packages/SystemUI/res-keyguard/values/colors.xml
@@ -19,4 +19,6 @@
<color name="bubbleHourHandColor">#C97343</color>
<!-- Default color for minute hand of Bubble clock. -->
<color name="bubbleMinuteHandColor">#F5C983</color>
+ <!-- Accent color for Typographic clock. -->
+ <color name="typeClockAccentColor">#F5C983</color>
</resources>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 1d5aa6d..7432f9c 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -402,4 +402,87 @@
number">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact carrier for details.</item>
</plurals>
+ <!-- Header for typographic clock face. [CHAR LIMIT=8] -->
+ <string name="type_clock_header">It\u2019s</string>
+
+ <!-- Hour displayed in words on the typographic clock face. [CHAR LIMIT=8] -->
+ <string-array name="type_clock_hours">
+ <item>Twelve</item>
+ <item>One</item>
+ <item>Two</item>
+ <item>Three</item>
+ <item>Four</item>
+ <item>Five</item>
+ <item>Six</item>
+ <item>Seven</item>
+ <item>Eight</item>
+ <item>Nine</item>
+ <item>Ten</item>
+ <item>Eleven</item>
+ </string-array>
+
+ <!-- Minutes displayed in words on the typographic clock face. [CHAR LIMIT=16] -->
+ <string-array name="type_clock_minutes">
+ <item>O\u2019Clock</item>
+ <item>O\u2019One</item>
+ <item>O\u2019Two</item>
+ <item>O\u2019Three</item>
+ <item>O\u2019Four</item>
+ <item>O\u2019Five</item>
+ <item>O\u2019Six</item>
+ <item>O\u2019Seven</item>
+ <item>O\u2019Eight</item>
+ <item>O\u2019Nine</item>
+ <item>Ten</item>
+ <item>Eleven</item>
+ <item>Twelve</item>
+ <item>Thirteen</item>
+ <item>Fourteen</item>
+ <item>Fifteen</item>
+ <item>Sixteen</item>
+ <item>Seventeen</item>
+ <item>Eighteen</item>
+ <item>Nineteen</item>
+ <item>Twenty</item>
+ <item>Twenty\nOne</item>
+ <item>Twenty\nTwo</item>
+ <item>Twenty\nThree</item>
+ <item>Twenty\nFour</item>
+ <item>Twenty\nFive</item>
+ <item>Twenty\nSix</item>
+ <item>Twenty\nSeven</item>
+ <item>Twenty\nEight</item>
+ <item>Twenty\nNine</item>
+ <item>Thirty</item>
+ <item>Thirty\nOne</item>
+ <item>Thirty\nTwo</item>
+ <item>Thirty\nThree</item>
+ <item>Thirty\nFour</item>
+ <item>Thirty\nFive</item>
+ <item>Thirty\nSix</item>
+ <item>Thirty\nSeven</item>
+ <item>Thirty\nEight</item>
+ <item>Thirty\nNine</item>
+ <item>Forty</item>
+ <item>Forty\nOne</item>
+ <item>Forty\nTwo</item>
+ <item>Forty\nThree</item>
+ <item>Forty\nFour</item>
+ <item>Forty\nFive</item>
+ <item>Forty\nSix</item>
+ <item>Forty\nSeven</item>
+ <item>Forty\nEight</item>
+ <item>Forty\nNine</item>
+ <item>Fifty</item>
+ <item>Fifty\nOne</item>
+ <item>Fifty\nTwo</item>
+ <item>Fifty\nThree</item>
+ <item>Fifty\nFour</item>
+ <item>Fifty\nFive</item>
+ <item>Fifty\nSix</item>
+ <item>Fifty\nSeven</item>
+ <item>Fifty\nEight</item>
+ <item>Fifty\nNine</item>
+ </string-array>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index e9ce1a6..1aff394 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -20,6 +20,7 @@
import com.android.keyguard.clock.BubbleClockController;
import com.android.keyguard.clock.StretchAnalogClockController;
+import com.android.keyguard.clock.TypeClockController;
import com.android.systemui.Dependency;
import com.android.systemui.plugins.ClockPlugin;
import com.android.systemui.statusbar.StatusBarState;
@@ -153,6 +154,12 @@
Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
StretchAnalogClockController.class.getName(),
() -> StretchAnalogClockController.build(mLayoutInflater)))
+ .withDefault(
+ new SettingsGattedSupplier(
+ mContentResolver,
+ Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE,
+ TypeClockController.class.getName(),
+ () -> TypeClockController.build(mLayoutInflater)))
.build();
mContentResolver.registerContentObserver(
Settings.Secure.getUriFor(Settings.Secure.LOCK_SCREEN_CUSTOM_CLOCK_FACE),
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 5aa5668..3591dc8 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -36,6 +36,7 @@
*/
private View mDigitalClock;
private View mAnalogClock;
+ private View mTypeClock;
/**
* Pixel shifting amplitidues used to prevent screen burn-in.
@@ -60,6 +61,7 @@
super.onFinishInflate();
mDigitalClock = findViewById(R.id.digital_clock);
mAnalogClock = findViewById(R.id.analog_clock);
+ mTypeClock = findViewById(R.id.type_clock);
// Get pixel shifting X, Y amplitudes from resources.
Resources resources = getResources();
@@ -89,5 +91,11 @@
mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
+ offsetY);
}
+
+ // Put the typographic clock part way down the screen.
+ if (mTypeClock != null) {
+ mTypeClock.setX(offsetX);
+ mTypeClock.setY(0.2f * getHeight() + offsetY);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
index 91cec863..87347545 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -80,6 +80,7 @@
*/
public void setMinuteHandColor(int color) {
mMinutePaint.setColor(color);
+ invalidate();
}
private void init() {
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
new file mode 100644
index 0000000..17d929d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
@@ -0,0 +1,106 @@
+/*
+ * 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.keyguard.clock;
+
+import android.graphics.Paint.Style;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import com.android.keyguard.R;
+import com.android.systemui.plugins.ClockPlugin;
+
+import java.util.TimeZone;
+
+/**
+ * Plugin for a custom Typographic clock face that displays the time in words.
+ */
+public class TypeClockController implements ClockPlugin {
+
+ /**
+ * Custom clock shown on AOD screen and behind stack scroller on lock.
+ */
+ private View mView;
+ private TypographicClock mTypeClock;
+
+ /**
+ * Small clock shown on lock screen above stack scroller.
+ */
+ private View mLockClockContainer;
+
+ /**
+ * Controller for transition into dark state.
+ */
+ private CrossFadeDarkController mDarkController;
+
+ private TypeClockController() {}
+
+ /**
+ * Create a TypeClockController instance.
+ *
+ * @param inflater Inflater used to inflate custom clock views.
+ */
+ public static TypeClockController build(LayoutInflater inflater) {
+ TypeClockController controller = new TypeClockController();
+ controller.createViews(inflater);
+ return controller;
+ }
+
+ private void createViews(LayoutInflater inflater) {
+ mView = inflater.inflate(R.layout.type_clock, null);
+ mTypeClock = mView.findViewById(R.id.type_clock);
+
+ // For now, this view is used to hide the default digital clock.
+ // Need better transition to lock screen.
+ mLockClockContainer = inflater.inflate(R.layout.digital_clock, null);
+ mLockClockContainer.setVisibility(View.GONE);
+ }
+
+ @Override
+ public View getView() {
+ return mLockClockContainer;
+ }
+
+ @Override
+ public View getBigClockView() {
+ return mView;
+ }
+
+ @Override
+ public void setStyle(Style style) {}
+
+ @Override
+ public void setTextColor(int color) {
+ mTypeClock.setTextColor(color);
+ }
+
+ @Override
+ public void dozeTimeTick() {
+ mTypeClock.onTimeChanged();
+ }
+
+ @Override
+ public void setDarkAmount(float darkAmount) {}
+
+ @Override
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mTypeClock.onTimeZoneChanged(timeZone);
+ }
+
+ @Override
+ public boolean shouldShowStatusArea() {
+ return false;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
new file mode 100644
index 0000000..5f9da3e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
@@ -0,0 +1,110 @@
+/*
+ * 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.keyguard.clock;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.text.format.DateFormat;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.keyguard.R;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * Clock that presents the time in words.
+ */
+public class TypographicClock extends LinearLayout {
+
+ private final String[] mHours;
+ private final String[] mMinutes;
+ private TextView mHeaderText;
+ private TextView mHourText;
+ private TextView mMinuteText;
+ private Calendar mTime;
+ private String mDescFormat;
+ private TimeZone mTimeZone;
+
+ public TypographicClock(Context context) {
+ this(context, null);
+ }
+
+ public TypographicClock(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public TypographicClock(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mTime = Calendar.getInstance();
+ mDescFormat = ((SimpleDateFormat) DateFormat.getTimeFormat(context)).toLocalizedPattern();
+ Resources res = context.getResources();
+ mHours = res.getStringArray(R.array.type_clock_hours);
+ mMinutes = res.getStringArray(R.array.type_clock_minutes);
+ }
+
+ /**
+ * Call when the time changes to update the text of the time.
+ */
+ public void onTimeChanged() {
+ mTime.setTimeInMillis(System.currentTimeMillis());
+ setContentDescription(DateFormat.format(mDescFormat, mTime));
+ final int hour = mTime.get(Calendar.HOUR);
+ mHourText.setText(mHours[hour % 12]);
+ final int minute = mTime.get(Calendar.MINUTE);
+ mMinuteText.setText(mMinutes[minute % 60]);
+ invalidate();
+ }
+
+ /**
+ * Call when the time zone has changed to update clock time.
+ *
+ * @param timeZone The updated time zone that will be used.
+ */
+ public void onTimeZoneChanged(TimeZone timeZone) {
+ mTimeZone = timeZone;
+ mTime.setTimeZone(timeZone);
+ }
+
+ /**
+ * Set the color of the text used to display the time.
+ *
+ * This is necessary when the wallpaper shown behind the clock on the
+ * lock screen changes.
+ */
+ public void setTextColor(int color) {
+ mHourText.setTextColor(color);
+ mMinuteText.setTextColor(color);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mHeaderText = findViewById(R.id.header);
+ mHourText = findViewById(R.id.hour);
+ mMinuteText = findViewById(R.id.minute);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mTime = Calendar.getInstance(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
+ onTimeChanged();
+ }
+}
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 31310f5..32cc0e6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -141,6 +141,7 @@
private KeyguardAffordanceHelper mAffordanceHelper;
private KeyguardUserSwitcher mKeyguardUserSwitcher;
private KeyguardStatusBarView mKeyguardStatusBar;
+ private ViewGroup mBigClockContainer;
private QS mQs;
private FrameLayout mQsFrame;
@VisibleForTesting
@@ -348,8 +349,8 @@
mKeyguardStatusView = findViewById(R.id.keyguard_status_view);
KeyguardClockSwitch keyguardClockSwitch = findViewById(R.id.keyguard_clock_container);
- ViewGroup bigClockContainer = findViewById(R.id.big_clock_container);
- keyguardClockSwitch.setBigClockContainer(bigClockContainer);
+ mBigClockContainer = findViewById(R.id.big_clock_container);
+ keyguardClockSwitch.setBigClockContainer(mBigClockContainer);
mNotificationContainerParent = findViewById(R.id.notification_container_parent);
mNotificationStackScroller = findViewById(R.id.notification_stack_scroller);
@@ -585,6 +586,11 @@
mClockPositionResult.clockX, CLOCK_ANIMATION_PROPERTIES, animateClock);
PropertyAnimator.setProperty(mKeyguardStatusView, AnimatableProperty.Y,
mClockPositionResult.clockY, CLOCK_ANIMATION_PROPERTIES, animateClock);
+ // Move big clock up while pulling up the bouncer
+ PropertyAnimator.setProperty(mBigClockContainer, AnimatableProperty.Y,
+ MathUtils.lerp(-mBigClockContainer.getHeight(), 0,
+ Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(getExpandedFraction())),
+ CLOCK_ANIMATION_PROPERTIES, animateClock);
updateClock();
stackScrollerPadding = mClockPositionResult.stackScrollerPadding;
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index ec6d20d..c992da4 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -252,9 +252,8 @@
@Override // from AbstractMasterSystemService
protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
boolean disabled) {
- return new AutofillManagerServiceImpl(this, mLock, mRequestsHistory,
- mUiLatencyHistory, mWtfHistory, resolvedUserId, mUi, mAutofillCompatState,
- disabled);
+ return new AutofillManagerServiceImpl(this, mLock, mUiLatencyHistory,
+ mWtfHistory, resolvedUserId, mUi, mAutofillCompatState, disabled);
}
@Override // AbstractMasterSystemService
@@ -291,6 +290,13 @@
return mSupportedSmartSuggestionModes;
}
+ /**
+ * Logs a request so it's dumped later...
+ */
+ void logRequestLocked(@NonNull String historyItem) {
+ mRequestsHistory.log(historyItem);
+ }
+
// Called by AutofillManagerServiceImpl, doesn't need to check permission
boolean isInstantServiceAllowed() {
return mAllowInstantService;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d037b08..954b67e 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -108,7 +108,6 @@
private static final Random sRandom = new Random();
- private final LocalLog mRequestsHistory;
private final LocalLog mUiLatencyHistory;
private final LocalLog mWtfHistory;
private final FieldClassificationStrategy mFieldClassificationStrategy;
@@ -166,12 +165,12 @@
@Nullable
private RemoteAugmentedAutofillService mRemoteAugmentedAutofillService;
- AutofillManagerServiceImpl(AutofillManagerService master, Object lock, LocalLog requestsHistory,
+ AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
- AutofillCompatState autofillCompatState, boolean disabled) {
+ AutofillCompatState autofillCompatState,
+ boolean disabled) {
super(master, lock, userId);
- mRequestsHistory = requestsHistory;
mUiLatencyHistory = uiLatencyHistory;
mWtfHistory = wtfHistory;
mUi = ui;
@@ -310,7 +309,7 @@
+ " s=" + mInfo.getServiceInfo().packageName
+ " u=" + mUserId + " i=" + autofillId + " b=" + virtualBounds
+ " hc=" + hasCallback + " f=" + flags;
- mRequestsHistory.log(historyItem);
+ mMaster.logRequestLocked(historyItem);
newSession.updateLocked(autofillId, virtualBounds, value, ACTION_START_SESSION, flags);
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index a5ef21a..7dfd8fe 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2610,6 +2610,13 @@
+ " when server returned null for session " + this.id);
}
+ final String historyItem =
+ "aug:id=" + id + " u=" + uid + " m=" + mode
+ + " a=" + ComponentName.flattenToShortString(mComponentName)
+ + " f=" + mCurrentViewId
+ + " s=" + remoteService.getComponentName();
+ mService.getMaster().logRequestLocked(historyItem);
+
final AutofillValue currentValue = mViewStates.get(mCurrentViewId).getCurrentValue();
// TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index e0e81ff..79f8a7e 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -494,20 +494,18 @@
mUserId);
mBaseStateDir = checkNotNull(baseStateDir, "baseStateDir cannot be null");
- mBaseStateDir.mkdirs();
- if (!SELinux.restoreconRecursive(mBaseStateDir)) {
- Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
- }
-
- mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
- // TODO(b/120424138): Remove when the system user moves out of the cache dir. The cache dir
- // is managed by init.rc so we don't have to create it below.
- if (userId != UserHandle.USER_SYSTEM) {
- mDataDir.mkdirs();
- if (!SELinux.restoreconRecursive(mDataDir)) {
- Slog.w(TAG, "SELinux restorecon failed on " + mDataDir);
+ // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
+ // directory. Per-user CE directories are managed by vold.
+ if (userId == UserHandle.USER_SYSTEM) {
+ mBaseStateDir.mkdirs();
+ if (!SELinux.restorecon(mBaseStateDir)) {
+ Slog.w(TAG, "SELinux restorecon failed on " + mBaseStateDir);
}
}
+
+ // TODO (b/120424138): The system user currently uses the cache which is managed by init.rc
+ // Initialization and restorecon is managed by vold for per-user CE directories.
+ mDataDir = checkNotNull(dataDir, "dataDir cannot be null");
mBackupPasswordManager = new BackupPasswordManager(mContext, mBaseStateDir, mRng);
// Receivers for scheduled backups and transport initialization operations.
diff --git a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
index 862ca71..cfc129e 100644
--- a/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
+++ b/services/backup/java/com/android/server/backup/keyvalue/KeyValueBackupTask.java
@@ -45,6 +45,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.SELinux;
+import android.os.UserHandle;
import android.os.WorkSource;
import com.android.internal.annotations.GuardedBy;
@@ -686,8 +687,12 @@
ParcelFileDescriptor.open(
mNewStateFile, MODE_READ_WRITE | MODE_CREATE | MODE_TRUNCATE);
- if (!SELinux.restorecon(mBackupDataFile)) {
- mReporter.onRestoreconFailed(mBackupDataFile);
+ // TODO (b/120424138): Remove once the system user is migrated to use the per-user CE
+ // directory. Per-user CE directories are managed by vold.
+ if (mUserId == UserHandle.USER_SYSTEM) {
+ if (!SELinux.restorecon(mBackupDataFile)) {
+ mReporter.onRestoreconFailed(mBackupDataFile);
+ }
}
IBackupTransport transport = mTransportClient.connectOrThrow("KVBT.extractAgentData()");
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index dc0f602..e4bbcd6 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -32,6 +32,7 @@
import android.os.ShellCallback;
import android.os.UserHandle;
import android.os.UserManager;
+import android.util.LocalLog;
import android.util.Slog;
import android.view.contentcapture.IContentCaptureManager;
@@ -69,6 +70,8 @@
private final LocalService mLocalService = new LocalService();
+ private final LocalLog mRequestsHistory = new LocalLog(20);
+
public ContentCaptureManagerService(@NonNull Context context) {
super(context, new FrameworkResourcesServiceNameResolver(context,
com.android.internal.R.string.config_defaultContentCaptureService),
@@ -154,6 +157,13 @@
}
}
+ /**
+ * Logs a request so it's dumped later...
+ */
+ void logRequestLocked(@NonNull String historyItem) {
+ mRequestsHistory.log(historyItem);
+ }
+
private ActivityManagerInternal getAmInternal() {
synchronized (mLock) {
if (mAm == null) {
@@ -217,9 +227,29 @@
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(getContext(), TAG, pw)) return;
+ boolean showHistory = true;
+ if (args != null) {
+ for (String arg : args) {
+ switch(arg) {
+ case "--no-history":
+ showHistory = false;
+ break;
+ case "--help":
+ pw.println("Usage: dumpsys content_capture [--no-history]");
+ return;
+ default:
+ Slog.w(TAG, "Ignoring invalid dump arg: " + arg);
+ }
+ }
+ }
+
synchronized (mLock) {
dumpLocked("", pw);
}
+ if (showHistory) {
+ pw.println(); pw.println("Requests history:"); pw.println();
+ mRequestsHistory.reverseDump(fd, pw, args);
+ }
}
@Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index 1dae2ce..8d2c79b 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -85,7 +85,6 @@
ContentCapturePerUserService(@NonNull ContentCaptureManagerService master,
@NonNull Object lock, boolean disabled, @UserIdInt int userId) {
super(master, lock, userId);
-
updateRemoteServiceLocked(disabled);
}
@@ -170,14 +169,24 @@
@NonNull ComponentName componentName, int taskId, int displayId,
@NonNull String sessionId, int uid, int flags,
@NonNull IResultReceiver clientReceiver) {
- if (!isEnabledLocked()) {
+
+ final ComponentName serviceComponentName = getServiceComponentName();
+ final boolean enabled = isEnabledLocked();
+ final String historyItem =
+ "id=" + sessionId + " uid=" + uid
+ + " a=" + ComponentName.flattenToShortString(componentName)
+ + " t=" + taskId + " d=" + displayId
+ + " s=" + ComponentName.flattenToShortString(serviceComponentName)
+ + " u=" + mUserId + " f=" + flags + (enabled ? "" : " (disabled)");
+ mMaster.logRequestLocked(historyItem);
+
+ if (!enabled) {
// TODO: it would be better to split in differet reasons, like
// STATE_DISABLED_NO_SERVICE and STATE_DISABLED_BY_DEVICE_POLICY
setClientState(clientReceiver, STATE_DISABLED | STATE_NO_SERVICE,
/* binder= */ null);
return;
}
- final ComponentName serviceComponentName = getServiceComponentName();
if (serviceComponentName == null) {
// TODO(b/111276913): this happens when the system service is starting, we should
// probably handle it in a more elegant way (like waiting for boot_complete or
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index ebe0083..3c52e17 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -83,6 +83,8 @@
*/
@GuardedBy("mLock")
public void sendActivitySnapshotLocked(@NonNull SnapshotData snapshotData) {
+ mService.getMaster().logRequestLocked("snapshot: id=" + mId);
+
mRemoteService.onActivitySnapshotRequest(mId, snapshotData);
}
diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java
index 16143d3..74fbea1 100644
--- a/services/core/java/com/android/server/om/IdmapManager.java
+++ b/services/core/java/com/android/server/om/IdmapManager.java
@@ -24,11 +24,14 @@
import android.annotation.NonNull;
import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
+import android.os.Build.VERSION_CODES;
import android.os.IBinder;
import android.os.IIdmap2;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.util.Slog;
@@ -51,6 +54,13 @@
private final Installer mInstaller;
private IIdmap2 mIdmap2Service;
+ private static final boolean VENDOR_IS_Q_OR_LATER;
+ static {
+ // STOPSHIP(b/119390857): Check api version once Q sdk version is finalized
+ final String value = SystemProperties.get("ro.vndk.version", "Q");
+ VENDOR_IS_Q_OR_LATER = value.equals("Q") || value.equals("q");
+ }
+
IdmapManager(final Installer installer) {
mInstaller = installer;
if (FEATURE_FLAG_IDMAP2) {
@@ -69,10 +79,13 @@
final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath();
try {
if (FEATURE_FLAG_IDMAP2) {
- if (mIdmap2Service.verifyIdmap(overlayPath, userId)) {
+ int policies = determineFulfilledPolicies(overlayPackage);
+ boolean enforce = enforceOverlayable(overlayPackage);
+ if (mIdmap2Service.verifyIdmap(overlayPath, policies, enforce, userId)) {
return true;
}
- return mIdmap2Service.createIdmap(targetPath, overlayPath, userId) != null;
+ return mIdmap2Service.createIdmap(targetPath, overlayPath, policies, enforce,
+ userId) != null;
} else {
mInstaller.idmap(targetPath, overlayPath, sharedGid);
return true;
@@ -156,4 +169,71 @@
}, SECOND_IN_MILLIS);
}
}
+
+ /**
+ * Checks if overlayable and policies should be enforced on the specified overlay for backwards
+ * compatibility with pre-Q overlays.
+ */
+ private boolean enforceOverlayable(@NonNull final PackageInfo overlayPackage) {
+ final ApplicationInfo ai = overlayPackage.applicationInfo;
+ if (ai.targetSdkVersion >= VERSION_CODES.Q) {
+ // Always enforce policies for overlays targeting Q+.
+ return true;
+ }
+
+ if (ai.isVendor() && !VENDOR_IS_Q_OR_LATER) {
+ // If the overlay is on a pre-Q vendor partition, do not enforce overlayable
+ // restrictions on this overlay because the pre-Q platform has no understanding of
+ // overlayable.
+ return false;
+ }
+
+ // Do not enforce overlayable restrictions on pre-Q overlays signed with the
+ // platform signature.
+ return !ai.isSignedWithPlatformKey();
+ }
+
+ /**
+ * Retrieves a bitmask for idmap2 that represents the policies the specified overlay fulfills.
+ * @throws SecurityException if the overlay is not allowed to overlay any resource
+ */
+ private int determineFulfilledPolicies(@NonNull final PackageInfo overlayPackage)
+ throws SecurityException {
+ final ApplicationInfo ai = overlayPackage.applicationInfo;
+ final boolean overlayIsQOrLater = ai.targetSdkVersion >= VERSION_CODES.Q;
+
+ int fulfilledPolicies = 0;
+
+ // TODO(b/119402606) : Add signature policy
+
+ // Vendor partition (/vendor)
+ if (ai.isVendor()) {
+ if (overlayIsQOrLater) {
+ fulfilledPolicies |= IIdmap2.POLICY_VENDOR_PARTITION;
+ } else if (VENDOR_IS_Q_OR_LATER) {
+ throw new SecurityException("Overlay must target Q sdk or higher");
+ }
+ }
+
+ // Product partition (/product)
+ if (ai.isProduct()) {
+ if (overlayIsQOrLater) {
+ fulfilledPolicies |= IIdmap2.POLICY_PRODUCT_PARTITION;
+ } else {
+ throw new SecurityException("Overlay must target Q sdk or higher");
+ }
+ }
+
+ // System partition (/system)
+ if (ai.isSystemApp()) {
+ if (overlayIsQOrLater) {
+ fulfilledPolicies |= IIdmap2.POLICY_SYSTEM_PARTITION;
+ } else {
+ throw new SecurityException("Overlay must target Q sdk or higher");
+ }
+ }
+
+ // All overlays can overlay resources with the public policy
+ return fulfilledPolicies | IIdmap2.POLICY_PUBLIC;
+ }
}
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index b0d2704..1cbf0bf 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -270,7 +270,9 @@
Slog.d(TAG, "onTargetPackageUpgraded packageName=" + packageName + " userId=" + userId);
}
- updateAllOverlaysForTarget(packageName, userId, 0);
+ if (updateAllOverlaysForTarget(packageName, userId, 0)) {
+ mListener.onOverlaysChanged(packageName, userId);
+ }
}
void onTargetPackageRemoved(@NonNull final String packageName, final int userId) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 70ead41..6fe32c5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1343,6 +1343,7 @@
final @Nullable String mWellbeingPackage;
final @Nullable String mDocumenterPackage;
final @Nullable String mConfiguratorPackage;
+ final @Nullable String mAppPredictionServicePackage;
final @NonNull String mServicesSystemSharedLibraryPackageName;
final @NonNull String mSharedSystemSharedLibraryPackageName;
@@ -2868,6 +2869,7 @@
mDocumenterPackage = getDocumenterPackageName();
mConfiguratorPackage =
mContext.getString(R.string.config_deviceConfiguratorPackageName);
+ mAppPredictionServicePackage = getAppPredictionServicePackageName();
// Now that we know all of the shared libraries, update all clients to have
// the correct library paths.
@@ -3750,7 +3752,7 @@
/**
* Returns whether or not a full application can see an instant application.
* <p>
- * Currently, there are three cases in which this can occur:
+ * Currently, there are four cases in which this can occur:
* <ol>
* <li>The calling application is a "special" process. Special processes
* are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li>
@@ -3758,6 +3760,7 @@
* {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li>
* <li>The calling application is the default launcher on the
* system partition.</li>
+ * <li>The calling application is the default app prediction service.</li>
* </ol>
*/
private boolean canViewInstantApps(int callingUid, int userId) {
@@ -3775,6 +3778,11 @@
&& isCallerSameApp(homeComponent.getPackageName(), callingUid)) {
return true;
}
+ // TODO(b/122900055) Change/Remove this and replace with new permission role.
+ if (mAppPredictionServicePackage != null
+ && isCallerSameApp(mAppPredictionServicePackage, callingUid)) {
+ return true;
+ }
}
return false;
}
@@ -5490,13 +5498,13 @@
final int callingUserId = UserHandle.getUserId(callingUid);
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
// Map to base uids.
- uid1 = UserHandle.getAppId(uid1);
- uid2 = UserHandle.getAppId(uid2);
+ final int appId1 = UserHandle.getAppId(uid1);
+ final int appId2 = UserHandle.getAppId(uid2);
// reader
synchronized (mPackages) {
Signature[] s1;
Signature[] s2;
- Object obj = mSettings.getSettingLPr(uid1);
+ Object obj = mSettings.getSettingLPr(appId1);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
@@ -5515,7 +5523,7 @@
} else {
return PackageManager.SIGNATURE_UNKNOWN_PACKAGE;
}
- obj = mSettings.getSettingLPr(uid2);
+ obj = mSettings.getSettingLPr(appId2);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
@@ -5570,11 +5578,11 @@
final int callingUid = Binder.getCallingUid();
final int callingUserId = UserHandle.getUserId(callingUid);
// Map to base uids.
- uid = UserHandle.getAppId(uid);
+ final int appId = UserHandle.getAppId(uid);
// reader
synchronized (mPackages) {
final PackageParser.SigningDetails signingDetails;
- final Object obj = mSettings.getSettingLPr(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj != null) {
if (obj instanceof SharedUserSetting) {
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
@@ -5690,10 +5698,10 @@
final int callingUid = Binder.getCallingUid();
final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null;
final int userId = UserHandle.getUserId(uid);
- uid = UserHandle.getAppId(uid);
+ final int appId = UserHandle.getAppId(uid);
// reader
synchronized (mPackages) {
- Object obj = mSettings.getSettingLPr(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
if (isCallerInstantApp) {
return null;
@@ -5728,8 +5736,9 @@
if (getInstantAppPackageName(callingUid) != null) {
return null;
}
+ final int appId = UserHandle.getAppId(uid);
synchronized (mPackages) {
- Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.name + ":" + sus.userId;
@@ -5756,8 +5765,8 @@
final String[] names = new String[uids.length];
synchronized (mPackages) {
for (int i = uids.length - 1; i >= 0; i--) {
- final int uid = uids[i];
- Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+ final int appId = UserHandle.getAppId(uids[i]);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
names[i] = "shared:" + sus.name;
@@ -5805,8 +5814,9 @@
if (getInstantAppPackageName(callingUid) != null) {
return 0;
}
+ final int appId = UserHandle.getAppId(uid);
synchronized (mPackages) {
- Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.pkgFlags;
@@ -5827,8 +5837,9 @@
if (getInstantAppPackageName(callingUid) != null) {
return 0;
}
+ final int appId = UserHandle.getAppId(uid);
synchronized (mPackages) {
- Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
return sus.pkgPrivateFlags;
@@ -5848,10 +5859,10 @@
if (getInstantAppPackageName(Binder.getCallingUid()) != null) {
return false;
}
- uid = UserHandle.getAppId(uid);
+ final int appId = UserHandle.getAppId(uid);
// reader
synchronized (mPackages) {
- Object obj = mSettings.getSettingLPr(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
final Iterator<PackageSetting> it = sus.packages.iterator();
@@ -13781,6 +13792,11 @@
ServiceManager.getService(Context.BACKUP_SERVICE));
if (bm != null) {
int userId = args.user.getIdentifier();
+ // For backwards compatibility as USER_ALL previously routed directly to USER_SYSTEM
+ // in the BackupManager. USER_ALL is used in compatibility tests.
+ if (userId == UserHandle.USER_ALL) {
+ userId = UserHandle.USER_SYSTEM;
+ }
if (DEBUG_INSTALL) {
Log.v(TAG, "token " + token + " to BM for possible restore for user " + userId);
}
@@ -18947,7 +18963,8 @@
@GuardedBy("mPackages")
private int getUidTargetSdkVersionLockedLPr(int uid) {
- Object obj = mSettings.getSettingLPr(uid);
+ final int appId = UserHandle.getAppId(uid);
+ final Object obj = mSettings.getSettingLPr(appId);
if (obj instanceof SharedUserSetting) {
final SharedUserSetting sus = (SharedUserSetting) obj;
int vers = Build.VERSION_CODES.CUR_DEVELOPMENT;
@@ -19138,7 +19155,7 @@
// writer
synchronized (mPackages) {
PackageParser.Package pkg = mPackages.get(packageName);
- if (pkg == null || pkg.applicationInfo.uid != callingUid) {
+ if (pkg == null || !isCallerSameApp(packageName, callingUid)) {
if (mContext.checkCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
!= PackageManager.PERMISSION_GRANTED) {
@@ -19811,6 +19828,14 @@
.setPackage(launcherComponent.getPackageName());
mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
}
+ // TODO(b/122900055) Change/Remove this and replace with new permission role.
+ if (mAppPredictionServicePackage != null) {
+ Intent predictorIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, sessionInfo)
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+ .setPackage(mAppPredictionServicePackage);
+ mContext.sendBroadcastAsUser(predictorIntent, UserHandle.of(launcherUid));
+ }
}
}
@@ -19963,6 +19988,20 @@
return mContext.getString(R.string.config_defaultWellbeingPackage);
}
+ private String getAppPredictionServicePackageName() {
+ String flattenedAppPredictionServiceComponentName =
+ mContext.getString(R.string.config_defaultAppPredictionService);
+ if (flattenedAppPredictionServiceComponentName == null) {
+ return null;
+ }
+ ComponentName appPredictionServiceComponentName =
+ ComponentName.unflattenFromString(flattenedAppPredictionServiceComponentName);
+ if (appPredictionServiceComponentName == null) {
+ return null;
+ }
+ return appPredictionServiceComponentName.getPackageName();
+ }
+
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 95da209..b0f2326 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -2790,13 +2790,13 @@
// dataPath - path to package's data path
// seinfo - seinfo label for the app (assigned at install time)
// gids - supplementary gids this app launches with
+ // profileableFromShellFlag - 0 or 1 if the package is profileable from shell.
//
// NOTE: We prefer not to expose all ApplicationInfo flags for now.
//
// DO NOT MODIFY THIS FORMAT UNLESS YOU CAN ALSO MODIFY ITS USERS
// FROM NATIVE CODE. AT THE MOMENT, LOOK AT THE FOLLOWING SOURCES:
- // frameworks/base/libs/packagelistparser
- // system/core/run-as/run-as.c
+ // system/core/libpackagelistparser
//
sb.setLength(0);
sb.append(ai.packageName);
@@ -2816,6 +2816,8 @@
} else {
sb.append("none");
}
+ sb.append(" ");
+ sb.append(ai.isProfileableByShell() ? "1" : "0");
sb.append("\n");
writer.append(sb);
}
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index 45c975b..055c941 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -62,6 +62,8 @@
mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
+ // TODO: STOPSHIP: Remove the following code once we remove default_sms_application
+ // and use the new config_defaultRoleHolders.
if (result == null) {
Collection<SmsApplication.SmsApplicationData> applications =
SmsApplication.getApplicationCollectionAsUser(mContext, userId);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index c0ec367..5516b23 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -229,9 +229,12 @@
// Any role for which we have a record are already migrated
RoleUserState userState = getOrCreateUserState(userId);
if (!userState.isRoleAvailable(role)) {
- userState.addRoleName(role);
List<String> roleHolders = mLegacyRoleResolver.getRoleHolders(role, userId);
+ if (roleHolders.isEmpty()) {
+ return;
+ }
Slog.i(LOG_TAG, "Migrating " + role + ", legacy holders: " + roleHolders);
+ userState.addRoleName(role);
int size = roleHolders.size();
for (int i = 0; i < size; i++) {
userState.addRoleHolder(role, roleHolders.get(i));
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 9f8af50..b8634d8 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2508,6 +2508,13 @@
final IBinder binder =
(freezeScreenIfNeeded && appToken != null) ? appToken.asBinder() : null;
mAppWindowToken.setOrientation(requestedOrientation, binder, this);
+
+ // Push the new configuration to the requested app in case where it's not pushed, e.g. when
+ // the request is handled at task level with letterbox.
+ if (!getMergedOverrideConfiguration().equals(
+ mLastReportedConfiguration.getMergedConfiguration())) {
+ ensureActivityConfiguration(0 /* globalChanges */, false /* preserveWindow */);
+ }
}
int getOrientation() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index b735115..6527ca0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -328,14 +328,6 @@
private int mLastOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
/**
- * Flag indicating that the application is receiving an orientation that has different metrics
- * than it expected. E.g. Portrait instead of Landscape.
- *
- * @see #updateRotationUnchecked()
- */
- private boolean mAltOrientation = false;
-
- /**
* Orientation forced by some window. If there is no visible window that specifies orientation
* it is set to {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_UNSPECIFIED}.
*
@@ -1085,10 +1077,6 @@
return mLastOrientation;
}
- boolean getAltOrientation() {
- return mAltOrientation;
- }
-
int getLastWindowForcedOrientation() {
return mLastWindowForcedOrientation;
}
@@ -1130,15 +1118,9 @@
boolean rotationNeedsUpdate() {
final int lastOrientation = getLastOrientation();
final int oldRotation = getRotation();
- final boolean oldAltOrientation = getAltOrientation();
final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
- final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
- lastOrientation, rotation);
- if (oldRotation == rotation && oldAltOrientation == altOrientation) {
- return false;
- }
- return true;
+ return oldRotation != rotation;
}
/**
@@ -1336,7 +1318,6 @@
final int oldRotation = mRotation;
final int lastOrientation = mLastOrientation;
- final boolean oldAltOrientation = mAltOrientation;
final int rotation = mDisplayRotation.rotationForOrientation(lastOrientation, oldRotation);
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Computed rotation=" + rotation + " for display id="
+ mDisplayId + " based on lastOrientation=" + lastOrientation
@@ -1368,35 +1349,26 @@
}
final boolean rotateSeamlessly = mayRotateSeamlessly;
- // TODO: Implement forced rotation changes.
- // Set mAltOrientation to indicate that the application is receiving
- // an orientation that has different metrics than it expected.
- // eg. Portrait instead of Landscape.
-
- final boolean altOrientation = !mDisplayRotation.rotationHasCompatibleMetrics(
- lastOrientation, rotation);
-
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
+ " selected orientation " + lastOrientation
+ ", got rotation " + rotation + " which has "
- + (altOrientation ? "incompatible" : "compatible") + " metrics");
+ + " metrics");
- if (oldRotation == rotation && oldAltOrientation == altOrientation) {
+ if (oldRotation == rotation) {
// No change.
return false;
}
if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
+ " rotation changed to " + rotation
- + (altOrientation ? " (alt)" : "") + " from " + oldRotation
- + (oldAltOrientation ? " (alt)" : "") + ", lastOrientation=" + lastOrientation);
+ + " from " + oldRotation
+ + ", lastOrientation=" + lastOrientation);
if (DisplayContent.deltaRotation(rotation, oldRotation) != 2) {
mWaitingForConfig = true;
}
mRotation = rotation;
- mAltOrientation = altOrientation;
mWmService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_ACTIVE;
mWmService.mH.sendNewMessageDelayed(WindowManagerService.H.WINDOW_FREEZE_TIMEOUT,
@@ -1538,26 +1510,8 @@
private DisplayInfo updateDisplayAndOrientation(int uiMode) {
// Use the effective "visual" dimensions based on current rotation
final boolean rotated = (mRotation == ROTATION_90 || mRotation == ROTATION_270);
- final int realdw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
- final int realdh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
- int dw = realdw;
- int dh = realdh;
-
- if (mAltOrientation) {
- if (realdw > realdh) {
- // Turn landscape into portrait.
- int maxw = (int)(realdh/1.3f);
- if (maxw < realdw) {
- dw = maxw;
- }
- } else {
- // Turn portrait into landscape.
- int maxh = (int)(realdw/1.3f);
- if (maxh < realdh) {
- dh = maxh;
- }
- }
- }
+ final int dw = rotated ? mBaseDisplayHeight : mBaseDisplayWidth;
+ final int dh = rotated ? mBaseDisplayWidth : mBaseDisplayHeight;
// Update application display metrics.
final WmDisplayCutout wmDisplayCutout = calculateDisplayCutoutForRotation(mRotation);
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index 7aabc15..bc165dc 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -676,36 +676,6 @@
return rotation == mPortraitRotation || rotation == mUpsideDownRotation;
}
- /**
- * Given an orientation constant and a rotation, returns true if the rotation
- * has compatible metrics to the requested orientation. For example, if
- * the application requested landscape and got seascape, then the rotation
- * has compatible metrics; if the application requested portrait and got landscape,
- * then the rotation has incompatible metrics; if the application did not specify
- * a preference, then anything goes.
- *
- * @param orientation An orientation constant, such as
- * {@link android.content.pm.ActivityInfo#SCREEN_ORIENTATION_LANDSCAPE}.
- * @param rotation The rotation to check.
- * @return True if the rotation is compatible with the requested orientation.
- */
- boolean rotationHasCompatibleMetrics(int orientation, int rotation) {
- switch (orientation) {
- case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:
- case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:
- case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:
- return isAnyPortrait(rotation);
-
- case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:
- case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:
- case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:
- return isLandscapeOrSeascape(rotation);
-
- default:
- return true;
- }
- }
-
private boolean isValidRotationChoice(final int preferredRotation) {
// Determine if the given app orientation is compatible with the provided rotation choice.
switch (mCurrentAppOrientation) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0c4f496..fda7a85 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5943,8 +5943,6 @@
pw.print(" apps="); pw.print(mAppsFreezingScreen);
final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
pw.print(" mRotation="); pw.print(defaultDisplayContent.getRotation());
- pw.print(" mAltOrientation=");
- pw.println(defaultDisplayContent.getAltOrientation());
pw.print(" mLastWindowForcedOrientation=");
pw.print(defaultDisplayContent.getLastWindowForcedOrientation());
pw.print(" mLastOrientation=");
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
index f947bac..56f4a85 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityDisplayTests.java
@@ -57,11 +57,6 @@
@Presubmit
public class ActivityDisplayTests extends ActivityTestsBase {
- @Before
- public void setUp() throws Exception {
- setupActivityTaskManagerService();
- }
-
@Test
public void testLastFocusedStackIsUpdatedWhenMovingStack() {
// Create a stack at bottom.
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 cac9cf6..ee22861 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -70,8 +70,6 @@
@Before
public void setUpAMLO() throws Exception {
- setupActivityTaskManagerService();
-
mLaunchObserver = mock(ActivityMetricsLaunchObserver.class);
// ActivityStackSupervisor always creates its own instance of ActivityMetricsLogger.
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 06360c2..8be63fc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -19,8 +19,10 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
@@ -39,6 +41,7 @@
import static org.junit.Assert.assertTrue;
import android.app.ActivityOptions;
+import android.app.servertransaction.ActivityConfigurationChangeItem;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.PauseActivityItem;
import android.content.pm.ActivityInfo;
@@ -69,7 +72,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
mStack = (TestActivityStack) new StackBuilder(mRootActivityContainer).build();
mTask = mStack.getChildAt(0);
mActivity = mTask.getTopActivity();
@@ -321,4 +323,44 @@
assertEquals(ActivityTaskManagerService.RELAUNCH_REASON_NONE,
mActivity.mRelaunchReason);
}
+
+ @Test
+ public void testSetRequestedOrientationUpdatesConfiguration() throws Exception {
+ mActivity.setState(ActivityStack.ActivityState.RESUMED, "Testing");
+
+ mTask.onRequestedOverrideConfigurationChanged(mTask.getConfiguration());
+ mActivity.setLastReportedConfiguration(new MergedConfiguration(new Configuration(),
+ mActivity.getConfiguration()));
+
+ mActivity.info.configChanges |= ActivityInfo.CONFIG_ORIENTATION;
+ final Configuration newConfig = new Configuration(mActivity.getConfiguration());
+ newConfig.orientation = newConfig.orientation == Configuration.ORIENTATION_PORTRAIT
+ ? Configuration.ORIENTATION_LANDSCAPE
+ : Configuration.ORIENTATION_PORTRAIT;
+
+ // Mimic the behavior that display doesn't handle app's requested orientation.
+ doAnswer(invocation -> {
+ mTask.onConfigurationChanged(newConfig);
+ return null;
+ }).when(mActivity.mAppWindowToken).setOrientation(anyInt(), any(), any());
+
+ final int requestedOrientation;
+ switch (newConfig.orientation) {
+ case Configuration.ORIENTATION_LANDSCAPE:
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+ break;
+ case Configuration.ORIENTATION_PORTRAIT:
+ requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+ break;
+ default:
+ throw new IllegalStateException("Orientation in new config should be either"
+ + "landscape or portrait.");
+ }
+ mActivity.setRequestedOrientation(requestedOrientation);
+
+ final ActivityConfigurationChangeItem expected =
+ ActivityConfigurationChangeItem.obtain(newConfig);
+ verify(mService.getLifecycleManager()).scheduleTransaction(eq(mActivity.app.getThread()),
+ eq(mActivity.appToken), eq(expected));
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
index f7b5d26..59e71c4 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java
@@ -64,7 +64,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index fda23e9..35c1ede 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -75,7 +75,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
mDefaultDisplay = mRootActivityContainer.getDefaultDisplay();
mStack = spy(mDefaultDisplay.createStack(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD,
true /* onTop */));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
index 2ba2fdb..96db38b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStartControllerTests.java
@@ -56,7 +56,6 @@
@Before
public void setUp() throws Exception {
- mService = createActivityTaskManagerService();
mFactory = mock(Factory.class);
mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
mStarter = spy(new ActivityStarter(mController, mService,
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
index 898d107..a381023 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -117,7 +117,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
mController = mock(ActivityStartController.class);
mActivityMetricsLogger = mock(ActivityMetricsLogger.class);
clearInvocations(mActivityMetricsLogger);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
index d462e69..68df87e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTestsBase.java
@@ -111,6 +111,10 @@
@Before
public void setUpBase() {
mTestInjector.setUp();
+
+ mService = new TestActivityTaskManagerService(mContext);
+ mSupervisor = mService.mStackSupervisor;
+ mRootActivityContainer = mService.mRootActivityContainer;
}
@After
@@ -122,17 +126,6 @@
}
}
- ActivityTaskManagerService createActivityTaskManagerService() {
- mService = new TestActivityTaskManagerService(mContext);
- mSupervisor = mService.mStackSupervisor;
- mRootActivityContainer = mService.mRootActivityContainer;
- return mService;
- }
-
- void setupActivityTaskManagerService() {
- createActivityTaskManagerService();
- }
-
/** Creates a {@link TestActivityDisplay}. */
TestActivityDisplay createNewActivityDisplay() {
return TestActivityDisplay.create(mSupervisor, sNextDisplayId++);
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index 0c6e632..123de2d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -60,7 +60,7 @@
@BeforeClass
public static void setUpRootWindowContainerMock() {
- final WindowManagerService wm = WmServiceUtils.getWindowManagerService();
+ final WindowManagerService wm = TestSystemServices.getWindowManagerService();
// For unit test, we don't need to test performSurfacePlacement to prevent some abnormal
// interaction with surfaceflinger native side.
sOriginalRootWindowContainer = wm.mRoot;
@@ -74,7 +74,7 @@
@AfterClass
public static void tearDownRootWindowContainerMock() {
- final WindowManagerService wm = WmServiceUtils.getWindowManagerService();
+ final WindowManagerService wm = TestSystemServices.getWindowManagerService();
wm.mRoot = sOriginalRootWindowContainer;
sOriginalRootWindowContainer = null;
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
index 8c3dec7..b28ae40 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java
@@ -71,7 +71,6 @@
@Before
public void setUp() throws Exception {
- mService = createActivityTaskManagerService();
mPersister = new TestLaunchParamsPersister();
mController = new LaunchParamsController(mService, mPersister);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
index 8635364..aeda473 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java
@@ -102,8 +102,6 @@
mFolder = new File(cacheFolder, "launch_params_tests");
deleteRecursively(mFolder);
- setupActivityTaskManagerService();
-
mDisplayUniqueId = "test:" + Integer.toString(sNextUniqueId++);
final DisplayInfo info = new DisplayInfo();
info.uniqueId = mDisplayUniqueId;
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index efd7d25..beaac8e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -52,7 +52,6 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- mService = createActivityTaskManagerService();
mService.mH.runWithScissors(() -> {
mHandler = new TestHandler(null, mClock);
}, 0);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
index a3f535a..e3bacf9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java
@@ -82,7 +82,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
mFullscreenStack = mRootActivityContainer.getDefaultDisplay().createStack(
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
index a8b6dc3..dc96480 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java
@@ -49,7 +49,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
mRunningTasks = new RunningTasks();
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
index 53e99fa..ace179a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java
@@ -75,10 +75,6 @@
@Before
public void setUp() throws Exception {
- setupActivityTaskManagerService();
- mService.mSupportsFreeformWindowManagement = true;
- when(mSupervisor.canUseActivityOptionsLaunchBounds(any())).thenCallRealMethod();
-
mActivity = new ActivityBuilder(mService).build();
mActivity.appInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1;
mActivity.info.applicationInfo.flags |= ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES;
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index 99be50b..e182c45 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -90,7 +90,6 @@
@Before
public void setUp() throws Exception {
TaskRecord.setTaskRecordFactory(null);
- setupActivityTaskManagerService();
mParentBounds = new Rect(10 /*left*/, 30 /*top*/, 80 /*right*/, 60 /*bottom*/);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
similarity index 97%
rename from services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
rename to services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
index 05ac8c1..b151fb7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WmServiceUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestSystemServices.java
@@ -66,7 +66,7 @@
/**
* A Test utility class to create a mock {@link WindowManagerService} instance for tests.
*/
-class WmServiceUtils {
+class TestSystemServices {
private static StaticMockitoSession sMockitoSession;
private static WindowManagerService sService;
private static TestWindowManagerPolicy sPolicy;
@@ -78,7 +78,7 @@
.strictness(Strictness.LENIENT)
.startMocking();
- runWithDexmakerShareClassLoader(WmServiceUtils::setUpTestWindowService);
+ runWithDexmakerShareClassLoader(TestSystemServices::setUpTestWindowService);
}
static void tearDownWindowManagerService() {
@@ -147,7 +147,7 @@
final WindowManagerGlobalLock wmLock = new WindowManagerGlobalLock();
doReturn(wmLock).when(atms).getGlobalLock();
- sPolicy = new TestWindowManagerPolicy(WmServiceUtils::getWindowManagerService);
+ sPolicy = new TestWindowManagerPolicy(TestSystemServices::getWindowManagerService);
sService = WindowManagerService.main(context, ims, false, false, sPolicy, atms);
sService.onInitReady();
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 89c1551..e38118e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -101,14 +101,14 @@
public static void setUpOnceBase() {
AttributeCache.init(getInstrumentation().getTargetContext());
- WmServiceUtils.setUpWindowManagerService();
+ TestSystemServices.setUpWindowManagerService();
sPowerManagerWrapper = mock(WindowState.PowerManagerWrapper.class);
}
@AfterClass
public static void tearDonwOnceBase() {
- WmServiceUtils.tearDownWindowManagerService();
+ TestSystemServices.tearDownWindowManagerService();
}
@Before
@@ -120,7 +120,7 @@
final Context context = getInstrumentation().getTargetContext();
- mWm = WmServiceUtils.getWindowManagerService();
+ mWm = TestSystemServices.getWindowManagerService();
beforeCreateDisplay();
context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -198,7 +198,7 @@
}
// Cleaned up everything in Handler.
- WmServiceUtils.cleanupWindowManagerHandlers();
+ TestSystemServices.cleanupWindowManagerHandlers();
} catch (Exception e) {
Log.e(TAG, "Failed to tear down test", e);
throw e;
@@ -219,7 +219,7 @@
* Waits until the main handler for WM has processed all messages.
*/
void waitUntilHandlersIdle() {
- WmServiceUtils.waitUntilWindowManagerHandlersIdle();
+ TestSystemServices.waitUntilWindowManagerHandlersIdle();
}
private WindowToken createWindowToken(
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index c816701..9fee593 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -805,9 +805,11 @@
PhoneStateListener psl = mPhoneStateListenerWeakRef.get();
if (psl == null) return;
- Binder.withCleanCallingIdentity(
- () -> mExecutor.execute(
- () -> psl.onDataConnectionStateChanged(state, networkType)));
+ Binder.withCleanCallingIdentity(() -> mExecutor.execute(
+ () -> {
+ psl.onDataConnectionStateChanged(state, networkType);
+ psl.onDataConnectionStateChanged(state);
+ }));
}
public void onDataActivity(int direction) {
diff --git a/telephony/java/android/telephony/emergency/EmergencyNumber.java b/telephony/java/android/telephony/emergency/EmergencyNumber.java
index a5f56bb..e68256d 100644
--- a/telephony/java/android/telephony/emergency/EmergencyNumber.java
+++ b/telephony/java/android/telephony/emergency/EmergencyNumber.java
@@ -27,6 +27,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
@@ -176,6 +177,12 @@
* Bit-field which indicates the number is from the platform-maintained database.
*/
public static final int EMERGENCY_NUMBER_SOURCE_DATABASE = 1 << 4;
+ /**
+ * Bit-field which indicates the number is from test mode.
+ *
+ * @hide
+ */
+ public static final int EMERGENCY_NUMBER_SOURCE_TEST = 1 << 5;
/** Bit-field which indicates the number is from the modem config. */
public static final int EMERGENCY_NUMBER_SOURCE_MODEM_CONFIG =
EmergencyNumberSource.MODEM_CONFIG;
@@ -327,6 +334,21 @@
}
/**
+ * Returns the bitmask of emergency service categories of the emergency number for
+ * internal dialing.
+ *
+ * @return bitmask of the emergency service categories
+ *
+ * @hide
+ */
+ public @EmergencyServiceCategories int getEmergencyServiceCategoryBitmaskInternalDial() {
+ if (mEmergencyNumberSourceBitmask == EMERGENCY_NUMBER_SOURCE_DATABASE) {
+ return EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED;
+ }
+ return mEmergencyServiceCategoryBitmask;
+ }
+
+ /**
* Returns the emergency service categories of the emergency number.
*
* Note: if the emergency number is in {@link #EMERGENCY_SERVICE_CATEGORY_UNSPECIFIED}, only
@@ -577,6 +599,7 @@
emergencyNumberList.remove(i--);
}
}
+ Collections.sort(emergencyNumberList);
}
/**
@@ -613,6 +636,12 @@
if (first.getEmergencyCallRouting() != second.getEmergencyCallRouting()) {
return false;
}
+ // Never merge two numbers if one of them is from test mode but the other one is not;
+ // This supports to remove a number from the test mode.
+ if (first.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)
+ ^ second.isFromSources(EMERGENCY_NUMBER_SOURCE_TEST)) {
+ return false;
+ }
return true;
}
@@ -638,4 +667,13 @@
}
return null;
}
+
+ /**
+ * Validate Emergency Number address that only allows '0'-'9', '*', or '#'
+ *
+ * @hide
+ */
+ public static boolean validateEmergencyNumberAddress(String address) {
+ return address.matches("[0-9*#]+");
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 525a96a..59167b7 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -347,6 +347,9 @@
private @EmergencyCallRouting int mEmergencyCallRouting =
EmergencyNumber.EMERGENCY_CALL_ROUTING_UNKNOWN;
+ /** Indicates if the call is for testing purpose */
+ private boolean mEmergencyCallTesting = false;
+
/**
* Extras associated with this {@link ImsCallProfile}.
* <p>
@@ -534,9 +537,10 @@
+ ", callType=" + mCallType
+ ", restrictCause=" + mRestrictCause
+ ", mediaProfile=" + mMediaProfile.toString()
- + ", emergencyServiceCategories=" + mEmergencyCallRouting
+ + ", emergencyServiceCategories=" + mEmergencyServiceCategories
+ ", emergencyUrns=" + mEmergencyUrns
- + ", emergencyCallRouting=" + mEmergencyCallRouting + " }";
+ + ", emergencyCallRouting=" + mEmergencyCallRouting
+ + ", emergencyCallTesting=" + mEmergencyCallTesting + " }";
}
@Override
@@ -554,6 +558,7 @@
out.writeInt(mEmergencyServiceCategories);
out.writeStringList(mEmergencyUrns);
out.writeInt(mEmergencyCallRouting);
+ out.writeBoolean(mEmergencyCallTesting);
}
private void readFromParcel(Parcel in) {
@@ -564,6 +569,7 @@
mEmergencyServiceCategories = in.readInt();
mEmergencyUrns = in.createStringArrayList();
mEmergencyCallRouting = in.readInt();
+ mEmergencyCallTesting = in.readBoolean();
}
public static final Creator<ImsCallProfile> CREATOR = new Creator<ImsCallProfile>() {
@@ -784,9 +790,11 @@
* @hide
*/
public void setEmergencyCallInfo(EmergencyNumber num) {
- setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmask());
+ setEmergencyServiceCategories(num.getEmergencyServiceCategoryBitmaskInternalDial());
setEmergencyUrns(num.getEmergencyUrns());
setEmergencyCallRouting(num.getEmergencyCallRouting());
+ setEmergencyCallTesting(num.getEmergencyNumberSourceBitmask()
+ == EmergencyNumber.EMERGENCY_NUMBER_SOURCE_TEST);
}
/**
@@ -843,6 +851,15 @@
}
/**
+ * Set if this is for testing emergency call, only valid if {@link #getServiceType} returns
+ * {@link #SERVICE_TYPE_EMERGENCY}.
+ */
+ @VisibleForTesting
+ public void setEmergencyCallTesting(boolean isTesting) {
+ mEmergencyCallTesting = isTesting;
+ }
+
+ /**
* Get the emergency service categories, only valid if {@link #getServiceType} returns
* {@link #SERVICE_TYPE_EMERGENCY}
*
@@ -892,4 +909,11 @@
public @EmergencyCallRouting int getEmergencyCallRouting() {
return mEmergencyCallRouting;
}
+
+ /**
+ * Get if the emergency call is for testing purpose.
+ */
+ public boolean isEmergencyCallTesting() {
+ return mEmergencyCallTesting;
+ }
}
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e2350fe..9414abd 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -92,7 +92,7 @@
public static final int WIFI_MODE_WIFI_PREFERRED = 2;
/**
- * Callback class for receiving Registration callback events.
+ * Callback class for receiving IMS network Registration callback events.
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback) (RegistrationCallback)
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
*/
@@ -241,7 +241,8 @@
}
/**
- * Receives IMS capability status updates from the ImsService.
+ * Receives IMS capability status updates from the ImsService. This information is also
+ * available via the {@link #isAvailable(int, int)} method below.
*
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback) (CapabilityCallback)
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
@@ -290,6 +291,8 @@
* If unavailable, the feature is not able to support the unavailable capability at this
* time.
*
+ * This information can also be queried using the {@link #isAvailable(int, int)} API.
+ *
* @param capabilities The new availability of the capabilities.
*/
public void onCapabilitiesStatusChanged(
@@ -304,7 +307,7 @@
/**@hide*/
// Only exposed as public method for compatibility with deprecated ImsManager APIs.
// TODO: clean up dependencies and change back to private visibility.
- public void setExecutor(Executor executor) {
+ public final void setExecutor(Executor executor) {
mBinder.setExecutor(executor);
}
}
@@ -342,8 +345,7 @@
* Registers a {@link RegistrationCallback} with the system, which will provide registration
* updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}. Use
* {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to Subscription changed
- * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up
- * after a subscription is removed.
+ * events and call {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current registration state.
@@ -351,6 +353,12 @@
* @param executor The executor the callback events should be run on.
* @param c The {@link RegistrationCallback} to be added.
* @see #unregisterImsRegistrationCallback(RegistrationCallback)
+ * @throws IllegalArgumentException if the subscription associated with this callback is not
+ * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+ * {@link CapabilityCallback} callback.
+ * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerImsRegistrationCallback(@CallbackExecutor Executor executor,
@@ -370,11 +378,17 @@
}
/**
- * Removes an existing {@link RegistrationCallback}. Ensure to call this method when cleaning
- * up to avoid memory leaks or when the subscription is removed.
+ * Removes an existing {@link RegistrationCallback}.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
+ *
* @param c The {@link RegistrationCallback} to be removed.
* @see SubscriptionManager.OnSubscriptionsChangedListener
* @see #registerImsRegistrationCallback(Executor, RegistrationCallback)
+ * @throws IllegalArgumentException if the subscription ID associated with this callback is
+ * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterImsRegistrationCallback(@NonNull RegistrationCallback c) {
@@ -389,12 +403,14 @@
}
/**
- * Registers a {@link CapabilityCallback} with the system, which will provide MmTel capability
- * updates for the subscription specified in {@link #createForSubscriptionId(Context, int)}.
+ * Registers a {@link CapabilityCallback} with the system, which will provide MmTel service
+ * availability updates for the subscription specified in
+ * {@link #createForSubscriptionId(Context, int)}. The method {@link #isAvailable(int, int)}
+ * can also be used to query this information at any time.
+ *
* Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
* subscription changed events and call
- * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up after a
- * subscription is removed.
+ * {@link #unregisterImsRegistrationCallback(RegistrationCallback)} to clean up.
*
* When the callback is registered, it will initiate the callback c to be called with the
* current capabilities.
@@ -402,9 +418,15 @@
* @param executor The executor the callback events should be run on.
* @param c The MmTel {@link CapabilityCallback} to be registered.
* @see #unregisterMmTelCapabilityCallback(CapabilityCallback)
+ * @throws IllegalArgumentException if the subscription associated with this callback is not
+ * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or
+ * {@link CapabilityCallback} callback.
+ * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
- public void registerMmTelCapabilityCallback(@CallbackExecutor Executor executor,
+ public void registerMmTelCapabilityCallback(@NonNull @CallbackExecutor Executor executor,
@NonNull CapabilityCallback c) {
if (c == null) {
throw new IllegalArgumentException("Must include a non-null RegistrationCallback.");
@@ -421,10 +443,15 @@
}
/**
- * Removes an existing MmTel {@link CapabilityCallback}. Be sure to call this when cleaning
- * up to avoid memory leaks.
+ * Removes an existing MmTel {@link CapabilityCallback}.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed. If this method is called for an
+ * inactive subscription, it will result in a no-op.
* @param c The MmTel {@link CapabilityCallback} to be removed.
* @see #registerMmTelCapabilityCallback(Executor, CapabilityCallback)
+ * @throws IllegalArgumentException if the subscription ID associated with this callback is
+ * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterMmTelCapabilityCallback(@NonNull CapabilityCallback c) {
diff --git a/telephony/java/android/telephony/ims/ProvisioningManager.java b/telephony/java/android/telephony/ims/ProvisioningManager.java
index 916e282..d37198a 100644
--- a/telephony/java/android/telephony/ims/ProvisioningManager.java
+++ b/telephony/java/android/telephony/ims/ProvisioningManager.java
@@ -133,33 +133,40 @@
}
/**
- * Register a new {@link Callback} to listen to changes to changes in
- * IMS provisioning. Use {@link SubscriptionManager.OnSubscriptionsChangedListener} to listen to
- * Subscription changed events and call
- * {@link #unregisterProvisioningChangedCallback(Callback)} to clean up after a
- * subscription is removed.
+ * Register a new {@link Callback} to listen to changes to changes in IMS provisioning.
+ *
+ * When the subscription associated with this callback is removed (SIM removed, ESIM swap,
+ * etc...), this callback will automatically be removed.
* @param executor The {@link Executor} to call the callback methods on
* @param callback The provisioning callbackto be registered.
* @see #unregisterProvisioningChangedCallback(Callback)
* @see SubscriptionManager.OnSubscriptionsChangedListener
+ * @throws IllegalArgumentException if the subscription associated with this callback is not
+ * active (SIM is not inserted, ESIM inactive) or the subscription is invalid.
+ * @throws IllegalStateException if the subscription associated with this callback is valid, but
+ * the {@link ImsService} associated with the subscription is not available. This can happen if
+ * the service crashed, for example.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void registerProvisioningChangedCallback(@CallbackExecutor Executor executor,
@NonNull Callback callback) {
callback.setExecutor(executor);
try {
- getITelephony().registerImsProvisioningChangedCallback(mSubId,
- callback.getBinder());
+ getITelephony().registerImsProvisioningChangedCallback(mSubId, callback.getBinder());
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
}
/**
- * Unregister an existing {@link Callback}. Ensure to call this method when cleaning
- * up to avoid memory leaks or when the subscription is removed.
+ * Unregister an existing {@link Callback}. When the subscription associated with this
+ * callback is removed (SIM removed, ESIM swap, etc...), this callback will automatically be
+ * removed. If this method is called for an inactive subscription, it will result in a no-op.
* @param callback The existing {@link Callback} to be removed.
* @see #registerProvisioningChangedCallback(Executor, Callback)
+ *
+ * @throws IllegalArgumentException if the subscription associated with this callback is
+ * invalid.
*/
@RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
public void unregisterProvisioningChangedCallback(@NonNull Callback callback) {
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c5d82c5..f8e4adc 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -41,6 +41,7 @@
import android.telephony.SignalStrength;
import android.telephony.TelephonyHistogram;
import android.telephony.VisualVoicemailSmsFilterSettings;
+import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsConfig;
import android.telephony.ims.aidl.IImsConfigCallback;
@@ -1776,4 +1777,14 @@
* Set the String provisioning value for the provisioning key specified.
*/
int setImsProvisioningString(int subId, int key, String value);
+
+ /**
+ * Update Emergency Number List for Test Mode.
+ */
+ void updateEmergencyNumberListTestMode(int action, in EmergencyNumber num);
+
+ /**
+ * Get the full emergency number list for Test Mode.
+ */
+ List<String> getEmergencyNumberListTestMode();
}
diff --git a/tests/ActivityViewTest/AndroidManifest.xml b/tests/ActivityViewTest/AndroidManifest.xml
index 0be1ea0..17eb029 100644
--- a/tests/ActivityViewTest/AndroidManifest.xml
+++ b/tests/ActivityViewTest/AndroidManifest.xml
@@ -57,5 +57,10 @@
android:exported="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
</activity>
+
+ <activity android:name=".ActivityViewVisibilityActivity"
+ android:label="AV Visibility"
+ android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density">
+ </activity>
</application>
</manifest>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
index ba2e911..efcaef6 100644
--- a/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
+++ b/tests/ActivityViewTest/res/layout/activity_view_main_activity.xml
@@ -41,4 +41,10 @@
android:text="Test Resize ActivityView"
android:textAllCaps="false"/>
+ <Button
+ android:id="@+id/visibility_activity_view_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Test ActivityView Visibility"
+ android:textAllCaps="false"/>
</LinearLayout>
diff --git a/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
new file mode 100644
index 0000000..d29d4df
--- /dev/null
+++ b/tests/ActivityViewTest/res/layout/activity_view_visibility_activity.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#cfd8dc">
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <Button
+ android:id="@+id/activity_launch_button"
+ android:layout_width="200dp"
+ android:layout_height="wrap_content"
+ android:text="Launch test activity" />
+
+ <Spinner
+ android:id="@+id/visibility_spinner"
+ android:layout_width="200dp"
+ android:layout_height="match_parent"/>
+
+ </LinearLayout>
+
+ <ActivityView
+ android:id="@+id/activity_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+</LinearLayout>
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
index 66f0c6a..4f09c28 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewMainActivity.java
@@ -35,5 +35,8 @@
findViewById(R.id.resize_activity_view_button).setOnClickListener(
v -> startActivity(new Intent(this, ActivityViewResizeActivity.class)));
+
+ findViewById(R.id.visibility_activity_view_button).setOnClickListener(
+ v -> startActivity(new Intent(this, ActivityViewVisibilityActivity.class)));
}
}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
index ba2c764..52aba2b 100644
--- a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewTestActivity.java
@@ -24,12 +24,14 @@
import android.app.Activity;
import android.content.res.Configuration;
import android.os.Bundle;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.TextView;
public class ActivityViewTestActivity extends Activity {
+ private static final String TAG = "ActivityViewTestActivity";
private View mRoot;
private TextView mTextView;
@@ -84,6 +86,7 @@
}
private void updateStateText(String state) {
+ Log.d(TAG, state);
mTextView.setText(state);
}
diff --git a/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
new file mode 100644
index 0000000..ecd2cf3
--- /dev/null
+++ b/tests/ActivityViewTest/src/com/google/android/test/activityview/ActivityViewVisibilityActivity.java
@@ -0,0 +1,75 @@
+/**
+ * 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.google.android.test.activityview;
+
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import android.app.Activity;
+import android.app.ActivityView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+import android.widget.Spinner;
+
+public class ActivityViewVisibilityActivity extends Activity {
+ private static final String[] sVisibilityOptions = {"VISIBLE", "INVISIBLE", "GONE"};
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_view_visibility_activity);
+
+ final ActivityView activityView = findViewById(R.id.activity_view);
+ final Button launchButton = findViewById(R.id.activity_launch_button);
+ launchButton.setOnClickListener(v -> {
+ final Intent intent = new Intent(this, ActivityViewTestActivity.class);
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ activityView.startActivity(intent);
+ });
+
+ final Spinner visibilitySpinner = findViewById(R.id.visibility_spinner);
+ final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
+ android.R.layout.simple_spinner_item, sVisibilityOptions);
+ adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ visibilitySpinner.setAdapter(adapter);
+ visibilitySpinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ @Override
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ switch (position) {
+ case 0:
+ activityView.setVisibility(VISIBLE);
+ break;
+ case 1:
+ activityView.setVisibility(INVISIBLE);
+ break;
+ case 2:
+ activityView.setVisibility(GONE);
+ break;
+ }
+ }
+
+ @Override
+ public void onNothingSelected(AdapterView<?> parent) {
+ }
+ });
+ }
+}
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index 58702dc..e0d2f48 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -1164,8 +1164,6 @@
current_policies |= OverlayableItem::Policy::kPublic;
} else if (trimmed_part == "product") {
current_policies |= OverlayableItem::Policy::kProduct;
- } else if (trimmed_part == "product_services") {
- current_policies |= OverlayableItem::Policy::kProductServices;
} else if (trimmed_part == "system") {
current_policies |= OverlayableItem::Policy::kSystem;
} else if (trimmed_part == "vendor") {
diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp
index debca9c..827c7de 100644
--- a/tools/aapt2/ResourceParser_test.cpp
+++ b/tools/aapt2/ResourceParser_test.cpp
@@ -935,9 +935,6 @@
<policy type="product">
<item type="string" name="bar" />
</policy>
- <policy type="product_services">
- <item type="string" name="baz" />
- </policy>
<policy type="system">
<item type="string" name="fiz" />
</policy>
@@ -966,14 +963,6 @@
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct));
- search_result = table_.FindResource(test::ParseNameOrDie("string/baz"));
- ASSERT_TRUE(search_result);
- ASSERT_THAT(search_result.value().entry, NotNull());
- ASSERT_TRUE(search_result.value().entry->overlayable_item);
- result_overlayable_item = search_result.value().entry->overlayable_item.value();
- EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
- EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices));
-
search_result = table_.FindResource(test::ParseNameOrDie("string/fiz"));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
@@ -1028,7 +1017,7 @@
TEST_F(ResourceParserTest, ParseOverlayableMultiplePolicy) {
std::string input = R"(
<overlayable name="Name">
- <policy type="vendor|product_services">
+ <policy type="vendor|public">
<item type="string" name="foo" />
</policy>
<policy type="product|system">
@@ -1044,7 +1033,7 @@
OverlayableItem result_overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kVendor
- | OverlayableItem::Policy::kProductServices));
+ | OverlayableItem::Policy::kPublic));
search_result = table_.FindResource(test::ParseNameOrDie("string/bar"));
ASSERT_TRUE(search_result);
@@ -1139,7 +1128,7 @@
std::string input = R"(
<overlayable name="Name">
<policy type="vendor|product">
- <policy type="product_services">
+ <policy type="public">
<item type="string" name="foo" />
</policy>
</policy>
diff --git a/tools/aapt2/ResourceTable.h b/tools/aapt2/ResourceTable.h
index eaf6a47..7ca99ea 100644
--- a/tools/aapt2/ResourceTable.h
+++ b/tools/aapt2/ResourceTable.h
@@ -92,9 +92,6 @@
// The resource can be overlaid by any overlay on the product partition.
kProduct = 0x08,
-
- // The resource can be overlaid by any overlay on the product services partition.
- kProductServices = 0x10
};
std::shared_ptr<Overlayable> overlayable;
diff --git a/tools/aapt2/ResourceTable_test.cpp b/tools/aapt2/ResourceTable_test.cpp
index a733134..b97dc6b 100644
--- a/tools/aapt2/ResourceTable_test.cpp
+++ b/tools/aapt2/ResourceTable_test.cpp
@@ -248,7 +248,7 @@
Source("res/values/overlayable.xml", 40));
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= OverlayableItem::Policy::kProduct;
- overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
+ overlayable_item.policies |= OverlayableItem::Policy::kVendor;
overlayable_item.comment = "comment";
overlayable_item.source = Source("res/values/overlayable.xml", 42);
@@ -265,7 +265,7 @@
EXPECT_THAT(result_overlayable_item.overlayable->source.path, Eq("res/values/overlayable.xml"));
EXPECT_THAT(result_overlayable_item.overlayable->source.line, 40);
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kProduct
- | OverlayableItem::Policy::kProductServices));
+ | OverlayableItem::Policy::kVendor));
ASSERT_THAT(result_overlayable_item.comment, StrEq("comment"));
EXPECT_THAT(result_overlayable_item.source.path, Eq("res/values/overlayable.xml"));
EXPECT_THAT(result_overlayable_item.source.line, 42);
diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto
index da541be..73b568e 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -155,7 +155,6 @@
SYSTEM = 1;
VENDOR = 2;
PRODUCT = 3;
- PRODUCT_SERVICES = 4;
}
// The location of the <item> declaration in source.
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 7d4c6f3..40aaa05 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -473,10 +473,6 @@
& ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION) {
policies |= OverlayableItem::Policy::kProduct;
}
- if (policy_header->policy_flags
- & ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION) {
- policies |= OverlayableItem::Policy::kProductServices;
- }
const ResTable_ref* const ref_begin = reinterpret_cast<const ResTable_ref*>(
((uint8_t *)policy_header) + util::DeviceToHost32(policy_header->header.headerSize));
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index c4ecbaf..9d341cc 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -485,9 +485,6 @@
if (item.policies & OverlayableItem::Policy::kProduct) {
policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION;
}
- if (item.policies & OverlayableItem::Policy::kProductServices) {
- policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION;
- }
}
auto policy = overlayable_chunk->policy_ids.find(policy_flags);
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 18fecf6..ddc1173 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -660,12 +660,10 @@
OverlayableItem overlayable_item_zero(overlayable);
overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
- overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
std::string name_one = "com.app.test:integer/overlayable_one_item";
OverlayableItem overlayable_item_one(overlayable);
overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
- overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
std::string name_two = "com.app.test:integer/overlayable_two_item";
OverlayableItem overlayable_item_two(overlayable);
@@ -698,16 +696,14 @@
ASSERT_TRUE(search_result.value().entry->overlayable_item);
OverlayableItem& overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kSystem
- | OverlayableItem::Policy::kProduct
- | OverlayableItem::Policy::kProductServices);
+ | OverlayableItem::Policy::kProduct);
search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
ASSERT_TRUE(search_result.value().entry->overlayable_item);
overlayable_item = search_result.value().entry->overlayable_item.value();
- EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic
- | OverlayableItem::Policy::kProductServices);
+ EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic);
search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
ASSERT_TRUE(search_result);
@@ -735,13 +731,11 @@
OverlayableItem overlayable_item_zero(group);
overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct;
overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem;
- overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices;
auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization");
std::string name_one = "com.app.test:integer/overlayable_one";
OverlayableItem overlayable_item_one(group_one);
overlayable_item_one.policies |= OverlayableItem::Policy::kPublic;
- overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices;
std::string name_two = "com.app.test:integer/overlayable_two";
OverlayableItem overlayable_item_two(group);
@@ -773,8 +767,7 @@
EXPECT_EQ(result_overlayable.overlayable->name, "TestName");
EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme");
EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem
- | OverlayableItem::Policy::kProduct
- | OverlayableItem::Policy::kProductServices);
+ | OverlayableItem::Policy::kProduct);
search_result = output_table.FindResource(test::ParseNameOrDie(name_one));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
@@ -782,8 +775,7 @@
result_overlayable = search_result.value().entry->overlayable_item.value();
EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization");
- EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic
- | OverlayableItem::Policy::kProductServices);
+ EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic);
search_result = output_table.FindResource(test::ParseNameOrDie(name_two));
ASSERT_TRUE(search_result);
ASSERT_THAT(search_result.value().entry, NotNull());
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 6b5746d..aff1b39 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -390,9 +390,6 @@
case pb::OverlayableItem::PRODUCT:
out_overlayable->policies |= OverlayableItem::Policy::kProduct;
break;
- case pb::OverlayableItem::PRODUCT_SERVICES:
- out_overlayable->policies |= OverlayableItem::Policy::kProductServices;
- break;
default:
*out_error = "unknown overlayable policy";
return false;
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 76fbb46..b549e23 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -303,9 +303,6 @@
if (overlayable_item.policies & OverlayableItem::Policy::kProduct) {
pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT);
}
- if (overlayable_item.policies & OverlayableItem::Policy::kProductServices) {
- pb_overlayable_item->add_policy(pb::OverlayableItem::PRODUCT_SERVICES);
- }
if (overlayable_item.policies & OverlayableItem::Policy::kSystem) {
pb_overlayable_item->add_policy(pb::OverlayableItem::SYSTEM);
}
diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 4a3c1b8..cce3939 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -519,7 +519,7 @@
OverlayableItem overlayable_item_bar(std::make_shared<Overlayable>(
"TaskBar", "overlay://theme"));
- overlayable_item_bar.policies |= OverlayableItem::Policy::kProductServices;
+ overlayable_item_bar.policies |= OverlayableItem::Policy::kPublic;
overlayable_item_bar.policies |= OverlayableItem::Policy::kVendor;
OverlayableItem overlayable_item_baz(std::make_shared<Overlayable>(
@@ -565,7 +565,7 @@
overlayable_item = search_result.value().entry->overlayable_item.value();
EXPECT_THAT(overlayable_item.overlayable->name, Eq("TaskBar"));
EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme"));
- EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kProductServices
+ EXPECT_THAT(overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
| OverlayableItem::Policy::kVendor));
search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/baz"));
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 921d634..ad3674e 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -484,7 +484,7 @@
OverlayableItem overlayable_item(overlayable);
overlayable_item.policies |= OverlayableItem::Policy::kPublic;
- overlayable_item.policies |= OverlayableItem::Policy::kProductServices;
+ overlayable_item.policies |= OverlayableItem::Policy::kSystem;
std::unique_ptr<ResourceTable> table_b =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
@@ -506,7 +506,7 @@
EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("CustomizableResources"));
EXPECT_THAT(result_overlayable_item.overlayable->actor, Eq("overlay://customization"));
EXPECT_THAT(result_overlayable_item.policies, Eq(OverlayableItem::Policy::kPublic
- | OverlayableItem::Policy::kProductServices));
+ | OverlayableItem::Policy::kSystem));
}
TEST_F(TableMergerTest, SameResourceDifferentNameFail) {
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index 840af5d..35fba3d 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -16,6 +16,7 @@
package android.net.wifi;
+import android.annotation.SystemApi;
import android.annotation.UnsupportedAppUsage;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkUtils;
@@ -470,6 +471,7 @@
}
/** {@hide} */
+ @SystemApi
public boolean isOsuAp() {
return mOsuAp;
}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 559f4ad..801342d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -236,9 +236,11 @@
public static final int WIFI_CREDENTIAL_FORGOT = 1;
/** @hide */
+ @SystemApi
public static final int PASSPOINT_HOME_NETWORK = 0;
/** @hide */
+ @SystemApi
public static final int PASSPOINT_ROAMING_NETWORK = 1;
/**
@@ -1219,7 +1221,11 @@
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> getAllMatchingWifiConfigs(
@NonNull List<ScanResult> scanResults) {
List<Pair<WifiConfiguration, Map<Integer, List<ScanResult>>>> configs = new ArrayList<>();
@@ -1258,7 +1264,11 @@
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public Map<OsuProvider, List<ScanResult>> getMatchingOsuProviders(
List<ScanResult> scanResults) {
try {
@@ -1281,7 +1291,11 @@
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public Map<OsuProvider, PasspointConfiguration> getMatchingPasspointConfigsForOsuProviders(
@NonNull Set<OsuProvider> osuProviders) {
try {
@@ -1727,7 +1741,13 @@
* @param fqdn The FQDN of the Passpoint configuration to be removed
* @throws IllegalArgumentException if no configuration is associated with the given FQDN.
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public void removePasspointConfiguration(String fqdn) {
try {
if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
@@ -1745,7 +1765,13 @@
*
* @return A list of {@link PasspointConfiguration}
* @throws UnsupportedOperationException if Passpoint is not enabled on the device.
+ * @deprecated This is no longer supported.
*/
+ @Deprecated
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public List<PasspointConfiguration> getPasspointConfigurations() {
try {
return mService.getPasspointConfigurations();
@@ -4323,6 +4349,11 @@
* @param callback {@link ProvisioningCallback} for updates regarding provisioning flow
* @hide
*/
+ @SystemApi
+ @RequiresPermission(anyOf = {
+ android.Manifest.permission.NETWORK_SETTINGS,
+ android.Manifest.permission.NETWORK_SETUP_WIZARD
+ })
public void startSubscriptionProvisioning(OsuProvider provider, ProvisioningCallback callback,
@Nullable Handler handler) {
Looper looper = (handler == null) ? Looper.getMainLooper() : handler.getLooper();
diff --git a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
index 6d82ca1..f91790f 100644
--- a/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
+++ b/wifi/java/android/net/wifi/hotspot2/OsuProvider.java
@@ -16,6 +16,7 @@
package android.net.wifi.hotspot2;
+import android.annotation.SystemApi;
import android.graphics.drawable.Icon;
import android.net.Uri;
import android.net.wifi.WifiSsid;
@@ -36,16 +37,19 @@
*
* @hide
*/
+@SystemApi
public final class OsuProvider implements Parcelable {
/**
* OSU (Online Sign-Up) method: OMA DM (Open Mobile Alliance Device Management).
* For more info, refer to Section 8.3 of the Hotspot 2.0 Release 2 Technical Specification.
+ * @hide
*/
public static final int METHOD_OMA_DM = 0;
/**
* OSU (Online Sign-Up) method: SOAP XML SPP (Subscription Provisioning Protocol).
* For more info, refer to Section 8.4 of the Hotspot 2.0 Release 2 Technical Specification.
+ * @hide
*/
public static final int METHOD_SOAP_XML_SPP = 1;
@@ -84,6 +88,7 @@
*/
private final Icon mIcon;
+ /** @hide */
public OsuProvider(WifiSsid osuSsid, Map<String, String> friendlyNames,
String serviceDescription, Uri serverUri, String nai, List<Integer> methodList,
Icon icon) {
@@ -104,6 +109,7 @@
* Copy constructor.
*
* @param source The source to copy from
+ * @hide
*/
public OsuProvider(OsuProvider source) {
if (source == null) {
@@ -130,10 +136,12 @@
mIcon = source.mIcon;
}
+ /** @hide */
public WifiSsid getOsuSsid() {
return mOsuSsid;
}
+ /** @hide */
public void setOsuSsid(WifiSsid osuSsid) {
mOsuSsid = osuSsid;
}
@@ -162,10 +170,12 @@
return mFriendlyNames.get(mFriendlyNames.keySet().stream().findFirst().get());
}
+ /** @hide */
public Map<String, String> getFriendlyNameList() {
return mFriendlyNames;
}
+ /** @hide */
public String getServiceDescription() {
return mServiceDescription;
}
@@ -174,14 +184,17 @@
return mServerUri;
}
+ /** @hide */
public String getNetworkAccessIdentifier() {
return mNetworkAccessIdentifier;
}
+ /** @hide */
public List<Integer> getMethodList() {
return mMethodList;
}
+ /** @hide */
public Icon getIcon() {
return mIcon;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
index a62d63c..1ee874a 100644
--- a/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
+++ b/wifi/java/android/net/wifi/hotspot2/ProvisioningCallback.java
@@ -16,6 +16,7 @@
package android.net.wifi.hotspot2;
+import android.annotation.SystemApi;
import android.net.wifi.WifiManager;
import android.os.Handler;
@@ -25,6 +26,7 @@
*
* @hide
*/
+@SystemApi
public abstract class ProvisioningCallback {
/**