Merge "Allow standby timeouts to occur after usage"
diff --git a/api/current.txt b/api/current.txt
index a3a4676..97b065e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -6541,6 +6541,7 @@
field public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 2; // 0x2
field public static final int LOCK_TASK_FEATURE_RECENTS = 8; // 0x8
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
+ field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -31987,6 +31988,7 @@
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
@@ -38429,6 +38431,16 @@
field public final int errno;
}
+ public class Int32Ref {
+ ctor public Int32Ref(int);
+ field public int value;
+ }
+
+ public class Int64Ref {
+ ctor public Int64Ref(long);
+ field public long value;
+ }
+
public final class Os {
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -38498,7 +38510,8 @@
method public static void remove(java.lang.String) throws android.system.ErrnoException;
method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
- method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static void setegid(int) throws android.system.ErrnoException;
@@ -38523,7 +38536,8 @@
method public static int umask(int);
method public static android.system.StructUtsname uname();
method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
- method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -40417,6 +40431,7 @@
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -48972,6 +48987,7 @@
public abstract interface TextClassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
+ method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
@@ -48982,6 +48998,36 @@
field public static final java.lang.String TYPE_URL = "url";
}
+ public final class TextLinks {
+ method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+ method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+ }
+
+ public static final class TextLinks.Builder {
+ ctor public TextLinks.Builder(java.lang.String);
+ method public android.view.textclassifier.TextLinks.Builder addLink(android.view.textclassifier.TextLinks.TextLink);
+ method public android.view.textclassifier.TextLinks build();
+ }
+
+ public static final class TextLinks.Options {
+ method public android.os.LocaleList getDefaultLocales();
+ }
+
+ public static final class TextLinks.Options.Builder {
+ ctor public TextLinks.Options.Builder();
+ method public android.view.textclassifier.TextLinks.Options build();
+ method public android.view.textclassifier.TextLinks.Options.Builder setLocaleList(android.os.LocaleList);
+ }
+
+ public static final class TextLinks.TextLink {
+ ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public float getConfidenceScore(java.lang.String);
+ method public int getEnd();
+ method public java.lang.String getEntity(int);
+ method public int getEntityCount();
+ method public int getStart();
+ }
+
public final class TextSelection {
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3eeadaf..61aaf18 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6788,6 +6788,7 @@
field public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 2; // 0x2
field public static final int LOCK_TASK_FEATURE_RECENTS = 8; // 0x8
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
+ field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -34726,6 +34727,7 @@
field public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11; // 0xb
field public static final int POST_INSTALL_RUNNER_ERROR = 5; // 0x5
field public static final int SUCCESS = 0; // 0x0
+ field public static final int UPDATED_BUT_NOT_ACTIVE = 52; // 0x34
}
public static final class UpdateEngine.UpdateStatusConstants {
@@ -34839,6 +34841,7 @@
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int RESTRICTION_NOT_SET = 0; // 0x0
@@ -41729,6 +41732,16 @@
field public final int errno;
}
+ public class Int32Ref {
+ ctor public Int32Ref(int);
+ field public int value;
+ }
+
+ public class Int64Ref {
+ ctor public Int64Ref(long);
+ field public long value;
+ }
+
public final class Os {
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -41798,7 +41811,8 @@
method public static void remove(java.lang.String) throws android.system.ErrnoException;
method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
- method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static void setegid(int) throws android.system.ErrnoException;
@@ -41823,7 +41837,8 @@
method public static int umask(int);
method public static android.system.StructUtsname uname();
method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
- method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -52711,6 +52726,7 @@
public abstract interface TextClassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
+ method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
@@ -52721,6 +52737,36 @@
field public static final java.lang.String TYPE_URL = "url";
}
+ public final class TextLinks {
+ method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+ method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+ }
+
+ public static final class TextLinks.Builder {
+ ctor public TextLinks.Builder(java.lang.String);
+ method public android.view.textclassifier.TextLinks.Builder addLink(android.view.textclassifier.TextLinks.TextLink);
+ method public android.view.textclassifier.TextLinks build();
+ }
+
+ public static final class TextLinks.Options {
+ method public android.os.LocaleList getDefaultLocales();
+ }
+
+ public static final class TextLinks.Options.Builder {
+ ctor public TextLinks.Options.Builder();
+ method public android.view.textclassifier.TextLinks.Options build();
+ method public android.view.textclassifier.TextLinks.Options.Builder setLocaleList(android.os.LocaleList);
+ }
+
+ public static final class TextLinks.TextLink {
+ ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public float getConfidenceScore(java.lang.String);
+ method public int getEnd();
+ method public java.lang.String getEntity(int);
+ method public int getEntityCount();
+ method public int getStart();
+ }
+
public final class TextSelection {
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
diff --git a/api/test-current.txt b/api/test-current.txt
index 110cd9a..2a2967e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -6615,6 +6615,7 @@
field public static final int LOCK_TASK_FEATURE_NOTIFICATIONS = 2; // 0x2
field public static final int LOCK_TASK_FEATURE_RECENTS = 8; // 0x8
field public static final int LOCK_TASK_FEATURE_SYSTEM_INFO = 1; // 0x1
+ field public static final int MAKE_USER_EPHEMERAL = 2; // 0x2
field public static final java.lang.String MIME_TYPE_PROVISIONING_NFC = "application/com.android.managedprovisioning";
field public static final int PASSWORD_QUALITY_ALPHABETIC = 262144; // 0x40000
field public static final int PASSWORD_QUALITY_ALPHANUMERIC = 327680; // 0x50000
@@ -12308,6 +12309,7 @@
method public static int getWALAutoCheckpoint();
method public static int getWALConnectionPoolSize();
method public static java.lang.String getWALSyncMode();
+ method public static boolean isCompatibilityWalSupported();
method public static int releaseMemory();
}
@@ -32255,6 +32257,7 @@
field public static final java.lang.String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps";
field public static final java.lang.String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone";
field public static final java.lang.String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer";
+ field public static final java.lang.String DISALLOW_USER_SWITCH = "no_user_switch";
field public static final java.lang.String ENSURE_VERIFY_APPS = "ensure_verify_apps";
field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending";
field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1
@@ -35545,6 +35548,7 @@
field public static final java.lang.String ALLOWED_GEOLOCATION_ORIGINS = "allowed_geolocation_origins";
field public static final deprecated java.lang.String ALLOW_MOCK_LOCATION = "mock_location";
field public static final java.lang.String ANDROID_ID = "android_id";
+ field public static final java.lang.String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";
field public static final java.lang.String AUTOFILL_SERVICE = "autofill_service";
field public static final deprecated java.lang.String BACKGROUND_DATA = "background_data";
field public static final deprecated java.lang.String BLUETOOTH_ON = "bluetooth_on";
@@ -37600,6 +37604,13 @@
method public android.service.autofill.Dataset.Builder setValue(android.view.autofill.AutofillId, android.view.autofill.AutofillValue, java.util.regex.Pattern, android.widget.RemoteViews);
}
+ public final class FieldsDetection implements android.os.Parcelable {
+ ctor public FieldsDetection(android.view.autofill.AutofillId, java.lang.String, java.lang.String);
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.service.autofill.FieldsDetection> CREATOR;
+ }
+
public final class FillCallback {
method public void onFailure(java.lang.CharSequence);
method public void onSuccess(android.service.autofill.FillResponse);
@@ -37625,6 +37636,7 @@
method public java.util.Map<android.view.autofill.AutofillId, java.lang.String> getChangedFields();
method public android.os.Bundle getClientState();
method public java.lang.String getDatasetId();
+ method public java.util.Map<java.lang.String, java.lang.Integer> getDetectedFields();
method public java.util.Set<java.lang.String> getIgnoredDatasetIds();
method public java.util.Map<android.view.autofill.AutofillId, java.util.Set<java.lang.String>> getManuallyEnteredField();
method public java.util.Set<java.lang.String> getSelectedDatasetIds();
@@ -37662,6 +37674,7 @@
method public android.service.autofill.FillResponse.Builder disableAutofill(long);
method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
+ method public android.service.autofill.FillResponse.Builder setFieldsDetection(android.service.autofill.FieldsDetection);
method public android.service.autofill.FillResponse.Builder setFlags(int);
method public android.service.autofill.FillResponse.Builder setIgnoredIds(android.view.autofill.AutofillId...);
method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
@@ -38809,6 +38822,16 @@
field public final int errno;
}
+ public class Int32Ref {
+ ctor public Int32Ref(int);
+ field public int value;
+ }
+
+ public class Int64Ref {
+ ctor public Int64Ref(long);
+ field public long value;
+ }
+
public final class Os {
method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
method public static boolean access(java.lang.String, int) throws android.system.ErrnoException;
@@ -38878,7 +38901,8 @@
method public static void remove(java.lang.String) throws android.system.ErrnoException;
method public static void removexattr(java.lang.String, java.lang.String) throws android.system.ErrnoException;
method public static void rename(java.lang.String, java.lang.String) throws android.system.ErrnoException;
- method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static deprecated long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.util.MutableLong, long) throws android.system.ErrnoException;
+ method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
method public static void setegid(int) throws android.system.ErrnoException;
@@ -38903,7 +38927,8 @@
method public static int umask(int);
method public static android.system.StructUtsname uname();
method public static void unsetenv(java.lang.String) throws android.system.ErrnoException;
- method public static int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static deprecated int waitpid(int, android.util.MutableInt, int) throws android.system.ErrnoException;
+ method public static int waitpid(int, android.system.Int32Ref, int) throws android.system.ErrnoException;
method public static int write(java.io.FileDescriptor, java.nio.ByteBuffer) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int write(java.io.FileDescriptor, byte[], int, int) throws android.system.ErrnoException, java.io.InterruptedIOException;
method public static int writev(java.io.FileDescriptor, java.lang.Object[], int[], int[]) throws android.system.ErrnoException, java.io.InterruptedIOException;
@@ -40815,6 +40840,7 @@
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -49609,6 +49635,7 @@
public abstract interface TextClassifier {
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.view.textclassifier.TextClassification.Options);
method public default android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
+ method public default android.view.textclassifier.TextLinks generateLinks(java.lang.CharSequence, android.view.textclassifier.TextLinks.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.view.textclassifier.TextSelection.Options);
method public default android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
field public static final android.view.textclassifier.TextClassifier NO_OP;
@@ -49619,6 +49646,36 @@
field public static final java.lang.String TYPE_URL = "url";
}
+ public final class TextLinks {
+ method public boolean apply(android.text.SpannableString, java.util.function.Function<android.view.textclassifier.TextLinks.TextLink, android.text.style.ClickableSpan>);
+ method public java.util.Collection<android.view.textclassifier.TextLinks.TextLink> getLinks();
+ }
+
+ public static final class TextLinks.Builder {
+ ctor public TextLinks.Builder(java.lang.String);
+ method public android.view.textclassifier.TextLinks.Builder addLink(android.view.textclassifier.TextLinks.TextLink);
+ method public android.view.textclassifier.TextLinks build();
+ }
+
+ public static final class TextLinks.Options {
+ method public android.os.LocaleList getDefaultLocales();
+ }
+
+ public static final class TextLinks.Options.Builder {
+ ctor public TextLinks.Options.Builder();
+ method public android.view.textclassifier.TextLinks.Options build();
+ method public android.view.textclassifier.TextLinks.Options.Builder setLocaleList(android.os.LocaleList);
+ }
+
+ public static final class TextLinks.TextLink {
+ ctor public TextLinks.TextLink(java.lang.String, int, int, java.util.Map<java.lang.String, java.lang.Float>);
+ method public float getConfidenceScore(java.lang.String);
+ method public int getEnd();
+ method public java.lang.String getEntity(int);
+ method public int getEntityCount();
+ method public int getStart();
+ }
+
public final class TextSelection {
method public float getConfidenceScore(java.lang.String);
method public java.lang.String getEntity(int);
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 100a7a4..94f4adf 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -24,7 +24,11 @@
#include <limits.h>
#include <stdlib.h>
-using namespace android::util;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
using android::util::ProtoOutputStream;
using std::map;
using std::string;
@@ -166,17 +170,8 @@
mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
(long long)mCurrentBucketStartTimeNs);
- size_t bufferSize = mProto->size();
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
-
- size_t pos = 0;
- auto it = mProto->data();
- while (it.readBuffer() != NULL) {
- size_t toRead = it.currentToRead();
- std::memcpy(&buffer[pos], it.readBuffer(), toRead);
- pos += toRead;
- it.rp()->move(toRead);
- }
+ VLOG("metric %lld dump report now...", mMetric.metric_id());
+ std::unique_ptr<uint8_t[]> buffer = serializeProto();
startNewProtoOutputStream(endTime);
mPastBuckets.clear();
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index 3bfc724..c3af006 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -53,6 +53,7 @@
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
void onSlicedConditionMayChange(const uint64_t eventTime) override;
@@ -70,9 +71,12 @@
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const CountMetric mMetric;
+ // TODO: Add a lock to mPastBuckets.
std::unordered_map<HashableDimensionKey, std::vector<CountBucket>> mPastBuckets;
size_t mByteSize;
@@ -84,12 +88,6 @@
void flushCounterIfNeeded(const uint64_t newEventTime);
- std::unique_ptr<android::util::ProtoOutputStream> mProto;
-
- long long mProtoToken;
-
- void startNewProtoOutputStream(long long timestamp);
-
FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 09132bf..c0a0d98 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -23,6 +23,12 @@
#include <limits.h>
#include <stdlib.h>
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::ProtoOutputStream;
using std::string;
using std::unordered_map;
using std::vector;
@@ -31,6 +37,27 @@
namespace os {
namespace statsd {
+// for StatsLogReport
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_DURATION_METRICS = 6;
+// for DurationMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for DurationMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for DurationBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_DURATION = 3;
+
DurationMetricProducer::DurationMetricProducer(const DurationMetric& metric,
const int conditionIndex, const size_t startIndex,
const size_t stopIndex, const size_t stopAllIndex,
@@ -61,6 +88,8 @@
mConditionSliced = true;
}
+ startNewProtoOutputStream(mStartTimeNs);
+
VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -69,8 +98,15 @@
VLOG("~DurationMetric() called");
}
+void DurationMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DURATION_METRICS);
+}
+
unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
- vector<DurationBucketInfo>& bucket) {
+ vector<DurationBucket>& bucket) {
switch (mMetric.type()) {
case DurationMetric_AggregationType_DURATION_SUM:
return make_unique<OringDurationTracker>(mWizard, mConditionTrackerIndex,
@@ -124,29 +160,69 @@
}
StatsLogReport DurationMetricProducer::onDumpReport() {
- VLOG("metric %lld dump report now...", mMetric.metric_id());
- StatsLogReport report;
- report.set_metric_id(mMetric.metric_id());
- report.set_start_report_nanos(mStartTimeNs);
+ long long endTime = time(nullptr) * NS_PER_SEC;
+
// Dump current bucket if it's stale.
// If current bucket is still on-going, don't force dump current bucket.
// In finish(), We can force dump current bucket.
- flushIfNeeded(time(nullptr) * NS_PER_SEC);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+ flushIfNeeded(endTime);
+ VLOG("metric %lld dump report now...", mMetric.metric_id());
- StatsLogReport_DurationMetricDataWrapper* wrapper = report.mutable_duration_metrics();
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
+ VLOG(" dimension key %s", hashableKey.c_str());
auto it = mDimensionKeyMap.find(hashableKey);
if (it == mDimensionKeyMap.end()) {
ALOGW("Dimension key %s not found?!?! skip...", hashableKey.c_str());
continue;
}
- VLOG(" dimension key %s", hashableKey.c_str());
- addDurationBucketsToReport(*wrapper, it->second, pair.second);
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+
+ // First fill dimension (KeyValuePairs).
+ for (const auto& kv : it->second) {
+ long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION);
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
+ } else if (kv.has_value_int()) {
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ } else if (kv.has_value_bool()) {
+ mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ } else if (kv.has_value_float()) {
+ mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ }
+ mProto->end(dimensionToken);
+ }
+
+ // Then fill bucket_info (DurationBucketInfo).
+ for (const auto& bucket : pair.second) {
+ long long bucketInfoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_BUCKET_INFO);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_DURATION, (long long)bucket.mDuration);
+ mProto->end(bucketInfoToken);
+ VLOG("\t bucket [%lld - %lld] duration: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mDuration);
+ }
+
+ mProto->end(wrapperToken);
}
- return report;
-};
+
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+
+ std::unique_ptr<uint8_t[]> buffer = serializeProto();
+
+ startNewProtoOutputStream(endTime);
+ mPastBuckets.clear();
+
+ // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+ // return std::move(buffer);
+ return StatsLogReport();
+}
void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
@@ -188,17 +264,17 @@
if (matcherIndex == mStartIndex) {
it->second->noteStart(atomKey, condition, event.GetTimestampNs(), conditionKeys);
-
} else if (matcherIndex == mStopIndex) {
it->second->noteStop(atomKey, event.GetTimestampNs());
}
}
size_t DurationMetricProducer::byteSize() {
- // TODO: return actual proto size when ProtoOutputStream is ready for use for
- // DurationMetricsProducer.
- // return mProto->size();
- return 0;
+ size_t totalSize = 0;
+ for (const auto& pair : mPastBuckets) {
+ totalSize += pair.second.size() * kBucketSize;
+ }
+ return totalSize;
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 12ff58e..8fdd0d4 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -19,6 +19,7 @@
#include <unordered_map>
+#include <android/util/ProtoOutputStream.h>
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "MetricProducer.h"
@@ -48,6 +49,7 @@
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
void onSlicedConditionMayChange(const uint64_t eventTime) override;
@@ -65,6 +67,8 @@
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const DurationMetric mMetric;
@@ -81,7 +85,8 @@
const vector<KeyMatcher> mInternalDimension;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<DurationBucketInfo>> mPastBuckets;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>> mPastBuckets;
// The current bucket.
std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
@@ -89,9 +94,11 @@
void flushDurationIfNeeded(const uint64_t newEventTime);
- std::unique_ptr<DurationTracker> createDurationTracker(std::vector<DurationBucketInfo>& bucket);
+ std::unique_ptr<DurationTracker> createDurationTracker(std::vector<DurationBucket>& bucket);
void flushIfNeeded(uint64_t timestamp);
+
+ static const size_t kBucketSize = sizeof(DurationBucket{});
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index 677ae38..ee0bfde 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -23,7 +23,11 @@
#include <limits.h>
#include <stdlib.h>
-using namespace android::util;
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
using android::util::ProtoOutputStream;
using std::map;
using std::string;
@@ -87,15 +91,7 @@
size_t bufferSize = mProto->size();
VLOG("metric %lld dump report now... proto size: %zu ", mMetric.metric_id(), bufferSize);
- std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
- size_t pos = 0;
- auto it = mProto->data();
- while (it.readBuffer() != NULL) {
- size_t toRead = it.currentToRead();
- std::memcpy(&buffer[pos], it.readBuffer(), toRead);
- pos += toRead;
- it.rp()->move(toRead);
- }
+ std::unique_ptr<uint8_t[]> buffer = serializeProto();
startNewProtoOutputStream(endTime);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 0fc2b5b..2ca8181 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -49,6 +49,7 @@
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
void onSlicedConditionMayChange(const uint64_t eventTime) override;
@@ -60,14 +61,11 @@
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
+protected:
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const EventMetric mMetric;
-
- std::unique_ptr<android::util::ProtoOutputStream> mProto;
-
- long long mProtoToken;
-
- void startNewProtoOutputStream(long long timestamp);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 285c8f4..dcfcc19 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -24,6 +24,12 @@
#include <limits.h>
#include <stdlib.h>
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::ProtoOutputStream;
using std::map;
using std::string;
using std::unordered_map;
@@ -33,6 +39,27 @@
namespace os {
namespace statsd {
+// for StatsLogReport
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_GAUGE_METRICS = 8;
+// for GaugeMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for GaugeMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for GaugeBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_GAUGE = 3;
+
GaugeMetricProducer::GaugeMetricProducer(const GaugeMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& wizard, const int pullTagId)
: MetricProducer((time(nullptr) * NS_PER_SEC), conditionIndex, wizard),
@@ -59,6 +86,8 @@
metric.bucket().bucket_size_millis());
}
+ startNewProtoOutputStream(mStartTimeNs);
+
VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -67,37 +96,23 @@
VLOG("~GaugeMetricProducer() called");
}
-void GaugeMetricProducer::finish() {
+void GaugeMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_GAUGE_METRICS);
}
-static void addSlicedGaugeToReport(const vector<KeyValuePair>& key,
- const vector<GaugeBucketInfo>& buckets,
- StatsLogReport_GaugeMetricDataWrapper& wrapper) {
- GaugeMetricData* data = wrapper.add_data();
- for (const auto& kv : key) {
- data->add_dimension()->CopyFrom(kv);
- }
- for (const auto& bucket : buckets) {
- data->add_bucket_info()->CopyFrom(bucket);
- VLOG("\t bucket [%lld - %lld] gauge: %lld", bucket.start_bucket_nanos(),
- bucket.end_bucket_nanos(), bucket.gauge());
- }
+void GaugeMetricProducer::finish() {
}
StatsLogReport GaugeMetricProducer::onDumpReport() {
VLOG("gauge metric %lld dump report now...", mMetric.metric_id());
- StatsLogReport report;
- report.set_metric_id(mMetric.metric_id());
- report.set_start_report_nanos(mStartTimeNs);
-
// Dump current bucket if it's stale.
// If current bucket is still on-going, don't force dump current bucket.
// In finish(), We can force dump current bucket.
flushGaugeIfNeededLocked(time(nullptr) * NS_PER_SEC);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
-
- StatsLogReport_GaugeMetricDataWrapper* wrapper = report.mutable_gauge_metrics();
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
@@ -108,10 +123,53 @@
}
VLOG(" dimension key %s", hashableKey.c_str());
- addSlicedGaugeToReport(it->second, pair.second, *wrapper);
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+
+ // First fill dimension (KeyValuePairs).
+ for (const auto& kv : it->second) {
+ long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION);
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
+ } else if (kv.has_value_int()) {
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ } else if (kv.has_value_bool()) {
+ mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ } else if (kv.has_value_float()) {
+ mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ }
+ mProto->end(dimensionToken);
+ }
+
+ // Then fill bucket_info (GaugeBucketInfo).
+ for (const auto& bucket : pair.second) {
+ long long bucketInfoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_BUCKET_INFO);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_GAUGE, (long long)bucket.mGauge);
+ mProto->end(bucketInfoToken);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mGauge);
+ }
+ mProto->end(wrapperToken);
}
- return report;
- // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+
+ std::unique_ptr<uint8_t[]> buffer = serializeProto();
+
+ startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
+ mPastBuckets.clear();
+ mByteSize = 0;
+
+ // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+ // return std::move(buffer);
+ return StatsLogReport();
+
+ // TODO: Clear mDimensionKeyMap once the report is dumped.
}
void GaugeMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
@@ -207,14 +265,15 @@
// Adjusts the bucket start time
int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- GaugeBucketInfo info;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
+ GaugeBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
for (const auto& slice : mCurrentSlicedBucket) {
- info.set_gauge(slice.second);
+ info.mGauge = slice.second;
auto& bucketList = mPastBuckets[slice.first];
bucketList.push_back(info);
+ mByteSize += sizeof(info);
VLOG("gauge metric %lld, dump key value: %s -> %ld", mMetric.metric_id(),
slice.first.c_str(), slice.second);
@@ -227,6 +286,10 @@
(long long)mCurrentBucketStartTimeNs);
}
+size_t GaugeMetricProducer::byteSize() {
+ return mByteSize;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index bf8a86f..3757174 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -18,6 +18,7 @@
#include <unordered_map>
+#include <android/util/ProtoOutputStream.h>
#include "../condition/ConditionTracker.h"
#include "../external/PullDataReceiver.h"
#include "../external/StatsPullerManager.h"
@@ -31,6 +32,12 @@
namespace os {
namespace statsd {
+struct GaugeBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mGauge;
+};
+
// This gauge metric producer first register the puller to automatically pull the gauge at the
// beginning of each bucket. If the condition is met, insert it to the bucket info. Otherwise
// proactively pull the gauge when the condition is changed to be true. Therefore, the gauge metric
@@ -52,12 +59,10 @@
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
- // TODO: implements it when supporting proto stream.
- size_t byteSize() override {
- return 0;
- };
+ size_t byteSize() override;
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
@@ -70,6 +75,8 @@
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
// The default bucket size for gauge metric is 1 second.
static const uint64_t kDefaultGaugemBucketSizeNs = 1000 * 1000 * 1000;
@@ -82,7 +89,8 @@
Mutex mLock;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<GaugeBucketInfo>> mPastBuckets;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
// The current bucket.
std::unordered_map<HashableDimensionKey, long> mCurrentSlicedBucket;
@@ -90,6 +98,8 @@
void flushGaugeIfNeededLocked(const uint64_t newEventTime);
long getGauge(const LogEvent& event);
+
+ size_t mByteSize;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 535f4a2..5ca83b2 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -64,6 +64,23 @@
scheduledPull);
}
+std::unique_ptr<uint8_t[]> MetricProducer::serializeProto() {
+ size_t bufferSize = mProto->size();
+
+ std::unique_ptr<uint8_t[]> buffer(new uint8_t[bufferSize]);
+
+ size_t pos = 0;
+ auto it = mProto->data();
+ while (it.readBuffer() != NULL) {
+ size_t toRead = it.currentToRead();
+ std::memcpy(&buffer[pos], it.readBuffer(), toRead);
+ pos += toRead;
+ it.rp()->move(toRead);
+ }
+
+ return buffer;
+}
+
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 6ba726f4..7ac97a8 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -59,6 +59,8 @@
// coming. MetricProducer should do the clean up, and dump existing data to dropbox.
virtual void finish() = 0;
+ // TODO: Pass a timestamp as a parameter in onDumpReport and update all its
+ // implementations.
virtual StatsLogReport onDumpReport() = 0;
virtual bool isConditionSliced() const {
@@ -109,6 +111,14 @@
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
const LogEvent& event, bool scheduledPull) = 0;
+
+ std::unique_ptr<android::util::ProtoOutputStream> mProto;
+
+ long long mProtoToken;
+
+ virtual void startNewProtoOutputStream(long long timestamp) = 0;
+
+ std::unique_ptr<uint8_t[]> serializeProto();
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 07a078f..41b7a5d 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -23,6 +23,12 @@
#include <limits.h>
#include <stdlib.h>
+using android::util::FIELD_TYPE_BOOL;
+using android::util::FIELD_TYPE_FLOAT;
+using android::util::FIELD_TYPE_INT32;
+using android::util::FIELD_TYPE_INT64;
+using android::util::FIELD_TYPE_MESSAGE;
+using android::util::ProtoOutputStream;
using std::list;
using std::make_shared;
using std::map;
@@ -34,6 +40,27 @@
namespace os {
namespace statsd {
+// for StatsLogReport
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_START_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
+const int FIELD_ID_VALUE_METRICS = 7;
+// for ValueMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for ValueMetricData
+const int FIELD_ID_DIMENSION = 1;
+const int FIELD_ID_BUCKET_INFO = 2;
+// for KeyValuePair
+const int FIELD_ID_KEY = 1;
+const int FIELD_ID_VALUE_STR = 2;
+const int FIELD_ID_VALUE_INT = 3;
+const int FIELD_ID_VALUE_BOOL = 4;
+const int FIELD_ID_VALUE_FLOAT = 5;
+// for ValueBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_VALUE = 3;
+
// ValueMetric has a minimum bucket size of 10min so that we don't pull too frequently
ValueMetricProducer::ValueMetricProducer(const ValueMetric& metric, const int conditionIndex,
const sp<ConditionWizard>& wizard, const int pullTagId,
@@ -55,6 +82,8 @@
metric.bucket().bucket_size_millis());
}
+ startNewProtoOutputStream(mStartTimeNs);
+
VLOG("value metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -63,25 +92,18 @@
VLOG("~ValueMetricProducer() called");
}
+void ValueMetricProducer::startNewProtoOutputStream(long long startTime) {
+ mProto = std::make_unique<ProtoOutputStream>();
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_METRIC_ID, mMetric.metric_id());
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_REPORT_NANOS, startTime);
+ mProtoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_VALUE_METRICS);
+}
+
void ValueMetricProducer::finish() {
// TODO: write the StatsLogReport to dropbox using
// DropboxWriter.
}
-static void addSlicedCounterToReport(StatsLogReport_ValueMetricDataWrapper& wrapper,
- const vector<KeyValuePair>& key,
- const vector<ValueBucketInfo>& buckets) {
- ValueMetricData* data = wrapper.add_data();
- for (const auto& kv : key) {
- data->add_dimension()->CopyFrom(kv);
- }
- for (const auto& bucket : buckets) {
- data->add_bucket_info()->CopyFrom(bucket);
- VLOG("\t bucket [%lld - %lld] value: %lld", bucket.start_bucket_nanos(),
- bucket.end_bucket_nanos(), bucket.value());
- }
-}
-
void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
}
@@ -89,26 +111,62 @@
StatsLogReport ValueMetricProducer::onDumpReport() {
VLOG("metric %lld dump report now...", mMetric.metric_id());
- StatsLogReport report;
- report.set_metric_id(mMetric.metric_id());
- report.set_start_report_nanos(mStartTimeNs);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
-
- StatsLogReport_ValueMetricDataWrapper* wrapper = report.mutable_value_metrics();
-
for (const auto& pair : mPastBuckets) {
const HashableDimensionKey& hashableKey = pair.first;
+ VLOG(" dimension key %s", hashableKey.c_str());
auto it = mDimensionKeyMap.find(hashableKey);
if (it == mDimensionKeyMap.end()) {
ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
continue;
}
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
- VLOG(" dimension key %s", hashableKey.c_str());
- addSlicedCounterToReport(*wrapper, it->second, pair.second);
+ // First fill dimension (KeyValuePairs).
+ for (const auto& kv : it->second) {
+ long long dimensionToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DIMENSION);
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_KEY, kv.key());
+ if (kv.has_value_str()) {
+ mProto->write(FIELD_TYPE_INT32 | FIELD_ID_VALUE_STR, kv.value_str());
+ } else if (kv.has_value_int()) {
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE_INT, kv.value_int());
+ } else if (kv.has_value_bool()) {
+ mProto->write(FIELD_TYPE_BOOL | FIELD_ID_VALUE_BOOL, kv.value_bool());
+ } else if (kv.has_value_float()) {
+ mProto->write(FIELD_TYPE_FLOAT | FIELD_ID_VALUE_FLOAT, kv.value_float());
+ }
+ mProto->end(dimensionToken);
+ }
+
+ // Then fill bucket_info (ValueBucketInfo).
+ for (const auto& bucket : pair.second) {
+ long long bucketInfoToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_BUCKET_INFO);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_START_BUCKET_NANOS,
+ (long long)bucket.mBucketStartNs);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_BUCKET_NANOS,
+ (long long)bucket.mBucketEndNs);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_VALUE, (long long)bucket.mValue);
+ mProto->end(bucketInfoToken);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mValue);
+ }
+ mProto->end(wrapperToken);
}
- return report;
- // TODO: Clear mPastBuckets, mDimensionKeyMap once the report is dumped.
+ mProto->end(mProtoToken);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS,
+ (long long)mCurrentBucketStartTimeNs);
+
+ VLOG("metric %lld dump report now...", mMetric.metric_id());
+ std::unique_ptr<uint8_t[]> buffer = serializeProto();
+
+ startNewProtoOutputStream(time(nullptr) * NS_PER_SEC);
+ mPastBuckets.clear();
+ mByteSize = 0;
+
+ // TODO: Once we migrate all MetricProducers to use ProtoOutputStream, we should return this:
+ // return std::move(buffer);
+ return StatsLogReport();
+
+ // TODO: Clear mDimensionKeyMap once the report is dumped.
}
void ValueMetricProducer::onConditionChanged(const bool condition, const uint64_t eventTime) {
@@ -207,20 +265,21 @@
VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
(int)mCurrentSlicedBucket.size());
- ValueBucketInfo info;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
+ ValueBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
for (const auto& slice : mCurrentSlicedBucket) {
long value = 0;
for (const auto& pair : slice.second.raw) {
value += pair.second - pair.first;
}
- info.set_value(value);
+ info.mValue = value;
VLOG(" %s, %ld", slice.first.c_str(), value);
// it will auto create new vector of ValuebucketInfo if the key is not found.
auto& bucketList = mPastBuckets[slice.first];
bucketList.push_back(info);
+ mByteSize += sizeof(info);
}
// Reset counters
@@ -235,6 +294,10 @@
(long long)mCurrentBucketStartTimeNs);
}
+size_t ValueMetricProducer::byteSize() {
+ return mByteSize;
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 548cd44..8437665 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -30,6 +30,12 @@
namespace os {
namespace statsd {
+struct ValueBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mValue;
+};
+
class ValueMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
public:
ValueMetricProducer(const ValueMetric& valueMetric, const int conditionIndex,
@@ -42,15 +48,14 @@
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
void onSlicedConditionMayChange(const uint64_t eventTime);
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
- // TODO: Implement this later.
- size_t byteSize() override {
- return 0;
- };
+
+ size_t byteSize() override;
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
@@ -63,6 +68,8 @@
bool condition, const LogEvent& event,
bool scheduledPull) override;
+ void startNewProtoOutputStream(long long timestamp) override;
+
private:
const ValueMetric mMetric;
@@ -84,11 +91,14 @@
std::unordered_map<HashableDimensionKey, Interval> mNextSlicedBucket;
// Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<ValueBucketInfo>> mPastBuckets;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<ValueBucket>> mPastBuckets;
long get_value(const LogEvent& event);
void flush_if_needed(const uint64_t eventTimeNs);
+
+ size_t mByteSize;
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 0d0d9a4..aeb234d 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -47,10 +47,16 @@
DurationInfo() : state(kStopped), lastStartTime(0), lastDuration(0){};
};
+struct DurationBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mDuration;
+};
+
class DurationTracker {
public:
DurationTracker(sp<ConditionWizard> wizard, int conditionIndex, uint64_t currentBucketStartNs,
- uint64_t bucketSizeNs, std::vector<DurationBucketInfo>& bucket)
+ uint64_t bucketSizeNs, std::vector<DurationBucket>& bucket)
: mWizard(wizard),
mConditionTrackerIndex(conditionIndex),
mCurrentBucketStartTimeNs(currentBucketStartNs),
@@ -77,7 +83,7 @@
int64_t mBucketSizeNs;
- std::vector<DurationBucketInfo>& mBucket; // where to write output
+ std::vector<DurationBucket>& mBucket; // where to write output
int64_t mDuration; // current recorded duration result
};
@@ -86,4 +92,4 @@
} // namespace os
} // namespace android
-#endif // DURATION_TRACKER_H
\ No newline at end of file
+#endif // DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 856ca9d..a4d3098 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -25,7 +25,7 @@
MaxDurationTracker::MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket)
+ std::vector<DurationBucket>& bucket)
: DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket) {
}
@@ -106,10 +106,12 @@
// adjust the bucket start time
int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- DurationBucketInfo info;
uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(endTime);
+
+ DurationBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = endTime;
+
uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
@@ -150,7 +152,7 @@
}
if (mDuration != 0) {
- info.set_duration_nanos(mDuration);
+ info.mDuration = mDuration;
mBucket.push_back(info);
VLOG(" final duration for last bucket: %lld", (long long)mDuration);
}
@@ -158,10 +160,10 @@
mDuration = 0;
if (hasOnGoingStartedEvent) {
for (int i = 1; i < numBucketsForward; i++) {
- DurationBucketInfo info;
- info.set_start_bucket_nanos(oldBucketStartTimeNs + mBucketSizeNs * i);
- info.set_end_bucket_nanos(endTime + mBucketSizeNs * i);
- info.set_duration_nanos(mBucketSizeNs);
+ DurationBucket info;
+ info.mBucketStartNs = oldBucketStartTimeNs + mBucketSizeNs * i;
+ info.mBucketEndNs = endTime + mBucketSizeNs * i;
+ info.mDuration = mBucketSizeNs;
mBucket.push_back(info);
VLOG(" filling gap bucket with duration %lld", (long long)mBucketSizeNs);
}
@@ -224,4 +226,4 @@
} // namespace statsd
} // namespace os
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index c74d070..de53d62 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -32,7 +32,7 @@
public:
MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket);
+ std::vector<DurationBucket>& bucket);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) override;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index e045fb4..e4f1d21 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -22,7 +22,7 @@
namespace statsd {
OringDurationTracker::OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket)
+ std::vector<DurationBucket>& bucket)
: DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket),
mStarted(),
mPaused() {
@@ -82,10 +82,10 @@
VLOG("OringDurationTracker Flushing.............");
// adjust the bucket start time
int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- DurationBucketInfo info;
+ DurationBucket info;
uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(endTime);
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = endTime;
uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
@@ -94,7 +94,7 @@
mDuration += (endTime - mLastStartTime);
}
if (mDuration != 0) {
- info.set_duration_nanos(mDuration);
+ info.mDuration = mDuration;
// it will auto create new vector of CountbucketInfo if the key is not found.
mBucket.push_back(info);
VLOG(" duration: %lld", (long long)mDuration);
@@ -102,10 +102,10 @@
if (mStarted.size() > 0) {
for (int i = 1; i < numBucketsForward; i++) {
- DurationBucketInfo info;
- info.set_start_bucket_nanos(oldBucketStartTimeNs + mBucketSizeNs * i);
- info.set_end_bucket_nanos(endTime + mBucketSizeNs * i);
- info.set_duration_nanos(mBucketSizeNs);
+ DurationBucket info;
+ info.mBucketStartNs = oldBucketStartTimeNs + mBucketSizeNs * i;
+ info.mBucketEndNs = endTime + mBucketSizeNs * i;
+ info.mDuration = mBucketSizeNs;
mBucket.push_back(info);
VLOG(" add filling bucket with duration %lld", (long long)mBucketSizeNs);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index 5425251..b54dafa 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -29,7 +29,7 @@
public:
OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- std::vector<DurationBucketInfo>& bucket);
+ std::vector<DurationBucket>& bucket);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) override;
@@ -54,4 +54,4 @@
} // namespace os
} // namespace android
-#endif // ORING_DURATION_TRACKER_H
\ No newline at end of file
+#endif // ORING_DURATION_TRACKER_H
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index f2abe7b..58bf1b3 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -39,7 +39,7 @@
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
@@ -55,13 +55,13 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(20, buckets[0].duration_nanos());
+ EXPECT_EQ(20, buckets[0].mDuration);
}
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
@@ -73,8 +73,8 @@
tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ((long long)(bucketSizeNs - 1), buckets[0].duration_nanos());
- EXPECT_EQ((long long)bucketSizeNs, buckets[1].duration_nanos());
+ EXPECT_EQ((long long)(bucketSizeNs - 1), buckets[0].mDuration);
+ EXPECT_EQ((long long)bucketSizeNs, buckets[1].mDuration);
}
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
@@ -86,7 +86,7 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -103,7 +103,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5, buckets[0].duration_nanos());
+ EXPECT_EQ(5, buckets[0].mDuration);
}
} // namespace statsd
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 338d55d..74a6f11 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -40,7 +40,7 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -56,7 +56,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(durationTimeNs, buckets[0].duration_nanos());
+ EXPECT_EQ(durationTimeNs, buckets[0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChange) {
@@ -68,7 +68,7 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucketInfo> buckets;
+ vector<DurationBucket> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
@@ -85,7 +85,7 @@
tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5, buckets[0].duration_nanos());
+ EXPECT_EQ(5, buckets[0].mDuration);
}
} // namespace statsd
} // namespace os
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 7703fdc..bc344d7 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3943,9 +3943,6 @@
android.telephony.VoLteServiceState
android.telephony.VoLteServiceState$1
android.telephony.gsm.GsmCellLocation
-android.telephony.ims.ImsServiceProxy$INotifyStatusChanged
-android.telephony.ims.ImsServiceProxyCompat
-android.telephony.ims.feature.IMMTelFeature
android.telephony.ims.stub.ImsConfigImplBase
android.telephony.ims.stub.ImsEcbmImplBase
android.telephony.ims.stub.ImsUtImplBase
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 772c6d6..f0226b7 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3246,6 +3246,7 @@
* that uses {@link DeviceAdminInfo#USES_POLICY_WIPE_DATA}
*/
public void wipeData(int flags) {
+ throwIfParentInstance("wipeData");
final String wipeReasonForUser = mContext.getString(
R.string.work_profile_deleted_description_dpm_wipe);
wipeDataInternal(flags, wipeReasonForUser);
@@ -3270,6 +3271,7 @@
* @throws IllegalArgumentException if the input reason string is null or empty.
*/
public void wipeDataWithReason(int flags, @NonNull CharSequence reason) {
+ throwIfParentInstance("wipeDataWithReason");
Preconditions.checkNotNull(reason, "CharSequence is null");
wipeDataInternal(flags, reason.toString());
}
@@ -3283,7 +3285,6 @@
* @hide
*/
private void wipeDataInternal(int flags, @NonNull String wipeReasonForUser) {
- throwIfParentInstance("wipeDataWithReason");
if (mService != null) {
try {
mService.wipeDataWithReason(flags, wipeReasonForUser);
@@ -6096,8 +6097,8 @@
/**
* Flag used by {@link #createAndManageUser} to specify that the user should be created
- * ephemeral.
- * @hide
+ * ephemeral. Ephemeral users will be removed after switching to another user or rebooting the
+ * device.
*/
public static final int MAKE_USER_EPHEMERAL = 0x0002;
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index f4fdcaa..5673361 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1184,10 +1184,10 @@
}
/**
- * Sets the UID that initiated package installation. This is informational
+ * Sets the UID that initiated the package installation. This is informational
* and may be used as a signal for anti-malware purposes.
*
- * @see PackageManager#EXTRA_VERIFICATION_INSTALLER_UID
+ * @see Intent#EXTRA_ORIGINATING_UID
*/
public void setOriginatingUid(int originatingUid) {
this.originatingUid = originatingUid;
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 361b81b..b692039 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -416,7 +416,8 @@
boolean foreignKeyModeChanged = configuration.foreignKeyConstraintsEnabled
!= mConfiguration.foreignKeyConstraintsEnabled;
boolean walModeChanged = ((configuration.openFlags ^ mConfiguration.openFlags)
- & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
+ & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0
+ || configuration.useCompatibilityWal != mConfiguration.useCompatibilityWal;
boolean localeChanged = !configuration.locale.equals(mConfiguration.locale);
// Update configuration parameters.
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index bb2a517..d6d9764 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -83,7 +83,6 @@
/**
* Returns true if compatibility WAL mode is supported. In this mode, only
* database journal mode is changed. Connection pool will use at most one connection.
- * @hide
*/
public static boolean isCompatibilityWalSupported() {
return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
index 46bb346..394ac42 100644
--- a/core/java/android/net/ConnectivityMetricsEvent.java
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -18,6 +18,7 @@
import android.os.Parcel;
import android.os.Parcelable;
+
import com.android.internal.util.BitUtils;
/**
@@ -80,7 +81,7 @@
StringBuilder buffer = new StringBuilder("ConnectivityMetricsEvent(");
buffer.append(String.format("%tT.%tL", timestamp, timestamp));
if (netId != 0) {
- buffer.append(", ").append(netId);
+ buffer.append(", ").append("netId=").append(netId);
}
if (ifname != null) {
buffer.append(", ").append(ifname);
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index 16b1452..64f8f39 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -78,7 +78,11 @@
/**
* AES-GCM Authentication/Integrity + Encryption/Ciphering Algorithm.
*
- * <p>Valid lengths for this key are {128, 192, 256}.
+ * <p>Valid lengths for keying material are {160, 224, 288}.
+ *
+ * <p>As per RFC4106 (Section 8.1), keying material consists of a 128, 192, or 256 bit AES key
+ * followed by a 32-bit salt. RFC compliance requires that the salt must be unique per
+ * invocation with the same key.
*
* <p>Valid ICV (truncation) lengths are {64, 96, 128}.
*/
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index d7b3256..eccd5f4 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -136,7 +136,7 @@
}
@Override
- protected void finalize() {
+ protected void finalize() throws Throwable {
if (mCloseGuard != null) {
mCloseGuard.warnIfOpen();
}
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 05c8afb..6e4a231 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -16,18 +16,18 @@
package android.net;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.InputStream;
-import java.io.FileDescriptor;
-import java.net.SocketOptions;
-
import android.system.ErrnoException;
+import android.system.Int32Ref;
import android.system.Os;
import android.system.OsConstants;
import android.system.StructLinger;
import android.system.StructTimeval;
-import android.util.MutableInt;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.SocketOptions;
/**
* Socket implementation used for android.net.LocalSocket and
@@ -62,7 +62,7 @@
FileDescriptor myFd = fd;
if (myFd == null) throw new IOException("socket closed");
- MutableInt avail = new MutableInt(0);
+ Int32Ref avail = new Int32Ref(0);
try {
Os.ioctlInt(myFd, OsConstants.FIONREAD, avail);
} catch (ErrnoException e) {
@@ -167,7 +167,7 @@
if (myFd == null) throw new IOException("socket closed");
// Loop until the output buffer is empty.
- MutableInt pending = new MutableInt(0);
+ Int32Ref pending = new Int32Ref(0);
while (true) {
try {
// See linux/net/unix/af_unix.c
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
new file mode 100644
index 0000000..e76d17d
--- /dev/null
+++ b/core/java/android/net/MacAddress.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2017 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.net;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.Arrays;
+
+/**
+ * @hide
+ */
+public final class MacAddress {
+
+ // TODO: add isLocallyAssigned().
+ // TODO: add getRandomAddress() factory method.
+
+ private static final int ETHER_ADDR_LEN = 6;
+ private static final byte FF = (byte) 0xff;
+ @VisibleForTesting
+ static final byte[] ETHER_ADDR_BROADCAST = { FF, FF, FF, FF, FF, FF };
+
+ public enum MacAddressType {
+ UNICAST,
+ MULTICAST,
+ BROADCAST;
+ }
+
+ /** Return true if the given byte array is not null and has the length of a mac address. */
+ public static boolean isMacAddress(byte[] addr) {
+ return addr != null && addr.length == ETHER_ADDR_LEN;
+ }
+
+ /**
+ * Return the MacAddressType of the mac address represented by the given byte array,
+ * or null if the given byte array does not represent an mac address. */
+ public static MacAddressType macAddressType(byte[] addr) {
+ if (!isMacAddress(addr)) {
+ return null;
+ }
+ if (Arrays.equals(addr, ETHER_ADDR_BROADCAST)) {
+ return MacAddressType.BROADCAST;
+ }
+ if ((addr[0] & 0x01) == 1) {
+ return MacAddressType.MULTICAST;
+ }
+ return MacAddressType.UNICAST;
+ }
+}
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index d5377c7..9edcc0e 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -1066,7 +1066,7 @@
return null;
}
- int end = authority.indexOf('@');
+ int end = authority.lastIndexOf('@');
return end == NOT_FOUND ? null : authority.substring(0, end);
}
@@ -1090,7 +1090,7 @@
}
// Parse out user info and then port.
- int userInfoSeparator = authority.indexOf('@');
+ int userInfoSeparator = authority.lastIndexOf('@');
int portSeparator = authority.indexOf(':', userInfoSeparator);
String encodedHost = portSeparator == NOT_FOUND
@@ -1116,7 +1116,7 @@
// Make sure we look for the port separtor *after* the user info
// separator. We have URLs with a ':' in the user info.
- int userInfoSeparator = authority.indexOf('@');
+ int userInfoSeparator = authority.lastIndexOf('@');
int portSeparator = authority.indexOf(':', userInfoSeparator);
if (portSeparator == NOT_FOUND) {
diff --git a/core/java/android/net/metrics/ConnectStats.java b/core/java/android/net/metrics/ConnectStats.java
index 2495cab..b320b75 100644
--- a/core/java/android/net/metrics/ConnectStats.java
+++ b/core/java/android/net/metrics/ConnectStats.java
@@ -119,7 +119,8 @@
@Override
public String toString() {
- StringBuilder builder = new StringBuilder("ConnectStats(").append(netId).append(", ");
+ StringBuilder builder =
+ new StringBuilder("ConnectStats(").append("netId=").append(netId).append(", ");
for (int t : BitUtils.unpackBits(transports)) {
builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
}
diff --git a/core/java/android/net/metrics/DnsEvent.java b/core/java/android/net/metrics/DnsEvent.java
index 81b098b..5aa705b 100644
--- a/core/java/android/net/metrics/DnsEvent.java
+++ b/core/java/android/net/metrics/DnsEvent.java
@@ -85,7 +85,8 @@
@Override
public String toString() {
- StringBuilder builder = new StringBuilder("DnsEvent(").append(netId).append(", ");
+ StringBuilder builder =
+ new StringBuilder("DnsEvent(").append("netId=").append(netId).append(", ");
for (int t : BitUtils.unpackBits(transports)) {
builder.append(NetworkCapabilities.transportNameOf(t)).append(", ");
}
diff --git a/core/java/android/os/UpdateEngine.java b/core/java/android/os/UpdateEngine.java
index ee0b623..c6149be 100644
--- a/core/java/android/os/UpdateEngine.java
+++ b/core/java/android/os/UpdateEngine.java
@@ -67,6 +67,7 @@
public static final int PAYLOAD_HASH_MISMATCH_ERROR = 10;
public static final int PAYLOAD_SIZE_MISMATCH_ERROR = 11;
public static final int DOWNLOAD_PAYLOAD_VERIFICATION_ERROR = 12;
+ public static final int UPDATED_BUT_NOT_ACTIVE = 52;
}
/**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index c54b72d..28836e4 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -792,6 +792,19 @@
public static final String DISALLOW_AUTOFILL = "no_autofill";
/**
+ * Specifies if user switching is blocked on the current user.
+ *
+ * <p> This restriction can only be set by the device owner, it will be applied to all users.
+ *
+ * <p>The default value is <code>false</code>.
+ *
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
+ * @see #getUserRestrictions()
+ */
+ public static final String DISALLOW_USER_SWITCH = "no_user_switch";
+
+ /**
* Application restriction key that is used to indicate the pending arrival
* of real restrictions for the app.
*
@@ -917,7 +930,7 @@
/**
* Returns whether switching users is currently allowed.
* <p>For instance switching users is not allowed if the current user is in a phone call,
- * or system user hasn't been unlocked yet
+ * system user hasn't been unlocked yet, or {@link #DISALLOW_USER_SWITCH} is set.
* @hide
*/
public boolean canSwitchUsers() {
@@ -927,7 +940,9 @@
boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
boolean inCall = TelephonyManager.getDefault().getCallState()
!= TelephonyManager.CALL_STATE_IDLE;
- return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall;
+ boolean isUserSwitchDisallowed = hasUserRestriction(DISALLOW_USER_SWITCH);
+ return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall
+ && !isUserSwitchDisallowed;
}
/**
@@ -2298,6 +2313,9 @@
if (!supportsMultipleUsers()) {
return false;
}
+ if (hasUserRestriction(DISALLOW_USER_SWITCH)) {
+ return false;
+ }
// If Demo Mode is on, don't show user switcher
if (isDeviceInDemoMode(mContext)) {
return false;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 0a20c43..1716305 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5317,6 +5317,15 @@
public static final String AUTOFILL_SERVICE = "autofill_service";
/**
+ * Experimental autofill feature.
+ *
+ * <p>TODO(b/67867469): remove once feature is finished
+ * @hide
+ */
+ @TestApi
+ public static final String AUTOFILL_FEATURE_FIELD_DETECTION = "autofill_field_detection";
+
+ /**
* @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
*/
@Deprecated
diff --git a/core/java/android/service/autofill/FieldsDetection.java b/core/java/android/service/autofill/FieldsDetection.java
new file mode 100644
index 0000000..550ecf6
--- /dev/null
+++ b/core/java/android/service/autofill/FieldsDetection.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.service.autofill;
+
+import android.annotation.TestApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.view.autofill.AutofillId;
+
+/**
+ * Class by service to improve autofillable fields detection by tracking the meaning of fields
+ * manually edited by the user (when they match values provided by the service).
+ *
+ * TODO(b/67867469):
+ * - proper javadoc
+ * - unhide / remove testApi
+ * - add FieldsDetection management so service can set it just once and reference it in further
+ * calls to improve performance (and also API to refresh it)
+ * - rename to FieldsDetectionInfo or FieldClassification? (same for CTS tests)
+ * - add FieldsDetectionUnitTest once API is well-defined
+ * @hide
+ */
+@TestApi
+public final class FieldsDetection implements Parcelable {
+
+ private final AutofillId mFieldId;
+ private final String mRemoteId;
+ private final String mValue;
+
+ /**
+ * Creates a field detection for just one field / value pair.
+ *
+ * @param fieldId autofill id of the field in the screen.
+ * @param remoteId id used by the service to identify the field later.
+ * @param value field value known to the service.
+ *
+ * TODO(b/67867469):
+ * - proper javadoc
+ * - change signature to allow more fields / values / match methods
+ * - might also need to use a builder, where the constructor is the id for the fieldsdetector
+ * - might need id for values as well
+ * - add @NonNull / check it / add unit tests
+ * - make 'value' input more generic so it can accept distance-based match and other matches
+ * - throw exception if field value is less than X characters (somewhere between 7-10)
+ * - make sure to limit total number of fields to around 10 or so
+ * - use AutofillValue instead of String (so it can compare dates, for example)
+ */
+ public FieldsDetection(AutofillId fieldId, String remoteId, String value) {
+ mFieldId = fieldId;
+ mRemoteId = remoteId;
+ mValue = value;
+ }
+
+ /** @hide */
+ public AutofillId getFieldId() {
+ return mFieldId;
+ }
+
+ /** @hide */
+ public String getRemoteId() {
+ return mRemoteId;
+ }
+
+ /** @hide */
+ public String getValue() {
+ return mValue;
+ }
+
+ /////////////////////////////////////
+ // Object "contract" methods. //
+ /////////////////////////////////////
+ @Override
+ public String toString() {
+ // Cannot disclose remoteId or value because they could contain PII
+ return new StringBuilder("FieldsDetection: [field=").append(mFieldId)
+ .append(", remoteId_length=").append(mRemoteId.length())
+ .append(", value_length=").append(mValue.length())
+ .append("]").toString();
+ }
+
+ /////////////////////////////////////
+ // Parcelable "contract" methods. //
+ /////////////////////////////////////
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeParcelable(mFieldId, flags);
+ parcel.writeString(mRemoteId);
+ parcel.writeString(mValue);
+ }
+
+ public static final Parcelable.Creator<FieldsDetection> CREATOR =
+ new Parcelable.Creator<FieldsDetection>() {
+ @Override
+ public FieldsDetection createFromParcel(Parcel parcel) {
+ // TODO(b/67867469): remove comment below if it does not use a builder at the end
+ // Always go through the builder to ensure the data ingested by
+ // the system obeys the contract of the builder to avoid attacks
+ // using specially crafted parcels.
+ return new FieldsDetection(parcel.readParcelable(null), parcel.readString(),
+ parcel.readString());
+ }
+
+ @Override
+ public FieldsDetection[] newArray(int size) {
+ return new FieldsDetection[size];
+ }
+ };
+}
diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java
index b1857b3..736d9ef 100644
--- a/core/java/android/service/autofill/FillEventHistory.java
+++ b/core/java/android/service/autofill/FillEventHistory.java
@@ -19,6 +19,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.content.IntentSender;
import android.os.Bundle;
import android.os.Parcel;
@@ -164,6 +165,10 @@
dest.writeStringList(event.mManuallyFilledDatasetIds.get(j));
}
}
+ dest.writeString(event.mDetectedRemoteId);
+ if (event.mDetectedRemoteId != null) {
+ dest.writeInt(event.mDetectedFieldScore);
+ }
}
}
}
@@ -226,6 +231,7 @@
* <p>See {@link android.view.autofill.AutofillManager} for more information about autofill
* contexts.
*/
+ // TODO(b/67867469): update with field detection behavior
public static final int TYPE_CONTEXT_COMMITTED = 4;
/** @hide */
@@ -253,6 +259,9 @@
@Nullable private final ArrayList<AutofillId> mManuallyFilledFieldIds;
@Nullable private final ArrayList<ArrayList<String>> mManuallyFilledDatasetIds;
+ @Nullable private final String mDetectedRemoteId;
+ private final int mDetectedFieldScore;
+
/**
* Returns the type of the event.
*
@@ -355,6 +364,39 @@
}
/**
+ * Gets the results of the last {@link FieldsDetection} request.
+ *
+ * @return map of edit-distance match ({@code 0} means full match,
+ * {@code 1} means 1 character different, etc...) by remote id (as set in the
+ * {@link FieldsDetection} constructor), or {@code null} if none of the user-input values
+ * matched the requested detection.
+ *
+ * <p><b>Note: </b>Only set on events of type {@link #TYPE_CONTEXT_COMMITTED}, when the
+ * service requested {@link FillResponse.Builder#setFieldsDetection(FieldsDetection) fields
+ * detection}.
+ *
+ * TODO(b/67867469):
+ * - improve javadoc
+ * - refine score meaning (for example, should 1 be different of -1?)
+ * - mention when it's set
+ * - unhide
+ * - unhide / remove testApi
+ * - add @NonNull / check it / add unit tests
+ *
+ * @hide
+ */
+ @TestApi
+ @NonNull public Map<String, Integer> getDetectedFields() {
+ if (mDetectedRemoteId == null || mDetectedFieldScore == -1) {
+ return Collections.emptyMap();
+ }
+
+ final ArrayMap<String, Integer> map = new ArrayMap<>(1);
+ map.put(mDetectedRemoteId, mDetectedFieldScore);
+ return map;
+ }
+
+ /**
* Returns which fields were available on datasets provided by the service but manually
* entered by the user.
*
@@ -430,7 +472,6 @@
* and belonged to datasets.
* @param manuallyFilledDatasetIds The ids of datasets that had values matching the
* respective entry on {@code manuallyFilledFieldIds}.
- *
* @throws IllegalArgumentException If the length of {@code changedFieldIds} and
* {@code changedDatasetIds} doesn't match.
* @throws IllegalArgumentException If the length of {@code manuallyFilledFieldIds} and
@@ -438,13 +479,15 @@
*
* @hide
*/
+ // TODO(b/67867469): document detection field parameters once stable
public Event(int eventType, @Nullable String datasetId, @Nullable Bundle clientState,
@Nullable List<String> selectedDatasetIds,
@Nullable ArraySet<String> ignoredDatasetIds,
@Nullable ArrayList<AutofillId> changedFieldIds,
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
- @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) {
+ @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
+ @Nullable String detectedRemoteId, int detectedFieldScore) {
mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_CONTEXT_COMMITTED,
"eventType");
mDatasetId = datasetId;
@@ -467,6 +510,8 @@
}
mManuallyFilledFieldIds = manuallyFilledFieldIds;
mManuallyFilledDatasetIds = manuallyFilledDatasetIds;
+ mDetectedRemoteId = detectedRemoteId;
+ mDetectedFieldScore = detectedFieldScore;
}
@Override
@@ -479,6 +524,8 @@
+ ", changedDatasetsIds=" + mChangedDatasetIds
+ ", manuallyFilledFieldIds=" + mManuallyFilledFieldIds
+ ", manuallyFilledDatasetIds=" + mManuallyFilledDatasetIds
+ + ", detectedRemoteId=" + mDetectedRemoteId
+ + ", detectedFieldScore=" + mDetectedFieldScore
+ "]";
}
}
@@ -514,11 +561,15 @@
} else {
manuallyFilledDatasetIds = null;
}
+ final String detectedRemoteId = parcel.readString();
+ final int detectedFieldScore = detectedRemoteId == null ? -1
+ : parcel.readInt();
selection.addEvent(new Event(eventType, datasetId, clientState,
selectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds));
+ manuallyFilledFieldIds, manuallyFilledDatasetIds,
+ detectedRemoteId, detectedFieldScore));
}
return selection;
}
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index 2f6342a..4e6a884 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -22,6 +22,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.app.Activity;
import android.content.IntentSender;
import android.content.pm.ParceledListSlice;
@@ -75,6 +76,7 @@
private final @Nullable AutofillId[] mAuthenticationIds;
private final @Nullable AutofillId[] mIgnoredIds;
private final long mDisableDuration;
+ private final @Nullable FieldsDetection mFieldsDetection;
private final int mFlags;
private int mRequestId;
@@ -87,6 +89,7 @@
mAuthenticationIds = builder.mAuthenticationIds;
mIgnoredIds = builder.mIgnoredIds;
mDisableDuration = builder.mDisableDuration;
+ mFieldsDetection = builder.mFieldsDetection;
mFlags = builder.mFlags;
mRequestId = INVALID_REQUEST_ID;
}
@@ -132,6 +135,11 @@
}
/** @hide */
+ public @Nullable FieldsDetection getFieldsDetection() {
+ return mFieldsDetection;
+ }
+
+ /** @hide */
public int getFlags() {
return mFlags;
}
@@ -167,6 +175,7 @@
private AutofillId[] mAuthenticationIds;
private AutofillId[] mIgnoredIds;
private long mDisableDuration;
+ private FieldsDetection mFieldsDetection;
private int mFlags;
private boolean mDestroyed;
@@ -315,6 +324,25 @@
}
/**
+ * TODO(b/67867469):
+ * - javadoc it
+ * - javadoc how to check results
+ * - unhide
+ * - unhide / remove testApi
+ * - throw exception (and document) if response has datasets or saveinfo
+ * - throw exception (and document) if id on fieldsDetection is ignored
+ *
+ * @hide
+ */
+ @TestApi
+ public Builder setFieldsDetection(@NonNull FieldsDetection fieldsDetection) {
+ throwIfDestroyed();
+ throwIfDisableAutofillCalled();
+ mFieldsDetection = Preconditions.checkNotNull(fieldsDetection);
+ return this;
+ }
+
+ /**
* Sets flags changing the response behavior.
*
* @param flags a combination of {@link #FLAG_TRACK_CONTEXT_COMMITED} and
@@ -365,7 +393,8 @@
if (duration <= 0) {
throw new IllegalArgumentException("duration must be greater than 0");
}
- if (mAuthentication != null || mDatasets != null || mSaveInfo != null) {
+ if (mAuthentication != null || mDatasets != null || mSaveInfo != null
+ || mFieldsDetection != null) {
throw new IllegalStateException("disableAutofill() must be the only method called");
}
@@ -388,11 +417,11 @@
*/
public FillResponse build() {
throwIfDestroyed();
-
if (mAuthentication == null && mDatasets == null && mSaveInfo == null
- && mDisableDuration == 0) {
- throw new IllegalStateException("need to provide at least one DataSet or a "
- + "SaveInfo or an authentication with a presentation or disable autofill");
+ && mDisableDuration == 0 && mFieldsDetection == null) {
+ throw new IllegalStateException("need to provide: at least one DataSet, or a "
+ + "SaveInfo, or an authentication with a presentation, "
+ + "or a FieldsDetection, or disable autofill");
}
mDestroyed = true;
return new FillResponse(this);
@@ -430,6 +459,7 @@
.append(", ignoredIds=").append(Arrays.toString(mIgnoredIds))
.append(", disableDuration=").append(mDisableDuration)
.append(", flags=").append(mFlags)
+ .append(", fieldDetection=").append(mFieldsDetection)
.append("]")
.toString();
}
@@ -453,6 +483,7 @@
parcel.writeParcelable(mPresentation, flags);
parcel.writeParcelableArray(mIgnoredIds, flags);
parcel.writeLong(mDisableDuration);
+ parcel.writeParcelable(mFieldsDetection, flags);
parcel.writeInt(mFlags);
parcel.writeInt(mRequestId);
}
@@ -488,6 +519,10 @@
if (disableDuration > 0) {
builder.disableAutofill(disableDuration);
}
+ final FieldsDetection fieldsDetection = parcel.readParcelable(null);
+ if (fieldsDetection != null) {
+ builder.setFieldsDetection(fieldsDetection);
+ }
builder.setFlags(parcel.readInt());
final FillResponse response = builder.build();
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
index 0b9552e..b07e94a 100644
--- a/core/java/android/util/apk/ApkVerityBuilder.java
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -252,6 +252,7 @@
byte[] rootHash = new byte[DIGEST_SIZE_BYTES];
BufferedDigester digester = new BufferedDigester(salt, ByteBuffer.wrap(rootHash));
digester.consume(slice(output, 0, CHUNK_SIZE_BYTES));
+ digester.finish();
return rootHash;
}
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index 2166f6e..7c76bab 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -70,6 +70,7 @@
* Name of the file that holds the shaders cache.
*/
private static final String CACHE_PATH_SHADERS = "com.android.opengl.shaders_cache";
+ private static final String CACHE_PATH_SKIASHADERS = "com.android.skia.shaders_cache";
/**
* System property used to enable or disable threaded rendering profiling.
@@ -272,7 +273,9 @@
* @hide
*/
public static void setupDiskCache(File cacheDir) {
- ThreadedRenderer.setupShadersDiskCache(new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath());
+ ThreadedRenderer.setupShadersDiskCache(
+ new File(cacheDir, CACHE_PATH_SHADERS).getAbsolutePath(),
+ new File(cacheDir, CACHE_PATH_SKIASHADERS).getAbsolutePath());
}
/**
@@ -1007,7 +1010,7 @@
/** Not actually public - internal use only. This doc to make lint happy */
public static native void disableVsync();
- static native void setupShadersDiskCache(String cacheFile);
+ static native void setupShadersDiskCache(String cacheFile, String skiaCacheFile);
private static native void nRotateProcessStatsBuffer();
private static native void nSetProcessStatsBuffer(int fd);
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 69cc100..7e1846a 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -225,9 +225,6 @@
*/
public abstract boolean isKeyguardLocked();
- /** @return {@code true} if the keyguard is going away. */
- public abstract boolean isKeyguardGoingAway();
-
/**
* @return Whether the keyguard is showing and not occluded.
*/
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 07455c1d..e35bb92 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -154,6 +154,21 @@
}
/**
+ * Returns a {@link TextLinks} that may be applied to the text to annotate it with links
+ * information.
+ *
+ * @param text the text to generate annotations for
+ * @param options configuration for link generation. If null, defaults will be used.
+ *
+ * @throws IllegalArgumentException if text is null
+ */
+ @WorkerThread
+ default TextLinks generateLinks(
+ @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ return new TextLinks.Builder(text.toString()).build();
+ }
+
+ /**
* Logs a TextClassifier event.
*
* @param source the text classifier used to generate this event
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 2799f2b..9c4fd57 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -209,6 +209,32 @@
}
@Override
+ public TextLinks generateLinks(
+ @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ Preconditions.checkNotNull(text);
+ final String textString = text.toString();
+ final TextLinks.Builder builder = new TextLinks.Builder(textString);
+ try {
+ LocaleList defaultLocales = options != null ? options.getDefaultLocales() : null;
+ final SmartSelection smartSelection = getSmartSelection(defaultLocales);
+ final SmartSelection.AnnotatedSpan[] annotations = smartSelection.annotate(textString);
+ for (SmartSelection.AnnotatedSpan span : annotations) {
+ final Map<String, Float> entityScores = new HashMap<>();
+ final SmartSelection.ClassificationResult[] results = span.getClassification();
+ for (int i = 0; i < results.length; i++) {
+ entityScores.put(results[i].mCollection, results[i].mScore);
+ }
+ builder.addLink(new TextLinks.TextLink(
+ textString, span.getStartIndex(), span.getEndIndex(), entityScores));
+ }
+ } catch (Throwable t) {
+ // Avoid throwing from this method. Log the error.
+ Log.e(LOG_TAG, "Error getting links info.", t);
+ }
+ return builder.build();
+ }
+
+ @Override
public void logEvent(String source, String event) {
if (LOG_TAG.equals(source)) {
mMetricsLogger.count(event, 1);
@@ -680,8 +706,8 @@
intents.add(new Intent(Intent.ACTION_SENDTO)
.setData(Uri.parse(String.format("mailto:%s", text))));
intents.add(new Intent(Intent.ACTION_INSERT_OR_EDIT)
- .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
- .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
+ .setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE)
+ .putExtra(ContactsContract.Intents.Insert.EMAIL, text));
break;
case TextClassifier.TYPE_PHONE:
intents.add(new Intent(Intent.ACTION_DIAL)
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
new file mode 100644
index 0000000..f3cc827
--- /dev/null
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.textclassifier;
+
+import android.annotation.FloatRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.LocaleList;
+import android.text.SpannableString;
+import android.text.style.ClickableSpan;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+/**
+ * A collection of links, representing subsequences of text and the entity types (phone number,
+ * address, url, etc) they may be.
+ */
+public final class TextLinks {
+ private final String mFullText;
+ private final List<TextLink> mLinks;
+
+ private TextLinks(String fullText, Collection<TextLink> links) {
+ mFullText = fullText;
+ mLinks = Collections.unmodifiableList(new ArrayList<>(links));
+ }
+
+ /**
+ * Returns an unmodifiable Collection of the links.
+ */
+ public Collection<TextLink> getLinks() {
+ return mLinks;
+ }
+
+ /**
+ * Annotates the given text with the generated links. It will fail if the provided text doesn't
+ * match the original text used to crete the TextLinks.
+ *
+ * @param text the text to apply the links to. Must match the original text.
+ * @param spanFactory a factory to generate spans from TextLinks. Will use a default if null.
+ *
+ * @return Success or failure.
+ */
+ public boolean apply(
+ @NonNull SpannableString text,
+ @Nullable Function<TextLink, ClickableSpan> spanFactory) {
+ Preconditions.checkNotNull(text);
+ if (!mFullText.equals(text.toString())) {
+ return false;
+ }
+
+ if (spanFactory == null) {
+ spanFactory = DEFAULT_SPAN_FACTORY;
+ }
+ for (TextLink link : mLinks) {
+ final ClickableSpan span = spanFactory.apply(link);
+ if (span != null) {
+ text.setSpan(span, link.getStart(), link.getEnd(), 0);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * A link, identifying a substring of text and possible entity types for it.
+ */
+ public static final class TextLink {
+ private final EntityConfidence<String> mEntityScores;
+ private final String mOriginalText;
+ private final int mStart;
+ private final int mEnd;
+
+ /**
+ * Create a new TextLink.
+ *
+ * @throws IllegalArgumentException if entityScores is null or empty.
+ */
+ public TextLink(String originalText, int start, int end, Map<String, Float> entityScores) {
+ Preconditions.checkNotNull(originalText);
+ Preconditions.checkNotNull(entityScores);
+ Preconditions.checkArgument(!entityScores.isEmpty());
+ Preconditions.checkArgument(start <= end);
+ mOriginalText = originalText;
+ mStart = start;
+ mEnd = end;
+ mEntityScores = new EntityConfidence<>();
+
+ for (Map.Entry<String, Float> entry : entityScores.entrySet()) {
+ mEntityScores.setEntityType(entry.getKey(), entry.getValue());
+ }
+ }
+
+ /**
+ * Returns the start index of this link in the original text.
+ *
+ * @return the start index.
+ */
+ public int getStart() {
+ return mStart;
+ }
+
+ /**
+ * Returns the end index of this link in the original text.
+ *
+ * @return the end index.
+ */
+ public int getEnd() {
+ return mEnd;
+ }
+
+ /**
+ * Returns the number of entity types that have confidence scores.
+ *
+ * @return the entity count.
+ */
+ public int getEntityCount() {
+ return mEntityScores.getEntities().size();
+ }
+
+ /**
+ * Returns the entity type at a given index. Entity types are sorted by confidence.
+ *
+ * @return the entity type at the provided index.
+ */
+ @NonNull public @TextClassifier.EntityType String getEntity(int index) {
+ return mEntityScores.getEntities().get(index);
+ }
+
+ /**
+ * Returns the confidence score for a particular entity type.
+ *
+ * @param entityType the entity type.
+ */
+ public @FloatRange(from = 0.0, to = 1.0) float getConfidenceScore(
+ @TextClassifier.EntityType String entityType) {
+ return mEntityScores.getConfidenceScore(entityType);
+ }
+ }
+
+ /**
+ * Optional input parameters for generating TextLinks.
+ */
+ public static final class Options {
+ private final LocaleList mLocaleList;
+
+ private Options(LocaleList localeList) {
+ this.mLocaleList = localeList;
+ }
+
+ /**
+ * Builder to construct Options.
+ */
+ public static final class Builder {
+ private LocaleList mLocaleList;
+
+ /**
+ * Sets the LocaleList to use.
+ *
+ * @return this Builder.
+ */
+ public Builder setLocaleList(@Nullable LocaleList localeList) {
+ this.mLocaleList = localeList;
+ return this;
+ }
+
+ /**
+ * Builds the Options object.
+ */
+ public Options build() {
+ return new Options(mLocaleList);
+ }
+ }
+ public @Nullable LocaleList getDefaultLocales() {
+ return mLocaleList;
+ }
+ };
+
+ /**
+ * A function to create spans from TextLinks.
+ *
+ * Applies only to TextViews.
+ * We can hide this until we are convinced we want it to be part of the public API.
+ *
+ * @hide
+ */
+ public static final Function<TextLink, ClickableSpan> DEFAULT_SPAN_FACTORY =
+ new Function<TextLink, ClickableSpan>() {
+ @Override
+ public ClickableSpan apply(TextLink textLink) {
+ // TODO: Implement.
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+ };
+
+ /**
+ * A builder to construct a TextLinks instance.
+ */
+ public static final class Builder {
+ private final String mFullText;
+ private final Collection<TextLink> mLinks;
+
+ /**
+ * Create a new TextLinks.Builder.
+ *
+ * @param fullText The full text that links will be added to.
+ */
+ public Builder(@NonNull String fullText) {
+ mFullText = Preconditions.checkNotNull(fullText);
+ mLinks = new ArrayList<>();
+ }
+
+ /**
+ * Adds a TextLink.
+ *
+ * @return this instance.
+ */
+ public Builder addLink(TextLink link) {
+ Preconditions.checkNotNull(link);
+ mLinks.add(link);
+ return this;
+ }
+
+ /**
+ * Constructs a TextLinks instance.
+ *
+ * @return the constructed TextLinks.
+ */
+ public TextLinks build() {
+ return new TextLinks(mFullText, mLinks);
+ }
+ }
+}
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index e6da69d..7451d31 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -6557,12 +6557,12 @@
* Adds "PROCESS_TEXT" menu items to the specified menu.
*/
public void onInitializeMenu(Menu menu) {
- final int size = mSupportedActivities.size();
loadSupportedActivities();
+ final int size = mSupportedActivities.size();
for (int i = 0; i < size; i++) {
final ResolveInfo resolveInfo = mSupportedActivities.get(i);
menu.add(Menu.NONE, Menu.NONE,
- Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i++,
+ Editor.MENU_ITEM_ORDER_PROCESS_TEXT_INTENT_ACTIONS_START + i,
getLabel(resolveInfo))
.setIntent(createProcessTextIntentForResolveInfo(resolveInfo))
.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 8dc8cab..e91db13 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1354,6 +1354,7 @@
}
mDecorView = createDecorView(mBackgroundView);
+ mDecorView.setIsRootNamespace(true);
// The background owner should be elevated so that it casts a shadow.
mBackgroundView.setElevation(mElevation);
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 9e6985c..1a19a40 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -36,6 +36,7 @@
#include <hwui/Typeface.h>
#include <utils/FatVector.h>
#include <minikin/FontFamily.h>
+#include <minikin/LocaleList.h>
#include <memory>
@@ -43,9 +44,10 @@
struct NativeFamilyBuilder {
NativeFamilyBuilder(uint32_t langId, int variant)
- : langId(langId), variant(variant), allowUnsupportedFont(false) {}
+ : langId(langId), variant(static_cast<minikin::FontVariant>(variant)),
+ allowUnsupportedFont(false) {}
uint32_t langId;
- int variant;
+ minikin::FontVariant variant;
bool allowUnsupportedFont;
std::vector<minikin::Font> fonts;
std::vector<minikin::FontVariation> axes;
@@ -55,10 +57,9 @@
NativeFamilyBuilder* builder;
if (langs != nullptr) {
ScopedUtfChars str(env, langs);
- builder = new NativeFamilyBuilder(
- minikin::FontStyle::registerLocaleList(str.c_str()), variant);
+ builder = new NativeFamilyBuilder(minikin::registerLocaleList(str.c_str()), variant);
} else {
- builder = new NativeFamilyBuilder(minikin::FontStyle::registerLocaleList(""), variant);
+ builder = new NativeFamilyBuilder(minikin::registerLocaleList(""), variant);
}
return reinterpret_cast<jlong>(builder);
}
@@ -121,14 +122,14 @@
std::make_shared<MinikinFontSkia>(std::move(face), fontPtr, fontSize, ttcIndex,
builder->axes);
- int weight = givenWeight / 100;
+ int weight = givenWeight;
bool italic = givenItalic == 1;
if (givenWeight == RESOLVE_BY_FONT_TABLE || givenItalic == RESOLVE_BY_FONT_TABLE) {
int os2Weight;
bool os2Italic;
if (!minikin::FontFamily::analyzeStyle(minikinFont, &os2Weight, &os2Italic)) {
ALOGE("analyzeStyle failed. Using default style");
- os2Weight = 4;
+ os2Weight = 400;
os2Italic = false;
}
if (givenWeight == RESOLVE_BY_FONT_TABLE) {
@@ -139,7 +140,8 @@
}
}
- builder->fonts.push_back(minikin::Font(minikinFont, minikin::FontStyle(weight, italic)));
+ builder->fonts.push_back(minikin::Font(minikinFont,
+ minikin::FontStyle(weight, static_cast<minikin::FontSlant>(italic))));
builder->axes.clear();
return true;
}
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e8e3f57..5f32d37 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -41,6 +41,7 @@
#include <hwui/Paint.h>
#include <hwui/Typeface.h>
#include <minikin/GraphemeBreak.h>
+#include <minikin/LocaleList.h>
#include <minikin/Measurement.h>
#include <unicode/utf16.h>
@@ -546,9 +547,9 @@
static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
ScopedUtfChars localesChars(env, locales);
- jint minikinLangListId = minikin::FontStyle::registerLocaleList(localesChars.c_str());
- obj->setMinikinLangListId(minikinLangListId);
- return minikinLangListId;
+ jint minikinLocaleListId = minikin::registerLocaleList(localesChars.c_str());
+ obj->setMinikinLocaleListId(minikinLocaleListId);
+ return minikinLocaleListId;
}
static void setFontFeatureSettings(JNIEnv* env, jobject clazz, jlong paintHandle, jstring settings) {
@@ -580,7 +581,7 @@
// restore the original settings.
paint->setTextSkewX(saveSkewX);
paint->setFakeBoldText(savefakeBold);
- if (paint->getFontVariant() == minikin::VARIANT_ELEGANT) {
+ if (paint->getFontVariant() == minikin::FontVariant::ELEGANT) {
SkScalar size = paint->getTextSize();
metrics->fTop = -size * kElegantTop / 2048;
metrics->fBottom = -size * kElegantBottom / 2048;
@@ -871,20 +872,20 @@
obj->setTextAlign(align);
}
- static void setTextLocalesByMinikinLangListId(jlong objHandle,
- jint minikinLangListId) {
+ static void setTextLocalesByMinikinLocaleListId(jlong objHandle,
+ jint minikinLocaleListId) {
Paint* obj = reinterpret_cast<Paint*>(objHandle);
- obj->setMinikinLangListId(minikinLangListId);
+ obj->setMinikinLocaleListId(minikinLocaleListId);
}
static jboolean isElegantTextHeight(jlong paintHandle) {
Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- return obj->getFontVariant() == minikin::VARIANT_ELEGANT;
+ return obj->getFontVariant() == minikin::FontVariant::ELEGANT;
}
static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
Paint* obj = reinterpret_cast<Paint*>(paintHandle);
- obj->setFontVariant(aa ? minikin::VARIANT_ELEGANT : minikin::VARIANT_DEFAULT);
+ obj->setFontVariant(aa ? minikin::FontVariant::ELEGANT : minikin::FontVariant::DEFAULT);
}
static jfloat getTextSize(jlong paintHandle) {
@@ -1080,8 +1081,8 @@
{"nSetTypeface","(JJ)V", (void*) PaintGlue::setTypeface},
{"nGetTextAlign","(J)I", (void*) PaintGlue::getTextAlign},
{"nSetTextAlign","(JI)V", (void*) PaintGlue::setTextAlign},
- {"nSetTextLocalesByMinikinLangListId","(JI)V",
- (void*) PaintGlue::setTextLocalesByMinikinLangListId},
+ {"nSetTextLocalesByMinikinLocaleListId","(JI)V",
+ (void*) PaintGlue::setTextLocalesByMinikinLocaleListId},
{"nIsElegantTextHeight","(J)Z", (void*) PaintGlue::isElegantTextHeight},
{"nSetElegantTextHeight","(JZ)V", (void*) PaintGlue::setElegantTextHeight},
{"nGetTextSize","(J)F", (void*) PaintGlue::getTextSize},
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index d5f2a5c..3e4073f 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -83,7 +83,7 @@
static jint Typeface_getWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
- return face->fStyle.getWeight() * 100;
+ return face->fStyle.weight;
}
static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index c1419ba..ac79249 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -67,6 +67,18 @@
return width - get(mIndents, lineNo);
}
+ float getMinLineWidth() override {
+ // A simpler algorithm would have been simply looping until the larger of
+ // mFirstLineCount and mIndents.size()-mOffset, but that does unnecessary calculations
+ // when mFirstLineCount is large. Instead, we measure the first line, all the lines that
+ // have an indent, and the first line after firstWidth ends and restWidth starts.
+ float minWidth = std::min(getLineWidth(0), getLineWidth(mFirstLineCount));
+ for (size_t lineNo = 1; lineNo + mOffset < mIndents.size(); lineNo++) {
+ minWidth = std::min(minWidth, getLineWidth(lineNo));
+ }
+ return minWidth;
+ }
+
float getLeftPadding(size_t lineNo) override {
return get(mLeftPaddings, lineNo);
}
@@ -126,19 +138,17 @@
class StyleRun : public Run {
public:
StyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint,
- std::shared_ptr<minikin::FontCollection>&& collection,
- minikin::FontStyle&& style, bool isRtl)
+ std::shared_ptr<minikin::FontCollection>&& collection, bool isRtl)
: Run(start, end), mPaint(std::move(paint)), mCollection(std::move(collection)),
- mStyle(std::move(style)), mIsRtl(isRtl) {}
+ mIsRtl(isRtl) {}
void addTo(minikin::LineBreaker* lineBreaker) override {
- lineBreaker->addStyleRun(&mPaint, mCollection, mStyle, mStart, mEnd, mIsRtl);
+ lineBreaker->addStyleRun(&mPaint, mCollection, mStart, mEnd, mIsRtl);
}
private:
minikin::MinikinPaint mPaint;
std::shared_ptr<minikin::FontCollection> mCollection;
- minikin::FontStyle mStyle;
const bool mIsRtl;
};
@@ -167,10 +177,9 @@
mRightPaddings(std::move(rightPaddings)) {}
void addStyleRun(int32_t start, int32_t end, minikin::MinikinPaint&& paint,
- std::shared_ptr<minikin::FontCollection> collection,
- minikin::FontStyle&& style, bool isRtl) {
+ std::shared_ptr<minikin::FontCollection> collection, bool isRtl) {
mRuns.emplace_back(std::make_unique<StyleRun>(
- start, end, std::move(paint), std::move(collection), std::move(style), isRtl));
+ start, end, std::move(paint), std::move(collection), isRtl));
}
void addReplacementRun(int32_t start, int32_t end, float width, uint32_t localeListId) {
@@ -323,15 +332,9 @@
static void nAddStyleRun(jlong nativePtr, jlong nativePaint, jint start, jint end, jboolean isRtl) {
StaticLayoutNative* builder = toNative(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- const Typeface* typeface = paint->getAndroidTypeface();
- minikin::MinikinPaint minikinPaint;
- const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
- minikin::FontStyle style = MinikinUtils::prepareMinikinPaint(&minikinPaint, paint,
- typeface);
-
- builder->addStyleRun(
- start, end, std::move(minikinPaint), resolvedTypeface->fFontCollection, std::move(style),
- isRtl);
+ const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
+ minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
+ builder->addStyleRun(start, end, std::move(minikinPaint), typeface->fFontCollection, isRtl);
}
// CriticalNative
@@ -339,7 +342,7 @@
jfloat width) {
StaticLayoutNative* builder = toNative(nativePtr);
Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- builder->addReplacementRun(start, end, width, paint->getMinikinLangListId());
+ builder->addReplacementRun(start, end, width, paint->getMinikinLocaleListId());
}
static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 57263b1..870a0c2 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -54,6 +54,7 @@
#include <renderthread/RenderProxy.h>
#include <renderthread/RenderTask.h>
#include <renderthread/RenderThread.h>
+#include <pipeline/skia/ShaderCache.h>
namespace android {
@@ -970,10 +971,14 @@
// ----------------------------------------------------------------------------
static void android_view_ThreadedRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
- jstring diskCachePath) {
+ jstring diskCachePath, jstring skiaDiskCachePath) {
const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
android::egl_set_cache_filename(cacheArray);
env->ReleaseStringUTFChars(diskCachePath, cacheArray);
+
+ const char* skiaCacheArray = env->GetStringUTFChars(skiaDiskCachePath, NULL);
+ uirenderer::skiapipeline::ShaderCache::get().setFilename(skiaCacheArray);
+ env->ReleaseStringUTFChars(skiaDiskCachePath, skiaCacheArray);
}
// ----------------------------------------------------------------------------
@@ -1018,7 +1023,7 @@
{ "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
{ "nSerializeDisplayListTree", "(J)V", (void*) android_view_ThreadedRenderer_serializeDisplayListTree },
{ "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
- { "setupShadersDiskCache", "(Ljava/lang/String;)V",
+ { "setupShadersDiskCache", "(Ljava/lang/String;Ljava/lang/String;)V",
(void*) android_view_ThreadedRenderer_setupShadersDiskCache },
{ "nAddRenderNode", "(JJZ)V", (void*) android_view_ThreadedRenderer_addRenderNode},
{ "nRemoveRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_removeRenderNode},
diff --git a/core/jni/hwbinder/EphemeralStorage.cpp b/core/jni/hwbinder/EphemeralStorage.cpp
index 4996bc8..3b18f2b 100644
--- a/core/jni/hwbinder/EphemeralStorage.cpp
+++ b/core/jni/hwbinder/EphemeralStorage.cpp
@@ -111,6 +111,7 @@
break; \
}
+__attribute__((no_sanitize("unsigned-integer-overflow")))
void EphemeralStorage::release(JNIEnv *env) {
for (size_t i = mItems.size(); i--;) {
const Item &item = mItems[i];
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 57312e7..2389d4d 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -146,7 +146,7 @@
<string name="httpErrorConnect" msgid="8714273236364640549">"Tidak dapat tersambung ke server."</string>
<string name="httpErrorIO" msgid="2340558197489302188">"Tidak dapat berkomunikasi dengan server. Coba lagi nanti."</string>
<string name="httpErrorTimeout" msgid="4743403703762883954">"Sambungan ke server terputus."</string>
- <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Laman ini berisi terlalu banyak pengalihan server."</string>
+ <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"Halaman ini berisi terlalu banyak pengalihan server."</string>
<string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"Protokol tidak didukung."</string>
<string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"Tidak dapat membuat sambungan aman."</string>
<string name="httpErrorBadUrl" msgid="3636929722728881972">"Tidak dapat membuka halaman karena URL tidak valid."</string>
@@ -295,7 +295,7 @@
<string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Mengontrol perbesaran layar"</string>
<string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Mengontrol tingkat zoom dan pemosisian layar."</string>
<string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Melakukan isyarat"</string>
- <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggesek, mencubit, dan melakukan isyarat lainnya."</string>
+ <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Dapat mengetuk, menggeser, mencubit, dan melakukan isyarat lainnya."</string>
<string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Gestur sidik jari"</string>
<string name="capability_desc_canCaptureFingerprintGestures" msgid="7102111919385702482">"Dapat merekam gestur yang dilakukan di sensor sidik jari perangkat."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"nonaktifkan atau ubah bilah status"</string>
@@ -318,8 +318,8 @@
<string name="permdesc_receiveMms" msgid="533019437263212260">"Memungkinkan aplikasi menerima dan memproses pesan MMS. Ini artinya aplikasi dapat memantau atau menghapus pesan yang dikirim ke perangkat Anda tanpa menunjukkannya kepada Anda."</string>
<string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"membaca pesan siaran seluler"</string>
<string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Mengizinkan aplikasi membaca pesan siaran seluler yang diterima perangkat Anda. Notifikasi siaran seluler dikirimkan di beberapa lokasi untuk memperingatkan Anda tentang situasi darurat. Aplikasi berbahaya dapat mengganggu kinerja atau operasi perangkat Anda saat siaran seluler darurat diterima."</string>
- <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"baca umpan langganan"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Mengizinkan apl mendapatkan detail tentang umpan yang saat ini sedang disinkronkan."</string>
+ <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"baca feed langganan"</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Mengizinkan apl mendapatkan detail tentang feed yang saat ini sedang disinkronkan."</string>
<string name="permlab_sendSms" msgid="7544599214260982981">"mengirim dan melihat pesan SMS"</string>
<string name="permdesc_sendSms" msgid="7094729298204937667">"Memungkinkan aplikasi mengirim pesan SMS. Izin ini dapat mengakibatkan biaya tak terduga. Aplikasi berbahaya dapat membebankan biaya kepada Anda dengan mengirim pesan tanpa konfirmasi dari Anda."</string>
<string name="permlab_readSms" msgid="8745086572213270480">"membaca pesan teks (SMS atau MMS) Anda"</string>
@@ -802,11 +802,11 @@
<string name="factorytest_not_system" msgid="4435201656767276723">"Tindakan FACTORY_TEST hanya didukung untuk paket yang terpasang pada /system/app."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Tidak ada paket yang memberikan tindakan FACTORY_TEST."</string>
<string name="factorytest_reboot" msgid="6320168203050791643">"Mulai ulang"</string>
- <string name="js_dialog_title" msgid="1987483977834603872">"Laman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
+ <string name="js_dialog_title" msgid="1987483977834603872">"Halaman pada \"<xliff:g id="TITLE">%s</xliff:g>\" menyatakan:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload_title" msgid="2619376555525116593">"Konfirmasi Navigasi"</string>
- <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Keluar dari Laman ini"</string>
- <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Tetap di Laman ini"</string>
+ <string name="js_dialog_before_unload_positive_button" msgid="3112752010600484130">"Keluar dari Halaman ini"</string>
+ <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Tetap di Halaman ini"</string>
<string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nYakin ingin beranjak dari halaman ini?"</string>
<string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
<string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
@@ -1042,7 +1042,7 @@
<string name="force_close" msgid="8346072094521265605">"Oke"</string>
<string name="report" msgid="4060218260984795706">"Laporkan"</string>
<string name="wait" msgid="7147118217226317732">"Tunggu"</string>
- <string name="webpage_unresponsive" msgid="3272758351138122503">"Laman ini tidak menanggapi.\n\nApakah Anda ingin menutupnya?"</string>
+ <string name="webpage_unresponsive" msgid="3272758351138122503">"Halaman ini tidak menanggapi.\n\nApakah Anda ingin menutupnya?"</string>
<string name="launch_warning_title" msgid="1547997780506713581">"Apl dialihkan"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> telah diluncurkan aslinya."</string>
@@ -1371,7 +1371,7 @@
<string name="shareactionprovider_share_with" msgid="806688056141131819">"Berbagi dengan"</string>
<string name="shareactionprovider_share_with_application" msgid="5627411384638389738">"Berbagi dengan <xliff:g id="APPLICATION_NAME">%s</xliff:g>"</string>
<string name="content_description_sliding_handle" msgid="415975056159262248">"Gagang geser. Sentuh & tahan."</string>
- <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Gesek untuk membuka kunci."</string>
+ <string name="description_target_unlock_tablet" msgid="3833195335629795055">"Geser untuk membuka kunci."</string>
<string name="action_bar_home_description" msgid="5293600496601490216">"Navigasi ke beranda"</string>
<string name="action_bar_up_description" msgid="2237496562952152589">"Navigasi naik"</string>
<string name="action_menu_overflow_description" msgid="2295659037509008453">"Opsi lainnya"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 96a9eda..af37300 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -36,7 +36,7 @@
<string name="serviceDisabled" msgid="1937553226592516411">"सेवा अक्षम केली गेली आहे."</string>
<string name="serviceRegistered" msgid="6275019082598102493">"नोंदणी यशस्वी झाली."</string>
<string name="serviceErased" msgid="1288584695297200972">"मिटवणे यशस्वी झाले."</string>
- <string name="passwordIncorrect" msgid="7612208839450128715">"अयोग्य संकेतशब्द."</string>
+ <string name="passwordIncorrect" msgid="7612208839450128715">"अयोग्य पासवर्ड."</string>
<string name="mmiComplete" msgid="8232527495411698359">"MMI पूर्ण."</string>
<string name="badPin" msgid="9015277645546710014">"आपण टाइप केलेला जुना पिन योग्य नाही."</string>
<string name="badPuk" msgid="5487257647081132201">"आपण टाइप केलेला PUK योग्य नाही."</string>
@@ -59,7 +59,7 @@
<string name="CfMmi" msgid="5123218989141573515">"कॉल फॉरवर्डिंग"</string>
<string name="CwMmi" msgid="9129678056795016867">"कॉल प्रतीक्षा"</string>
<string name="BaMmi" msgid="455193067926770581">"कॉल सोडून"</string>
- <string name="PwdMmi" msgid="7043715687905254199">"संकेतशब्द बदल"</string>
+ <string name="PwdMmi" msgid="7043715687905254199">"पासवर्ड बदल"</string>
<string name="PinMmi" msgid="3113117780361190304">"पिन बदल"</string>
<string name="CnipMmi" msgid="3110534680557857162">"कॉल करण्याचा नंबर आहे"</string>
<string name="CnirMmi" msgid="3062102121430548731">"कॉल करणारे नंबर प्रतिबंधित"</string>
@@ -192,9 +192,9 @@
<string name="reboot_to_update_title" msgid="6212636802536823850">"Android सिस्टम अपडेट"</string>
<string name="reboot_to_update_prepare" msgid="6305853831955310890">"अपडेट करण्याची तयारी करत आहे…"</string>
<string name="reboot_to_update_package" msgid="3871302324500927291">"अपडेट पॅकेज प्रक्रिया करत आहे…"</string>
- <string name="reboot_to_update_reboot" msgid="6428441000951565185">"रीस्टार्ट करीत आहे..."</string>
+ <string name="reboot_to_update_reboot" msgid="6428441000951565185">"रीस्टार्ट करत आहे..."</string>
<string name="reboot_to_reset_title" msgid="4142355915340627490">"फॅक्टरी डेटा रीसेट"</string>
- <string name="reboot_to_reset_message" msgid="2432077491101416345">"रीस्टार्ट करीत आहे..."</string>
+ <string name="reboot_to_reset_message" msgid="2432077491101416345">"रीस्टार्ट करत आहे..."</string>
<string name="shutdown_progress" msgid="2281079257329981203">"बंद होत आहे…"</string>
<string name="shutdown_confirm" product="tablet" msgid="3385745179555731470">"आपला टॅबलेट बंद होईल."</string>
<string name="shutdown_confirm" product="tv" msgid="476672373995075359">"आपला टीव्ही बंद होईल."</string>
@@ -215,7 +215,7 @@
<string name="bugreport_title" msgid="2667494803742548533">"बग रीपोर्ट घ्या"</string>
<string name="bugreport_message" msgid="398447048750350456">"ई-मेल संदेश म्हणून पाठविण्यासाठी, हे तुमच्या सद्य डिव्हाइस स्थितीविषयी माहिती संकलित करेल. बग रीपोर्ट सुरू करण्यापासून तो पाठविण्यापर्यंत थोडा वेळ लागेल; कृपया धीर धरा."</string>
<string name="bugreport_option_interactive_title" msgid="8635056131768862479">"परस्परसंवादी अहवाल"</string>
- <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"बहुतांश प्रसंगांमध्ये याचा वापर करा. ते आपल्याला अहवालाच्या प्रगतीचा मागोवा घेण्याची, समस्येविषयी आणखी तपाशील प्रविष्ट करण्याची आणि स्क्रीनशॉट घेण्याची अनुमती देते. ते कदाचित अहवाल देण्यासाठी बराच वेळ घेणारे कमी-वापरलेले विभाग वगळू शकते."</string>
+ <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"बहुतांश प्रसंगांमध्ये याचा वापर करा. ते आपल्याला अहवालाच्या प्रगतीचा मागोवा घेण्याची, समस्येविषयी आणखी तपाशील एंटर करण्याची आणि स्क्रीनशॉट घेण्याची अनुमती देते. ते कदाचित अहवाल देण्यासाठी बराच वेळ घेणारे कमी-वापरलेले विभाग वगळू शकते."</string>
<string name="bugreport_option_full_title" msgid="6354382025840076439">"संपूर्ण अहवाल"</string>
<string name="bugreport_option_full_summary" msgid="7210859858969115745">"तुमचे डिव्हाइस प्रतिसाद देत नाही किंवा खूप धीमे असते किंवा तुम्हाला सर्व अहवाल विभागांची आवश्यकता असते तेव्हा कमीतकमी सिस्टम हस्तक्षेपासाठी या पर्यायाचा वापर करा. तुम्हाला आणखी तपशील एंटर करण्याची किंवा अतिरिक्त स्क्रीनशॉट घेण्याची अनुमती देत नाही."</string>
<plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
@@ -461,13 +461,13 @@
<string name="permdesc_changeWimaxState" product="tv" msgid="6022307083934827718">"WiMAX नेटवर्कवरून टीव्ही कनेक्ट करण्यासाठी आणि त्यावरून टीव्ही डिस्कनेक्ट करण्यासाठी अॅपला अनुमती देते."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="697025043004923798">"WiMAX नेटवर्कवर फोन कनेक्ट करण्यास आणि त्यावरून फोन डिस्कनेक्ट करण्यास अॅप ला अनुमती देते."</string>
<string name="permlab_bluetooth" msgid="6127769336339276828">"ब्लूटूथ डीव्हाइससह जोडा"</string>
- <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"टॅबलेटवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन स्थापित करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"टीव्हीवर ब्लूटूथचे कॉंफिगरेशन पाहण्यासाठी आणि जोडलेल्या डीव्हाइससह कनेक्शन स्थापित करण्यासाठी आणि स्वीकारण्यासाठी अॅपला अनुमती देते."</string>
- <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"फोनवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन स्थापित करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
+ <string name="permdesc_bluetooth" product="tablet" msgid="3480722181852438628">"टॅबलेटवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="3974124940101104206">"टीव्हीवर ब्लूटूथचे कॉंफिगरेशन पाहण्यासाठी आणि जोडलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी अॅपला अनुमती देते."</string>
+ <string name="permdesc_bluetooth" product="default" msgid="3207106324452312739">"फोनवर ब्लूटूथ चे कॉंफिगरेशन पाहण्यासाठी आणि पेअर केलेल्या डीव्हाइससह कनेक्शन इंस्टॉल करण्यासाठी आणि स्वीकारण्यासाठी, अॅप ला अनुमती देते."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"फील्ड जवळील कम्युनिकेशन नियंत्रित करा"</string>
<string name="permdesc_nfc" msgid="7120611819401789907">"फील्ड जवळील कम्युनिकेशन (NFC) टॅग, कार्डे आणि वाचक यांच्यासह संवाद करण्यासाठी अॅपला अनुमती देते."</string>
<string name="permlab_disableKeyguard" msgid="3598496301486439258">"आपले स्क्रीन लॉक अक्षम करा"</string>
- <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"कीलॉक आणि कोणतीही संबद्ध संकेतशब्द सुरक्षितता अक्षम करण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, येणारा फोन कॉल प्राप्त करताना फोन कीलॉक अक्षम करतो, नंतर जेव्हा कॉल समाप्त होतो तेव्हा तो कीलॉक पुन्हा-सक्षम करतो."</string>
+ <string name="permdesc_disableKeyguard" msgid="6034203065077122992">"कीलॉक आणि कोणतीही संबद्ध पासवर्ड सुरक्षितता अक्षम करण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, येणारा फोन कॉल प्राप्त करताना फोन कीलॉक अक्षम करतो, नंतर जेव्हा कॉल समाप्त होतो तेव्हा तो कीलॉक पुन्हा-सक्षम करतो."</string>
<string name="permlab_manageFingerprint" msgid="5640858826254575638">"फिंगरप्रिंट हार्डवेअर व्यवस्थापित करा"</string>
<string name="permdesc_manageFingerprint" msgid="178208705828055464">"वापर करण्याकरिता फिंगरप्रिंट टेम्पलेट जोडण्यासाठी आणि हटविण्यासाठी पद्धती रद्द करण्यास अॅपला अनुमती देते."</string>
<string name="permlab_useFingerprint" msgid="3150478619915124905">"फिंगरप्रिंट हार्डवेअर वापरा"</string>
@@ -550,15 +550,15 @@
<string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"वाहक सेवांवर प्रतिबद्ध करण्यासाठी होल्डरला अनुमती देते. सामान्य अॅप्ससाठी कधीही आवश्यकता नसावी."</string>
<string name="permlab_access_notification_policy" msgid="4247510821662059671">"व्यत्यय आणू नका अॅक्सेस करा"</string>
<string name="permdesc_access_notification_policy" msgid="3296832375218749580">"व्यत्यय आणू नका कॉन्फिगरेशन वाचण्यासाठी आणि लिहिण्यासाठी अॅपला अनुमती देते."</string>
- <string name="policylab_limitPassword" msgid="4497420728857585791">"संकेतशब्द नियम सेट करा"</string>
+ <string name="policylab_limitPassword" msgid="4497420728857585791">"पासवर्ड नियम सेट करा"</string>
<string name="policydesc_limitPassword" msgid="2502021457917874968">"स्क्रीन लॉक पासवर्ड आणि पिन मध्ये अनुमती दिलेले लांबी आणि वर्ण नियंत्रित करा."</string>
<string name="policylab_watchLogin" msgid="5091404125971980158">"स्क्रीन अनलॉक प्रयत्नांचे परीक्षण करा"</string>
- <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा टॅबलेट लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास टॅबलेटचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास टीव्हीचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास फोनचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टॅबलेट लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या संकेतशब्दांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
- <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"टाइप केलेल्या अयोग्य संकेतशब्दांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच संकेतशब्द टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin" product="tablet" msgid="3215729294215070072">"टाइप केलेल्या अयोग्य पासवर्डांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा टॅबलेट लॉक करा किंवा बरेच पासवर्ड टाइप केले असल्यास टॅबलेटचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin" product="TV" msgid="2707817988309890256">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या पासवर्डांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे पासवर्ड टाइप केले असल्यास टीव्हीचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin" product="default" msgid="5712323091846761073">"टाइप केलेल्या अयोग्य पासवर्डांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच पासवर्ड टाइप केले असल्यास फोनचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="4280246270601044505">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या पासवर्डांच्या संख्येचे परीक्षण करा आणि टॅबलेट लॉक करा किंवा अनेक चुकीचे पासवर्ड टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="TV" msgid="3484832653564483250">"स्क्रीन अनलॉक करताना टाइप केलेल्या चुकीच्या पासवर्डांच्या संख्येचे परीक्षण करा आणि टीव्ही लॉक करा किंवा अनेक चुकीचे पासवर्ड टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
+ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="2185480427217127147">"टाइप केलेल्या अयोग्य पासवर्डांच्या अंकांचे परीक्षण करा. स्क्रीन अनलॉक केली जाते, तेव्हा फोन लॉक करा किंवा बरेच पासवर्ड टाइप केले असल्यास या वापरकर्त्याचा सर्व डेटा मिटवा."</string>
<string name="policylab_resetPassword" msgid="4934707632423915395">"स्क्रीन लॉक बदला"</string>
<string name="policydesc_resetPassword" msgid="1278323891710619128">"स्क्रीन लॉक बदला."</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"स्क्रीन लॉक करा"</string>
@@ -573,8 +573,8 @@
<string name="policydesc_wipeData_secondaryUser" product="default" msgid="6787904546711590238">"कोणत्याही चेतावणी शिवाय या वापरकर्त्याचा या फोनवरील डेटा मिटवा."</string>
<string name="policylab_setGlobalProxy" msgid="2784828293747791446">"डिव्हाइस समग्र प्रॉक्सी सेट करा"</string>
<string name="policydesc_setGlobalProxy" msgid="8459859731153370499">"धोरण सक्षम असताना वापरण्यासाठी डिव्हाइस समग्र प्रॉक्सी सेट करा. फक्त डिव्हाइस मालक समग्र प्रॉक्सी सेट करु शकतो."</string>
- <string name="policylab_expirePassword" msgid="5610055012328825874">"स्क्रीन लॉक संकेतशब्द कालबाह्यता सेट करा"</string>
- <string name="policydesc_expirePassword" msgid="5367525762204416046">"लॉक-स्क्रीन संकेतशब्द किती वारंवार बदलणे आवश्यक आहे ते बदला."</string>
+ <string name="policylab_expirePassword" msgid="5610055012328825874">"स्क्रीन लॉक पासवर्ड कालबाह्यता सेट करा"</string>
+ <string name="policydesc_expirePassword" msgid="5367525762204416046">"लॉक-स्क्रीन पासवर्ड किती वारंवार बदलणे आवश्यक आहे ते बदला."</string>
<string name="policylab_encryptedStorage" msgid="8901326199909132915">"स्टोरेज एंक्रिप्शन सेट करा"</string>
<string name="policydesc_encryptedStorage" msgid="2637732115325316992">"स्टोअर केलेला अॅप डेटा एंक्रिप्ट केला जाणे आवश्यक आहे."</string>
<string name="policylab_disableCamera" msgid="6395301023152297826">"कॅमेरे अक्षम करा"</string>
@@ -699,8 +699,8 @@
<string name="keyguard_password_enter_puk_code" msgid="4800725266925845333">"PUK आणि नवीन पिन कोड टाइप करा"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="1341112146710087048">"PUK कोड"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8027680321614196258">"नवीन पिन कोड"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"संकेतशब्द टाइप करण्यासाठी टॅप करा"</font></string>
- <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करण्यासाठी संकेतशब्द टाइप करा"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="2644215452200037944"><font size="17">"पासवर्ड टाइप करण्यासाठी टॅप करा"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="1054721668279049780">"अनलॉक करण्यासाठी पासवर्ड टाइप करा"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="6391755146112503443">"अनलॉक करण्यासाठी पिन टाइप करा"</string>
<string name="keyguard_password_wrong_pin_code" msgid="2422225591006134936">"अयोग्य पिन कोड."</string>
<string name="keyguard_label_text" msgid="861796461028298424">"अनलॉक करण्यासाठी, मेनू दाबा नंतर 0."</string>
@@ -739,7 +739,7 @@
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"सिम कार्ड लॉक केलेले आहे."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"सिम कार्ड अनलॉक करत आहे…"</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="6481623830344107222">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="lockscreen_too_many_failed_password_attempts_dialog_message" msgid="2725973286239344555">"आपण आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="lockscreen_too_many_failed_pin_attempts_dialog_message" msgid="6216672706545696955">"आपण आपला पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="9191611984625460820">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीचा रेखांकित केला आहे. <xliff:g id="NUMBER_1">%2$d</xliff:g> अधिक अयशस्वी प्रयत्नांनंतर, तुमच्याला आपले Google साइन इन वापरून आपला टॅब्लेट अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="5316664559603394684">"तुम्ही <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा आपला अनलॉक पॅटर्न अयोग्यरीत्या काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुमच्याला आपले Google साइन इन वापरून आपला टीव्ही अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांनी पुन्हा प्रयत्न करा."</string>
@@ -756,10 +756,10 @@
<string name="lockscreen_glogin_too_many_attempts" msgid="2751368605287288808">"बरेच पॅटर्न प्रयत्न"</string>
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"अनलॉक करण्यासाठी, आपल्या Google खात्यासह साइन इन करा."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"वापरकर्तानाव (ईमेल)"</string>
- <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"संकेतशब्द"</string>
+ <string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"पासवर्ड"</string>
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"साइन इन करा"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"अवैध वापरकर्तानाव किंवा पासवर्ड."</string>
- <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"आपले वापरकर्तानाव किंवा संकेतशब्द विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
+ <string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"आपले वापरकर्तानाव किंवा पासवर्ड विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"तपासत आहे..."</string>
<string name="lockscreen_unlock_label" msgid="737440483220667054">"अनलॉक करा"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"ध्वनी सुरु"</string>
@@ -788,7 +788,7 @@
<string name="keyguard_accessibility_pattern_unlock" msgid="1490840706075246612">"पॅटर्न अनलॉक."</string>
<string name="keyguard_accessibility_face_unlock" msgid="4817282543351718535">"चेहरा अनलॉक."</string>
<string name="keyguard_accessibility_pin_unlock" msgid="2469687111784035046">"पिन अनलॉक."</string>
- <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"संकेतशब्द अनलॉक."</string>
+ <string name="keyguard_accessibility_password_unlock" msgid="7675777623912155089">"पासवर्ड अनलॉक."</string>
<string name="keyguard_accessibility_pattern_area" msgid="7679891324509597904">"पॅटर्न क्षेत्र."</string>
<string name="keyguard_accessibility_slide_area" msgid="6736064494019979544">"स्लाइड क्षेत्र."</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
@@ -840,7 +840,7 @@
<string name="permdesc_addVoicemail" msgid="6604508651428252437">"आपल्या व्हॉइसमेल इनबॉक्समध्ये संदेश जोडण्यासाठी अॅप ला अनुमती देते."</string>
<string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"ब्राउझर भौगोलिक स्थान परवानग्या सुधारित करा"</string>
<string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"ब्राउझरच्या भौगोलिक स्थान परवानग्या सुधारित करण्यासाठी अॅप ला अनुमती देते. दुर्भावनापूर्ण अॅप्स यादृच्छिक वेबसाइटवर स्थान माहिती पाठविण्यास अनुमती देण्यासाठी याचा वापर करू शकतात."</string>
- <string name="save_password_message" msgid="767344687139195790">"ब्राउझरने हा संकेतशब्द लक्षात ठेवावा असे आपण इच्छिता?"</string>
+ <string name="save_password_message" msgid="767344687139195790">"ब्राउझरने हा पासवर्ड लक्षात ठेवावा असे आपण इच्छिता?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"आत्ता नाही"</string>
<string name="save_password_remember" msgid="6491879678996749466">"लक्षात ठेवा"</string>
<string name="save_password_never" msgid="8274330296785855105">"कधीही नाही"</string>
@@ -994,7 +994,7 @@
<string name="yes" msgid="5362982303337969312">"ठीक"</string>
<string name="no" msgid="5141531044935541497">"रद्द करा"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"लक्ष द्या"</string>
- <string name="loading" msgid="7933681260296021180">"लोड करीत आहे..."</string>
+ <string name="loading" msgid="7933681260296021180">"लोड करत आहे..."</string>
<string name="capital_on" msgid="1544682755514494298">"चालू"</string>
<string name="capital_off" msgid="6815870386972805832">"बंद"</string>
<string name="whichApplication" msgid="4533185947064773386">"याचा वापर करून क्रिया पूर्ण करा"</string>
@@ -1058,9 +1058,9 @@
<string name="android_upgrading_fstrim" msgid="8036718871534640010">"संचयन ऑप्टिमाइझ करत आहे."</string>
<string name="android_upgrading_notification_title" msgid="8428357096969413169">"Android अपडेट संपवत आहे..."</string>
<string name="android_upgrading_notification_body" msgid="5761201379457064286">"श्रेणीसुधारणा पूर्ण होईपर्यंत काही अॅप्स योग्यरित्या कार्य करणार नाहीत"</string>
- <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> श्रेणीसुधारित करीत आहे…"</string>
+ <string name="app_upgrading_toast" msgid="3008139776215597053">"<xliff:g id="APPLICATION">%1$s</xliff:g> श्रेणीसुधारित करत आहे…"</string>
<string name="android_upgrading_apk" msgid="7904042682111526169">"<xliff:g id="NUMBER_1">%2$d</xliff:g> पैकी <xliff:g id="NUMBER_0">%1$d</xliff:g> अॅप ऑप्टिमाइझ करत आहे."</string>
- <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करीत आहे."</string>
+ <string name="android_preparing_apk" msgid="8162599310274079154">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करत आहे."</string>
<string name="android_upgrading_starting_apps" msgid="451464516346926713">"अॅप्स प्रारंभ करत आहे."</string>
<string name="android_upgrading_complete" msgid="1405954754112999229">"बूट समाप्त होत आहे."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> चालत आहे"</string>
@@ -1074,7 +1074,7 @@
<string name="dump_heap_notification" msgid="2618183274836056542">"<xliff:g id="PROC">%1$s</xliff:g> ने मेमेरी मर्यादा वाढविली"</string>
<string name="dump_heap_notification_detail" msgid="6901391084243999274">"हीप डंप संकलित केला गेला आहे; सामायिक करण्यासाठी टॅप करा"</string>
<string name="dump_heap_title" msgid="5864292264307651673">"हीप डंप सामायिक करायचे?"</string>
- <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने त्याची <xliff:g id="SIZE">%2$s</xliff:g> ची प्रक्रिया मेमरी मर्यादा ओलांडली आहे. त्याच्या विकासकासह सामायिक करण्यासाठी आपल्याकरिता हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये आपली कोणतीही वैयक्तिक माहिती असू शकते ज्यात अॅप्लिकेशन प्रवेश करू शकतो."</string>
+ <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> प्रक्रियेने त्याची <xliff:g id="SIZE">%2$s</xliff:g> ची प्रक्रिया मेमरी मर्यादा ओलांडली आहे. त्याच्या विकासकासह सामायिक करण्यासाठी तुमच्यासाठी हीप डंप उपलब्ध आहे. सावधगिरी बाळगा: या हीप डंपमध्ये आपली कोणतीही वैयक्तिक माहिती असू शकते ज्यात अॅप्लिकेशन प्रवेश करू शकतो."</string>
<string name="sendText" msgid="5209874571959469142">"मजकुरासाठी क्रिया निवडा"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"रिंगर व्हॉल्यूम"</string>
<string name="volume_music" msgid="5421651157138628171">"मीडिया व्हॉल्यूम"</string>
@@ -1185,7 +1185,7 @@
<string name="perm_costs_money" msgid="4902470324142151116">"यासाठी आपले पैसे खर्च होऊ शकतात"</string>
<string name="dlg_ok" msgid="7376953167039865701">"ठीक"</string>
<string name="usb_charging_notification_title" msgid="6895185153353640787">"USB हे डिव्हाइस चार्ज करत आहे"</string>
- <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करीत आहे"</string>
+ <string name="usb_supplying_notification_title" msgid="5310642257296510271">"USB संलग्न केलेल्या डिव्हाइसला पॉवरचा पुरवठा करत आहे"</string>
<string name="usb_mtp_notification_title" msgid="8396264943589760855">"स्थानांतरणासाठी USB"</string>
<string name="usb_ptp_notification_title" msgid="1347328437083192112">"फोटो स्थानांतरणासाठी USB"</string>
<string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI साठी USB"</string>
@@ -1210,11 +1210,11 @@
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="alert_windows_notification_channel_group_name" msgid="1463953341148606396">"इतर अॅप्सवर दाखवा"</string>
- <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> इतर अॅप्सवर प्रदर्शित करीत आहे"</string>
- <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्य अॅप्सवर प्रदर्शित करीत आहे"</string>
+ <string name="alert_windows_notification_channel_name" msgid="3116610965549449803">"<xliff:g id="NAME">%s</xliff:g> इतर अॅप्सवर प्रदर्शित करत आहे"</string>
+ <string name="alert_windows_notification_title" msgid="3697657294867638947">"<xliff:g id="NAME">%s</xliff:g> अन्य अॅप्सवर प्रदर्शित करत आहे"</string>
<string name="alert_windows_notification_message" msgid="8917232109522912560">"<xliff:g id="NAME">%s</xliff:g> ने हे वैशिष्ट्य वापरू नये असे आपण इच्छित असल्यास, सेटिंग्ज उघडण्यासाठी टॅप करा आणि ते बंद करा."</string>
<string name="alert_windows_notification_turn_off_action" msgid="3367294525884949878">"बंद करा"</string>
- <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करीत आहे"</string>
+ <string name="ext_media_checking_notification_title" msgid="5734005953288045806">"<xliff:g id="NAME">%s</xliff:g> तयार करत आहे"</string>
<string name="ext_media_checking_notification_message" msgid="4747432538578886744">"त्रुटींसाठी तपासत आहे"</string>
<string name="ext_media_new_notification_message" msgid="7589986898808506239">"नवीन <xliff:g id="NAME">%s</xliff:g> आढळले"</string>
<string name="ext_media_ready_notification_message" msgid="4083398150380114462">"फोटो आणि मीडिया स्थानांतरित करण्यासाठी"</string>
@@ -1250,7 +1250,7 @@
<string name="ext_media_status_unmountable" msgid="805594039236667894">"दूषित झाले"</string>
<string name="ext_media_status_unsupported" msgid="4691436711745681828">"समर्थित नसलेले"</string>
<string name="ext_media_status_ejecting" msgid="5463887263101234174">"बाहेर काढत आहे…"</string>
- <string name="ext_media_status_formatting" msgid="1085079556538644861">"फॉर्मेट करीत आहे..."</string>
+ <string name="ext_media_status_formatting" msgid="1085079556538644861">"फॉर्मेट करत आहे..."</string>
<string name="ext_media_status_missing" msgid="5638633895221670766">"घातले नाही"</string>
<string name="activity_list_empty" msgid="1675388330786841066">"कोणत्याही जुळणाऱ्या अॅक्टिव्हिटी आढळल्या नाहीत."</string>
<string name="permlab_route_media_output" msgid="6243022988998972085">"मीडिया आउटपुट मार्गस्थ करा"</string>
@@ -1365,7 +1365,7 @@
<string name="keyboardview_keycode_done" msgid="1992571118466679775">"पूर्ण झाले"</string>
<string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"मोड बदल"</string>
<string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
- <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"प्रविष्ट करा"</string>
+ <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"एंटर करा"</string>
<string name="activitychooserview_choose_application" msgid="2125168057199941199">"एक अॅप निवडा"</string>
<string name="activitychooserview_choose_application_error" msgid="8624618365481126668">"<xliff:g id="APPLICATION_NAME">%s</xliff:g> लाँच करू शकलो नाही"</string>
<string name="shareactionprovider_share_with" msgid="806688056141131819">"यांच्यासह सामायिक करा"</string>
@@ -1438,7 +1438,7 @@
<string name="media_route_chooser_extended_settings" msgid="87015534236701604">"सेटिंग्ज"</string>
<string name="media_route_controller_disconnect" msgid="8966120286374158649">"डिस्कनेक्ट करा"</string>
<string name="media_route_status_scanning" msgid="7279908761758293783">"स्कॅन करत आहे..."</string>
- <string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट करीत आहे..."</string>
+ <string name="media_route_status_connecting" msgid="6422571716007825440">"कनेक्ट करत आहे..."</string>
<string name="media_route_status_available" msgid="6983258067194649391">"उपलब्ध"</string>
<string name="media_route_status_not_available" msgid="6739899962681886401">"उपलब्ध नाही"</string>
<string name="media_route_status_in_use" msgid="4533786031090198063">"वापरात आहे"</string>
@@ -1449,18 +1449,18 @@
<string name="display_manager_overlay_display_secure_suffix" msgid="6022119702628572080">", सुरक्षित"</string>
<string name="kg_forgot_pattern_button_text" msgid="8852021467868220608">"पॅटर्न विसरलात"</string>
<string name="kg_wrong_pattern" msgid="1850806070801358830">"चुकीचा पॅटर्न"</string>
- <string name="kg_wrong_password" msgid="2333281762128113157">"चुकीचा संकेतशब्द"</string>
+ <string name="kg_wrong_password" msgid="2333281762128113157">"चुकीचा पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="1131306510833563801">"चुकीचा पिन"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="8790651267324125694">
<item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> सेकंदात पुन्हा प्रयत्न करा.</item>
<item quantity="other"><xliff:g id="NUMBER">%d</xliff:g> सेकंदांत पुन्हा प्रयत्न करा.</item>
</plurals>
<string name="kg_pattern_instructions" msgid="398978611683075868">"तुमचा पॅटर्न काढा"</string>
- <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम पिन प्रविष्ट करा"</string>
- <string name="kg_pin_instructions" msgid="2377242233495111557">"पिन प्रविष्ट करा"</string>
- <string name="kg_password_instructions" msgid="5753646556186936819">"संकेतशब्द प्रविष्ट करा"</string>
- <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"सिम आता अक्षम केले आहे. सुरु ठेवण्यासाठी PUK कोड प्रविष्ट करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
- <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"इच्छित पिन कोड प्रविष्ट करा"</string>
+ <string name="kg_sim_pin_instructions" msgid="2319508550934557331">"सिम पिन एंटर करा"</string>
+ <string name="kg_pin_instructions" msgid="2377242233495111557">"पिन एंटर करा"</string>
+ <string name="kg_password_instructions" msgid="5753646556186936819">"पासवर्ड एंटर करा"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="453227143861735537">"सिम आता अक्षम केले आहे. सुरु ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="7871604527429602024">"इच्छित पिन कोड एंटर करा"</string>
<string name="kg_enter_confirm_pin_hint" msgid="325676184762529976">"इच्छित पिन कोड ची पुष्टी करा"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="8950398016976865762">"सिम कार्ड अनलॉक करत आहे…"</string>
<string name="kg_password_wrong_pin_code" msgid="1139324887413846912">"अयोग्य पिन कोड."</string>
@@ -1471,13 +1471,13 @@
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"बरेच पॅटर्न प्रयत्न"</string>
<string name="kg_login_instructions" msgid="1100551261265506448">"अनलॉक करण्यासाठी, आपल्या Google खात्यासह साइन इन करा."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"वापरकर्तानाव (ईमेल)"</string>
- <string name="kg_login_password_hint" msgid="9057289103827298549">"संकेतशब्द"</string>
+ <string name="kg_login_password_hint" msgid="9057289103827298549">"पासवर्ड"</string>
<string name="kg_login_submit_button" msgid="5355904582674054702">"साइन इन करा"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"अवैध वापरकर्तानाव किंवा पासवर्ड."</string>
- <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"आपले वापरकर्तानाव किंवा संकेतशब्द विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
+ <string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"आपले वापरकर्तानाव किंवा पासवर्ड विसरलात?\n "<b>"google.com/accounts/recovery"</b>" ला भेट द्या."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"खाते तपासत आहे…"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8276745642049502550">"आपण आपला पिन <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7813713389422226531">"आपण आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने टाइप केला आहे. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="74089475965050805">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1575557200627128949">"आपण <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा टॅबलेट अनलॉक करण्याचा अयोग्यपणे प्रयत्न केला. <xliff:g id="NUMBER_1">%2$d</xliff:g> आणखी अयशस्वी प्रयत्नांनंतर, टॅबलेट फॅक्टरी डीफॉल्टवर रीसेट केला जाईल आणि वापरकर्ता डेटा गमावेल."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="5621231220154419413">"आपण <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा टीव्ही अनलॉक करण्याचा अयोग्यरित्या प्रयत्न केला. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, टीव्ही फॅक्टरी डीफॉल्टवर रीसेट केला जाईल आणि सर्व वापरकर्ता डेटा गमावेल."</string>
@@ -1502,7 +1502,7 @@
<string name="accessibility_magnification_chooser_text" msgid="1227146738764986237">"मोठे करणे"</string>
<string name="user_switched" msgid="3768006783166984410">"वर्तमान वापरकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="user_switching_message" msgid="2871009331809089783">"<xliff:g id="NAME">%1$s</xliff:g> वर स्विच करत आहे…"</string>
- <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करीत आहे…"</string>
+ <string name="user_logging_out_message" msgid="8939524935808875155">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करत आहे…"</string>
<string name="owner_name" msgid="2716755460376028154">"मालक"</string>
<string name="error_message_title" msgid="4510373083082500195">"एरर"</string>
<string name="error_message_change_not_allowed" msgid="1238035947357923497">"या बदलास आपल्या प्रशासकाद्वारे अनुमती नाही"</string>
@@ -1598,7 +1598,7 @@
<string name="print_service_installed_title" msgid="2246317169444081628">"<xliff:g id="NAME">%s</xliff:g> सेवा स्थापित केली"</string>
<string name="print_service_installed_message" msgid="5897362931070459152">"सक्षम करण्यासाठी टॅप करा"</string>
<string name="restr_pin_enter_admin_pin" msgid="8641662909467236832">"प्रशासक पिन एंटर करा"</string>
- <string name="restr_pin_enter_pin" msgid="3395953421368476103">"पिन प्रविष्ट करा"</string>
+ <string name="restr_pin_enter_pin" msgid="3395953421368476103">"पिन एंटर करा"</string>
<string name="restr_pin_incorrect" msgid="8571512003955077924">"चुकीचा"</string>
<string name="restr_pin_enter_old_pin" msgid="1462206225512910757">"वर्तमान पिन"</string>
<string name="restr_pin_enter_new_pin" msgid="5959606691619959184">"नवीन पिन"</string>
@@ -1626,7 +1626,6 @@
<string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
<string name="lock_to_app_toast" msgid="6820571533009838261">"हा स्क्रीन अनपिन करण्यासाठी, मागे आणि अवलोकन बटणांना स्पर्श करून धरून ठेवा"</string>
- <string name="lock_to_app_toast_locked" msgid="7849470948648628704">"हे अॅप अनपिन केले जाऊ शकत नाही"</string>
<string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
<string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन केली"</string>
<string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"अनपिन करण्यापूर्वी पिन साठी विचारा"</string>
@@ -1771,7 +1770,7 @@
<string name="autofill_save_title_with_3types" msgid="6943161834231458441">"<b><xliff:g id="LABEL">%4$s</xliff:g></b>मध्ये <xliff:g id="TYPE_0">%1$s</xliff:g>, <xliff:g id="TYPE_1">%2$s</xliff:g> आणि <xliff:g id="TYPE_2">%3$s</xliff:g> सेव्ह करायची?"</string>
<string name="autofill_save_yes" msgid="6398026094049005921">"सेव्ह करा"</string>
<string name="autofill_save_no" msgid="2625132258725581787">"नाही, नको"</string>
- <string name="autofill_save_type_password" msgid="5288448918465971568">"संकेतशब्द"</string>
+ <string name="autofill_save_type_password" msgid="5288448918465971568">"पासवर्ड"</string>
<string name="autofill_save_type_address" msgid="4936707762193009542">"पत्ता"</string>
<string name="autofill_save_type_credit_card" msgid="7127694776265563071">"क्रेडिट कार्ड"</string>
<string name="autofill_save_type_username" msgid="239040540379769562">"वापरकर्तानाव"</string>
@@ -1782,14 +1781,10 @@
<string name="etws_primary_default_message_test" msgid="2709597093560037455">"आणीबाणी संदेश चाचणी"</string>
<string name="notification_reply_button_accessibility" msgid="3621714652387814344">"प्रत्युत्तर द्या"</string>
<string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
- <!-- no translation found for mmcc_authentication_reject (5767701075994754356) -->
- <skip />
- <!-- no translation found for mmcc_imsi_unknown_in_hlr (5316658473301462825) -->
- <skip />
- <!-- no translation found for mmcc_illegal_ms (807334478177362062) -->
- <skip />
- <!-- no translation found for mmcc_illegal_me (1950705155760872972) -->
- <skip />
+ <string name="mmcc_authentication_reject" msgid="5767701075994754356">"व्हॉइसची सिमला अनुमती नाही"</string>
+ <string name="mmcc_imsi_unknown_in_hlr" msgid="5316658473301462825">"सिममध्ये व्हॉइसची तरतूद नाही"</string>
+ <string name="mmcc_illegal_ms" msgid="807334478177362062">"व्हॉइसची सिमला अनुमती नाही"</string>
+ <string name="mmcc_illegal_me" msgid="1950705155760872972">"व्हॉइसची फोनला अनुमती नाही"</string>
<string name="popup_window_default_title" msgid="4874318849712115433">"पॉपअप विंडो"</string>
<string name="slice_more_content" msgid="8504342889413274608">"+ <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
<string name="shortcut_restored_on_lower_version" msgid="5270675146351613828">"या शॉर्टकटला नवीनतम अॅपची आवश्यकता आहे"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 429ecf1..bf0f46a 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -282,7 +282,7 @@
<string name="permgrouprequest_camera" msgid="810824326507258410">"படங்களை எடுக்கவும் வீடியோவைப் பதிவுசெய்யவும், <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>க்கு அணுகல் வழங்கவும்"</string>
<string name="permgrouplab_phone" msgid="5229115638567440675">"ஃபோன்"</string>
<string name="permgroupdesc_phone" msgid="6234224354060641055">"யாரையும் தொலைபேசியில் அழைக்கலாம்"</string>
- <string name="permgrouprequest_phone" msgid="7084161459732093690">"மொபைல் அழைப்புகளைச் செய்யவும், அவற்றை நிர்வகிக்கவும், <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>க்கு அனுமதி வழங்கவும்"</string>
+ <string name="permgrouprequest_phone" msgid="7084161459732093690">"மொபைல் அழைப்புகளைச் செய்யவும், அவற்றை நிர்வகிக்கவும், <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>க்கு அனுமதி வழங்கவா"</string>
<string name="permgrouplab_sensors" msgid="416037179223226722">"உடல் சென்சார்கள்"</string>
<string name="permgroupdesc_sensors" msgid="7147968539346634043">"உங்கள் உடல் இயக்கம் பற்றி உணர்விகள் கூறும் தகவலைப் பார்க்கலாம்"</string>
<string name="permgrouprequest_sensors" msgid="8631146669524259656">"உடலியக்கக் குறிகள் பற்றிய உணர்வித் தரவை அணுக, <b><xliff:g id="APP_NAME">%1$s</xliff:g></b>க்கு அனுமதி வழங்கவும்"</string>
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 6fa28b1..27b7f9e 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -187,6 +187,11 @@
uri = Uri.parse("http://localhost");
assertEquals("localhost", uri.getHost());
assertEquals(-1, uri.getPort());
+
+ uri = Uri.parse("http://a:a@example.com:a@example2.com/path");
+ assertEquals("a:a@example.com:a@example2.com", uri.getAuthority());
+ assertEquals("example2.com", uri.getHost());
+ assertEquals(-1, uri.getPort());
}
@SmallTest
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 2a6c22e..41686fa 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -18,6 +18,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import android.os.LocaleList;
@@ -32,6 +34,8 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Collection;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class TextClassificationManagerTest {
@@ -174,6 +178,23 @@
}
@Test
+ public void testGenerateLinks() {
+ if (isTextClassifierDisabled()) return;
+
+ checkGenerateLinksFindsLink(
+ "The number is +12122537077. See you tonight!",
+ "+12122537077",
+ TextClassifier.TYPE_PHONE);
+
+ checkGenerateLinksFindsLink(
+ "The address is 1600 Amphitheater Parkway, Mountain View, CA. See you tonight!",
+ "1600 Amphitheater Parkway, Mountain View, CA",
+ TextClassifier.TYPE_ADDRESS);
+
+ // TODO: Add more entity types when the model supports them.
+ }
+
+ @Test
public void testSetTextClassifier() {
TextClassifier classifier = mock(TextClassifier.class);
mTcm.setTextClassifier(classifier);
@@ -184,6 +205,24 @@
return mClassifier == TextClassifier.NO_OP;
}
+ private void checkGenerateLinksFindsLink(String text, String classifiedText, String type) {
+ assertTrue(text.contains(classifiedText));
+ int startIndex = text.indexOf(classifiedText);
+ int endIndex = startIndex + classifiedText.length();
+
+ Collection<TextLinks.TextLink> links = mClassifier.generateLinks(text, null).getLinks();
+ for (TextLinks.TextLink link : links) {
+ if (text.subSequence(link.getStart(), link.getEnd()).equals(classifiedText)) {
+ assertEquals(type, link.getEntity(0));
+ assertEquals(startIndex, link.getStart());
+ assertEquals(endIndex, link.getEnd());
+ assertTrue(link.getConfidenceScore(type) > .9);
+ return;
+ }
+ }
+ fail(); // Subsequence was not identified.
+ }
+
private static Matcher<TextSelection> isTextSelection(
final int startIndex, final int endIndex, final String type) {
return new BaseMatcher<TextSelection>() {
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
index b6986d5..0355f82 100644
--- a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -48,6 +48,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Predicate;
/**
* Espresso utility methods for the floating toolbar.
@@ -175,31 +176,10 @@
* @throws AssertionError if the assertion fails
*/
public static void assertFloatingToolbarDoesNotContainItem(String itemLabel) {
- onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
- @Override
- public boolean matchesSafely(View view) {
- return doesNotContainItem(view);
- }
-
- @Override
- public void describeTo(Description description) {}
-
- private boolean doesNotContainItem(View view) {
- if (view.getTag() instanceof MenuItem) {
- if (itemLabel.equals(((MenuItem) view.getTag()).getTitle().toString())) {
- return false;
- }
- } else if (view instanceof ViewGroup) {
- ViewGroup viewGroup = (ViewGroup) view;
- for (int i = 0; i < viewGroup.getChildCount(); i++) {
- if (doesNotContainItem(viewGroup.getChildAt(i))) {
- return false;
- }
- }
- }
- return true;
- }
- }));
+ final Predicate<View> hasMenuItemLabel = view ->
+ view.getTag() instanceof MenuItem
+ && itemLabel.equals(((MenuItem) view.getTag()).getTitle().toString());
+ assertFloatingToolbarMenuItem(hasMenuItemLabel, false);
}
/**
@@ -209,23 +189,30 @@
* @throws AssertionError if the assertion fails
*/
public static void assertFloatingToolbarDoesNotContainItem(final int menuItemId) {
+ final Predicate<View> hasMenuItemId = view ->
+ view.getTag() instanceof MenuItem
+ && ((MenuItem) view.getTag()).getItemId() == menuItemId;
+ assertFloatingToolbarMenuItem(hasMenuItemId, false);
+ }
+
+ private static void assertFloatingToolbarMenuItem(
+ final Predicate<View> predicate, final boolean positiveAssertion) {
onFloatingToolBar().check(matches(new TypeSafeMatcher<View>() {
@Override
public boolean matchesSafely(View view) {
- return !hasMenuItemWithSpecifiedId(view);
+ return positiveAssertion == containsItem(view);
}
@Override
public void describeTo(Description description) {}
- private boolean hasMenuItemWithSpecifiedId(View view) {
- if (view.getTag() instanceof MenuItem
- && ((MenuItem) view.getTag()).getItemId() == menuItemId) {
+ private boolean containsItem(View view) {
+ if (predicate.test(view)) {
return true;
} else if (view instanceof ViewGroup) {
ViewGroup viewGroup = (ViewGroup) view;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
- if (hasMenuItemWithSpecifiedId(viewGroup.getChildAt(i))) {
+ if (containsItem(viewGroup.getChildAt(i))) {
return true;
}
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 1a06a56..317144a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -88,7 +88,7 @@
* A map from a string representation of the LocaleList to Minikin's language list ID.
*/
@GuardedBy("sCacheLock")
- private static final HashMap<String, Integer> sMinikinLangListIdCache = new HashMap<>();
+ private static final HashMap<String, Integer> sMinikinLocaleListIdCache = new HashMap<>();
/**
* @hide
@@ -1445,16 +1445,16 @@
private void syncTextLocalesWithMinikin() {
final String languageTags = mLocales.toLanguageTags();
- final Integer minikinLangListId;
+ final Integer minikinLocaleListId;
synchronized (sCacheLock) {
- minikinLangListId = sMinikinLangListIdCache.get(languageTags);
- if (minikinLangListId == null) {
+ minikinLocaleListId = sMinikinLocaleListIdCache.get(languageTags);
+ if (minikinLocaleListId == null) {
final int newID = nSetTextLocales(mNativePaint, languageTags);
- sMinikinLangListIdCache.put(languageTags, newID);
+ sMinikinLocaleListIdCache.put(languageTags, newID);
return;
}
}
- nSetTextLocalesByMinikinLangListId(mNativePaint, minikinLangListId.intValue());
+ nSetTextLocalesByMinikinLocaleListId(mNativePaint, minikinLocaleListId.intValue());
}
/**
@@ -2918,8 +2918,8 @@
@CriticalNative
private static native void nSetTextAlign(long paintPtr, int align);
@CriticalNative
- private static native void nSetTextLocalesByMinikinLangListId(long paintPtr,
- int mMinikinLangListId);
+ private static native void nSetTextLocalesByMinikinLocaleListId(long paintPtr,
+ int mMinikinLocaleListId);
@CriticalNative
private static native void nSetShadowLayer(long paintPtr,
float radius, float dx, float dy, int color);
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
index 2644292..24ce1e4 100644
--- a/libs/hwui/Android.bp
+++ b/libs/hwui/Android.bp
@@ -68,6 +68,7 @@
],
static_libs: [
"libplatformprotos",
+ "libEGL_blobCache",
],
}
@@ -131,6 +132,7 @@
"pipeline/skia/LayerDrawable.cpp",
"pipeline/skia/RenderNodeDrawable.cpp",
"pipeline/skia/ReorderBarrierDrawables.cpp",
+ "pipeline/skia/ShaderCache.cpp",
"pipeline/skia/SkiaDisplayList.cpp",
"pipeline/skia/SkiaOpenGLPipeline.cpp",
"pipeline/skia/SkiaOpenGLReadback.cpp",
@@ -346,6 +348,7 @@
"tests/unit/RecordingCanvasTests.cpp",
"tests/unit/RenderNodeTests.cpp",
"tests/unit/RenderPropertiesTests.cpp",
+ "tests/unit/ShaderCacheTests.cpp",
"tests/unit/SkiaBehaviorTests.cpp",
"tests/unit/SkiaDisplayListTests.cpp",
"tests/unit/SkiaPipelineTests.cpp",
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index f739634..90fe0b7 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -26,39 +26,38 @@
namespace android {
-minikin::FontStyle MinikinUtils::prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- const Paint* paint, const Typeface* typeface) {
+minikin::MinikinPaint MinikinUtils::prepareMinikinPaint(const Paint* paint,
+ const Typeface* typeface) {
const Typeface* resolvedFace = Typeface::resolveDefault(typeface);
minikin::FontStyle resolved = resolvedFace->fStyle;
- /* Prepare minikin FontStyle */
- minikin::FontVariant minikinVariant = (paint->getFontVariant() == minikin::VARIANT_ELEGANT)
- ? minikin::VARIANT_ELEGANT
- : minikin::VARIANT_COMPACT;
- const uint32_t langListId = paint->getMinikinLangListId();
- minikin::FontStyle minikinStyle(langListId, minikinVariant, resolved.getWeight(),
- resolved.getItalic());
+ const minikin::FontVariant minikinVariant =
+ (paint->getFontVariant() == minikin::FontVariant::ELEGANT)
+ ? minikin::FontVariant::ELEGANT
+ : minikin::FontVariant::COMPACT;
+ minikin::MinikinPaint minikinPaint;
/* Prepare minikin Paint */
- minikinPaint->size =
+ minikinPaint.size =
paint->isLinearText() ? paint->getTextSize() : static_cast<int>(paint->getTextSize());
- minikinPaint->scaleX = paint->getTextScaleX();
- minikinPaint->skewX = paint->getTextSkewX();
- minikinPaint->letterSpacing = paint->getLetterSpacing();
- minikinPaint->wordSpacing = paint->getWordSpacing();
- minikinPaint->paintFlags = MinikinFontSkia::packPaintFlags(paint);
- minikinPaint->fontFeatureSettings = paint->getFontFeatureSettings();
- minikinPaint->hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit());
- return minikinStyle;
+ minikinPaint.scaleX = paint->getTextScaleX();
+ minikinPaint.skewX = paint->getTextSkewX();
+ minikinPaint.letterSpacing = paint->getLetterSpacing();
+ minikinPaint.wordSpacing = paint->getWordSpacing();
+ minikinPaint.paintFlags = MinikinFontSkia::packPaintFlags(paint);
+ minikinPaint.localeListId = paint->getMinikinLocaleListId();
+ minikinPaint.fontStyle = minikin::FontStyle(minikinVariant, resolved.weight, resolved.slant);
+ minikinPaint.fontFeatureSettings = paint->getFontFeatureSettings();
+ minikinPaint.hyphenEdit = minikin::HyphenEdit(paint->getHyphenEdit());
+ return minikinPaint;
}
minikin::Layout MinikinUtils::doLayout(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf, size_t start,
size_t count, size_t bufSize) {
- minikin::MinikinPaint minikinPaint;
- minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+ minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
minikin::Layout layout;
- layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint,
+ layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinPaint,
Typeface::resolveDefault(typeface)->fFontCollection);
return layout;
}
@@ -66,11 +65,10 @@
float MinikinUtils::measureText(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf, size_t start,
size_t count, size_t bufSize, float* advances) {
- minikin::MinikinPaint minikinPaint;
- minikin::FontStyle minikinStyle = prepareMinikinPaint(&minikinPaint, paint, typeface);
+ minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
const Typeface* resolvedTypeface = Typeface::resolveDefault(typeface);
- return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinStyle,
- minikinPaint, resolvedTypeface->fFontCollection, advances,
+ return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinPaint,
+ resolvedTypeface->fFontCollection, advances,
nullptr /* extent */, nullptr /* overhangs */);
}
@@ -109,4 +107,4 @@
SkPathMeasure measure(path, false);
return align * (layout.getAdvance() - measure.getLength());
}
-}
+} // namespace android
diff --git a/libs/hwui/hwui/MinikinUtils.h b/libs/hwui/hwui/MinikinUtils.h
index 8bb9179..7036cbe 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -34,9 +34,8 @@
class MinikinUtils {
public:
- ANDROID_API static minikin::FontStyle prepareMinikinPaint(minikin::MinikinPaint* minikinPaint,
- const Paint* paint,
- const Typeface* typeface);
+ ANDROID_API static minikin::MinikinPaint prepareMinikinPaint(const Paint* paint,
+ const Typeface* typeface);
ANDROID_API static minikin::Layout doLayout(const Paint* paint, minikin::Bidi bidiFlags,
const Typeface* typeface, const uint16_t* buf,
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index da7417a..76beb11 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -67,11 +67,11 @@
std::string getFontFeatureSettings() const { return mFontFeatureSettings; }
- void setMinikinLangListId(uint32_t minikinLangListId) {
- mMinikinLangListId = minikinLangListId;
+ void setMinikinLocaleListId(uint32_t minikinLocaleListId) {
+ mMinikinLocaleListId = minikinLocaleListId;
}
- uint32_t getMinikinLangListId() const { return mMinikinLangListId; }
+ uint32_t getMinikinLocaleListId() const { return mMinikinLocaleListId; }
void setFontVariant(minikin::FontVariant variant) { mFontVariant = variant; }
@@ -89,12 +89,13 @@
float mLetterSpacing = 0;
float mWordSpacing = 0;
std::string mFontFeatureSettings;
- uint32_t mMinikinLangListId;
+ uint32_t mMinikinLocaleListId;
minikin::FontVariant mFontVariant;
uint32_t mHyphenEdit = 0;
- // The native Typeface object has the same lifetime of the Java Typeface object. The Java Paint
- // object holds a strong reference to the Java Typeface object. Thus, following pointer can
- // never be a dangling pointer. Note that nullptr is valid: it means the default typeface.
+ // The native Typeface object has the same lifetime of the Java Typeface
+ // object. The Java Paint object holds a strong reference to the Java Typeface
+ // object. Thus, following pointer can never be a dangling pointer. Note that
+ // nullptr is valid: it means the default typeface.
const Typeface* mTypeface = nullptr;
};
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index 4f2b3bb..94492c5 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -23,15 +23,15 @@
, mLetterSpacing(0)
, mWordSpacing(0)
, mFontFeatureSettings()
- , mMinikinLangListId(0)
- , mFontVariant(minikin::VARIANT_DEFAULT) {}
+ , mMinikinLocaleListId(0)
+ , mFontVariant(minikin::FontVariant::DEFAULT) {}
Paint::Paint(const Paint& paint)
: SkPaint(paint)
, mLetterSpacing(paint.mLetterSpacing)
, mWordSpacing(paint.mWordSpacing)
, mFontFeatureSettings(paint.mFontFeatureSettings)
- , mMinikinLangListId(paint.mMinikinLangListId)
+ , mMinikinLocaleListId(paint.mMinikinLocaleListId)
, mFontVariant(paint.mFontVariant)
, mHyphenEdit(paint.mHyphenEdit)
, mTypeface(paint.mTypeface) {}
@@ -41,8 +41,8 @@
, mLetterSpacing(0)
, mWordSpacing(0)
, mFontFeatureSettings()
- , mMinikinLangListId(0)
- , mFontVariant(minikin::VARIANT_DEFAULT) {}
+ , mMinikinLocaleListId(0)
+ , mFontVariant(minikin::FontVariant::DEFAULT) {}
Paint::~Paint() {}
@@ -51,7 +51,7 @@
mLetterSpacing = other.mLetterSpacing;
mWordSpacing = other.mWordSpacing;
mFontFeatureSettings = other.mFontFeatureSettings;
- mMinikinLangListId = other.mMinikinLangListId;
+ mMinikinLocaleListId = other.mMinikinLocaleListId;
mFontVariant = other.mFontVariant;
mHyphenEdit = other.mHyphenEdit;
mTypeface = other.mTypeface;
@@ -62,7 +62,7 @@
return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
a.mLetterSpacing == b.mLetterSpacing && a.mWordSpacing == b.mWordSpacing &&
a.mFontFeatureSettings == b.mFontFeatureSettings &&
- a.mMinikinLangListId == b.mMinikinLangListId && a.mFontVariant == b.mFontVariant &&
+ a.mMinikinLocaleListId == b.mMinikinLocaleListId && a.mFontVariant == b.mFontVariant &&
a.mHyphenEdit == b.mHyphenEdit && a.mTypeface == b.mTypeface;
}
-}
+} // namespace android
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index c798e66..e527adc 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -44,9 +44,8 @@
}
static minikin::FontStyle computeMinikinStyle(int weight, bool italic) {
- // TODO: Better to use raw base weight value for font selection instead of dividing by 100.
- const int minikinWeight = uirenderer::MathUtils::clamp((weight + 50) / 100, 1, 10);
- return minikin::FontStyle(minikinWeight, italic);
+ return minikin::FontStyle(uirenderer::MathUtils::clamp(weight, 1, 1000),
+ static_cast<minikin::FontSlant>(italic));
}
// Resolve the relative weight from the baseWeight and target style.
@@ -192,8 +191,8 @@
hwTypeface->fFontCollection = collection;
hwTypeface->fAPIStyle = Typeface::kNormal;
hwTypeface->fBaseWeight = SkFontStyle::kNormal_Weight;
- hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
+ hwTypeface->fStyle = minikin::FontStyle();
Typeface::setDefault(hwTypeface);
}
-}
+} // namespace android
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
new file mode 100644
index 0000000..87edd69
--- /dev/null
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2017 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 "ShaderCache.h"
+#include <algorithm>
+#include <log/log.h>
+#include <thread>
+#include "FileBlobCache.h"
+#include "utils/TraceUtils.h"
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+// Cache size limits.
+static const size_t maxKeySize = 1024;
+static const size_t maxValueSize = 64 * 1024;
+static const size_t maxTotalSize = 512 * 1024;
+
+ShaderCache::ShaderCache() {
+ // There is an "incomplete FileBlobCache type" compilation error, if ctor is moved to header.
+}
+
+ShaderCache ShaderCache::sCache;
+
+ShaderCache& ShaderCache::get() {
+ return sCache;
+}
+
+void ShaderCache::initShaderDiskCache() {
+ ATRACE_NAME("initShaderDiskCache");
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (mFilename.length() > 0) {
+ mBlobCache.reset(new FileBlobCache(maxKeySize, maxValueSize, maxTotalSize, mFilename));
+ mInitialized = true;
+ }
+}
+
+void ShaderCache::setFilename(const char* filename) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mFilename = filename;
+}
+
+BlobCache* ShaderCache::getBlobCacheLocked() {
+ LOG_ALWAYS_FATAL_IF(!mInitialized, "ShaderCache has not been initialized");
+ return mBlobCache.get();
+}
+
+sk_sp<SkData> ShaderCache::load(const SkData& key) {
+ ATRACE_NAME("ShaderCache::load");
+ size_t keySize = key.size();
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (!mInitialized) {
+ ALOGE("ShaderCache::load not initialized");
+ return nullptr;
+ }
+
+ // mObservedBlobValueSize is reasonably big to avoid memory reallocation
+ // Allocate a buffer with malloc. SkData takes ownership of that allocation and will call free.
+ void* valueBuffer = malloc(mObservedBlobValueSize);
+ if (!valueBuffer) {
+ return nullptr;
+ }
+ BlobCache* bc = getBlobCacheLocked();
+ size_t valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
+ int maxTries = 3;
+ while (valueSize > mObservedBlobValueSize && maxTries > 0) {
+ mObservedBlobValueSize = std::min(valueSize, maxValueSize);
+ valueBuffer = realloc(valueBuffer, mObservedBlobValueSize);
+ if (!valueBuffer) {
+ return nullptr;
+ }
+ valueSize = bc->get(key.data(), keySize, valueBuffer, mObservedBlobValueSize);
+ maxTries--;
+ }
+ if (!valueSize) {
+ free(valueBuffer);
+ return nullptr;
+ }
+ if (valueSize > mObservedBlobValueSize) {
+ ALOGE("ShaderCache::load value size is too big %d", (int) valueSize);
+ free(valueBuffer);
+ return nullptr;
+ }
+ return SkData::MakeFromMalloc(valueBuffer, valueSize);
+}
+
+void ShaderCache::store(const SkData& key, const SkData& data) {
+ ATRACE_NAME("ShaderCache::store");
+ std::lock_guard<std::mutex> lock(mMutex);
+
+ if (!mInitialized) {
+ ALOGE("ShaderCache::store not initialized");
+ return;
+ }
+
+ size_t valueSize = data.size();
+ size_t keySize = key.size();
+ if (keySize == 0 || valueSize == 0 || valueSize >= maxValueSize) {
+ ALOGW("ShaderCache::store: sizes %d %d not allowed", (int)keySize, (int)valueSize);
+ return;
+ }
+
+ const void* value = data.data();
+
+ BlobCache* bc = getBlobCacheLocked();
+ bc->set(key.data(), keySize, value, valueSize);
+
+ if (!mSavePending && mDeferredSaveDelay > 0) {
+ mSavePending = true;
+ std::thread deferredSaveThread([this]() {
+ sleep(mDeferredSaveDelay);
+ std::lock_guard<std::mutex> lock(mMutex);
+ ATRACE_NAME("ShaderCache::saveToDisk");
+ if (mInitialized && mBlobCache) {
+ mBlobCache->writeToFile();
+ }
+ mSavePending = false;
+ });
+ deferredSaveThread.detach();
+ }
+}
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/ShaderCache.h b/libs/hwui/pipeline/skia/ShaderCache.h
new file mode 100644
index 0000000..27473d6
--- /dev/null
+++ b/libs/hwui/pipeline/skia/ShaderCache.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#pragma once
+
+#include <cutils/compiler.h>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+#include <GrContextOptions.h>
+
+namespace android {
+
+class BlobCache;
+class FileBlobCache;
+
+namespace uirenderer {
+namespace skiapipeline {
+
+class ShaderCache : public GrContextOptions::PersistentCache {
+public:
+ /**
+ * "get" returns a pointer to the singleton ShaderCache object. This
+ * singleton object will never be destroyed.
+ */
+ ANDROID_API static ShaderCache& get();
+
+ /**
+ * "initShaderDiskCache" loads the serialized cache contents from disk and puts the ShaderCache
+ * into an initialized state, such that it is able to insert and retrieve entries from the
+ * cache. This should be called when HWUI pipeline is initialized. When not in the initialized
+ * state the load and store methods will return without performing any cache operations.
+ */
+ virtual void initShaderDiskCache();
+
+ /**
+ * "setFilename" sets the name of the file that should be used to store
+ * cache contents from one program invocation to another. This function does not perform any
+ * disk operation and it should be invoked before "initShaderCache".
+ */
+ virtual void setFilename(const char* filename);
+
+ /**
+ * "load" attempts to retrieve the value blob associated with a given key
+ * blob from cache. This will be called by Skia, when it needs to compile a new SKSL shader.
+ */
+ sk_sp<SkData> load(const SkData& key) override;
+
+ /**
+ * "store" attempts to insert a new key/value blob pair into the cache.
+ * This will be called by Skia after it compiled a new SKSL shader
+ */
+ void store(const SkData& key, const SkData& data) override;
+
+private:
+ // Creation and (the lack of) destruction is handled internally.
+ ShaderCache();
+
+ // Copying is disallowed.
+ ShaderCache(const ShaderCache&) = delete;
+ void operator=(const ShaderCache&) = delete;
+
+ /**
+ * "getBlobCacheLocked" returns the BlobCache object being used to store the
+ * key/value blob pairs. If the BlobCache object has not yet been created,
+ * this will do so, loading the serialized cache contents from disk if
+ * possible.
+ */
+ BlobCache* getBlobCacheLocked();
+
+ /**
+ * "mInitialized" indicates whether the ShaderCache is in the initialized
+ * state. It is initialized to false at construction time, and gets set to
+ * true when initialize is called.
+ * When in this state, the cache behaves as normal. When not,
+ * the load and store methods will return without performing any cache
+ * operations.
+ */
+ bool mInitialized = false;
+
+ /**
+ * "mBlobCache" is the cache in which the key/value blob pairs are stored. It
+ * is initially NULL, and will be initialized by getBlobCacheLocked the
+ * first time it's needed.
+ * The blob cache contains the Android build number. We treat version mismatches as an empty
+ * cache (logic implemented in BlobCache::unflatten).
+ */
+ std::unique_ptr<FileBlobCache> mBlobCache;
+
+ /**
+ * "mFilename" is the name of the file for storing cache contents in between
+ * program invocations. It is initialized to an empty string at
+ * construction time, and can be set with the setCacheFilename method. An
+ * empty string indicates that the cache should not be saved to or restored
+ * from disk.
+ */
+ std::string mFilename;
+
+ /**
+ * "mSavePending" indicates whether or not a deferred save operation is
+ * pending. Each time a key/value pair is inserted into the cache via
+ * load, a deferred save is initiated if one is not already pending.
+ * This will wait some amount of time and then trigger a save of the cache
+ * contents to disk.
+ */
+ bool mSavePending = false;
+
+ /**
+ * "mObservedBlobValueSize" is the maximum value size observed by the cache reading function.
+ */
+ size_t mObservedBlobValueSize = 20*1024;
+
+ /**
+ * The time in seconds to wait before saving newly inserted cache entries.
+ */
+ unsigned int mDeferredSaveDelay = 4;
+
+ /**
+ * "mMutex" is the mutex used to prevent concurrent access to the member
+ * variables. It must be locked whenever the member variables are accessed.
+ */
+ mutable std::mutex mMutex;
+
+ /**
+ * "sCache" is the singleton ShaderCache object.
+ */
+ static ShaderCache sCache;
+
+ friend class ShaderCacheTestUtils; //used for unit testing
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index a33b287..c22364b 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -18,6 +18,7 @@
#include "Layer.h"
#include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
#include "renderstate/RenderState.h"
#include <GrContextOptions.h>
@@ -127,6 +128,8 @@
}
contextOptions->fExecutor = mTaskProcessor.get();
}
+
+ contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get();
}
void CacheManager::trimMemory(TrimMemoryMode mode) {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index c117cb8..574bb02 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,6 +16,7 @@
#include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
#include "CanvasContext.h"
#include "EglManager.h"
#include "OpenGLReadback.h"
@@ -105,6 +106,7 @@
mRenderState = new RenderState(*this);
mVkManager = new VulkanManager(*this);
mCacheManager = new CacheManager(mDisplayInfo);
+ uirenderer::skiapipeline::ShaderCache::get().initShaderDiskCache();
}
void RenderThread::dumpGraphicsMemory(int fd) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 3272d69..1d8cdd6 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -107,8 +107,11 @@
mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
+ GrContextOptions options;
+ options.fDisableDistanceFieldPaths = true;
+ mRenderThread.cacheManager().configureContext(&options);
mRenderThread.setGrContext(
- GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get()));
+ GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get(), options));
DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
diff --git a/libs/hwui/tests/unit/ShaderCacheTests.cpp b/libs/hwui/tests/unit/ShaderCacheTests.cpp
new file mode 100644
index 0000000..43080a9
--- /dev/null
+++ b/libs/hwui/tests/unit/ShaderCacheTests.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2017 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 <gtest/gtest.h>
+#include <dirent.h>
+#include <cutils/properties.h>
+#include <cstdint>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include "pipeline/skia/ShaderCache.h"
+#include "FileBlobCache.h"
+
+using namespace android::uirenderer::skiapipeline;
+
+namespace android {
+namespace uirenderer {
+namespace skiapipeline {
+
+class ShaderCacheTestUtils {
+public:
+ /**
+ * "setSaveDelay" sets the time in seconds to wait before saving newly inserted cache entries.
+ * If set to 0, then deferred save is disabled.
+ */
+ static void setSaveDelay(ShaderCache& cache, unsigned int saveDelay) {
+ cache.mDeferredSaveDelay = saveDelay;
+ }
+
+ /**
+ * "terminate" optionally stores the BlobCache on disk and release all in-memory cache.
+ * Next call to "initShaderDiskCache" will load again the in-memory cache from disk.
+ */
+ static void terminate(ShaderCache& cache, bool saveContent) {
+ std::lock_guard<std::mutex> lock(cache.mMutex);
+ if (cache.mInitialized && cache.mBlobCache && saveContent) {
+ cache.mBlobCache->writeToFile();
+ }
+ cache.mBlobCache = NULL;
+ }
+};
+
+} /* namespace skiapipeline */
+} /* namespace uirenderer */
+} /* namespace android */
+
+
+namespace {
+
+std::string getExternalStorageFolder() {
+ return getenv("EXTERNAL_STORAGE");
+}
+
+bool folderExist(const std::string& folderName) {
+ DIR* dir = opendir(folderName.c_str());
+ if (dir) {
+ closedir(dir);
+ return true;
+ }
+ return false;
+}
+
+bool checkShader(const sk_sp<SkData>& shader, const char* program) {
+ sk_sp<SkData> shader2 = SkData::MakeWithCString(program);
+ return shader->size() == shader2->size()
+ && 0 == memcmp(shader->data(), shader2->data(), shader->size());
+}
+
+bool checkShader(const sk_sp<SkData>& shader, std::vector<char>& program) {
+ sk_sp<SkData> shader2 = SkData::MakeWithCopy(program.data(), program.size());
+ return shader->size() == shader2->size()
+ && 0 == memcmp(shader->data(), shader2->data(), shader->size());
+}
+
+void setShader(sk_sp<SkData>& shader, const char* program) {
+ shader = SkData::MakeWithCString(program);
+}
+
+void setShader(sk_sp<SkData>& shader, std::vector<char>& program) {
+ shader = SkData::MakeWithCopy(program.data(), program.size());
+}
+
+
+
+#define GrProgramDescTest(a) (*SkData::MakeWithCString(#a).get())
+
+TEST(ShaderCacheTest, testWriteAndRead) {
+ if (!folderExist(getExternalStorageFolder())) {
+ //don't run the test if external storage folder is not available
+ return;
+ }
+ std::string cacheFile1 = getExternalStorageFolder() + "/shaderCacheTest1";
+ std::string cacheFile2 = getExternalStorageFolder() + "/shaderCacheTest2";
+
+ //remove any test files from previous test run
+ int deleteFile = remove(cacheFile1.c_str());
+ ASSERT_TRUE(0 == deleteFile || ENOENT == errno);
+
+ //read the cache from a file that does not exist
+ ShaderCache::get().setFilename(cacheFile1.c_str());
+ ShaderCacheTestUtils::setSaveDelay(ShaderCache::get(), 0); //disable deferred save
+ ShaderCache::get().initShaderDiskCache();
+
+ //read a key - should not be found since the cache is empty
+ sk_sp<SkData> outVS;
+ ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
+
+ //write to the in-memory cache without storing on disk and verify we read the same values
+ sk_sp<SkData> inVS;
+ setShader(inVS, "sassas");
+ ShaderCache::get().store(GrProgramDescTest(100), *inVS.get());
+ setShader(inVS, "someVS");
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
+ ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(100))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS, "sassas"));
+ ASSERT_NE((outVS = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS, "someVS"));
+
+ //store content to disk and release in-memory cache
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+
+ //change to a file that does not exist and verify load fails
+ ShaderCache::get().setFilename(cacheFile2.c_str());
+ ShaderCache::get().initShaderDiskCache();
+ ASSERT_EQ(ShaderCache::get().load(GrProgramDescTest(432)), sk_sp<SkData>());
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+
+ //load again content from disk from an existing file and check the data is read correctly
+ ShaderCache::get().setFilename(cacheFile1.c_str());
+ ShaderCache::get().initShaderDiskCache();
+ sk_sp<SkData> outVS2;
+ ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS2, "someVS"));
+
+ //change data, store to disk, read back again and verify data has been changed
+ setShader(inVS, "ewData1");
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+ ShaderCache::get().initShaderDiskCache();
+ ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS2, "ewData1"));
+
+
+ //write and read big data chunk (50K)
+ size_t dataSize = 50*1024;
+ std::vector<char> dataBuffer(dataSize);
+ for (size_t i = 0; i < dataSize; i++) {
+ dataBuffer[0] = dataSize % 256;
+ }
+ setShader(inVS, dataBuffer);
+ ShaderCache::get().store(GrProgramDescTest(432), *inVS.get());
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), true);
+ ShaderCache::get().initShaderDiskCache();
+ ASSERT_NE((outVS2 = ShaderCache::get().load(GrProgramDescTest(432))), sk_sp<SkData>());
+ ASSERT_TRUE(checkShader(outVS2, dataBuffer));
+
+ ShaderCacheTestUtils::terminate(ShaderCache::get(), false);
+ remove(cacheFile1.c_str());
+}
+
+} // namespace
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index aad1fd6..1fcc028 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -81,127 +81,139 @@
TEST(TypefaceTest, createWithDifferentBaseWeight) {
std::unique_ptr<Typeface> bold(Typeface::createWithDifferentBaseWeight(nullptr, 700));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, bold->fAPIStyle);
std::unique_ptr<Typeface> light(Typeface::createWithDifferentBaseWeight(nullptr, 300));
- EXPECT_EQ(3, light->fStyle.getWeight());
- EXPECT_FALSE(light->fStyle.getItalic());
+ EXPECT_EQ(300, light->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, light->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, light->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_fromRegular) {
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(nullptr, Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(nullptr, Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(nullptr, Typeface::kItalic));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);
std::unique_ptr<Typeface> boldItalic(Typeface::createRelative(nullptr, Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_BoldBase) {
std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 700));
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.NORMAL);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(7, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(700, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(10, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(1000, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.ITALIC);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(7, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(700, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD_ITALIC);
+ // In Java, Typeface.create(Typeface.create("sans-serif-bold"),
+ // Typeface.BOLD_ITALIC);
std::unique_ptr<Typeface> boldItalic(
Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(10, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(1000, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_LightBase) {
std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 300));
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.NORMAL);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(3, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(300, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(6, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(600, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.ITLIC);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.ITLIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(3, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(300, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
- // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD_ITALIC);
+ // In Java, Typeface.create(Typeface.create("sans-serif-light"),
+ // Typeface.BOLD_ITALIC);
std::unique_ptr<Typeface> boldItalic(
Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(6, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(600, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createRelativeTest_fromBoldStyled) {
std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, Typeface::kBold));
- // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.NORMAL);
+ // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD);
+ // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.ITALIC);
+ // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD_ITALIC);
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.BOLD_ITALIC);
std::unique_ptr<Typeface> boldItalic(
Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
@@ -209,31 +221,35 @@
std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, Typeface::kItalic));
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.NORMAL);
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
- // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD);
+ // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT,
+ // Typeface.ITALIC), Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.ITALIC);
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD_ITALIC);
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.BOLD_ITALIC);
std::unique_ptr<Typeface> boldItalic(
Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
@@ -245,8 +261,8 @@
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.NORMAL);
std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), Typeface::kNormal));
- EXPECT_EQ(4, normal->fStyle.getWeight());
- EXPECT_FALSE(normal->fStyle.getItalic());
+ EXPECT_EQ(400, normal->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, normal->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, normal->fAPIStyle);
// In Java,
@@ -254,8 +270,8 @@
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.BOLD);
std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), Typeface::kBold));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java,
@@ -263,8 +279,8 @@
// .setWeight(700).setItalic(false).build();
// Typeface.create(typeface, Typeface.ITALIC);
std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), Typeface::kItalic));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
@@ -273,89 +289,99 @@
// Typeface.create(typeface, Typeface.BOLD_ITALIC);
std::unique_ptr<Typeface> boldItalic(
Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
TEST(TypefaceTest, createAbsolute) {
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
// .build();
std::unique_ptr<Typeface> regular(Typeface::createAbsolute(nullptr, 400, false));
- EXPECT_EQ(4, regular->fStyle.getWeight());
- EXPECT_FALSE(regular->fStyle.getItalic());
+ EXPECT_EQ(400, regular->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, regular->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
// .build();
std::unique_ptr<Typeface> bold(Typeface::createAbsolute(nullptr, 700, false));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
// .build();
std::unique_ptr<Typeface> italic(Typeface::createAbsolute(nullptr, 400, true));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
// .build();
std::unique_ptr<Typeface> boldItalic(Typeface::createAbsolute(nullptr, 700, true));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
// In Java,
- // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
+ // new
+ // Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
// .build();
std::unique_ptr<Typeface> over1000(Typeface::createAbsolute(nullptr, 1100, false));
- EXPECT_EQ(10, over1000->fStyle.getWeight());
- EXPECT_FALSE(over1000->fStyle.getItalic());
+ EXPECT_EQ(1000, over1000->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, over1000->fStyle.slant);
EXPECT_EQ(Typeface::kBold, over1000->fAPIStyle);
}
TEST(TypefaceTest, createFromFamilies_Single) {
- // In Java, new Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
+ // In Java, new
+ // Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
std::unique_ptr<Typeface> regular(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular), 400, false));
- EXPECT_EQ(4, regular->fStyle.getWeight());
- EXPECT_FALSE(regular->fStyle.getItalic());
+ EXPECT_EQ(400, regular->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, regular->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle);
- // In Java, new Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
+ // In Java, new
+ // Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
std::unique_ptr<Typeface> bold(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 700, false));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
- // In Java, new Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
+ // In Java, new
+ // Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
std::unique_ptr<Typeface> italic(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic), 400, true));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
+ // new
+ // Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
std::unique_ptr<Typeface> boldItalic(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), 700, true));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java,
- // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
+ // new
+ // Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
std::unique_ptr<Typeface> over1000(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 1100, false));
- EXPECT_EQ(10, over1000->fStyle.getWeight());
- EXPECT_FALSE(over1000->fStyle.getItalic());
+ EXPECT_EQ(1000, over1000->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, over1000->fStyle.slant);
EXPECT_EQ(Typeface::kBold, over1000->fAPIStyle);
}
@@ -363,30 +389,30 @@
// In Java, new Typeface.Builder("Roboto-Regular.ttf").build();
std::unique_ptr<Typeface> regular(Typeface::createFromFamilies(
makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(4, regular->fStyle.getWeight());
- EXPECT_FALSE(regular->fStyle.getItalic());
+ EXPECT_EQ(400, regular->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, regular->fStyle.slant);
EXPECT_EQ(Typeface::kNormal, regular->fAPIStyle);
// In Java, new Typeface.Builder("Roboto-Bold.ttf").build();
std::unique_ptr<Typeface> bold(Typeface::createFromFamilies(
makeSingleFamlyVector(kRobotoBold), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(7, bold->fStyle.getWeight());
- EXPECT_FALSE(bold->fStyle.getItalic());
+ EXPECT_EQ(700, bold->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, bold->fStyle.slant);
EXPECT_EQ(Typeface::kBold, bold->fAPIStyle);
// In Java, new Typeface.Builder("Roboto-Italic.ttf").build();
std::unique_ptr<Typeface> italic(Typeface::createFromFamilies(
makeSingleFamlyVector(kRobotoItalic), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(4, italic->fStyle.getWeight());
- EXPECT_TRUE(italic->fStyle.getItalic());
+ EXPECT_EQ(400, italic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, italic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
// In Java, new Typeface.Builder("Roboto-BoldItalic.ttf").build();
std::unique_ptr<Typeface> boldItalic(
Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic),
RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
}
@@ -396,8 +422,8 @@
buildFamily(kRobotoBoldItalic)};
std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(
std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(4, typeface->fStyle.getWeight());
- EXPECT_FALSE(typeface->fStyle.getItalic());
+ EXPECT_EQ(400, typeface->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, typeface->fStyle.slant);
}
TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) {
@@ -405,8 +431,8 @@
buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)};
std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(
std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
- EXPECT_EQ(7, typeface->fStyle.getWeight());
- EXPECT_FALSE(typeface->fStyle.getItalic());
+ EXPECT_EQ(700, typeface->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, typeface->fStyle.slant);
}
} // namespace
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index f4c9bb3..4fe9d56 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -16,7 +16,6 @@
package com.android.settingslib.graph;
-import android.animation.ArgbEvaluator;
import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
@@ -100,7 +99,7 @@
final int N = levels.length();
mColors = new int[2 * N];
- for (int i=0; i < N; i++) {
+ for (int i = 0; i < N; i++) {
mColors[2 * i] = levels.getInt(i, 0);
if (colors.getType(i) == TypedValue.TYPE_ATTRIBUTE) {
mColors[2 * i + 1] = Utils.getColorAttr(context, colors.getThemeAttributeId(i, 0));
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
index fdbbf14..dd55188 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPointPreference.java
@@ -31,15 +31,17 @@
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
+import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.android.settingslib.R;
import com.android.settingslib.TronUtils;
+import com.android.settingslib.TwoTargetPreference;
import com.android.settingslib.Utils;
import com.android.settingslib.wifi.AccessPoint.Speed;
-public class AccessPointPreference extends Preference {
+public class AccessPointPreference extends TwoTargetPreference {
private static final int[] STATE_SECURED = {
R.attr.state_encrypted
@@ -126,7 +128,6 @@
int iconResId, boolean forSavedNetworks, StateListDrawable frictionSld,
int level, IconInjector iconInjector) {
super(context);
- setWidgetLayoutResource(R.layout.access_point_friction_widget);
mBadgeCache = cache;
mAccessPoint = accessPoint;
mForSavedNetworks = forSavedNetworks;
@@ -165,6 +166,20 @@
ImageView frictionImageView = (ImageView) view.findViewById(R.id.friction_icon);
bindFrictionImage(frictionImageView);
+ setDividerVisibility(view, View.GONE);
+ }
+
+ protected void setDividerVisibility(final PreferenceViewHolder view,
+ @View.Visibility int visibility) {
+ final View divider = view.findViewById(R.id.two_target_divider);
+ if (divider != null) {
+ divider.setVisibility(visibility);
+ }
+ }
+
+ @Override
+ protected int getSecondTargetResId() {
+ return R.layout.access_point_friction_widget;
}
protected void updateIcon(int level, Context context) {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
index 3af9768..1f9070c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TestConfig.java
@@ -16,8 +16,10 @@
package com.android.settingslib;
+import android.os.Build;
+
public class TestConfig {
- public static final int SDK_VERSION = 25;
+ public static final int SDK_VERSION = Build.VERSION_CODES.O;
public static final String MANIFEST_PATH =
"frameworks/base/packages/SettingsLib/tests/robotests/AndroidManifest.xml";
}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
index 3522b8a..e022232 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/graph/BatteryMeterDrawableBaseTest.java
@@ -18,6 +18,7 @@
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import android.content.Context;
@@ -35,11 +36,13 @@
import org.mockito.MockitoAnnotations;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.annotation.Config;
+import org.robolectric.util.ReflectionHelpers;
@RunWith(SettingsLibRobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION,
shadows = SettingsLibShadowResources.class)
public class BatteryMeterDrawableBaseTest {
+ private static final int CRITICAL_LEVEL = 5;
private static final int PADDING = 5;
private static final int HEIGHT = 80;
private static final int WIDTH = 40;
@@ -53,7 +56,8 @@
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
- mBatteryMeterDrawableBase = new BatteryMeterDrawableBase(mContext, 0 /* frameColor */);
+ mBatteryMeterDrawableBase = spy(new BatteryMeterDrawableBase(mContext, 0 /* frameColor */));
+ ReflectionHelpers.setField(mBatteryMeterDrawableBase, "mCriticalLevel", CRITICAL_LEVEL);
}
@Test
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 8ab95f9..cfda6cc 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -25,12 +25,11 @@
<string name="keyguard_password_enter_puk_code" msgid="670683628782925409">"सिम PUK आणि नवीन पिन कोड टाइप करा"</string>
<string name="keyguard_password_enter_puk_prompt" msgid="3747778500166059332">"सिम PUK कोड"</string>
<string name="keyguard_password_enter_pin_prompt" msgid="8188243197504453830">"नवीन सिम पिन कोड"</string>
- <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"संकेतशब्द टाइप करण्यासाठी स्पर्श करा"</font></string>
- <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"अनलॉक करण्यासाठी संकेतशब्द टाइप करा"</string>
+ <string name="keyguard_password_entry_touch_hint" msgid="5790410752696806482"><font size="17">"पासवर्ड टाइप करण्यासाठी स्पर्श करा"</font></string>
+ <string name="keyguard_password_enter_password_code" msgid="595980919238127672">"अनलॉक करण्यासाठी पासवर्ड टाइप करा"</string>
<string name="keyguard_password_enter_pin_password_code" msgid="7504123374204446086">"अनलॉक करण्यासाठी पिन टाइप करा"</string>
<string name="keyguard_password_wrong_pin_code" msgid="6535018036285012028">"चुकीचा पिन कोड."</string>
- <!-- no translation found for keyguard_sim_error_message_short (592109500618448312) -->
- <skip />
+ <string name="keyguard_sim_error_message_short" msgid="592109500618448312">"अवैध कार्ड."</string>
<string name="keyguard_charged" msgid="2222329688813033109">"चार्ज झाली"</string>
<string name="keyguard_plugged_in" msgid="89308975354638682">"चार्ज होत आहे"</string>
<string name="keyguard_plugged_in_charging_fast" msgid="8869226755413795173">"द्रुतपणे चार्ज होत आहे"</string>
@@ -54,10 +53,10 @@
<string name="keyguard_accessibility_next_alarm" msgid="5835196989158584991">"पुढील अलार्म <xliff:g id="ALARM">%1$s</xliff:g> साठी सेट केला"</string>
<string name="keyboardview_keycode_delete" msgid="6883116827512721630">"हटवा"</string>
<string name="disable_carrier_button_text" msgid="6914341927421916114">"eSIM बंद करा"</string>
- <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"प्रविष्ट करा"</string>
+ <string name="keyboardview_keycode_enter" msgid="4505833604411016668">"एंटर करा"</string>
<string name="kg_forgot_pattern_button_text" msgid="534245177645252620">"पॅटर्न विसरलात"</string>
<string name="kg_wrong_pattern" msgid="7620081431514773802">"चुकीचा पॅटर्न"</string>
- <string name="kg_wrong_password" msgid="4580683060277329277">"चुकीचा संकेतशब्द"</string>
+ <string name="kg_wrong_password" msgid="4580683060277329277">"चुकीचा पासवर्ड"</string>
<string name="kg_wrong_pin" msgid="4785660766909463466">"चुकीचा पिन"</string>
<plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="4368805541257003755">
<item quantity="one"><xliff:g id="NUMBER">%d</xliff:g> सेकंदात पुन्हा प्रयत्न करा.</item>
@@ -67,20 +66,20 @@
<string name="kg_sim_pin_instructions" msgid="6389000973113699187">"सिम पिन एंटर करा"</string>
<string name="kg_sim_pin_instructions_multi" msgid="1643757228644271861">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" साठी सिम पिन एंटर करा"</string>
<string name="kg_sim_lock_instructions_esim" msgid="4957650659201013804">"मोबाइल सेवांशिवाय डिव्हाइस वापरण्यासाठी eSIM बंद करा."</string>
- <string name="kg_pin_instructions" msgid="4069609316644030034">"पिन प्रविष्ट करा"</string>
- <string name="kg_password_instructions" msgid="136952397352976538">"संकेतशब्द प्रविष्ट करा"</string>
- <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड प्रविष्ट करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
- <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड प्रविष्ट करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
- <string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"इच्छित पिन कोड प्रविष्ट करा"</string>
+ <string name="kg_pin_instructions" msgid="4069609316644030034">"पिन एंटर करा"</string>
+ <string name="kg_password_instructions" msgid="136952397352976538">"पासवर्ड एंटर करा"</string>
+ <string name="kg_puk_enter_puk_hint" msgid="2288964170039899277">"सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_puk_hint_multi" msgid="1373131883510840794">"\"<xliff:g id="CARRIER">%1$s</xliff:g>\" सिम आता अक्षम केले आहे. सुरू ठेवण्यासाठी PUK कोड एंटर करा. तपशीलांसाठी वाहकाशी संपर्क साधा."</string>
+ <string name="kg_puk_enter_pin_hint" msgid="3137789674920391087">"इच्छित पिन कोड एंटर करा"</string>
<string name="kg_enter_confirm_pin_hint" msgid="3089485999116759671">"इच्छित पिन कोड ची पुष्टी करा"</string>
<string name="kg_sim_unlock_progress_dialog_message" msgid="4471738151810900114">"सिम कार्ड अनलॉक करत आहे…"</string>
<string name="kg_invalid_sim_pin_hint" msgid="3057533256729513335">"4 ते 8 अंकांचा पिन टाईप करा."</string>
<string name="kg_invalid_sim_puk_hint" msgid="6003602401368264144">"PUK कोड 8 अंकी किंवा त्यापेक्षा अधिकचा असावा."</string>
- <string name="kg_invalid_puk" msgid="5399287873762592502">"योग्य PUK कोड पुन्हा प्रविष्ट करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
+ <string name="kg_invalid_puk" msgid="5399287873762592502">"योग्य PUK कोड पुन्हा एंटर करा. पुनःपुन्हा प्रयत्न करणे सिम कायमचे अक्षम करेल."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="5672736555427444330">"पिन कोड जुळत नाहीत"</string>
<string name="kg_login_too_many_attempts" msgid="6604574268387867255">"खूप जास्त पॅटर्न प्रयत्न"</string>
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="8637788033282252027">"आपण आपला PIN <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
- <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"आपण आपला संकेतशब्द <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
+ <string name="kg_too_many_failed_password_attempts_dialog_message" msgid="7724148763268377734">"आपण आपला पासवर्ड <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने टाइप केला आहे. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="4820967667848302092">"तुम्ही आपला अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यरितीने काढला. \n\n <xliff:g id="NUMBER_1">%2$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="1629351522209932316">"आपण टॅबलेट अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हे टॅबलेट रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
<string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="3921998703529189931">"आपण फोन अनलॉक करण्याचा <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा चुकीच्या पद्धतीने प्रयत्न केला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, हा फोन रीसेट केला जाईल, जे त्याचा सर्व डेटा हटवेल."</string>
@@ -117,10 +116,10 @@
<string name="kg_prompt_reason_restart_password" msgid="6984641181515902406">"डिव्हाइस रीस्टार्ट झाल्यावर पासवर्ड आवश्यक आहे"</string>
<string name="kg_prompt_reason_timeout_pattern" msgid="5304487696073914063">"अतिरिक्त सुरक्षिततेसाठी पॅटर्न आवश्यक आहे"</string>
<string name="kg_prompt_reason_timeout_pin" msgid="8851462864335757813">"अतिरिक्त सुरक्षिततेसाठी पिन आवश्यक आहे"</string>
- <string name="kg_prompt_reason_timeout_password" msgid="6563904839641583441">"अतिरिक्त सुरक्षिततेसाठी संकेतशब्द आवश्यक आहे"</string>
+ <string name="kg_prompt_reason_timeout_password" msgid="6563904839641583441">"अतिरिक्त सुरक्षिततेसाठी पासवर्ड आवश्यक आहे"</string>
<string name="kg_prompt_reason_switch_profiles_pattern" msgid="3398054847288438444">"तुम्ही प्रोफाईल स्विच करता तेव्हा पॅटर्न आवश्यक आहे"</string>
<string name="kg_prompt_reason_switch_profiles_pin" msgid="7426368139226961699">"आपण प्रोफाईल स्विच करता तेव्हा पिन आवश्यक आहे"</string>
- <string name="kg_prompt_reason_switch_profiles_password" msgid="8383831046318421845">"आपण प्रोफाईल स्विच करता तेव्हा संकेतशब्द आवश्यक आहे"</string>
+ <string name="kg_prompt_reason_switch_profiles_password" msgid="8383831046318421845">"आपण प्रोफाईल स्विच करता तेव्हा पासवर्ड आवश्यक आहे"</string>
<string name="kg_prompt_reason_device_admin" msgid="3452168247888906179">"प्रशासकाद्वारे लॉक केलेले डिव्हाइस"</string>
<string name="kg_prompt_reason_user_request" msgid="8236951765212462286">"डिव्हाइस मॅन्युअली लॉक केले होते"</string>
<plurals name="kg_prompt_reason_time_pattern" formatted="false" msgid="71299470072448533">
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 4487abc..3d9a2dc 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -34,44 +34,9 @@
android:id="@+id/volume_dialog_rows"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingEnd="@dimen/volume_button_size"
android:orientation="vertical" >
<!-- volume rows added and removed here! :-) -->
</LinearLayout>
-
- <include layout="@layout/volume_zen_footer" />
-
- <!-- Only shown from Tuner setting -->
- <include layout="@layout/tuner_zen_mode_panel" />
</LinearLayout>
- <LinearLayout
- android:id="@+id/volume_dialog_content"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:layout_alignParentEnd="true"
- android:layout_alignParentTop="true"
- android:layout_marginEnd="@dimen/volume_expander_margin_end" >
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:maxLines="1"
- android:textAppearance="@style/TextAppearance.Volume.Header" />
- <com.android.keyguard.AlphaOptimizedImageButton
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/volume_expand_button"
- style="@style/VolumeButtons"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:clickable="true"
- android:soundEffectsEnabled="false"
- android:src="@drawable/ic_volume_collapse_animation"
- android:background="@drawable/ripple_drawable"
- tools:ignore="RtlHardcoded"
- />
-
- </LinearLayout>
</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/volume_zen_footer.xml b/packages/SystemUI/res/layout/volume_zen_footer.xml
deleted file mode 100644
index df79c5f..0000000
--- a/packages/SystemUI/res/layout/volume_zen_footer.xml
+++ /dev/null
@@ -1,127 +0,0 @@
-<!--
- Copyright (C) 2015 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<com.android.systemui.volume.ZenFooter xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:id="@+id/volume_zen_footer"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:paddingBottom="8dp" > <!-- extends LinearLayout -->
-
- <View
- android:id="@+id/zen_embedded_divider"
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:layout_marginTop="8dp"
- android:background="@color/qs_tile_divider" />
-
- <RelativeLayout
- android:id="@+id/zen_introduction"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginStart="16dp"
- android:layout_marginEnd="16dp"
- android:paddingBottom="8dp"
- android:background="@drawable/zen_introduction_message_background"
- android:theme="@*android:style/ThemeOverlay.DeviceDefault.Accent.Light">
-
- <ImageView
- android:id="@+id/zen_introduction_confirm"
- android:layout_width="48dp"
- android:layout_height="48dp"
- android:layout_marginEnd="8dp"
- android:layout_alignParentEnd="true"
- android:background="@drawable/btn_borderless_rect"
- android:clickable="true"
- android:contentDescription="@string/accessibility_desc_close"
- android:scaleType="center"
- android:src="@drawable/ic_close_white_rounded" />
-
- <TextView
- android:id="@+id/zen_introduction_message"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="12dp"
- android:layout_marginStart="24dp"
- android:textDirection="locale"
- android:lineSpacingMultiplier="1.20029"
- android:layout_toStartOf="@id/zen_introduction_confirm"
- android:text="@string/zen_alarms_introduction"
- android:textAppearance="@style/TextAppearance.QS.Introduction" />
-
- <View
- android:layout_width="0dp"
- android:layout_height="16dp"
- android:layout_below="@id/zen_introduction_message"
- android:layout_alignParentEnd="true" />
-
- </RelativeLayout>
-
-
- <LinearLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@+id/volume_zen_icon"
- android:layout_width="@dimen/volume_button_size"
- android:layout_height="@dimen/volume_button_size"
- android:layout_marginEnd="7dp"
- android:scaleType="center" />
-
- <LinearLayout
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical" >
-
- <TextView
- android:id="@+id/volume_zen_summary_line_1"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.Volume.ZenSummary" />
-
- <TextView
- android:id="@+id/volume_zen_summary_line_2"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginTop="1dp"
- android:textDirection="locale"
- android:textAppearance="@style/TextAppearance.Volume.ZenDetail" />
-
- </LinearLayout>
-
- </LinearLayout>
-
- <TextView
- android:id="@+id/volume_zen_end_now"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="end"
- android:layout_marginEnd="8dp"
- android:clickable="true"
- android:focusable="true"
- android:paddingStart="15dp"
- android:paddingEnd="15dp"
- android:text="@string/volume_zen_end_now"
- android:textColor="?android:attr/colorAccent"
- android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
-</com.android.systemui.volume.ZenFooter>
diff --git a/packages/SystemUI/res/values-in/config.xml b/packages/SystemUI/res/values-in/config.xml
index 5309563..9857f13 100644
--- a/packages/SystemUI/res/values-in/config.xml
+++ b/packages/SystemUI/res/values-in/config.xml
@@ -22,5 +22,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for config_overviewServiceComponent (2288311504315574053) -->
+ <skip />
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 27d5f1b..255ba2c 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -358,12 +358,12 @@
<string name="keyguard_more_overflow_text" msgid="9195222469041601365">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="1288875699658819755">"Notifikasi kurang darurat di bawah"</string>
<string name="notification_tap_again" msgid="7590196980943943842">"Tap lagi untuk membuka"</string>
- <string name="keyguard_unlock" msgid="8043466894212841998">"Gesek ke atas untuk membuka kunci"</string>
+ <string name="keyguard_unlock" msgid="8043466894212841998">"Geser ke atas untuk membuka kunci"</string>
<string name="do_disclosure_generic" msgid="5615898451805157556">"Perangkat ini dikelola oleh organisasi"</string>
<string name="do_disclosure_with_name" msgid="5640615509915445501">"Perangkat ini dikelola oleh <xliff:g id="ORGANIZATION_NAME">%s</xliff:g>"</string>
- <string name="phone_hint" msgid="4872890986869209950">"Gesek dari ikon untuk telepon"</string>
- <string name="voice_hint" msgid="8939888732119726665">"Gesek dari ikon untuk mengaktifkan bantuan suara"</string>
- <string name="camera_hint" msgid="7939688436797157483">"Gesek dari ikon untuk kamera"</string>
+ <string name="phone_hint" msgid="4872890986869209950">"Geser dari ikon untuk telepon"</string>
+ <string name="voice_hint" msgid="8939888732119726665">"Geser dari ikon untuk bantuan suara"</string>
+ <string name="camera_hint" msgid="7939688436797157483">"Geser dari ikon untuk kamera"</string>
<string name="interruption_level_none_with_warning" msgid="5114872171614161084">"Senyap total. Tindakan ini juga akan mensenyapkan pembaca layar."</string>
<string name="interruption_level_none" msgid="6000083681244492992">"Senyap total"</string>
<string name="interruption_level_priority" msgid="6426766465363855505">"Hanya untuk prioritas"</string>
@@ -499,7 +499,7 @@
<string name="volume_stream_content_description_mute" msgid="3625049841390467354">"%1$s. Ketuk untuk membisukan. Layanan aksesibilitas mungkin dibisukan."</string>
<string name="volume_stream_content_description_vibrate_a11y" msgid="6427727603978431301">"%1$s. Tap untuk menyetel agar bergetar."</string>
<string name="volume_stream_content_description_mute_a11y" msgid="8995013018414535494">"%1$s. Tap untuk menonaktifkan."</string>
- <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrol volume %s ditampilkan. Gesek ke atas untuk menutup."</string>
+ <string name="volume_dialog_accessibility_shown_message" msgid="1834631467074259998">"Kontrol volume %s ditampilkan. Geser ke atas untuk menutup."</string>
<string name="volume_dialog_accessibility_dismissed_message" msgid="51543526013711399">"Kontrol volume disembunyikan"</string>
<string name="system_ui_tuner" msgid="708224127392452018">"Penyetel Antarmuka Pengguna Sistem"</string>
<string name="show_battery_percentage" msgid="5444136600512968798">"Tampilkan persentase baterai yang tersemat"</string>
diff --git a/packages/SystemUI/res/values-mr/config.xml b/packages/SystemUI/res/values-mr/config.xml
index 5309563..9857f13 100644
--- a/packages/SystemUI/res/values-mr/config.xml
+++ b/packages/SystemUI/res/values-mr/config.xml
@@ -22,5 +22,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for config_overviewServiceComponent (2288311504315574053) -->
+ <skip />
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index b5975b1..2a9ec0c 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -137,7 +137,7 @@
<string name="accessibility_desc_on" msgid="2385254693624345265">"चालू."</string>
<string name="accessibility_desc_off" msgid="6475508157786853157">"बंद."</string>
<string name="accessibility_desc_connected" msgid="8366256693719499665">"कनेक्ट केले."</string>
- <string name="accessibility_desc_connecting" msgid="3812924520316280149">"कनेक्ट करीत आहे."</string>
+ <string name="accessibility_desc_connecting" msgid="3812924520316280149">"कनेक्ट करत आहे."</string>
<string name="accessibility_data_connection_gprs" msgid="1606477224486747751">"GPRS"</string>
<string name="accessibility_data_connection_1x" msgid="994133468120244018">"1 X"</string>
<string name="accessibility_data_connection_hspa" msgid="2032328855462645198">"HSPA"</string>
@@ -168,7 +168,7 @@
<string name="accessibility_overflow_action" msgid="5681882033274783311">"सर्व सूचना पहा"</string>
<string name="accessibility_remove_notification" msgid="3603099514902182350">"सूचना साफ करा."</string>
<string name="accessibility_gps_enabled" msgid="3511469499240123019">"GPS सक्षम केले."</string>
- <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त करीत आहे."</string>
+ <string name="accessibility_gps_acquiring" msgid="8959333351058967158">"GPS प्राप्त करत आहे."</string>
<string name="accessibility_tty_enabled" msgid="4613200365379426561">"TeleTypewriter सक्षम केले."</string>
<string name="accessibility_ringer_vibrate" msgid="666585363364155055">"रिंगर कंपन."</string>
<string name="accessibility_ringer_silent" msgid="9061243307939135383">"रिंगर मूक."</string>
@@ -179,7 +179,7 @@
<string name="accessibility_recents_item_dismissed" msgid="6803574935084867070">"<xliff:g id="APP">%s</xliff:g> डिसमिस केला."</string>
<string name="accessibility_recents_all_items_dismissed" msgid="4464697366179168836">"अलीकडील सर्व अॅप्लिकेशन डिसमिस झाले."</string>
<string name="accessibility_recents_item_open_app_info" msgid="5107479759905883540">"<xliff:g id="APP">%s</xliff:g> अॅप्लिकेशन माहिती उघडा."</string>
- <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करीत आहे."</string>
+ <string name="accessibility_recents_item_launched" msgid="7616039892382525203">"<xliff:g id="APP">%s</xliff:g> प्रारंभ करत आहे."</string>
<string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना डिसमिस केल्या."</string>
<string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
<string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"द्रुत सेटिंग्ज."</string>
@@ -310,7 +310,7 @@
<string name="quick_settings_done" msgid="3402999958839153376">"पूर्ण झाले"</string>
<string name="quick_settings_connected" msgid="1722253542984847487">"कनेक्ट केलेले"</string>
<string name="quick_settings_connected_battery_level" msgid="4136051440381328892">"कनेक्ट केलेले आहे, बॅटरी <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करीत आहे..."</string>
+ <string name="quick_settings_connecting" msgid="47623027419264404">"कनेक्ट करत आहे..."</string>
<string name="quick_settings_tethering_label" msgid="7153452060448575549">"टेदरिंग"</string>
<string name="quick_settings_hotspot_label" msgid="6046917934974004879">"हॉटस्पॉट"</string>
<string name="quick_settings_notifications_label" msgid="4818156442169154523">"सूचना"</string>
diff --git a/packages/SystemUI/res/values-ta/config.xml b/packages/SystemUI/res/values-ta/config.xml
index 5309563..9857f13 100644
--- a/packages/SystemUI/res/values-ta/config.xml
+++ b/packages/SystemUI/res/values-ta/config.xml
@@ -22,5 +22,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- no translation found for config_overviewServiceComponent (2288311504315574053) -->
+ <skip />
<string name="doze_pickup_subtype_performs_proximity_check" msgid="533127617385956583"></string>
</resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 32f502b..46ea494 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -105,13 +105,6 @@
android:title="@string/volume_and_do_not_disturb">
<!-- Action for this is
- MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_PANEL -->
- <com.android.systemui.tuner.TunerSwitch
- android:key="sysui_show_full_zen"
- android:title="@string/tuner_full_zen_title"
- sysui:metricsAction="314" />
-
- <!-- Action for this is
MetricsConstants.ACTION_TUNER_DO_NOT_DISTURB_VOLUME_SHORTCUT -->
<com.android.systemui.tuner.TunerSwitch
android:key="sysui_volume_down_silent,sysui_volume_up_silent"
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
index 3878cd1..528e242 100644
--- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -70,7 +70,7 @@
private final DeviceProvisionedListener mDeviceProvisionedCallback =
new DeviceProvisionedListener() {
@Override
- public void onDeviceProvisionedChanged() {
+ public void onUserSetupChanged() {
if (mDeviceProvisionedController.isCurrentUserSetup()) {
startConnectionToCurrentUser();
}
@@ -78,7 +78,6 @@
@Override
public void onUserSwitched() {
- disconnectFromLauncherService();
mConnectionBackoffAttempts = 0;
startConnectionToCurrentUser();
}
@@ -100,8 +99,10 @@
}
public void startConnectionToCurrentUser() {
+ disconnectFromLauncherService();
+
// If user has not setup yet or already connected, do not try to connect
- if (!mDeviceProvisionedController.isCurrentUserSetup() || mOverviewProxy != null) {
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) {
return;
}
mHandler.removeCallbacks(mConnectionRunnable);
@@ -124,7 +125,9 @@
}
private void disconnectFromLauncherService() {
- mContext.unbindService(mOverviewServiceConnection);
- mOverviewProxy = null;
+ if (mOverviewProxy != null) {
+ mContext.unbindService(mOverviewServiceConnection);
+ mOverviewProxy = null;
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index 532ead1..5ffd785 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -338,7 +338,9 @@
final boolean isDemo = UserManager.isDeviceInDemoMode(mContext);
- mMultiUserSwitch.setVisibility(mExpanded && mMultiUserSwitch.hasMultipleUsers() && !isDemo
+
+ mMultiUserSwitch.setVisibility(mExpanded
+ && UserManager.get(mContext).isUserSwitcherEnabled()
? View.VISIBLE : View.INVISIBLE);
mEdit.setVisibility(isDemo || !mExpanded ? View.INVISIBLE : View.VISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
index f6d36e8..ee8f18e 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogComponent.java
@@ -96,7 +96,6 @@
private VolumeDialog createDefault() {
VolumeDialogImpl impl = new VolumeDialogImpl(mContext);
- impl.setStreamImportant(AudioManager.STREAM_ALARM, true);
impl.setStreamImportant(AudioManager.STREAM_SYSTEM, false);
impl.setAutomute(true);
impl.setSilentMode(false);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 761e979..1ecaa13 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -26,16 +26,13 @@
import android.app.Dialog;
import android.app.KeyguardManager;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.PixelFormat;
import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.media.AudioSystem;
import android.os.Debug;
@@ -44,9 +41,6 @@
import android.os.Message;
import android.os.SystemClock;
import android.provider.Settings.Global;
-import android.transition.AutoTransition;
-import android.transition.Transition;
-import android.transition.TransitionManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Slog;
@@ -74,16 +68,12 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.Interpolators;
-import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.plugins.VolumeDialog;
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
import com.android.systemui.plugins.VolumeDialogController.StreamState;
import com.android.systemui.statusbar.policy.ZenModeController;
-import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerZenModePanel;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -96,7 +86,7 @@
*
* Methods ending in "H" must be called on the (ui) handler.
*/
-public class VolumeDialogImpl implements VolumeDialog, TunerService.Tunable {
+public class VolumeDialogImpl implements VolumeDialog {
private static final String TAG = Util.logTag(VolumeDialogImpl.class);
public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
@@ -113,7 +103,6 @@
private ViewGroup mDialogView;
private ViewGroup mDialogRowsView;
private ViewGroup mDialogContentView;
- private ImageButton mExpandButton;
private final List<VolumeRow> mRows = new ArrayList<>();
private ConfigurableTexts mConfigurableTexts;
private final SparseBooleanArray mDynamic = new SparseBooleanArray();
@@ -121,7 +110,6 @@
private final AudioManager mAudioManager;
private final AccessibilityManager mAccessibilityMgr;
private int mExpandButtonAnimationDuration;
- private ZenFooter mZenFooter;
private final Object mSafetyWarningLock = new Object();
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
@@ -131,7 +119,6 @@
private final ZenModeController mZenModeController;
private boolean mShowing;
- private boolean mExpanded;
private boolean mShowA11yStream;
private int mActiveStream;
@@ -139,7 +126,6 @@
private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
private State mState;
- private boolean mExpandButtonAnimationRunning;
private SafetyWarningDialog mSafetyWarning;
private Callback mCallback;
private boolean mPendingStateChanged;
@@ -148,9 +134,6 @@
private boolean mHovering = false;
private int mDensity;
- private boolean mShowFullZen;
- private TunerZenModePanel mZenPanel;
-
public VolumeDialogImpl(Context context) {
mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme);
mZenModeController = Dependency.get(ZenModeController.class);
@@ -173,7 +156,6 @@
mController.addCallback(mControllerCallbackH, mHandler);
mController.getState();
- Dependency.get(TunerService.class).addTunable(this, SHOW_FULL_ZEN);
final Configuration currentConfig = mContext.getResources().getConfiguration();
mDensity = currentConfig.densityDpi;
@@ -183,10 +165,6 @@
public void destroy() {
mAccessibility.destroy();
mController.removeCallback(mControllerCallbackH);
- if (mZenFooter != null) {
- mZenFooter.cleanup();
- }
- Dependency.get(TunerService.class).removeTunable(this);
mHandler.removeCallbacksAndMessages(null);
}
@@ -234,16 +212,9 @@
mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
- mExpanded = false;
- mExpandButton = (ImageButton) mDialogView.findViewById(R.id.volume_expand_button);
- mExpandButton.setOnClickListener(mClickExpand);
-
- mExpandButton.setVisibility(
- AudioSystem.isSingleVolume(mContext) ? View.GONE : View.VISIBLE);
updateWindowWidthH();
- updateExpandButtonH();
- mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView, mExpandButton,
+ mMotion = new VolumeDialogMotion(mDialog, mDialogView, mDialogContentView,
new VolumeDialogMotion.Callback() {
@Override
public void onAnimatingChanged(boolean animating) {
@@ -280,18 +251,6 @@
addExistingRows();
}
mExpandButtonAnimationDuration = res.getInteger(R.integer.volume_expand_animation_duration);
- mZenFooter = (ZenFooter) mDialog.findViewById(R.id.volume_zen_footer);
- mZenFooter.init(mZenModeController);
- mZenPanel = (TunerZenModePanel) mDialog.findViewById(R.id.tuner_zen_mode_panel);
- mZenPanel.init(mZenModeController);
- mZenPanel.setCallback(mZenPanelCallback);
- }
-
- @Override
- public void onTuningChanged(String key, String newValue) {
- if (SHOW_FULL_ZEN.equals(key)) {
- mShowFullZen = newValue != null && Integer.parseInt(newValue) != 0;
- }
}
private ColorStateList loadColorStateList(int colorResId) {
@@ -359,11 +318,6 @@
}
}
-
- private boolean isAttached() {
- return mDialogContentView != null && mDialogContentView.isAttachedToWindow();
- }
-
private VolumeRow getActiveRow() {
for (VolumeRow row : mRows) {
if (row.stream == mActiveStream) {
@@ -383,9 +337,6 @@
public void dump(PrintWriter writer) {
writer.println(VolumeDialogImpl.class.getSimpleName() + " state:");
writer.print(" mShowing: "); writer.println(mShowing);
- writer.print(" mExpanded: "); writer.println(mExpanded);
- writer.print(" mExpandButtonAnimationRunning: ");
- writer.println(mExpandButtonAnimationRunning);
writer.print(" mActiveStream: "); writer.println(mActiveStream);
writer.print(" mDynamic: "); writer.println(mDynamic);
writer.print(" mAutomute: "); writer.println(mAutomute);
@@ -514,11 +465,7 @@
if (mAccessibility.mFeedbackEnabled) return 20000;
if (mHovering) return 16000;
if (mSafetyWarning != null) return 5000;
- if (mExpanded || mExpandButtonAnimationRunning) return 5000;
if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
- if (mZenFooter.shouldShowIntroduction()) {
- return 6000;
- }
return 3000;
}
@@ -530,12 +477,7 @@
mHandler.removeMessages(H.SHOW);
if (!mShowing) return;
mShowing = false;
- mMotion.startDismiss(new Runnable() {
- @Override
- public void run() {
- updateExpandedH(false /* expanding */, true /* dismissing */);
- }
- });
+ mMotion.startDismiss();
if (mAccessibilityMgr.isEnabled()) {
AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
@@ -579,59 +521,6 @@
mHandler.sendEmptyMessageDelayed(H.UPDATE_BOTTOM_MARGIN, getConservativeCollapseDuration());
}
- private void updateExpandedH(final boolean expanded, final boolean dismissing) {
- if (mExpanded == expanded) return;
- mExpanded = expanded;
- mExpandButtonAnimationRunning = isAttached();
- if (D.BUG) Log.d(TAG, "updateExpandedH " + expanded);
- updateExpandButtonH();
- updateFooterH();
- TransitionManager.endTransitions(mDialogView);
- final VolumeRow activeRow = getActiveRow();
- if (!dismissing) {
- mWindow.setLayout(mWindow.getAttributes().width, ViewGroup.LayoutParams.MATCH_PARENT);
- TransitionManager.beginDelayedTransition(mDialogView, getTransition());
- }
- updateRowsH(activeRow);
- rescheduleTimeoutH();
- }
-
- private void updateExpandButtonH() {
- if (D.BUG) Log.d(TAG, "updateExpandButtonH");
- mExpandButton.setClickable(!mExpandButtonAnimationRunning);
- if (!(mExpandButtonAnimationRunning && isAttached())) {
- final int res = mExpanded ? R.drawable.ic_volume_collapse_animation
- : R.drawable.ic_volume_expand_animation;
- if (hasTouchFeature()) {
- mExpandButton.setImageResource(res);
- } else {
- // if there is no touch feature, show the volume ringer instead
- mExpandButton.setImageResource(R.drawable.ic_volume_ringer);
- mExpandButton.setBackgroundResource(0); // remove gray background emphasis
- }
- mExpandButton.setContentDescription(mContext.getString(mExpanded ?
- R.string.accessibility_volume_collapse : R.string.accessibility_volume_expand));
- }
- if (mExpandButtonAnimationRunning) {
- final Drawable d = mExpandButton.getDrawable();
- if (d instanceof AnimatedVectorDrawable) {
- // workaround to reset drawable
- final AnimatedVectorDrawable avd = (AnimatedVectorDrawable) d.getConstantState()
- .newDrawable();
- mExpandButton.setImageDrawable(avd);
- avd.start();
- mHandler.postDelayed(new Runnable() {
- @Override
- public void run() {
- mExpandButtonAnimationRunning = false;
- updateExpandButtonH();
- rescheduleTimeoutH();
- }
- }, mExpandButtonAnimationDuration);
- }
- }
- }
-
private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
boolean isActive = row == activeRow;
if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
@@ -639,15 +528,13 @@
}
// if the active row is accessibility, then continue to display previous
- // active row since accessibility is dispalyed under it
+ // active row since accessibility is displayed under it
if (activeRow.stream == AudioSystem.STREAM_ACCESSIBILITY &&
row.stream == mPrevActiveStream) {
return true;
}
- return mExpanded && row.view.getVisibility() == View.VISIBLE
- || (mExpanded && (row.important || isActive))
- || !mExpanded && isActive;
+ return row.important || isActive;
}
private void updateRowsH(final VolumeRow activeRow) {
@@ -709,38 +596,6 @@
for (VolumeRow row : mRows) {
updateVolumeRowH(row);
}
- updateFooterH();
- }
-
- private void updateFooterH() {
- if (D.BUG) Log.d(TAG, "updateFooterH");
- final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
- final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
- && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded)
- && !mZenPanel.isEditing();
-
- TransitionManager.endTransitions(mDialogView);
- TransitionManager.beginDelayedTransition(mDialogView, getTransition());
- if (wasVisible != visible && !visible) {
- prepareForCollapse();
- }
- Util.setVisOrGone(mZenFooter, visible);
- mZenFooter.update();
-
- final boolean fullWasVisible = mZenPanel.getVisibility() == View.VISIBLE;
- final boolean fullVisible = mShowFullZen && !visible;
- if (fullWasVisible != fullVisible) {
- Util.setVisOrGone(mZenPanel, fullVisible);
- if (fullVisible) {
- mZenPanel.setZenState(mState.zenMode);
- mZenPanel.setDoneListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mHandler.sendEmptyMessage(H.UPDATE_FOOTER);
- }
- });
- }
- }
}
private void updateVolumeRowH(VolumeRow row) {
@@ -860,7 +715,7 @@
}
private void updateVolumeRowSliderTintH(VolumeRow row, boolean isActive) {
- if (isActive && mExpanded) {
+ if (isActive) {
row.slider.requestFocus();
}
final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveSliderTint
@@ -980,43 +835,6 @@
}
}
- private AutoTransition getTransition() {
- AutoTransition transition = new AutoTransition();
- transition.setDuration(mExpandButtonAnimationDuration);
- transition.setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN);
- transition.addListener(new Transition.TransitionListener() {
- @Override
- public void onTransitionStart(Transition transition) {
- }
-
- @Override
- public void onTransitionEnd(Transition transition) {
- mWindow.setLayout(
- mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- @Override
- public void onTransitionCancel(Transition transition) {
- }
-
- @Override
- public void onTransitionPause(Transition transition) {
- mWindow.setLayout(
- mWindow.getAttributes().width, ViewGroup.LayoutParams.WRAP_CONTENT);
- }
-
- @Override
- public void onTransitionResume(Transition transition) {
- }
- });
- return transition;
- }
-
- private boolean hasTouchFeature() {
- final PackageManager pm = mContext.getPackageManager();
- return pm.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
- }
-
private final VolumeDialogController.Callbacks mControllerCallbackH
= new VolumeDialogController.Callbacks() {
@Override
@@ -1050,13 +868,11 @@
final int density = newConfig.densityDpi;
if (density != mDensity) {
mDialog.dismiss();
- mZenFooter.cleanup();
initDialog();
mDensity = density;
}
updateWindowWidthH();
mConfigurableTexts.update();
- mZenFooter.onConfigurationChanged();
}
@Override
@@ -1109,16 +925,6 @@
}
};
- private final OnClickListener mClickExpand = new OnClickListener() {
- @Override
- public void onClick(View v) {
- if (mExpandButtonAnimationRunning) return;
- final boolean newExpand = !mExpanded;
- Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand);
- updateExpandedH(newExpand, false /* dismissing */);
- }
- };
-
private final class H extends Handler {
private static final int SHOW = 1;
private static final int DISMISS = 2;
@@ -1128,7 +934,6 @@
private static final int RESCHEDULE_TIMEOUT = 6;
private static final int STATE_CHANGED = 7;
private static final int UPDATE_BOTTOM_MARGIN = 8;
- private static final int UPDATE_FOOTER = 9;
public H() {
super(Looper.getMainLooper());
@@ -1145,7 +950,6 @@
case RESCHEDULE_TIMEOUT: rescheduleTimeoutH(); break;
case STATE_CHANGED: onStateChangedH(mState); break;
case UPDATE_BOTTOM_MARGIN: updateDialogBottomMarginH(); break;
- case UPDATE_FOOTER: updateFooterH(); break;
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
index 01d31e2..2b65fbd 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogMotion.java
@@ -25,7 +25,6 @@
import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.content.DialogInterface.OnShowListener;
-import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.util.Log;
import android.view.View;
@@ -41,22 +40,19 @@
private final Dialog mDialog;
private final View mDialogView;
private final ViewGroup mContents; // volume rows + zen footer
- private final View mChevron;
private final Handler mHandler = new Handler();
private final Callback mCallback;
private boolean mAnimating; // show or dismiss animation is running
private boolean mShowing; // show animation is running
private boolean mDismissing; // dismiss animation is running
- private ValueAnimator mChevronPositionAnimator;
private ValueAnimator mContentsPositionAnimator;
- public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents, View chevron,
+ public VolumeDialogMotion(Dialog dialog, View dialogView, ViewGroup contents,
Callback callback) {
mDialog = dialog;
mDialogView = dialogView;
mContents = contents;
- mChevron = chevron;
mCallback = callback;
mDialog.setOnDismissListener(new OnDismissListener() {
@Override
@@ -117,15 +113,6 @@
mDialog.show();
}
- private int chevronDistance() {
- return mChevron.getHeight() / 6;
- }
-
- private int chevronPosY() {
- final Object tag = mChevron == null ? null : mChevron.getTag();
- return tag == null ? 0 : (Integer) tag;
- }
-
private void startShowAnimation() {
if (D.BUG) Log.d(TAG, "startShowAnimation");
mDialogView.animate()
@@ -133,28 +120,9 @@
.setDuration(scaledDuration(300))
.setInterpolator(new LogDecelerateInterpolator())
.setListener(null)
- .setUpdateListener(animation -> {
- if (mChevronPositionAnimator != null) {
- final float v = (Float) mChevronPositionAnimator.getAnimatedValue();
- if (mChevronPositionAnimator == null) return;
- // reposition chevron
- final int posY = chevronPosY();
- mChevron.setTranslationY(posY + v + -mDialogView.getTranslationY());
- }
- })
- .withEndAction(new Runnable() {
- @Override
- public void run() {
- if (mChevronPositionAnimator == null) return;
- // reposition chevron
- final int posY = chevronPosY();
- mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
- }
- })
.start();
- mContentsPositionAnimator = ValueAnimator.ofFloat(-chevronDistance(), 0)
- .setDuration(scaledDuration(400));
+ mContentsPositionAnimator = ValueAnimator.ofFloat(0).setDuration(scaledDuration(400));
mContentsPositionAnimator.addListener(new AnimatorListenerAdapter() {
private boolean mCancelled;
@@ -186,22 +154,9 @@
.setDuration(scaledDuration(150))
.setInterpolator(new PathInterpolator(0f, 0f, .2f, 1f))
.start();
-
- mChevronPositionAnimator = ValueAnimator.ofFloat(-chevronDistance(), 0)
- .setDuration(scaledDuration(250));
- mChevronPositionAnimator.setInterpolator(new PathInterpolator(.4f, 0f, .2f, 1f));
- mChevronPositionAnimator.start();
-
- mChevron.setAlpha(0);
- mChevron.animate()
- .alpha(1)
- .setStartDelay(scaledDuration(50))
- .setDuration(scaledDuration(150))
- .setInterpolator(new PathInterpolator(.4f, 0f, 1f, 1f))
- .start();
}
- public void startDismiss(final Runnable onComplete) {
+ public void startDismiss() {
if (D.BUG) Log.d(TAG, "startDismiss");
if (mDismissing) return;
setDismissing(true);
@@ -211,10 +166,6 @@
mContentsPositionAnimator.cancel();
}
mContents.animate().cancel();
- if (mChevronPositionAnimator != null) {
- mChevronPositionAnimator.cancel();
- }
- mChevron.animate().cancel();
setShowing(false);
}
mDialogView.animate()
@@ -225,8 +176,6 @@
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mContents.setTranslationY(-mDialogView.getTranslationY());
- final int posY = chevronPosY();
- mChevron.setTranslationY(posY + -mDialogView.getTranslationY());
}
})
.setListener(new AnimatorListenerAdapter() {
@@ -240,7 +189,6 @@
public void run() {
if (D.BUG) Log.d(TAG, "mDialog.dismiss()");
mDialog.dismiss();
- onComplete.run();
setDismissing(false);
}
}, PRE_DISMISS_DELAY);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java b/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
deleted file mode 100644
index 80e1629..0000000
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.volume;
-
-import android.animation.LayoutTransition;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.provider.Settings.Global;
-import android.service.notification.ZenModeConfig;
-import android.transition.AutoTransition;
-import android.transition.TransitionManager;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.TextView;
-
-import com.android.systemui.Prefs;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.policy.ZenModeController;
-
-import java.util.Objects;
-
-/**
- * Zen mode information (and end button) attached to the bottom of the volume dialog.
- */
-public class ZenFooter extends LinearLayout {
- private static final String TAG = Util.logTag(ZenFooter.class);
-
- private final Context mContext;
- private final ConfigurableTexts mConfigurableTexts;
-
- private ImageView mIcon;
- private TextView mSummaryLine1;
- private TextView mSummaryLine2;
- private TextView mEndNowButton;
- private View mZenIntroduction;
- private View mZenIntroductionConfirm;
- private TextView mZenIntroductionMessage;
- private int mZen = -1;
- private ZenModeConfig mConfig;
- private ZenModeController mController;
-
- public ZenFooter(Context context, AttributeSet attrs) {
- super(context, attrs);
- mContext = context;
- mConfigurableTexts = new ConfigurableTexts(mContext);
- final LayoutTransition layoutTransition = new LayoutTransition();
- layoutTransition.setDuration(new ValueAnimator().getDuration() / 2);
- setLayoutTransition(layoutTransition);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- mIcon = findViewById(R.id.volume_zen_icon);
- mSummaryLine1 = findViewById(R.id.volume_zen_summary_line_1);
- mSummaryLine2 = findViewById(R.id.volume_zen_summary_line_2);
- mEndNowButton = findViewById(R.id.volume_zen_end_now);
- mZenIntroduction = findViewById(R.id.zen_introduction);
- mZenIntroductionMessage = findViewById(R.id.zen_introduction_message);
- mConfigurableTexts.add(mZenIntroductionMessage, R.string.zen_alarms_introduction);
- mZenIntroductionConfirm = findViewById(R.id.zen_introduction_confirm);
- mZenIntroductionConfirm.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- confirmZenIntroduction();
- }
- });
- Util.setVisOrGone(mZenIntroduction, shouldShowIntroduction());
- mConfigurableTexts.add(mSummaryLine1);
- mConfigurableTexts.add(mSummaryLine2);
- mConfigurableTexts.add(mEndNowButton, R.string.volume_zen_end_now);
- }
-
- public void init(final ZenModeController controller) {
- mEndNowButton.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setZen(Global.ZEN_MODE_OFF);
- controller.setZen(Global.ZEN_MODE_OFF, null, TAG);
- }
- });
- mZen = controller.getZen();
- mConfig = controller.getConfig();
- mController = controller;
- mController.addCallback(mZenCallback);
- update();
- updateIntroduction();
- }
-
- public void cleanup() {
- mController.removeCallback(mZenCallback);
- }
-
- private void setZen(int zen) {
- if (mZen == zen) return;
- mZen = zen;
- update();
- post(() -> {
- updateIntroduction();
- });
- }
-
- private void setConfig(ZenModeConfig config) {
- if (Objects.equals(mConfig, config)) return;
- mConfig = config;
- update();
- }
-
- private void confirmZenIntroduction() {
- Prefs.putBoolean(mContext, Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, true);
- updateIntroduction();
- }
-
- private boolean isZenPriority() {
- return mZen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
- }
-
- private boolean isZenAlarms() {
- return mZen == Global.ZEN_MODE_ALARMS;
- }
-
- private boolean isZenNone() {
- return mZen == Global.ZEN_MODE_NO_INTERRUPTIONS;
- }
-
- public void update() {
- mIcon.setImageResource(isZenNone() ? R.drawable.ic_dnd_total_silence : R.drawable.ic_dnd);
- final String line1 =
- isZenPriority() ? mContext.getString(R.string.interruption_level_priority)
- : isZenAlarms() ? mContext.getString(R.string.interruption_level_alarms)
- : isZenNone() ? mContext.getString(R.string.interruption_level_none)
- : null;
- Util.setText(mSummaryLine1, line1);
-
- final CharSequence line2 = ZenModeConfig.getConditionSummary(mContext, mConfig,
- mController.getCurrentUser(), true /*shortVersion*/);
- Util.setText(mSummaryLine2, line2);
- }
-
- public boolean shouldShowIntroduction() {
- final boolean confirmed = Prefs.getBoolean(mContext,
- Prefs.Key.DND_CONFIRMED_ALARM_INTRODUCTION, false);
- return !confirmed && isZenAlarms();
- }
-
- public void updateIntroduction() {
- Util.setVisOrGone(mZenIntroduction, shouldShowIntroduction());
- }
-
- public void onConfigurationChanged() {
- mConfigurableTexts.update();
- }
-
- private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
- @Override
- public void onZenChanged(int zen) {
- setZen(zen);
- }
- @Override
- public void onConfigChanged(ZenModeConfig config) {
- setConfig(config);
- }
- };
-}
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 67fae5b..e74736a 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -43,6 +43,9 @@
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.STATUS_BAR" />
+ <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+ <uses-permission android:name="android.permission.REAL_GET_TASKS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
index 65d9699..fbcbd20 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java
@@ -23,6 +23,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
+import android.os.ParcelFileDescriptor;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.testing.LeakCheck;
@@ -34,6 +35,8 @@
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
+import java.io.FileInputStream;
+import java.io.IOException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@@ -84,6 +87,16 @@
return mContext;
}
+ protected void runShellCommand(String command) throws IOException {
+ ParcelFileDescriptor pfd = mRealInstrumentation.getUiAutomation()
+ .executeShellCommand(command);
+
+ // Read the input stream fully.
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ while (fis.read() != -1);
+ fis.close();
+ }
+
protected void waitForIdleSync() {
if (mHandler == null) {
mHandler = new Handler(Looper.getMainLooper());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java
new file mode 100644
index 0000000..bdbd244
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/RecentsTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 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.systemui.recents;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+
+import static com.android.systemui.recents.RecentsImpl.RECENTS_ACTIVITY;
+import static com.android.systemui.recents.RecentsImpl.RECENTS_PACKAGE;
+
+import static org.junit.Assert.fail;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.IActivityManager;
+import android.os.SystemClock;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.List;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class RecentsTest extends SysuiTestCase {
+
+ @Test
+ public void testRecentsActivityType() throws Exception {
+ // Clear the state
+ final IActivityManager am = ActivityManager.getService();
+ am.removeStacksWithActivityTypes(new int[] { ACTIVITY_TYPE_RECENTS });
+
+ // Toggle recents, use a shell command because it is not exported
+ runShellCommand("am start -n " + RECENTS_PACKAGE + "/" + RECENTS_ACTIVITY);
+
+ // Verify that an activity was launched with the right activity type
+ int retryCount = 0;
+ while (retryCount < 10) {
+ List<RunningTaskInfo> tasks = am.getTasks(Integer.MAX_VALUE);
+ for (RunningTaskInfo info : tasks) {
+ if (info.configuration.windowConfiguration.getActivityType()
+ == ACTIVITY_TYPE_RECENTS) {
+ // Found a recents activity with the right activity type
+ return;
+ }
+ }
+ SystemClock.sleep(50);
+ retryCount++;
+ }
+ fail("Expected Recents activity with ACTIVITY_TYPE_RECENTS");
+ }
+}
\ No newline at end of file
diff --git a/packages/VpnDialogs/res/values-ta/strings.xml b/packages/VpnDialogs/res/values-ta/strings.xml
index 81a1984..7daa11b 100644
--- a/packages/VpnDialogs/res/values-ta/strings.xml
+++ b/packages/VpnDialogs/res/values-ta/strings.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="prompt" msgid="3183836924226407828">"இணைப்புக் கோரிக்கை"</string>
- <string name="warning" msgid="809658604548412033">"VPN இணைப்பை அமைக்க <xliff:g id="APP">%s</xliff:g> விழைகிறது அதன்மூலம் இது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கும் அனுமதியைப் பெறும். நம்பகமான மூலத்தை மட்டுமே ஏற்கவும். VPN இயக்கத்தில் உள்ளபோது திரையில் மேல் பகுதியில் <br /> <br /> <img src=vpn_icon /> தோன்றும்."</string>
+ <string name="warning" msgid="809658604548412033">"VPN இணைப்பை அமைக்க <xliff:g id="APP">%s</xliff:g> விழைகிறது அதன்மூலம் இது நெட்வொர்க் ட்ராஃபிக்கைக் கண்காணிக்கும் அனுமதியைப் பெறும். நம்பகமான மூலத்தை மட்டுமே ஏற்கவும். <br /> <br /> VPN இயக்கத்தில் உள்ளபோது திரையில் மேல் பகுதியில் <img src=vpn_icon /> தோன்றும்."</string>
<string name="legacy_title" msgid="192936250066580964">"VPN இணைக்கப்பட்டது"</string>
<string name="session" msgid="6470628549473641030">"அமர்வு:"</string>
<string name="duration" msgid="3584782459928719435">"காலஅளவு:"</string>
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 06c110d..d661754 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1318,7 +1318,7 @@
private void unbindAllServicesLocked(UserState userState) {
List<AccessibilityServiceConnection> services = userState.mBoundServices;
- for (int count = services.size(); count > 1; count--) {
+ for (int count = services.size(); count > 0; count--) {
// When the service is unbound, it disappears from the list, so there's no need to
// keep track of the index
services.get(0).unbindLocked();
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d8eaccc..a3def14 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -602,7 +602,7 @@
if (isValidEventLocked("setAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_AUTHENTICATION_SELECTED, null, clientState, null, null,
- null, null, null, null));
+ null, null, null, null, null, -1));
}
}
}
@@ -616,7 +616,7 @@
if (isValidEventLocked("logDatasetAuthenticationSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_AUTHENTICATION_SELECTED, selectedDataset,
- clientState, null, null, null, null, null, null));
+ clientState, null, null, null, null, null, null, null, -1));
}
}
}
@@ -628,7 +628,7 @@
synchronized (mLock) {
if (isValidEventLocked("logSaveShown()", sessionId)) {
mEventHistory.addEvent(new Event(Event.TYPE_SAVE_SHOWN, null, clientState, null,
- null, null, null, null, null));
+ null, null, null, null, null, null, -1));
}
}
}
@@ -642,7 +642,7 @@
if (isValidEventLocked("logDatasetSelected()", sessionId)) {
mEventHistory.addEvent(
new Event(Event.TYPE_DATASET_SELECTED, selectedDataset, clientState, null,
- null, null, null, null, null));
+ null, null, null, null, null, null, -1));
}
}
}
@@ -656,13 +656,15 @@
@Nullable ArrayList<AutofillId> changedFieldIds,
@Nullable ArrayList<String> changedDatasetIds,
@Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
- @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds) {
+ @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
+ @Nullable String detectedRemoteId, int detectedFieldScore) {
synchronized (mLock) {
if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
mEventHistory.addEvent(new Event(Event.TYPE_CONTEXT_COMMITTED, null,
clientState, selectedDatasets, ignoredDatasets,
changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds));
+ manuallyFilledFieldIds, manuallyFilledDatasetIds,
+ detectedRemoteId, detectedFieldScore));
}
}
}
@@ -695,6 +697,7 @@
pw.print(prefix); pw.print("Default component: ");
pw.println(mContext.getString(R.string.config_defaultAutofillService));
pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+ pw.print(prefix); pw.print("Field detection: "); pw.println(isFieldDetectionEnabled());
pw.print(prefix); pw.print("Setup complete: "); pw.println(mSetupComplete);
pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
@@ -935,6 +938,13 @@
return false;
}
+ // TODO(b/67867469): remove once feature is finished
+ boolean isFieldDetectionEnabled() {
+ return Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.AUTOFILL_FEATURE_FIELD_DETECTION, 0,
+ mUserId) == 1;
+ }
+
@Override
public String toString() {
return "AutofillManagerServiceImpl: [userId=" + mUserId
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 3564432..5823ab1 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -54,6 +54,7 @@
import android.os.SystemClock;
import android.service.autofill.AutofillService;
import android.service.autofill.Dataset;
+import android.service.autofill.FieldsDetection;
import android.service.autofill.FillContext;
import android.service.autofill.FillRequest;
import android.service.autofill.FillResponse;
@@ -492,6 +493,13 @@
}
}
+ // TODO(b/67867469): remove once feature is finished
+ if (response.getFieldsDetection() != null && !mService.isFieldDetectionEnabled()) {
+ Slog.w(TAG, "Ignoring " + response + " because field detection is disabled");
+ processNullResponseLocked(requestFlags);
+ return;
+ }
+
mService.setLastResponse(serviceUid, id, response);
int sessionFinishedState = 0;
@@ -913,11 +921,29 @@
}
}
}
- if (!hasAtLeastOneDataset) {
- if (sVerbose) Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets)");
+ final FieldsDetection fieldsDetection = lastResponse.getFieldsDetection();
+
+ if (!hasAtLeastOneDataset && fieldsDetection == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "logContextCommittedLocked(): skipped (no datasets nor fields "
+ + "detection)");
+ }
return;
}
+ final AutofillId detectableFieldId;
+ final String detectableRemoteId;
+ String detectedRemoteId = null;
+ if (fieldsDetection == null) {
+ detectableFieldId = null;
+ detectableRemoteId = null;
+ } else {
+ detectableFieldId = fieldsDetection.getFieldId();
+ detectableRemoteId = fieldsDetection.getRemoteId();
+ }
+
+ int detectedFieldScore = -1;
+
for (int i = 0; i < mViewStates.size(); i++) {
final ViewState viewState = mViewStates.valueAt(i);
final int state = viewState.getState();
@@ -926,7 +952,6 @@
// - autofilled -> changedDatasetIds
// - not autofilled but matches a dataset value -> manuallyFilledIds
if ((state & ViewState.STATE_CHANGED) != 0) {
-
// Check if autofilled value was changed
if ((state & ViewState.STATE_AUTOFILLED) != 0) {
final String datasetId = viewState.getDatasetId();
@@ -958,7 +983,6 @@
changedFieldIds.add(viewState.id);
changedDatasetIds.add(datasetId);
} else {
- // Check if value match a dataset.
final AutofillValue currentValue = viewState.getCurrentValue();
if (currentValue == null) {
if (sDebug) {
@@ -967,58 +991,78 @@
}
continue;
}
- for (int j = 0; j < responseCount; j++) {
- final FillResponse response = mResponses.valueAt(j);
- final List<Dataset> datasets = response.getDatasets();
- if (datasets == null || datasets.isEmpty()) {
- if (sVerbose) Slog.v(TAG, "logContextCommitted() no datasets at " + j);
- } else {
- for (int k = 0; k < datasets.size(); k++) {
- final Dataset dataset = datasets.get(k);
- final String datasetId = dataset.getId();
- if (datasetId == null) {
- if (sVerbose) {
- Slog.v(TAG, "logContextCommitted() skipping idless dataset "
- + dataset);
- }
- } else {
- final ArrayList<AutofillValue> values = dataset.getFieldValues();
- for (int l = 0; l < values.size(); l++) {
- final AutofillValue candidate = values.get(l);
- if (currentValue.equals(candidate)) {
- if (sDebug) {
- Slog.d(TAG, "field " + viewState.id
- + " was manually filled with value set by "
- + "dataset " + datasetId);
- }
- if (manuallyFilledIds == null) {
- manuallyFilledIds = new ArrayMap<>();
- }
- ArraySet<String> datasetIds =
- manuallyFilledIds.get(viewState.id);
- if (datasetIds == null) {
- datasetIds = new ArraySet<>(1);
- manuallyFilledIds.put(viewState.id, datasetIds);
- }
- datasetIds.add(datasetId);
- }
- }
- if (mSelectedDatasetIds == null
- || !mSelectedDatasetIds.contains(datasetId)) {
- if (sVerbose) {
- Slog.v(TAG, "adding ignored dataset " + datasetId);
- }
- if (ignoredDatasets == null) {
- ignoredDatasets = new ArraySet<>();
- }
- ignoredDatasets.add(datasetId);
- }
+ // Check if value match a dataset.
+ if (hasAtLeastOneDataset) {
+ for (int j = 0; j < responseCount; j++) {
+ final FillResponse response = mResponses.valueAt(j);
+ final List<Dataset> datasets = response.getDatasets();
+ if (datasets == null || datasets.isEmpty()) {
+ if (sVerbose) {
+ Slog.v(TAG, "logContextCommitted() no datasets at " + j);
}
- }
- }
+ } else {
+ for (int k = 0; k < datasets.size(); k++) {
+ final Dataset dataset = datasets.get(k);
+ final String datasetId = dataset.getId();
+ if (datasetId == null) {
+ if (sVerbose) {
+ Slog.v(TAG, "logContextCommitted() skipping idless "
+ + "dataset " + dataset);
+ }
+ } else {
+ final ArrayList<AutofillValue> values =
+ dataset.getFieldValues();
+ for (int l = 0; l < values.size(); l++) {
+ final AutofillValue candidate = values.get(l);
+ if (currentValue.equals(candidate)) {
+ if (sDebug) {
+ Slog.d(TAG, "field " + viewState.id + " was "
+ + "manually filled with value set by "
+ + "dataset " + datasetId);
+ }
+ if (manuallyFilledIds == null) {
+ manuallyFilledIds = new ArrayMap<>();
+ }
+ ArraySet<String> datasetIds =
+ manuallyFilledIds.get(viewState.id);
+ if (datasetIds == null) {
+ datasetIds = new ArraySet<>(1);
+ manuallyFilledIds.put(viewState.id, datasetIds);
+ }
+ datasetIds.add(datasetId);
+ }
+ } // for l
+ if (mSelectedDatasetIds == null
+ || !mSelectedDatasetIds.contains(datasetId)) {
+ if (sVerbose) {
+ Slog.v(TAG, "adding ignored dataset " + datasetId);
+ }
+ if (ignoredDatasets == null) {
+ ignoredDatasets = new ArraySet<>();
+ }
+ ignoredDatasets.add(datasetId);
+ } // if
+ } // if
+ } // for k
+ } // else
+ } // for j
}
- }
- }
+
+ // Check if detectable field changed.
+ if (detectableFieldId != null && detectableFieldId.equals(viewState.id)
+ && currentValue.isText() && currentValue.getTextValue() != null) {
+ final String actualValue = currentValue.getTextValue().toString();
+ final String expectedValue = fieldsDetection.getValue();
+ if (actualValue.equalsIgnoreCase(expectedValue)) {
+ detectedRemoteId = detectableRemoteId;
+ detectedFieldScore = 0;
+ } else if (sVerbose) {
+ Slog.v(TAG, "Detection mismatch for field " + detectableFieldId);
+ }
+ // TODO(b/67867469): set score on partial hits
+ }
+ } // else
+ } // else
}
if (sVerbose) {
@@ -1027,7 +1071,10 @@
+ ", ignoredDatasetIds=" + ignoredDatasets
+ ", changedAutofillIds=" + changedFieldIds
+ ", changedDatasetIds=" + changedDatasetIds
- + ", manuallyFilledIds=" + manuallyFilledIds);
+ + ", manuallyFilledIds=" + manuallyFilledIds
+ + ", detectableFieldId=" + detectableFieldId
+ + ", detectedFieldScore=" + detectedFieldScore
+ );
}
ArrayList<AutofillId> manuallyFilledFieldIds = null;
@@ -1045,9 +1092,11 @@
manuallyFilledDatasetIds.add(new ArrayList<>(datasetIds));
}
}
+
mService.logContextCommitted(id, mClientState, mSelectedDatasetIds, ignoredDatasets,
changedFieldIds, changedDatasetIds,
- manuallyFilledFieldIds, manuallyFilledDatasetIds);
+ manuallyFilledFieldIds, manuallyFilledDatasetIds,
+ detectedRemoteId, detectedFieldScore);
}
/**
@@ -1535,6 +1584,10 @@
viewState = new ViewState(this, id, this,
isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
mViewStates.put(id, viewState);
+
+ // TODO(b/67867469): for optimization purposes, should also ignore if change is
+ // detectable, and batch-send them when the session is finished (but that will
+ // require tracking detectable fields on AutofillManager)
if (isIgnored) {
if (sDebug) Slog.d(TAG, "updateLocked(): ignoring view " + id);
return;
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index 1d8110f..832a66b 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -134,7 +134,11 @@
}
String getStateAsString() {
- return DebugUtils.flagsToString(ViewState.class, "STATE_", mState);
+ return getStateAsString(mState);
+ }
+
+ static String getStateAsString(int state) {
+ return DebugUtils.flagsToString(ViewState.class, "STATE_", state);
}
void setState(int state) {
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 1db2629..b2308d5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -201,6 +201,8 @@
private static final String TAG_STATES = TAG + POSTFIX_STATES;
private static final String TAG_SWITCH = TAG + POSTFIX_SWITCH;
private static final String TAG_VISIBILITY = TAG + POSTFIX_VISIBILITY;
+ // TODO(b/67864419): Remove once recents component is overridden
+ private static final String LEGACY_RECENTS_PACKAGE_NAME = "com.android.systemui.recents";
private static final boolean SHOW_ACTIVITY_START_TIME = true;
@@ -1057,7 +1059,8 @@
// We only allow home activities to be resizeable if they explicitly requested it.
info.resizeMode = RESIZE_MODE_UNRESIZEABLE;
}
- } else if (service.getRecentTasks().isRecentsComponent(realActivity, appInfo.uid)) {
+ } else if (realActivity.getClassName().contains(LEGACY_RECENTS_PACKAGE_NAME) ||
+ service.getRecentTasks().isRecentsComponent(realActivity, appInfo.uid)) {
activityType = ACTIVITY_TYPE_RECENTS;
} else if (options != null && options.getLaunchActivityType() == ACTIVITY_TYPE_ASSISTANT
&& canLaunchAssistActivity(launchedFromPackage)) {
@@ -2179,26 +2182,6 @@
mTmpConfig.unset();
computeBounds(mTmpBounds);
if (mTmpBounds.equals(mBounds)) {
- final ActivityStack stack = getStack();
- if (!mBounds.isEmpty() || task == null || stack == null || !task.mFullscreen) {
- // We don't want to influence the override configuration here if our task is in
- // multi-window mode or there is a bounds specified to calculate the override
- // config. In both of this cases the app should be compatible with whatever the
- // current configuration is or will be.
- return;
- }
-
- // Currently limited to the top activity for now to avoid situations where non-top
- // visible activity and top might have conflicting requests putting the non-top activity
- // windows in an odd state.
- final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
- final Configuration parentConfig = getParent().getConfiguration();
- if (top != this || isConfigurationCompatible(parentConfig)) {
- onOverrideConfigurationChanged(mTmpConfig);
- } else if (isConfigurationCompatible(
- mLastReportedConfiguration.getMergedConfiguration())) {
- onOverrideConfigurationChanged(mLastReportedConfiguration.getMergedConfiguration());
- }
return;
}
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 5a7e7ce..7896e2d 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -95,8 +95,8 @@
};
private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
- final ActivityRecord r = (ActivityRecord) m.obj;
- l.onActivityPinned(r.packageName, r.userId, r.getTask().taskId, r.getStackId());
+ l.onActivityPinned((String) m.obj /* packageName */, m.sendingUid /* userId */,
+ m.arg1 /* taskId */, m.arg2 /* stackId */);
};
private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> {
@@ -281,7 +281,9 @@
/** Notifies all listeners when an Activity is pinned. */
void notifyActivityPinned(ActivityRecord r) {
mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
- final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG, r);
+ final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
+ r.getTask().taskId, r.getStackId(), r.packageName);
+ msg.sendingUid = r.userId;
forAllLocalListeners(mNotifyActivityPinned, msg);
msg.sendToTarget();
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 781216c..cf9e6f3 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -59,8 +59,6 @@
// vendor.
if ("pm.dexopt.inactive".equals(sysPropName)) {
sysPropValue = "verify";
- } else if ("pm.dexopt.shared".equals(sysPropName)) {
- sysPropValue = "speed";
} else {
sysPropValue = SystemProperties.get(sysPropName);
}
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index c86122f..011e1ac 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -112,6 +112,7 @@
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
+ UserManager.DISALLOW_USER_SWITCH
});
/**
@@ -143,6 +144,13 @@
);
/**
+ * User restrictions that cannot be set by profile owners. Applied to all users.
+ */
+ private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
+ UserManager.DISALLOW_USER_SWITCH
+ );
+
+ /**
* User restrictions that can't be changed by device owner or profile owner.
*/
private static final Set<String> IMMUTABLE_BY_OWNERS = Sets.newArraySet(
@@ -311,6 +319,7 @@
*/
public static boolean canProfileOwnerChange(String restriction, int userId) {
return !IMMUTABLE_BY_OWNERS.contains(restriction)
+ && !DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction)
&& !(userId != UserHandle.USER_SYSTEM
&& PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction));
}
@@ -363,8 +372,9 @@
*/
private static boolean isGlobal(boolean isDeviceOwner, String key) {
return (isDeviceOwner &&
- (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key)|| GLOBAL_RESTRICTIONS.contains(key)))
- || PROFILE_GLOBAL_RESTRICTIONS.contains(key);
+ (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)))
+ || PROFILE_GLOBAL_RESTRICTIONS.contains(key)
+ || DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key);
}
/**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 45f645b..caf85b0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -1172,14 +1172,12 @@
+ ", mOrientationSensorEnabled=" + mOrientationSensorEnabled
+ ", mKeyguardDrawComplete=" + mKeyguardDrawComplete
+ ", mWindowManagerDrawComplete=" + mWindowManagerDrawComplete);
- final boolean keyguardGoingAway = mWindowManagerInternal.isKeyguardGoingAway();
boolean disable = true;
// Note: We postpone the rotating of the screen until the keyguard as well as the
// window manager have reported a draw complete or the keyguard is going away in dismiss
// mode.
- if (mScreenOnEarly && mAwake && ((mKeyguardDrawComplete && mWindowManagerDrawComplete)
- || keyguardGoingAway)) {
+ if (mScreenOnEarly && mAwake && ((mKeyguardDrawComplete && mWindowManagerDrawComplete))) {
if (needSensorRunningLp()) {
disable = false;
//enable listener if not already enabled
@@ -1190,7 +1188,7 @@
// the sensor reading was cleared which can cause it to relaunch the app that
// will show in the wrong orientation first before correcting leading to app
// launch delays.
- mOrientationListener.enable(!keyguardGoingAway /* clearCurrentRotation */);
+ mOrientationListener.enable(true /* clearCurrentRotation */);
if(localLOGV) Slog.v(TAG, "Enabling listeners");
mOrientationSensorEnabled = true;
}
@@ -1665,14 +1663,10 @@
private long getAccessibilityShortcutTimeout() {
ViewConfiguration config = ViewConfiguration.get(mContext);
- try {
- return Settings.Secure.getIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, mCurrentUserId) == 0
- ? config.getAccessibilityShortcutKeyTimeout()
- : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation();
- } catch (Settings.SettingNotFoundException e) {
- throw new RuntimeException(e);
- }
+ return Settings.Secure.getIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, mCurrentUserId) == 0
+ ? config.getAccessibilityShortcutKeyTimeout()
+ : config.getAccessibilityShortcutKeyTimeoutAfterConfirmation();
}
private long getScreenshotChordLongPressDelay() {
@@ -8090,22 +8084,28 @@
private int updateLightNavigationBarLw(int vis, WindowState opaque,
WindowState opaqueOrDimming) {
final WindowState imeWin = mWindowManagerFuncs.getInputMethodWindowLw();
-
- final WindowState navColorWin;
- if (imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM) {
- navColorWin = imeWin;
- } else {
- navColorWin = opaqueOrDimming;
+ final boolean isImeShownWithBottomNavBar =
+ imeWin != null && imeWin.isVisibleLw() && mNavigationBarPosition == NAV_BAR_BOTTOM;
+ if (isImeShownWithBottomNavBar) {
+ final int winFlags = PolicyControl.getWindowFlags(imeWin, null);
+ if ((winFlags & WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+ // If the IME window is visible and explicitly requesting custom nav bar background
+ // rendering, respect its light flag.
+ vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+ vis |= PolicyControl.getSystemUiVisibility(imeWin, null)
+ & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
+ return vis;
+ }
}
- if (navColorWin != null) {
- if (navColorWin == opaque) {
- // If the top fullscreen-or-dimming window is also the top fullscreen, respect
- // its light flag.
+ if (opaqueOrDimming != null) {
+ if (opaqueOrDimming == opaque) {
+ // If the top fullscreen-or-dimming window is also the top fullscreen window,
+ // respect its light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- vis |= PolicyControl.getSystemUiVisibility(navColorWin, null)
+ vis |= PolicyControl.getSystemUiVisibility(opaqueOrDimming, null)
& View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
- } else if (navColorWin.isDimming() || navColorWin == imeWin) {
+ } else if (opaqueOrDimming.isDimming() || isImeShownWithBottomNavBar) {
// Otherwise if it's dimming or it's the IME window, clear the light flag.
vis &= ~View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
}
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index cc4e0f8..76e25ba 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -52,6 +52,8 @@
/**
* Drag state per operation.
+ * Needs a lock of {@code WindowManagerService#mWindowMap} to read this. Needs both locks of
+ * {@code mWriteLock} and {@code WindowManagerService#mWindowMap} to update this.
* The variable is cleared by {@code #onDragStateClosedLocked} which is invoked by DragState
* itself, thus the variable can be null after calling DragState's methods.
*/
@@ -59,6 +61,38 @@
private WindowManagerService mService;
private final Handler mHandler;
+ /**
+ * Lock to preserve the order of state updates.
+ * The lock is used to process drag and drop state updates in order without having the window
+ * manager lock.
+ *
+ * Suppose DragDropController invokes a callback method A, then processes the following update
+ * A'. Same for a callback method B and the following update B'. The callback wants
+ * DragDropController to processes the updates in the order of A' then B'.
+ *
+ * Without mWriteLock: the following race can happen.
+ *
+ * 1. Thread a calls A.
+ * 2. Thread b calls B.
+ * 3. Thread b acquires the window manager lock
+ * 4. thread b processes the update B'
+ * 5. Thread a acquires the window manager lock
+ * 6. thread a processes the update A'
+ *
+ * With mWriteLock we can ensure the order of A' and B'
+ *
+ * 1. Thread a acquire mWriteLock
+ * 2. Thread a calls A
+ * 3. Thread a acquire the window manager lock
+ * 4. Thread a processes A'
+ * 5. Thread b acquire mWriteLock
+ * 6. Thread b calls B
+ * 7. Thread b acquire the window manager lock
+ * 8. Thread b processes B'
+ *
+ * Don't acquire the lock while holding the window manager lock, otherwise it causes a deadlock.
+ */
+ private final Object mWriteLock = new Object();
boolean dragDropActiveLocked() {
return mDragState != null;
@@ -85,46 +119,46 @@
+ " asbinder=" + window.asBinder());
}
- IBinder token = null;
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (dragDropActiveLocked()) {
+ Slog.w(TAG_WM, "Drag already in progress");
+ return null;
+ }
- synchronized (mService.mWindowMap) {
- if (dragDropActiveLocked()) {
- Slog.w(TAG_WM, "Drag already in progress");
- return null;
+ // TODO(multi-display): support other displays
+ final DisplayContent displayContent =
+ mService.getDefaultDisplayContentLocked();
+ final Display display = displayContent.getDisplay();
+
+ final SurfaceControl surface = new SurfaceControl.Builder(session)
+ .setName("drag surface")
+ .setSize(width, height)
+ .setFormat(PixelFormat.TRANSLUCENT)
+ .build();
+ surface.setLayerStack(display.getLayerStack());
+ float alpha = 1;
+ if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
+ alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
+ }
+ surface.setAlpha(alpha);
+
+ if (SHOW_TRANSACTIONS)
+ Slog.i(TAG_WM, " DRAG " + surface + ": CREATE");
+ outSurface.copyFrom(surface);
+ final IBinder winBinder = window.asBinder();
+ IBinder token = new Binder();
+ mDragState = new DragState(mService, token, surface, flags, winBinder);
+ mDragState.mPid = callerPid;
+ mDragState.mUid = callerUid;
+ mDragState.mOriginalAlpha = alpha;
+ token = mDragState.mToken = new Binder();
+
+ // 5 second timeout for this window to actually begin the drag
+ sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
+ return token;
}
-
- // TODO(multi-display): support other displays
- final DisplayContent displayContent =
- mService.getDefaultDisplayContentLocked();
- final Display display = displayContent.getDisplay();
-
- final SurfaceControl surface = new SurfaceControl.Builder(session)
- .setName("drag surface")
- .setSize(width, height)
- .setFormat(PixelFormat.TRANSLUCENT)
- .build();
- surface.setLayerStack(display.getLayerStack());
- float alpha = 1;
- if ((flags & View.DRAG_FLAG_OPAQUE) == 0) {
- alpha = DRAG_SHADOW_ALPHA_TRANSPARENT;
- }
- surface.setAlpha(alpha);
-
- if (SHOW_TRANSACTIONS) Slog.i(TAG_WM, " DRAG " + surface + ": CREATE");
- outSurface.copyFrom(surface);
- final IBinder winBinder = window.asBinder();
- token = new Binder();
- mDragState = new DragState(mService, token, surface, flags, winBinder);
- mDragState.mPid = callerPid;
- mDragState.mUid = callerUid;
- mDragState.mOriginalAlpha = alpha;
- token = mDragState.mToken = new Binder();
-
- // 5 second timeout for this window to actually begin the drag
- sendTimeoutMessage(MSG_DRAG_START_TIMEOUT, winBinder);
}
-
- return token;
}
boolean performDrag(IWindow window, IBinder dragToken,
@@ -134,75 +168,77 @@
Slog.d(TAG_WM, "perform drag: win=" + window + " data=" + data);
}
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.w(TAG_WM, "No drag prepared");
- throw new IllegalStateException("performDrag() without prepareDrag()");
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.w(TAG_WM, "No drag prepared");
+ throw new IllegalStateException("performDrag() without prepareDrag()");
+ }
+
+ if (dragToken != mDragState.mToken) {
+ Slog.w(TAG_WM, "Performing mismatched drag");
+ throw new IllegalStateException("performDrag() does not match prepareDrag()");
+ }
+
+ final WindowState callingWin = mService.windowForClientLocked(null, window, false);
+ if (callingWin == null) {
+ Slog.w(TAG_WM, "Bad requesting window " + window);
+ return false; // !!! TODO: throw here?
+ }
+
+ // !!! TODO: if input is not still focused on the initiating window, fail
+ // the drag initiation (e.g. an alarm window popped up just as the application
+ // called performDrag()
+
+ mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());
+
+ // !!! TODO: extract the current touch (x, y) in screen coordinates. That
+ // will let us eliminate the (touchX,touchY) parameters from the API.
+
+ // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
+ // the actual drag event dispatch stuff in the dragstate
+
+ final DisplayContent displayContent = callingWin.getDisplayContent();
+ if (displayContent == null) {
+ return false;
+ }
+ Display display = displayContent.getDisplay();
+ mDragState.register(display);
+ if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
+ mDragState.getInputChannel())) {
+ Slog.e(TAG_WM, "Unable to transfer touch focus");
+ mDragState.closeLocked();
+ return false;
+ }
+
+ mDragState.mDisplayContent = displayContent;
+ mDragState.mData = data;
+ mDragState.broadcastDragStartedLocked(touchX, touchY);
+ mDragState.overridePointerIconLocked(touchSource);
+
+ // remember the thumb offsets for later
+ mDragState.mThumbOffsetX = thumbCenterX;
+ mDragState.mThumbOffsetY = thumbCenterY;
+
+ // Make the surface visible at the proper location
+ final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM, ">>> OPEN TRANSACTION performDrag");
+ mService.openSurfaceTransaction();
+ try {
+ surfaceControl.setPosition(touchX - thumbCenterX,
+ touchY - thumbCenterY);
+ surfaceControl.setLayer(mDragState.getDragLayerLocked());
+ surfaceControl.setLayerStack(display.getLayerStack());
+ surfaceControl.show();
+ } finally {
+ mService.closeSurfaceTransaction("performDrag");
+ if (SHOW_LIGHT_TRANSACTIONS) {
+ Slog.i(TAG_WM, "<<< CLOSE TRANSACTION performDrag");
+ }
+ }
+
+ mDragState.notifyLocationLocked(touchX, touchY);
}
-
- if (dragToken != mDragState.mToken) {
- Slog.w(TAG_WM, "Performing mismatched drag");
- throw new IllegalStateException("performDrag() does not match prepareDrag()");
- }
-
- final WindowState callingWin = mService.windowForClientLocked(null, window, false);
- if (callingWin == null) {
- Slog.w(TAG_WM, "Bad requesting window " + window);
- return false; // !!! TODO: throw here?
- }
-
- // !!! TODO: if input is not still focused on the initiating window, fail
- // the drag initiation (e.g. an alarm window popped up just as the application
- // called performDrag()
-
- mHandler.removeMessages(MSG_DRAG_START_TIMEOUT, window.asBinder());
-
- // !!! TODO: extract the current touch (x, y) in screen coordinates. That
- // will let us eliminate the (touchX,touchY) parameters from the API.
-
- // !!! FIXME: put all this heavy stuff onto the mHandler looper, as well as
- // the actual drag event dispatch stuff in the dragstate
-
- final DisplayContent displayContent = callingWin.getDisplayContent();
- if (displayContent == null) {
- return false;
- }
- Display display = displayContent.getDisplay();
- mDragState.register(display);
- if (!mService.mInputManager.transferTouchFocus(callingWin.mInputChannel,
- mDragState.getInputChannel())) {
- Slog.e(TAG_WM, "Unable to transfer touch focus");
- mDragState.closeLocked();
- return false;
- }
-
- mDragState.mDisplayContent = displayContent;
- mDragState.mData = data;
- mDragState.broadcastDragStartedLocked(touchX, touchY);
- mDragState.overridePointerIconLocked(touchSource);
-
- // remember the thumb offsets for later
- mDragState.mThumbOffsetX = thumbCenterX;
- mDragState.mThumbOffsetY = thumbCenterY;
-
- // Make the surface visible at the proper location
- final SurfaceControl surfaceControl = mDragState.mSurfaceControl;
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
- TAG_WM, ">>> OPEN TRANSACTION performDrag");
- mService.openSurfaceTransaction();
- try {
- surfaceControl.setPosition(touchX - thumbCenterX,
- touchY - thumbCenterY);
- surfaceControl.setLayer(mDragState.getDragLayerLocked());
- surfaceControl.setLayerStack(display.getLayerStack());
- surfaceControl.show();
- } finally {
- mService.closeSurfaceTransaction("performDrag");
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
- TAG_WM, "<<< CLOSE TRANSACTION performDrag");
- }
-
- mDragState.notifyLocationLocked(touchX, touchY);
}
return true; // success!
@@ -214,32 +250,35 @@
Slog.d(TAG_WM, "Drop result=" + consumed + " reported by " + token);
}
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- // Most likely the drop recipient ANRed and we ended the drag
- // out from under it. Log the issue and move on.
- Slog.w(TAG_WM, "Drop result given but no drag in progress");
- return;
- }
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ // Most likely the drop recipient ANRed and we ended the drag
+ // out from under it. Log the issue and move on.
+ Slog.w(TAG_WM, "Drop result given but no drag in progress");
+ return;
+ }
- if (mDragState.mToken != token) {
- // We're in a drag, but the wrong window has responded.
- Slog.w(TAG_WM, "Invalid drop-result claim by " + window);
- throw new IllegalStateException("reportDropResult() by non-recipient");
- }
+ if (mDragState.mToken != token) {
+ // We're in a drag, but the wrong window has responded.
+ Slog.w(TAG_WM, "Invalid drop-result claim by " + window);
+ throw new IllegalStateException("reportDropResult() by non-recipient");
+ }
- // The right window has responded, even if it's no longer around,
- // so be sure to halt the timeout even if the later WindowState
- // lookup fails.
- mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
- WindowState callingWin = mService.windowForClientLocked(null, window, false);
- if (callingWin == null) {
- Slog.w(TAG_WM, "Bad result-reporting window " + window);
- return; // !!! TODO: throw here?
- }
+ // The right window has responded, even if it's no longer around,
+ // so be sure to halt the timeout even if the later WindowState
+ // lookup fails.
+ mHandler.removeMessages(MSG_DRAG_END_TIMEOUT, window.asBinder());
+ WindowState callingWin = mService.windowForClientLocked(null, window, false);
+ if (callingWin == null) {
+ Slog.w(TAG_WM, "Bad result-reporting window " + window);
+ return; // !!! TODO: throw here?
+ }
- mDragState.mDragResult = consumed;
- mDragState.endDragLocked();
+
+ mDragState.mDragResult = consumed;
+ mDragState.endDragLocked();
+ }
}
}
@@ -248,21 +287,23 @@
Slog.d(TAG_WM, "cancelDragAndDrop");
}
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
- throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
- }
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.w(TAG_WM, "cancelDragAndDrop() without prepareDrag()");
+ throw new IllegalStateException("cancelDragAndDrop() without prepareDrag()");
+ }
- if (mDragState.mToken != dragToken) {
- Slog.w(TAG_WM,
- "cancelDragAndDrop() does not match prepareDrag()");
- throw new IllegalStateException(
- "cancelDragAndDrop() does not match prepareDrag()");
- }
+ if (mDragState.mToken != dragToken) {
+ Slog.w(TAG_WM,
+ "cancelDragAndDrop() does not match prepareDrag()");
+ throw new IllegalStateException(
+ "cancelDragAndDrop() does not match prepareDrag()");
+ }
- mDragState.mDragResult = false;
- mDragState.cancelDragLocked();
+ mDragState.mDragResult = false;
+ mDragState.cancelDragLocked();
+ }
}
}
@@ -274,18 +315,20 @@
* @param newY Y coordinate value in dp in the screen coordinate
*/
void handleMotionEvent(boolean keepHandling, float newX, float newY) {
- synchronized (mService.mWindowMap) {
- if (!dragDropActiveLocked()) {
- // The drag has ended but the clean-up message has not been processed by
- // window manager. Drop events that occur after this until window manager
- // has a chance to clean-up the input handle.
- return;
- }
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (!dragDropActiveLocked()) {
+ // The drag has ended but the clean-up message has not been processed by
+ // window manager. Drop events that occur after this until window manager
+ // has a chance to clean-up the input handle.
+ return;
+ }
- if (keepHandling) {
- mDragState.notifyMoveLocked(newX, newY);
- } else {
- mDragState.notifyDropLocked(newX, newY);
+ if (keepHandling) {
+ mDragState.notifyMoveLocked(newX, newY);
+ } else {
+ mDragState.notifyDropLocked(newX, newY);
+ }
}
}
}
@@ -348,25 +391,29 @@
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout starting drag by win " + win);
}
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the app that has failed to start the drag in time
- if (mDragState != null) {
- mDragState.closeLocked();
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the app that has failed to start the drag in time
+ if (mDragState != null) {
+ mDragState.closeLocked();
+ }
}
}
break;
}
case MSG_DRAG_END_TIMEOUT: {
- IBinder win = (IBinder) msg.obj;
+ final IBinder win = (IBinder) msg.obj;
if (DEBUG_DRAG) {
Slog.w(TAG_WM, "Timeout ending drag to win " + win);
}
- synchronized (mService.mWindowMap) {
- // !!! TODO: ANR the drag-receiving app
- if (mDragState != null) {
- mDragState.mDragResult = false;
- mDragState.endDragLocked();
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ // !!! TODO: ANR the drag-receiving app
+ if (mDragState != null) {
+ mDragState.mDragResult = false;
+ mDragState.endDragLocked();
+ }
}
}
break;
@@ -375,23 +422,25 @@
case MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT: {
if (DEBUG_DRAG)
Slog.d(TAG_WM, "Drag ending; tearing down input channel");
- DragState.InputInterceptor interceptor = (DragState.InputInterceptor) msg.obj;
- if (interceptor != null) {
- synchronized (mService.mWindowMap) {
- interceptor.tearDown();
- }
+ final DragState.InputInterceptor interceptor =
+ (DragState.InputInterceptor) msg.obj;
+ if (interceptor == null) return;
+ synchronized (mService.mWindowMap) {
+ interceptor.tearDown();
}
break;
}
case MSG_ANIMATION_END: {
- synchronized (mService.mWindowMap) {
- if (mDragState == null) {
- Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
- "plyaing animation");
- return;
+ synchronized (mWriteLock) {
+ synchronized (mService.mWindowMap) {
+ if (mDragState == null) {
+ Slog.wtf(TAG_WM, "mDragState unexpectedly became null while " +
+ "plyaing animation");
+ return;
+ }
+ mDragState.closeLocked();
}
- mDragState.closeLocked();
}
break;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index f313f31..d9ba7d5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2916,10 +2916,9 @@
}
public void setKeyguardGoingAway(boolean keyguardGoingAway) {
-// TODO: Use of this can be removed. Revert ag/I8369723d6a77f2c602f1ef080371fa7cd9ee094e
-// synchronized (mWindowMap) {
-// mKeyguardGoingAway = keyguardGoingAway;
-// }
+ synchronized (mWindowMap) {
+ mKeyguardGoingAway = keyguardGoingAway;
+ }
}
// -------------------------------------------------------------
@@ -7278,11 +7277,6 @@
}
@Override
- public boolean isKeyguardGoingAway() {
- return WindowManagerService.this.mKeyguardGoingAway;
- }
-
- @Override
public boolean isKeyguardShowingAndNotOccluded() {
return WindowManagerService.this.isKeyguardShowingAndNotOccluded();
}
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index 11f508b..24f2014 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -65,28 +65,15 @@
int subClassID = deviceDesc->bDeviceSubClass;
// get the raw descriptors
- int fd = usb_device_get_fd(device);
- if (fd < 0) {
- ALOGE("usb_device_get_fd failed\n");
- usb_device_close(device);
- // TODO return an error code here?
- return 0;
- }
-
- // from android_hardware_UsbDeviceConnection_get_desc()
- jbyte rawdescriptors[MAX_DESCRIPTORS_LENGTH];
- lseek(fd, 0, SEEK_SET);
- int numBytes = read(fd, rawdescriptors, sizeof(rawdescriptors));
-
- usb_device_close(device);
-
+ int numBytes = usb_device_get_descriptors_length(device);
if (numBytes > 0) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
jobject thiz = (jobject)clientData;
jstring deviceAddress = env->NewStringUTF(devAddress);
jbyteArray descriptorsArray = env->NewByteArray(numBytes);
- env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawdescriptors);
+ const jbyte* rawDescriptors = (const jbyte*)usb_device_get_raw_descriptors(device);
+ env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawDescriptors);
env->CallBooleanMethod(thiz, method_usbDeviceAdded,
deviceAddress, classID, subClassID, descriptorsArray);
@@ -100,6 +87,8 @@
ALOGE("error reading descriptors\n");
}
+ usb_device_close(device);
+
return 0;
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 5c2b66f..31a1abb 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -86,6 +86,14 @@
*/
public class ApfFilter {
+ // Helper class for specifying functional filter parameters.
+ public static class ApfConfiguration {
+ public ApfCapabilities apfCapabilities;
+ public boolean multicastFilter;
+ public boolean ieee802_3Filter;
+ public int[] ethTypeBlackList;
+ }
+
// Enums describing the outcome of receiving an RA packet.
private static enum ProcessRaResult {
MATCH, // Received RA matched a known RA
@@ -261,17 +269,16 @@
private int mIPv4PrefixLength;
@VisibleForTesting
- ApfFilter(ApfCapabilities apfCapabilities, NetworkInterface networkInterface,
- IpClient.Callback ipClientCallback, boolean multicastFilter,
- boolean ieee802_3Filter, int[] ethTypeBlackList, IpConnectivityLog log) {
- mApfCapabilities = apfCapabilities;
+ ApfFilter(ApfConfiguration config, NetworkInterface networkInterface,
+ IpClient.Callback ipClientCallback, IpConnectivityLog log) {
+ mApfCapabilities = config.apfCapabilities;
mIpClientCallback = ipClientCallback;
mNetworkInterface = networkInterface;
- mMulticastFilter = multicastFilter;
- mDrop802_3Frames = ieee802_3Filter;
+ mMulticastFilter = config.multicastFilter;
+ mDrop802_3Frames = config.ieee802_3Filter;
// Now fill the black list from the passed array
- mEthTypeBlackList = filterEthTypeBlackList(ethTypeBlackList);
+ mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
mMetricsLog = log;
@@ -1160,9 +1167,10 @@
* Create an {@link ApfFilter} if {@code apfCapabilities} indicates support for packet
* filtering using APF programs.
*/
- public static ApfFilter maybeCreate(ApfCapabilities apfCapabilities,
- NetworkInterface networkInterface, IpClient.Callback ipClientCallback,
- boolean multicastFilter, boolean ieee802_3Filter, int[] ethTypeBlackList) {
+ public static ApfFilter maybeCreate(ApfConfiguration config,
+ NetworkInterface networkInterface, IpClient.Callback ipClientCallback) {
+ if (config == null) return null;
+ ApfCapabilities apfCapabilities = config.apfCapabilities;
if (apfCapabilities == null || networkInterface == null) return null;
if (apfCapabilities.apfVersionSupported == 0) return null;
if (apfCapabilities.maximumApfProgramSize < 512) {
@@ -1178,8 +1186,7 @@
Log.e(TAG, "Unsupported APF version: " + apfCapabilities.apfVersionSupported);
return null;
}
- return new ApfFilter(apfCapabilities, networkInterface, ipClientCallback,
- multicastFilter, ieee802_3Filter, ethTypeBlackList, new IpConnectivityLog());
+ return new ApfFilter(config, networkInterface, ipClientCallback, new IpConnectivityLog());
}
public synchronized void shutdown() {
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 24f1cf3..70983c8 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -1429,15 +1429,15 @@
@Override
public void enter() {
+ ApfFilter.ApfConfiguration apfConfig = new ApfFilter.ApfConfiguration();
+ apfConfig.apfCapabilities = mConfiguration.mApfCapabilities;
+ apfConfig.multicastFilter = mMulticastFiltering;
// Get the Configuration for ApfFilter from Context
- final boolean filter802_3Frames =
+ apfConfig.ieee802_3Filter =
mContext.getResources().getBoolean(R.bool.config_apfDrop802_3Frames);
-
- final int[] ethTypeBlackList = mContext.getResources().getIntArray(
- R.array.config_apfEthTypeBlackList);
-
- mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
- mCallback, mMulticastFiltering, filter802_3Frames, ethTypeBlackList);
+ apfConfig.ethTypeBlackList =
+ mContext.getResources().getIntArray(R.array.config_apfEthTypeBlackList);
+ mApfFilter = ApfFilter.maybeCreate(apfConfig, mNetworkInterface, mCallback);
// TODO: investigate the effects of any multicast filtering racing/interfering with the
// rest of this IP configuration startup.
if (mApfFilter == null) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 480be2e..882bf32 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -89,6 +89,7 @@
assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_RECORD_AUDIO));
assertFalse(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_WALLPAPER));
assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_ADD_USER));
+ assertTrue(UserRestrictionsUtils.canDeviceOwnerChange(UserManager.DISALLOW_USER_SWITCH));
}
public void testCanProfileOwnerChange() {
@@ -97,6 +98,8 @@
UserManager.DISALLOW_RECORD_AUDIO, user));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_WALLPAPER, user));
+ assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+ UserManager.DISALLOW_USER_SWITCH, user));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADD_USER, user));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
@@ -109,6 +112,8 @@
UserManager.DISALLOW_WALLPAPER, user));
assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADD_USER, user));
+ assertFalse(UserRestrictionsUtils.canProfileOwnerChange(
+ UserManager.DISALLOW_USER_SWITCH, user));
assertTrue(UserRestrictionsUtils.canProfileOwnerChange(
UserManager.DISALLOW_ADJUST_VOLUME, user));
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 27c5eab..693264c 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -18,10 +18,14 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
import static com.android.server.wm.WindowContainer.POSITION_TOP;
import static org.junit.Assert.assertEquals;
@@ -31,6 +35,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import android.annotation.SuppressLint;
import android.content.res.Configuration;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
@@ -379,6 +384,31 @@
assertEquals(-1, orderedDisplayIds.indexOfValue(dc.getDisplayId()));
}
+ @Test
+ @SuppressLint("InlinedApi")
+ public void testOrientationDefinedByKeyguard() {
+ final DisplayContent dc = createNewDisplay();
+ // Create a window that requests landscape orientation. It will define device orientation
+ // by default.
+ final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
+ window.mAppToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+
+ final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR, dc, "keyguard");
+ keyguard.mHasSurface = true;
+ keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+ assertEquals("Screen orientation must be defined by the app window by default",
+ SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
+
+ keyguard.mAttrs.screenOrientation = SCREEN_ORIENTATION_PORTRAIT;
+ assertEquals("Visible keyguard must influence device orientation",
+ SCREEN_ORIENTATION_PORTRAIT, dc.getOrientation());
+
+ sWm.setKeyguardGoingAway(true);
+ assertEquals("Keyguard that is going away must not influence device orientation",
+ SCREEN_ORIENTATION_LANDSCAPE, dc.getOrientation());
+ }
+
private static void verifySizes(DisplayContent displayContent, int expectedBaseWidth,
int expectedBaseHeight, int expectedBaseDensity) {
assertEquals(displayContent.mBaseDisplayWidth, expectedBaseWidth);
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 33d4721..5134c26 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -17,7 +17,7 @@
package com.android.server.wm;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManagerPolicy.NAV_BAR_BOTTOM;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -189,7 +189,7 @@
@Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
- return false;
+ return attrs.type == TYPE_STATUS_BAR;
}
@Override
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index 924f0de..5d03926 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -338,16 +338,18 @@
/**
* Send a text based SMS without writing it into the SMS Provider.
*
+ * <p>
+ * The message will be sent directly over the network and will not be visible in SMS
+ * applications. Intended for internal carrier use only.
+ * </p>
+ *
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE} or the calling app has carrier
* privileges.
* </p>
*
* @see #sendTextMessage(String, String, String, PendingIntent, PendingIntent)
- * @hide
*/
- @SystemApi
- @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
public void sendTextMessageWithoutPersisting(
String destinationAddress, String scAddress, String text,
PendingIntent sentIntent, PendingIntent deliveryIntent) {
diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java
index e40f20f..d7b6142 100644
--- a/telephony/java/android/telephony/Telephony.java
+++ b/telephony/java/android/telephony/Telephony.java
@@ -2828,6 +2828,26 @@
* @hide
*/
public static final int CARRIER_DELETED_BUT_PRESENT_IN_XML = 6;
+
+ /**
+ * The owner of the APN.
+ * <p>Type: INTEGER</p>
+ * @hide
+ */
+ public static final String OWNED_BY = "owned_by";
+
+ /**
+ * Possible value for the OWNED_BY field.
+ * APN is owned by DPC.
+ * @hide
+ */
+ public static final int OWNED_BY_DPC = 0;
+ /**
+ * Possible value for the OWNED_BY field.
+ * APN is owned by other sources.
+ * @hide
+ */
+ public static final int OWNED_BY_OTHERS = 1;
}
/**
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
deleted file mode 100644
index 31d3db4..0000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxy.java
+++ /dev/null
@@ -1,322 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telephony.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.feature.IRcsFeature;
-import android.telephony.ims.feature.ImsFeature;
-import android.util.Log;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsServiceController;
-import com.android.ims.internal.IImsServiceFeatureListener;
-import com.android.ims.internal.IImsUt;
-
-/**
- * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
- * the platform currently supports: MMTel and RCS.
- * @hide
- */
-
-public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
-
- protected String LOG_TAG = "ImsServiceProxy";
- private final int mSupportedFeature;
-
- // Start by assuming the proxy is available for usage.
- private boolean mIsAvailable = true;
- // ImsFeature Status from the ImsService. Cached.
- private Integer mFeatureStatusCached = null;
- private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
- private final Object mLock = new Object();
-
- public interface INotifyStatusChanged {
- void notifyStatusChanged();
- }
-
- private final IImsServiceFeatureListener mListenerBinder =
- new IImsServiceFeatureListener.Stub() {
-
- @Override
- public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
- // The feature has been re-enabled. This may happen when the service crashes.
- synchronized (mLock) {
- if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
- Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
- feature);
- mIsAvailable = true;
- }
- }
- }
-
- @Override
- public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
- synchronized (mLock) {
- if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
- Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
- feature);
- mIsAvailable = false;
- }
- }
- }
-
- @Override
- public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
- synchronized (mLock) {
- Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
- " status: " + status);
- if (mSlotId == slotId && feature == mSupportedFeature) {
- mFeatureStatusCached = status;
- if (mStatusCallback != null) {
- mStatusCallback.notifyStatusChanged();
- }
- }
- }
- }
- };
-
- public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
- super(slotId, binder);
- mSupportedFeature = featureType;
- }
-
- public ImsServiceProxy(int slotId, int featureType) {
- super(slotId, null /*IBinder*/);
- mSupportedFeature = featureType;
- }
-
- public IImsServiceFeatureListener getListener() {
- return mListenerBinder;
- }
-
- public void setBinder(IBinder binder) {
- mBinder = binder;
- }
-
- @Override
- public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
- incomingCallIntent, listener);
- }
- }
-
- @Override
- public void endSession(int sessionId) throws RemoteException {
- synchronized (mLock) {
- // Only check to make sure the binder connection still exists. This method should
- // still be able to be called when the state is STATE_NOT_AVAILABLE.
- checkBinderConnection();
- getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
- }
- }
-
- @Override
- public boolean isConnected(int callServiceType, int callType)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
- callServiceType, callType);
- }
- }
-
- @Override
- public boolean isOpened() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void addRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
- listener);
- }
- }
-
- @Override
- public void removeRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
- listener);
- }
- }
-
- @Override
- public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
- sessionId, callServiceType, callType);
- }
- }
-
- @Override
- public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
- IImsCallSessionListener listener) throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
- sessionId, profile, listener);
- }
- }
-
- @Override
- public IImsCallSession getPendingCallSession(int sessionId, String callId)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
- sessionId, callId);
- }
- }
-
- @Override
- public IImsUt getUtInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public IImsConfig getConfigInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void turnOnIms() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void turnOffIms() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public IImsEcbm getEcbmInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
- }
- }
-
- @Override
- public void setUiTTYMode(int uiTtyMode, Message onComplete)
- throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
- onComplete);
- }
- }
-
- @Override
- public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
- synchronized (mLock) {
- checkServiceIsReady();
- return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
- mSupportedFeature);
- }
- }
-
- @Override
- public int getFeatureStatus() {
- synchronized (mLock) {
- if (isBinderAlive() && mFeatureStatusCached != null) {
- Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
- return mFeatureStatusCached;
- }
- }
- // Don't synchronize on Binder call.
- Integer status = retrieveFeatureStatus();
- synchronized (mLock) {
- if (status == null) {
- return ImsFeature.STATE_NOT_AVAILABLE;
- }
- // Cache only non-null value for feature status.
- mFeatureStatusCached = status;
- }
- Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
- return status;
- }
-
- /**
- * Internal method used to retrieve the feature status from the corresponding ImsService.
- */
- private Integer retrieveFeatureStatus() {
- if (mBinder != null) {
- try {
- return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
- } catch (RemoteException e) {
- // Status check failed, don't update cache
- }
- }
- return null;
- }
-
- /**
- * @param c Callback that will fire when the feature status has changed.
- */
- public void setStatusCallback(INotifyStatusChanged c) {
- mStatusCallback = c;
- }
-
- @Override
- public boolean isBinderAlive() {
- return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
- }
-
- protected void checkServiceIsReady() throws RemoteException {
- if (!isBinderReady()) {
- throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
- }
- }
-
- private IImsServiceController getServiceInterface(IBinder b) {
- return IImsServiceController.Stub.asInterface(b);
- }
-}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
deleted file mode 100644
index 7ec9229..0000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telephony.ims;
-
-import android.app.PendingIntent;
-import android.os.IBinder;
-import android.os.Message;
-import android.os.RemoteException;
-import android.telephony.ims.feature.IMMTelFeature;
-import android.telephony.ims.feature.ImsFeature;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsService;
-import com.android.ims.internal.IImsUt;
-
-/**
- * Compatibility class that implements the new ImsService IMMTelFeature interface, but
- * uses the old IImsService interface to support older devices that implement the deprecated
- * opt/net/ims interface.
- * @hide
- */
-
-public class ImsServiceProxyCompat implements IMMTelFeature {
-
- private static final int SERVICE_ID = ImsFeature.MMTEL;
-
- protected final int mSlotId;
- protected IBinder mBinder;
-
- public ImsServiceProxyCompat(int slotId, IBinder binder) {
- mSlotId = slotId;
- mBinder = binder;
- }
-
- @Override
- public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
- listener);
- }
-
- @Override
- public void endSession(int sessionId) throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).close(sessionId);
- }
-
- @Override
- public boolean isConnected(int callServiceType, int callType)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).isConnected(SERVICE_ID, callServiceType, callType);
- }
-
- @Override
- public boolean isOpened() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).isOpened(SERVICE_ID);
- }
-
- @Override
- public void addRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
- }
-
- @Override
- public void removeRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException {
- // Not Implemented in old ImsService. If the registration listener becomes invalid, the
- // ImsService will remove.
- }
-
- @Override
- public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
- }
-
- @Override
- public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
- IImsCallSessionListener listener) throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
- }
-
- @Override
- public IImsCallSession getPendingCallSession(int sessionId, String callId)
- throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
- }
-
- @Override
- public IImsUt getUtInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getUtInterface(SERVICE_ID);
- }
-
- @Override
- public IImsConfig getConfigInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getConfigInterface(mSlotId);
- }
-
- @Override
- public void turnOnIms() throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).turnOnIms(mSlotId);
- }
-
- @Override
- public void turnOffIms() throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).turnOffIms(mSlotId);
- }
-
- @Override
- public IImsEcbm getEcbmInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getEcbmInterface(SERVICE_ID);
- }
-
- @Override
- public void setUiTTYMode(int uiTtyMode, Message onComplete)
- throws RemoteException {
- checkBinderConnection();
- getServiceInterface(mBinder).setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
- }
-
- @Override
- public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
- checkBinderConnection();
- return getServiceInterface(mBinder).getMultiEndpointInterface(SERVICE_ID);
- }
-
- /**
- * Base implementation, always returns READY for compatibility with old ImsService.
- */
- public int getFeatureStatus() {
- return ImsFeature.STATE_READY;
- }
-
- /**
- * @return false if the binder connection is no longer alive.
- */
- public boolean isBinderAlive() {
- return mBinder != null && mBinder.isBinderAlive();
- }
-
- /**
- * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
- * method returns false, it doesn't mean that the Binder connection is not available (use
- * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
- * at this time.
- *
- * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
- * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
- */
- public boolean isBinderReady() {
- return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
- }
-
- private IImsService getServiceInterface(IBinder b) {
- return IImsService.Stub.asInterface(b);
- }
-
- protected void checkBinderConnection() throws RemoteException {
- if (!isBinderAlive()) {
- throw new RemoteException("ImsServiceProxy is not available for that feature.");
- }
- }
-}
diff --git a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
deleted file mode 100644
index d65e27e..0000000
--- a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telephony.ims.feature;
-
-import android.app.PendingIntent;
-import android.os.Message;
-import android.os.RemoteException;
-
-import com.android.ims.ImsCallProfile;
-import com.android.ims.internal.IImsCallSession;
-import com.android.ims.internal.IImsCallSessionListener;
-import com.android.ims.internal.IImsConfig;
-import com.android.ims.internal.IImsEcbm;
-import com.android.ims.internal.IImsMultiEndpoint;
-import com.android.ims.internal.IImsRegistrationListener;
-import com.android.ims.internal.IImsUt;
-
-/**
- * MMTel interface for an ImsService. When updating this interface, ensure that base implementations
- * of your changes are also present in MMTelFeature for compatibility with older versions of the
- * MMTel feature.
- * @hide
- */
-
-public interface IMMTelFeature {
-
- /**
- * Notifies the MMTel feature that you would like to start a session. This should always be
- * done before making/receiving IMS calls. The IMS service will register the device to the
- * operator's network with the credentials (from ISIM) periodically in order to receive calls
- * from the operator's network. When the IMS service receives a new call, it will send out an
- * intent with the provided action string. The intent contains a call ID extra
- * {@link IImsCallSession#getCallId} and it can be used to take a call.
- *
- * @param incomingCallIntent When an incoming call is received, the IMS service will call
- * {@link PendingIntent#send} to send back the intent to the caller with
- * {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
- * It cannot be null.
- * @param listener To listen to IMS registration events; It cannot be null
- * @return an integer (greater than 0) representing the session id associated with the session
- * that has been started.
- */
- int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
- throws RemoteException;
-
- /**
- * End a previously started session using the associated sessionId.
- * @param sessionId an integer (greater than 0) representing the ongoing session. See
- * {@link #startSession}.
- */
- void endSession(int sessionId) throws RemoteException;
-
- /**
- * Checks if the IMS service has successfully registered to the IMS network with the specified
- * service & call type.
- *
- * @param callServiceType a service type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
- * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
- * @param callType a call type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
- * {@link ImsCallProfile#CALL_TYPE_VOICE}
- * {@link ImsCallProfile#CALL_TYPE_VT}
- * {@link ImsCallProfile#CALL_TYPE_VS}
- * @return true if the specified service id is connected to the IMS network; false otherwise
- * @throws RemoteException
- */
- boolean isConnected(int callServiceType, int callType) throws RemoteException;
-
- /**
- * Checks if the specified IMS service is opened.
- *
- * @return true if the specified service id is opened; false otherwise
- */
- boolean isOpened() throws RemoteException;
-
- /**
- * Add a new registration listener for the client associated with the session Id.
- * @param listener An implementation of IImsRegistrationListener.
- */
- void addRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException;
-
- /**
- * Remove a previously registered listener using {@link #addRegistrationListener} for the client
- * associated with the session Id.
- * @param listener A previously registered IImsRegistrationListener
- */
- void removeRegistrationListener(IImsRegistrationListener listener)
- throws RemoteException;
-
- /**
- * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
- *
- * @param sessionId a session id which is obtained from {@link #startSession}
- * @param callServiceType a service type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#SERVICE_TYPE_NONE}
- * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
- * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
- * @param callType a call type that is specified in {@link ImsCallProfile}
- * {@link ImsCallProfile#CALL_TYPE_VOICE}
- * {@link ImsCallProfile#CALL_TYPE_VT}
- * {@link ImsCallProfile#CALL_TYPE_VT_TX}
- * {@link ImsCallProfile#CALL_TYPE_VT_RX}
- * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
- * {@link ImsCallProfile#CALL_TYPE_VS}
- * {@link ImsCallProfile#CALL_TYPE_VS_TX}
- * {@link ImsCallProfile#CALL_TYPE_VS_RX}
- * @return a {@link ImsCallProfile} object
- */
- ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
- throws RemoteException;
-
- /**
- * Creates a {@link ImsCallSession} with the specified call profile.
- * Use other methods, if applicable, instead of interacting with
- * {@link ImsCallSession} directly.
- *
- * @param sessionId a session id which is obtained from {@link #startSession}
- * @param profile a call profile to make the call
- * @param listener An implementation of IImsCallSessionListener.
- */
- IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
- IImsCallSessionListener listener) throws RemoteException;
-
- /**
- * Retrieves the call session associated with a pending call.
- *
- * @param sessionId a session id which is obtained from {@link #startSession}
- * @param callId a call id to make the call
- */
- IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
-
- /**
- * @return The Ut interface for the supplementary service configuration.
- */
- IImsUt getUtInterface() throws RemoteException;
-
- /**
- * @return The config interface for IMS Configuration
- */
- IImsConfig getConfigInterface() throws RemoteException;
-
- /**
- * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
- * @param sessionId a session id which is obtained from {@link #startSession}
- */
- void turnOnIms() throws RemoteException;
-
- /**
- * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
- * @param sessionId a session id which is obtained from {@link #startSession}
- */
- void turnOffIms() throws RemoteException;
-
- /**
- * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
- */
- IImsEcbm getEcbmInterface() throws RemoteException;
-
- /**
- * Sets the current UI TTY mode for the MMTelFeature.
- * @param uiTtyMode An integer containing the new UI TTY Mode.
- * @param onComplete A {@link Message} to be used when the mode has been set.
- * @throws RemoteException
- */
- void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException;
-
- /**
- * @return MultiEndpoint interface for DEP notifications
- */
- IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException;
-}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
deleted file mode 100644
index e28e1b3..0000000
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License
- */
-
-package android.telephony.ims.feature;
-
-/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
- * @hide
- */
-
-public interface IRcsFeature {
-}
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
index a71f0bf..758c379 100644
--- a/telephony/java/android/telephony/ims/feature/MMTelFeature.java
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -32,90 +32,183 @@
import java.util.List;
/**
- * Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
- * MMTelFeature should extend this class and implement all methods that the service supports.
+ * Base implementation for MMTel.
+ * Any class wishing to use MMTelFeature should extend this class and implement all methods that the
+ * service supports.
*
* @hide
*/
-public class MMTelFeature extends ImsFeature implements IMMTelFeature {
+public class MMTelFeature extends ImsFeature {
- @Override
+ /**
+ * Notifies the MMTel feature that you would like to start a session. This should always be
+ * done before making/receiving IMS calls. The IMS service will register the device to the
+ * operator's network with the credentials (from ISIM) periodically in order to receive calls
+ * from the operator's network. When the IMS service receives a new call, it will send out an
+ * intent with the provided action string. The intent contains a call ID extra
+ * {@link IImsCallSession#getCallId} and it can be used to take a call.
+ *
+ * @param incomingCallIntent When an incoming call is received, the IMS service will call
+ * {@link PendingIntent#send} to send back the intent to the caller with
+ * ImsManager#INCOMING_CALL_RESULT_CODE as the result code and the intent to fill in the call
+ * ID; It cannot be null.
+ * @param listener To listen to IMS registration events; It cannot be null
+ * @return an integer (greater than 0) representing the session id associated with the session
+ * that has been started.
+ */
public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
return 0;
}
- @Override
+ /**
+ * End a previously started session using the associated sessionId.
+ * @param sessionId an integer (greater than 0) representing the ongoing session. See
+ * {@link #startSession}.
+ */
public void endSession(int sessionId) {
}
- @Override
+ /**
+ * Checks if the IMS service has successfully registered to the IMS network with the specified
+ * service & call type.
+ *
+ * @param callSessionType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * @return true if the specified service id is connected to the IMS network; false otherwise
+ */
public boolean isConnected(int callSessionType, int callType) {
return false;
}
- @Override
+ /**
+ * Checks if the specified IMS service is opened.
+ *
+ * @return true if the specified service id is opened; false otherwise
+ */
public boolean isOpened() {
return false;
}
- @Override
+ /**
+ * Add a new registration listener for the client associated with the session Id.
+ * @param listener An implementation of IImsRegistrationListener.
+ */
public void addRegistrationListener(IImsRegistrationListener listener) {
}
- @Override
+ /**
+ * Remove a previously registered listener using {@link #addRegistrationListener} for the client
+ * associated with the session Id.
+ * @param listener A previously registered IImsRegistrationListener
+ */
public void removeRegistrationListener(IImsRegistrationListener listener) {
}
- @Override
+ /**
+ * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callSessionType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NONE}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VT_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_RX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * {@link ImsCallProfile#CALL_TYPE_VS_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VS_RX}
+ * @return a {@link ImsCallProfile} object
+ */
public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
return null;
}
- @Override
+ /**
+ * Creates a {@link ImsCallSession} with the specified call profile.
+ * Use other methods, if applicable, instead of interacting with
+ * {@link ImsCallSession} directly.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param profile a call profile to make the call
+ * @param listener An implementation of IImsCallSessionListener.
+ */
public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) {
return null;
}
- @Override
+ /**
+ * Retrieves the call session associated with a pending call.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callId a call id to make the call
+ */
public IImsCallSession getPendingCallSession(int sessionId, String callId) {
return null;
}
- @Override
+ /**
+ * @return The Ut interface for the supplementary service configuration.
+ */
public IImsUt getUtInterface() {
return null;
}
- @Override
+ /**
+ * @return The config interface for IMS Configuration
+ */
public IImsConfig getConfigInterface() {
return null;
}
- @Override
+ /**
+ * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
+ */
public void turnOnIms() {
}
- @Override
+ /**
+ * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
+ */
public void turnOffIms() {
}
- @Override
+ /**
+ * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
+ */
public IImsEcbm getEcbmInterface() {
return null;
}
- @Override
+ /**
+ * Sets the current UI TTY mode for the MMTelFeature.
+ * @param uiTtyMode An integer containing the new UI TTY Mode.
+ * @param onComplete A {@link Message} to be used when the mode has been set.
+ */
public void setUiTTYMode(int uiTtyMode, Message onComplete) {
}
- @Override
+ /**
+ * @return MultiEndpoint interface for DEP notifications
+ */
public IImsMultiEndpoint getMultiEndpointInterface() {
return null;
}
- @Override
+ /**
+ * {@inheritDoc}
+ */
public void onFeatureRemoved() {
}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
index 9cddc1b..332cca3 100644
--- a/telephony/java/android/telephony/ims/feature/RcsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -18,11 +18,11 @@
/**
* Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
- * this class and provide implementations of the IRcsFeature methods that they support.
+ * this class and provide implementations of the RcsFeature methods that they support.
* @hide
*/
-public class RcsFeature extends ImsFeature implements IRcsFeature {
+public class RcsFeature extends ImsFeature {
public RcsFeature() {
super();
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index bb06d7e..f1e2262 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -31,7 +31,7 @@
import android.os.Message;
/**
- * See ImsService and IMMTelFeature for more information.
+ * See ImsService and MMTelFeature for more information.
* {@hide}
*/
interface IImsServiceController {
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index 0824c26..60327e5 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -10,25 +10,11 @@
# use appcompat/support lib from the tree, so improvements/
# regressions are reflected in test data
-LOCAL_RESOURCE_DIR := \
- $(LOCAL_PATH)/res \
- frameworks/support/core-ui/res \
- frameworks/support/design/res \
- frameworks/support/v7/appcompat/res \
- frameworks/support/v7/cardview/res \
- frameworks/support/v7/recyclerview/res \
- frameworks/support/v17/leanback/res
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
-LOCAL_AAPT_FLAGS := \
- --auto-add-overlay \
- --extra-packages android.support.coreui \
- --extra-packages android.support.design \
- --extra-packages android.support.v7.appcompat \
- --extra-packages android.support.v7.cardview \
- --extra-packages android.support.v7.recyclerview \
- --extra-packages android.support.v17.leanback
+LOCAL_USE_AAPT2 := true
-LOCAL_STATIC_JAVA_LIBRARIES := \
+LOCAL_STATIC_ANDROID_LIBRARIES := \
android-support-design \
android-support-v4 \
android-support-v7-appcompat \
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
new file mode 100644
index 0000000..3fa9c3a
--- /dev/null
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2017 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.net;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import android.net.MacAddress.MacAddressType;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.Arrays;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MacAddressTest {
+
+ static class AddrTypeTestCase {
+ byte[] addr;
+ MacAddressType expected;
+
+ static AddrTypeTestCase of(MacAddressType expected, int... addr) {
+ AddrTypeTestCase t = new AddrTypeTestCase();
+ t.expected = expected;
+ t.addr = toByteArray(addr);
+ return t;
+ }
+ }
+
+ @Test
+ public void testMacAddrTypes() {
+ AddrTypeTestCase[] testcases = {
+ AddrTypeTestCase.of(null),
+ AddrTypeTestCase.of(null, 0),
+ AddrTypeTestCase.of(null, 1, 2, 3, 4, 5),
+ AddrTypeTestCase.of(null, 1, 2, 3, 4, 5, 6, 7),
+ AddrTypeTestCase.of(MacAddressType.UNICAST, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0),
+ AddrTypeTestCase.of(MacAddressType.BROADCAST, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff),
+ AddrTypeTestCase.of(MacAddressType.MULTICAST, 1, 2, 3, 4, 5, 6),
+ AddrTypeTestCase.of(MacAddressType.MULTICAST, 11, 22, 33, 44, 55, 66),
+ AddrTypeTestCase.of(MacAddressType.MULTICAST, 33, 33, 0xaa, 0xbb, 0xcc, 0xdd)
+ };
+
+ for (AddrTypeTestCase t : testcases) {
+ MacAddressType got = MacAddress.macAddressType(t.addr);
+ String msg = String.format("expected type of %s to be %s, but got %s",
+ Arrays.toString(t.addr), t.expected, got);
+ assertEquals(msg, t.expected, got);
+ }
+ }
+
+ static byte[] toByteArray(int[] in) {
+ byte[] out = new byte[in.length];
+ for (int i = 0; i < in.length; i++) {
+ out[i] = (byte) in[i];
+ }
+ return out;
+ }
+}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 99a2ad9..725ddb9 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -29,9 +29,7 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkUtils;
-import android.net.apf.ApfCapabilities;
-import android.net.apf.ApfFilter;
-import android.net.apf.ApfGenerator;
+import android.net.apf.ApfFilter.ApfConfiguration;
import android.net.apf.ApfGenerator.IllegalInstructionException;
import android.net.apf.ApfGenerator.Register;
import android.net.ip.IpManager;
@@ -99,12 +97,24 @@
// least the minimum packet size.
private final static int MIN_PKT_SIZE = 15;
+ private static final ApfCapabilities MOCK_APF_CAPABILITIES =
+ new ApfCapabilities(2, 1700, ARPHRD_ETHER);
+
private final static boolean DROP_MULTICAST = true;
private final static boolean ALLOW_MULTICAST = false;
private final static boolean DROP_802_3_FRAMES = true;
private final static boolean ALLOW_802_3_FRAMES = false;
+ private static ApfConfiguration getDefaultConfig() {
+ ApfFilter.ApfConfiguration config = new ApfConfiguration();
+ config.apfCapabilities = MOCK_APF_CAPABILITIES;
+ config.multicastFilter = ALLOW_MULTICAST;
+ config.ieee802_3Filter = ALLOW_802_3_FRAMES;
+ config.ethTypeBlackList = new int[0];
+ return config;
+ }
+
private static String label(int code) {
switch (code) {
case PASS: return "PASS";
@@ -619,15 +629,13 @@
private static class TestApfFilter extends ApfFilter {
public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
- private FileDescriptor mWriteSocket;
+ private FileDescriptor mWriteSocket;
private final long mFixedTimeMs = SystemClock.elapsedRealtime();
- public TestApfFilter(IpManager.Callback ipManagerCallback, boolean multicastFilter,
- boolean ieee802_3Filter, int[] ethTypeBlackList,
+ public TestApfFilter(ApfConfiguration config, IpManager.Callback ipManagerCallback,
IpConnectivityLog log) throws Exception {
- super(new ApfCapabilities(2, 1700, ARPHRD_ETHER), NetworkInterface.getByName("lo"),
- ipManagerCallback, multicastFilter, ieee802_3Filter, ethTypeBlackList, log);
+ super(config, NetworkInterface.getByName("lo"), ipManagerCallback, log);
}
// Pretend an RA packet has been received and show it to ApfFilter.
@@ -755,10 +763,10 @@
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- final int[] ethTypeBlackList = {};
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -808,10 +816,9 @@
@Test
public void testApfFilterIPv6() throws Exception {
- final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
// Verify empty IPv6 packet is passed
@@ -846,15 +853,15 @@
final byte[] broadcastIpv4Addr = {(byte)192,0,2,(byte)255};
final byte[] multicastIpv4Addr = {(byte)224,0,0,1};
final byte[] multicastIpv6Addr = {(byte)0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,(byte)0xfb};
- final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
LinkAddress link = new LinkAddress(InetAddress.getByAddress(unicastIpv4Addr), 24);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -916,8 +923,9 @@
// Verify it can be initialized to on
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
assertDrop(program, mcastv4packet.array());
@@ -938,10 +946,9 @@
LinkAddress link = new LinkAddress(InetAddress.getByAddress(MOCK_IPV4_ADDR), 19);
LinkProperties lp = new LinkProperties();
lp.addLinkAddress(link);
- final int[] ethTypeBlackList = {};
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -962,8 +969,8 @@
// Now turn on the filter
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -993,8 +1000,8 @@
final int[] ipv4BlackList = {ETH_P_IP};
final int[] ipv4Ipv6BlackList = {ETH_P_IP, ETH_P_IPV6};
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, emptyBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
byte[] program = ipManagerCallback.getApfProgram();
@@ -1015,8 +1022,8 @@
// Now add IPv4 to the black list
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ipv4BlackList, mLog);
+ config.ethTypeBlackList = ipv4BlackList;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -1031,8 +1038,8 @@
// Now let us have both IPv4 and IPv6 in the black list
ipManagerCallback.resetApfProgramWait();
apfFilter.shutdown();
- apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- ALLOW_802_3_FRAMES, ipv4Ipv6BlackList, mLog);
+ config.ethTypeBlackList = ipv4Ipv6BlackList;
+ apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
apfFilter.setLinkProperties(lp);
program = ipManagerCallback.getApfProgram();
@@ -1070,10 +1077,11 @@
@Test
public void testApfFilterArp() throws Exception {
- final int[] ethTypeBlackList = {};
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- ApfFilter apfFilter = new TestApfFilter(ipManagerCallback, ALLOW_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
// Verify initially ARP request filter is off, and GARP filter is on.
verifyArpFilter(ipManagerCallback.getApfProgram(), PASS);
@@ -1194,9 +1202,10 @@
@Test
public void testApfFilterRa() throws Exception {
MockIpManagerCallback ipManagerCallback = new MockIpManagerCallback();
- final int[] ethTypeBlackList = {};
- TestApfFilter apfFilter = new TestApfFilter(ipManagerCallback, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, ipManagerCallback, mLog);
byte[] program = ipManagerCallback.getApfProgram();
final int ROUTER_LIFETIME = 1000;
@@ -1338,10 +1347,11 @@
public void testRaParsing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
- final int[] ethTypeBlackList = {};
MockIpManagerCallback cb = new MockIpManagerCallback();
- TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
@@ -1358,10 +1368,11 @@
public void testRaProcessing() throws Exception {
final int maxRandomPacketSize = 512;
final Random r = new Random();
- final int[] ethTypeBlackList = {};
MockIpManagerCallback cb = new MockIpManagerCallback();
- TestApfFilter apfFilter = new TestApfFilter(cb, DROP_MULTICAST,
- DROP_802_3_FRAMES, ethTypeBlackList, mLog);
+ ApfConfiguration config = getDefaultConfig();
+ config.multicastFilter = DROP_MULTICAST;
+ config.ieee802_3Filter = DROP_802_3_FRAMES;
+ TestApfFilter apfFilter = new TestApfFilter(config, cb, mLog);
for (int i = 0; i < 1000; i++) {
byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
r.nextBytes(packet);
diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
index 9e97d84b..5c031eb 100644
--- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java
@@ -64,6 +64,13 @@
return Arrays.asList(new Object[][] {{"8.8.4.4"}, {"2601::10"}});
}
+ private static final byte[] AEAD_KEY = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
+ 0x73, 0x61, 0x6C, 0x74
+ };
private static final byte[] CRYPT_KEY = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
@@ -87,7 +94,7 @@
private static final IpSecAlgorithm CRYPT_ALGO =
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY);
private static final IpSecAlgorithm AEAD_ALGO =
- new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, CRYPT_KEY, CRYPT_KEY.length * 4);
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, AEAD_KEY, 128);
private static final int[] DIRECTIONS =
new int[] {IpSecTransform.DIRECTION_IN, IpSecTransform.DIRECTION_OUT};
@@ -262,7 +269,7 @@
eq(new byte[] {}),
eq(0),
eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
- eq(CRYPT_KEY),
+ eq(AEAD_KEY),
anyInt(),
anyInt(),
anyInt(),
@@ -283,7 +290,7 @@
eq(new byte[] {}),
eq(0),
eq(IpSecAlgorithm.AUTH_CRYPT_AES_GCM),
- eq(CRYPT_KEY),
+ eq(AEAD_KEY),
anyInt(),
anyInt(),
anyInt(),
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index ae67f61..eb3a99a 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -113,6 +113,7 @@
"optimize/VersionCollapser.cpp",
"process/SymbolTable.cpp",
"split/TableSplitter.cpp",
+ "text/Printer.cpp",
"text/Unicode.cpp",
"text/Utf8Iterator.cpp",
"util/BigBuffer.cpp",
diff --git a/tools/aapt2/ConfigDescription.cpp b/tools/aapt2/ConfigDescription.cpp
index 59a6e12..f621660 100644
--- a/tools/aapt2/ConfigDescription.cpp
+++ b/tools/aapt2/ConfigDescription.cpp
@@ -882,6 +882,11 @@
return std::string(locale);
}
+std::string ConfigDescription::to_string() const {
+ const android::String8 str = toString();
+ return std::string(str.string(), str.size());
+}
+
bool ConfigDescription::Dominates(const ConfigDescription& o) const {
if (*this == o) {
return true;
diff --git a/tools/aapt2/ConfigDescription.h b/tools/aapt2/ConfigDescription.h
index c1d0e10..f719552 100644
--- a/tools/aapt2/ConfigDescription.h
+++ b/tools/aapt2/ConfigDescription.h
@@ -64,6 +64,8 @@
// Returns the BCP-47 language tag of this configuration's locale.
std::string GetBcp47LanguageTag(bool canonicalize = false) const;
+ std::string to_string() const;
+
/**
* A configuration X dominates another configuration Y, if X has at least the
* precedence of Y and X is strictly more general than Y: for any type defined
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 61c304b..08efc27 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -17,7 +17,6 @@
#include "Debug.h"
#include <algorithm>
-#include <iostream>
#include <map>
#include <memory>
#include <queue>
@@ -25,120 +24,244 @@
#include <vector>
#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
#include "ResourceTable.h"
#include "ResourceValues.h"
#include "ValueVisitor.h"
+#include "text/Printer.h"
#include "util/Util.h"
+using ::aapt::text::Printer;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
+
namespace aapt {
namespace {
-class PrintVisitor : public ConstValueVisitor {
+class ValueHeadlinePrinter : public ConstValueVisitor {
public:
using ConstValueVisitor::Visit;
+ explicit ValueHeadlinePrinter(const std::string& package, Printer* printer)
+ : package_(package), printer_(printer) {
+ }
+
void Visit(const Attribute* attr) override {
- std::cout << "(attr) type=";
- attr->PrintMask(&std::cout);
- static constexpr uint32_t kMask =
- android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
+ printer_->Print("(attr) type=");
+ printer_->Print(attr->MaskString());
+ if (!attr->symbols.empty()) {
+ printer_->Print(StringPrintf(" size=%zd", attr->symbols.size()));
+ }
+ }
+
+ void Visit(const Style* style) override {
+ printer_->Print(StringPrintf("(style) size=%zd", style->entries.size()));
+ if (style->parent) {
+ printer_->Print(" parent=");
+
+ const Reference& parent_ref = style->parent.value();
+ if (parent_ref.name) {
+ if (parent_ref.private_reference) {
+ printer_->Print("*");
+ }
+
+ const ResourceName& parent_name = parent_ref.name.value();
+ if (package_ != parent_name.package) {
+ printer_->Print(parent_name.package);
+ printer_->Print(":");
+ }
+ printer_->Print(to_string(parent_name.type));
+ printer_->Print("/");
+ printer_->Print(parent_name.entry);
+ if (parent_ref.id) {
+ printer_->Print(" (");
+ printer_->Print(parent_ref.id.value().to_string());
+ printer_->Print(")");
+ }
+ } else if (parent_ref.id) {
+ printer_->Print(parent_ref.id.value().to_string());
+ } else {
+ printer_->Print("???");
+ }
+ }
+ }
+
+ void Visit(const Array* array) override {
+ printer_->Print(StringPrintf("(array) size=%zd", array->elements.size()));
+ }
+
+ void Visit(const Plural* plural) override {
+ size_t count = std::count_if(plural->values.begin(), plural->values.end(),
+ [](const std::unique_ptr<Item>& v) { return v != nullptr; });
+ printer_->Print(StringPrintf("(plurals) size=%zd", count));
+ }
+
+ void Visit(const Styleable* styleable) override {
+ printer_->Println(StringPrintf("(styleable) size=%zd", styleable->entries.size()));
+ }
+
+ void VisitItem(const Item* item) override {
+ // Pretty much guaranteed to be one line.
+ if (const Reference* ref = ValueCast<Reference>(item)) {
+ // Special case Reference so that we can print local resources without a package name.
+ ref->PrettyPrint(package_, printer_);
+ } else {
+ item->PrettyPrint(printer_);
+ }
+ }
+
+ private:
+ std::string package_;
+ Printer* printer_;
+};
+
+class ValueBodyPrinter : public ConstValueVisitor {
+ public:
+ using ConstValueVisitor::Visit;
+
+ explicit ValueBodyPrinter(const std::string& package, Printer* printer)
+ : package_(package), printer_(printer) {
+ }
+
+ void Visit(const Attribute* attr) override {
+ constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
if (attr->type_mask & kMask) {
for (const auto& symbol : attr->symbols) {
- std::cout << "\n " << symbol.symbol.name.value().entry;
+ printer_->Print(symbol.symbol.name.value().entry);
if (symbol.symbol.id) {
- std::cout << " (" << symbol.symbol.id.value() << ")";
+ printer_->Print("(");
+ printer_->Print(symbol.symbol.id.value().to_string());
+ printer_->Print(")");
}
- std::cout << " = " << symbol.value;
+ printer_->Println(StringPrintf("=0x%08x", symbol.value));
}
}
}
void Visit(const Style* style) override {
- std::cout << "(style)";
- if (style->parent) {
- const Reference& parent_ref = style->parent.value();
- std::cout << " parent=";
- if (parent_ref.name) {
- if (parent_ref.private_reference) {
- std::cout << "*";
- }
- std::cout << parent_ref.name.value() << " ";
- }
-
- if (parent_ref.id) {
- std::cout << parent_ref.id.value();
- }
- }
-
for (const auto& entry : style->entries) {
- std::cout << "\n ";
if (entry.key.name) {
const ResourceName& name = entry.key.name.value();
- if (!name.package.empty()) {
- std::cout << name.package << ":";
+ if (!name.package.empty() && name.package != package_) {
+ printer_->Print(name.package);
+ printer_->Print(":");
}
- std::cout << name.entry;
+ printer_->Print(name.entry);
+
+ if (entry.key.id) {
+ printer_->Print("(");
+ printer_->Print(entry.key.id.value().to_string());
+ printer_->Print(")");
+ }
+ } else if (entry.key.id) {
+ printer_->Print(entry.key.id.value().to_string());
+ } else {
+ printer_->Print("???");
}
- if (entry.key.id) {
- std::cout << "(" << entry.key.id.value() << ")";
- }
-
- std::cout << "=" << *entry.value;
+ printer_->Print("=");
+ PrintItem(*entry.value);
+ printer_->Println();
}
}
void Visit(const Array* array) override {
- array->Print(&std::cout);
+ const size_t count = array->elements.size();
+ printer_->Print("[");
+ if (count > 0) {
+ for (size_t i = 0u; i < count; i++) {
+ if (i != 0u && i % 4u == 0u) {
+ printer_->Println();
+ printer_->Print(" ");
+ }
+ PrintItem(*array->elements[i]);
+ if (i != count - 1) {
+ printer_->Print(", ");
+ }
+ }
+ printer_->Println("]");
+ }
}
void Visit(const Plural* plural) override {
- plural->Print(&std::cout);
+ constexpr std::array<const char*, Plural::Count> kPluralNames = {
+ {"zero", "one", "two", "few", "many", "other"}};
+
+ for (size_t i = 0; i < Plural::Count; i++) {
+ if (plural->values[i] != nullptr) {
+ printer_->Print(StringPrintf("%s=", kPluralNames[i]));
+ PrintItem(*plural->values[i]);
+ printer_->Println();
+ }
+ }
}
void Visit(const Styleable* styleable) override {
- std::cout << "(styleable)";
for (const auto& attr : styleable->entries) {
- std::cout << "\n ";
if (attr.name) {
const ResourceName& name = attr.name.value();
- if (!name.package.empty()) {
- std::cout << name.package << ":";
+ if (!name.package.empty() && name.package != package_) {
+ printer_->Print(name.package);
+ printer_->Print(":");
}
- std::cout << name.entry;
+ printer_->Print(name.entry);
+
+ if (attr.id) {
+ printer_->Print("(");
+ printer_->Print(attr.id.value().to_string());
+ printer_->Print(")");
+ }
}
if (attr.id) {
- std::cout << "(" << attr.id.value() << ")";
+ printer_->Print(attr.id.value().to_string());
}
}
}
void VisitItem(const Item* item) override {
- item->Print(&std::cout);
+ // Intentionally left empty, we already printed the Items.
}
+
+ private:
+ void PrintItem(const Item& item) {
+ if (const Reference* ref = ValueCast<Reference>(&item)) {
+ // Special case Reference so that we can print local resources without a package name.
+ ref->PrettyPrint(package_, printer_);
+ } else {
+ item.PrettyPrint(printer_);
+ }
+ }
+
+ std::string package_;
+ Printer* printer_;
};
} // namespace
-void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options) {
- PrintVisitor visitor;
-
+void Debug::PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
+ Printer* printer) {
for (const auto& package : table.packages) {
- std::cout << "Package name=" << package->name;
- if (package->id) {
- std::cout << " id=" << std::hex << (int)package->id.value() << std::dec;
- }
- std::cout << std::endl;
+ ValueHeadlinePrinter headline_printer(package->name, printer);
+ ValueBodyPrinter body_printer(package->name, printer);
+ printer->Print("Package name=");
+ printer->Print(package->name);
+ if (package->id) {
+ printer->Print(StringPrintf(" id=%02x", package->id.value()));
+ }
+ printer->Println();
+
+ printer->Indent();
for (const auto& type : package->types) {
- std::cout << "\n type " << type->type;
+ printer->Print("type ");
+ printer->Print(to_string(type->type));
if (type->id) {
- std::cout << " id=" << std::hex << (int)type->id.value() << std::dec;
+ printer->Print(StringPrintf(" id=%02x", type->id.value()));
}
- std::cout << " entryCount=" << type->entries.size() << std::endl;
+ printer->Println(StringPrintf(" entryCount=%zd", type->entries.size()));
std::vector<const ResourceEntry*> sorted_entries;
for (const auto& entry : type->entries) {
@@ -156,35 +279,54 @@
sorted_entries.insert(iter, entry.get());
}
+ printer->Indent();
for (const ResourceEntry* entry : sorted_entries) {
const ResourceId id(package->id.value_or_default(0), type->id.value_or_default(0),
entry->id.value_or_default(0));
- const ResourceName name(package->name, type->type, entry->name);
- std::cout << " spec resource " << id << " " << name;
+ printer->Print("resource ");
+ printer->Print(id.to_string());
+ printer->Print(" ");
+
+ // Write the name without the package (this is obvious and too verbose).
+ printer->Print(to_string(type->type));
+ printer->Print("/");
+ printer->Print(entry->name);
+
switch (entry->symbol_status.state) {
case SymbolState::kPublic:
- std::cout << " PUBLIC";
+ printer->Print(" PUBLIC");
break;
case SymbolState::kPrivate:
- std::cout << " _PRIVATE_";
+ printer->Print(" _PRIVATE_");
break;
- default:
+ case SymbolState::kUndefined:
+ // Print nothing.
break;
}
- std::cout << std::endl;
+ printer->Println();
+ printer->Indent();
for (const auto& value : entry->values) {
- std::cout << " (" << value->config << ") ";
- value->value->Accept(&visitor);
+ printer->Print("(");
+ printer->Print(value->config.to_string());
+ printer->Print(") ");
+ value->value->Accept(&headline_printer);
if (options.show_sources && !value->value->GetSource().path.empty()) {
- std::cout << " src=" << value->value->GetSource();
+ printer->Print(" src=");
+ printer->Print(value->value->GetSource().to_string());
}
- std::cout << std::endl;
+ printer->Println();
+ printer->Indent();
+ value->value->Accept(&body_printer);
+ printer->Undent();
}
+ printer->Undent();
}
+ printer->Undent();
}
+ printer->Undent();
}
}
diff --git a/tools/aapt2/Debug.h b/tools/aapt2/Debug.h
index 296d04b..3c1ee4c 100644
--- a/tools/aapt2/Debug.h
+++ b/tools/aapt2/Debug.h
@@ -22,6 +22,7 @@
#include "Resource.h"
#include "ResourceTable.h"
+#include "text/Printer.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -31,9 +32,9 @@
};
struct Debug {
- static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options = {});
- static void PrintStyleGraph(ResourceTable* table,
- const ResourceName& target_style);
+ static void PrintTable(const ResourceTable& table, const DebugPrintTableOptions& options,
+ text::Printer* printer);
+ static void PrintStyleGraph(ResourceTable* table, const ResourceName& target_style);
static void DumpHex(const void* data, size_t len);
static void DumpXml(const xml::XmlResource& doc);
};
diff --git a/tools/aapt2/Resource.cpp b/tools/aapt2/Resource.cpp
index a9f5f29..b78f48c 100644
--- a/tools/aapt2/Resource.cpp
+++ b/tools/aapt2/Resource.cpp
@@ -17,13 +17,34 @@
#include "Resource.h"
#include <map>
+#include <sstream>
#include <string>
-using android::StringPiece;
+#include "android-base/stringprintf.h"
+
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
namespace aapt {
-StringPiece ToString(ResourceType type) {
+std::string ResourceId::to_string() const {
+ return StringPrintf("0x%08x", id);
+}
+
+std::string ResourceName::to_string() const {
+ return ResourceNameRef(*this).to_string();
+}
+
+std::string ResourceNameRef::to_string() const {
+ std::ostringstream str_stream;
+ if (!package.empty()) {
+ str_stream << package << ":";
+ }
+ str_stream << type << "/" << entry;
+ return str_stream.str();
+}
+
+StringPiece to_string(ResourceType type) {
switch (type) {
case ResourceType::kAnim:
return "anim";
diff --git a/tools/aapt2/Resource.h b/tools/aapt2/Resource.h
index 87b9867..96a0203 100644
--- a/tools/aapt2/Resource.h
+++ b/tools/aapt2/Resource.h
@@ -69,11 +69,10 @@
kXml,
};
-android::StringPiece ToString(ResourceType type);
+android::StringPiece to_string(ResourceType type);
/**
- * Returns a pointer to a valid ResourceType, or nullptr if
- * the string was invalid.
+ * Returns a pointer to a valid ResourceType, or nullptr if the string was invalid.
*/
const ResourceType* ParseResourceType(const android::StringPiece& str);
@@ -92,7 +91,7 @@
int compare(const ResourceName& other) const;
bool is_valid() const;
- std::string ToString() const;
+ std::string to_string() const;
};
/**
@@ -115,8 +114,10 @@
ResourceNameRef& operator=(ResourceNameRef&& rhs) = default;
ResourceNameRef& operator=(const ResourceName& rhs);
- ResourceName ToResourceName() const;
bool is_valid() const;
+
+ ResourceName ToResourceName() const;
+ std::string to_string() const;
};
constexpr const uint8_t kAppPackageId = 0x7fu;
@@ -149,6 +150,8 @@
uint8_t package_id() const;
uint8_t type_id() const;
uint16_t entry_id() const;
+
+ std::string to_string() const;
};
struct SourcedResourceName {
@@ -229,7 +232,9 @@
return (id & 0xff000000u) != 0 && (id & 0x00ff0000u) != 0;
}
-inline bool ResourceId::is_valid_dynamic() const { return (id & 0x00ff0000u) != 0; }
+inline bool ResourceId::is_valid_dynamic() const {
+ return (id & 0x00ff0000u) != 0;
+}
inline uint8_t ResourceId::package_id() const {
return static_cast<uint8_t>(id >> 24);
@@ -259,24 +264,16 @@
return lhs.id != rhs.id;
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceId& res_id) {
- std::ios_base::fmtflags old_flags = out.flags();
- char old_fill = out.fill();
- out << "0x" << std::internal << std::setfill('0') << std::setw(8) << std::hex
- << res_id.id;
- out.flags(old_flags);
- out.fill(old_fill);
- return out;
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceId& res_id) {
+ return out << res_id.to_string();
}
//
// ResourceType implementation.
//
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceType& val) {
- return out << ToString(val);
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceType& val) {
+ return out << to_string(val);
}
//
@@ -315,18 +312,8 @@
std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceName& name) {
- if (!name.package.empty()) {
- out << name.package << ":";
- }
- return out << name.type << "/" << name.entry;
-}
-
-inline std::string ResourceName::ToString() const {
- std::stringstream stream;
- stream << *this;
- return stream.str();
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceName& name) {
+ return out << name.to_string();
}
//
@@ -370,12 +357,8 @@
std::tie(rhs.package, rhs.type, rhs.entry);
}
-inline ::std::ostream& operator<<(::std::ostream& out,
- const ResourceNameRef& name) {
- if (!name.package.empty()) {
- out << name.package << ":";
- }
- return out << name.type << "/" << name.entry;
+inline ::std::ostream& operator<<(::std::ostream& out, const ResourceNameRef& name) {
+ return out << name.to_string();
}
inline bool operator<(const ResourceName& lhs, const ResourceNameRef& b) {
@@ -386,8 +369,7 @@
return ResourceNameRef(lhs) != rhs;
}
-inline bool operator==(const SourcedResourceName& lhs,
- const SourcedResourceName& rhs) {
+inline bool operator==(const SourcedResourceName& lhs, const SourcedResourceName& rhs) {
return lhs.name == rhs.name && lhs.line == rhs.line;
}
diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp
index 082fd86..b38d259 100644
--- a/tools/aapt2/ResourceValues.cpp
+++ b/tools/aapt2/ResourceValues.cpp
@@ -17,9 +17,12 @@
#include "ResourceValues.h"
#include <algorithm>
+#include <cinttypes>
#include <limits>
#include <set>
+#include <sstream>
+#include "android-base/stringprintf.h"
#include "androidfw/ResourceTypes.h"
#include "Resource.h"
@@ -27,8 +30,18 @@
#include "ValueVisitor.h"
#include "util/Util.h"
+using ::aapt::text::Printer;
+using ::android::StringPiece;
+using ::android::base::StringPrintf;
+
namespace aapt {
+void Value::PrettyPrint(Printer* printer) const {
+ std::ostringstream str_stream;
+ Print(&str_stream);
+ printer->Print(str_stream.str());
+}
+
std::ostream& operator<<(std::ostream& out, const Value& value) {
value.Print(&out);
return out;
@@ -155,6 +168,49 @@
}
}
+static void PrettyPrintReferenceImpl(const Reference& ref, bool print_package, Printer* printer) {
+ switch (ref.reference_type) {
+ case Reference::Type::kResource:
+ printer->Print("@");
+ break;
+
+ case Reference::Type::kAttribute:
+ printer->Print("?");
+ break;
+ }
+
+ if (!ref.name && !ref.id) {
+ printer->Print("null");
+ return;
+ }
+
+ if (ref.private_reference) {
+ printer->Print("*");
+ }
+
+ if (ref.name) {
+ const ResourceName& name = ref.name.value();
+ if (print_package) {
+ printer->Print(name.to_string());
+ } else {
+ printer->Print(to_string(name.type));
+ printer->Print("/");
+ printer->Print(name.entry);
+ }
+ } else if (ref.id && ref.id.value().is_valid_dynamic()) {
+ printer->Print(ref.id.value().to_string());
+ }
+}
+
+void Reference::PrettyPrint(Printer* printer) const {
+ PrettyPrintReferenceImpl(*this, true /*print_package*/, printer);
+}
+
+void Reference::PrettyPrint(const StringPiece& package, Printer* printer) const {
+ const bool print_package = name ? package != name.value().package : true;
+ PrettyPrintReferenceImpl(*this, print_package, printer);
+}
+
bool Id::Equals(const Value* value) const {
return ValueCast<Id>(value) != nullptr;
}
@@ -165,11 +221,16 @@
return true;
}
-Id* Id::Clone(StringPool* /*new_pool*/) const { return new Id(*this); }
+Id* Id::Clone(StringPool* /*new_pool*/) const {
+ return new Id(*this);
+}
-void Id::Print(std::ostream* out) const { *out << "(id)"; }
+void Id::Print(std::ostream* out) const {
+ *out << "(id)";
+}
-String::String(const StringPool::Ref& ref) : value(ref) {}
+String::String(const StringPool::Ref& ref) : value(ref) {
+}
bool String::Equals(const Value* value) const {
const String* other = ValueCast<String>(value);
@@ -218,7 +279,14 @@
*out << "(string) \"" << *value << "\"";
}
-StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {}
+void String::PrettyPrint(Printer* printer) const {
+ printer->Print("\"");
+ printer->Print(*value);
+ printer->Print("\"");
+}
+
+StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) {
+}
bool StyledString::Equals(const Value* value) const {
const StyledString* other = ValueCast<StyledString>(value);
@@ -269,7 +337,8 @@
}
}
-FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {}
+FileReference::FileReference(const StringPool::Ref& _path) : path(_path) {
+}
bool FileReference::Equals(const Value* value) const {
const FileReference* other = ValueCast<FileReference>(value);
@@ -302,7 +371,8 @@
*out << "(file) " << *path;
}
-BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {}
+BinaryPrimitive::BinaryPrimitive(const android::Res_value& val) : value(val) {
+}
BinaryPrimitive::BinaryPrimitive(uint8_t dataType, uint32_t data) {
value.dataType = dataType;
@@ -318,7 +388,7 @@
this->value.data == other->value.data;
}
-bool BinaryPrimitive::Flatten(android::Res_value* out_value) const {
+bool BinaryPrimitive::Flatten(::android::Res_value* out_value) const {
out_value->dataType = value.dataType;
out_value->data = util::HostToDevice32(value.data);
return true;
@@ -329,32 +399,110 @@
}
void BinaryPrimitive::Print(std::ostream* out) const {
+ *out << StringPrintf("(primitive) type=0x%02x data=0x%08x", value.dataType, value.data);
+}
+
+static std::string ComplexToString(uint32_t complex_value, bool fraction) {
+ using ::android::Res_value;
+
+ constexpr std::array<int, 4> kRadixShifts = {{23, 16, 8, 0}};
+
+ // Determine the radix that was used.
+ const uint32_t radix =
+ (complex_value >> Res_value::COMPLEX_RADIX_SHIFT) & Res_value::COMPLEX_RADIX_MASK;
+ const uint64_t mantissa = uint64_t{(complex_value >> Res_value::COMPLEX_MANTISSA_SHIFT) &
+ Res_value::COMPLEX_MANTISSA_MASK}
+ << kRadixShifts[radix];
+ const float value = mantissa * (1.0f / (1 << 23));
+
+ std::string str = StringPrintf("%f", value);
+
+ const int unit_type =
+ (complex_value >> Res_value::COMPLEX_UNIT_SHIFT) & Res_value::COMPLEX_UNIT_MASK;
+ if (fraction) {
+ switch (unit_type) {
+ case Res_value::COMPLEX_UNIT_FRACTION:
+ str += "%";
+ break;
+ case Res_value::COMPLEX_UNIT_FRACTION_PARENT:
+ str += "%p";
+ break;
+ default:
+ str += "???";
+ break;
+ }
+ } else {
+ switch (unit_type) {
+ case Res_value::COMPLEX_UNIT_PX:
+ str += "px";
+ break;
+ case Res_value::COMPLEX_UNIT_DIP:
+ str += "dp";
+ break;
+ case Res_value::COMPLEX_UNIT_SP:
+ str += "sp";
+ break;
+ case Res_value::COMPLEX_UNIT_PT:
+ str += "pt";
+ break;
+ case Res_value::COMPLEX_UNIT_IN:
+ str += "in";
+ break;
+ case Res_value::COMPLEX_UNIT_MM:
+ str += "mm";
+ break;
+ default:
+ str += "???";
+ break;
+ }
+ }
+ return str;
+}
+
+void BinaryPrimitive::PrettyPrint(Printer* printer) const {
+ using ::android::Res_value;
switch (value.dataType) {
- case android::Res_value::TYPE_NULL:
- if (value.data == android::Res_value::DATA_NULL_EMPTY) {
- *out << "(empty)";
+ case Res_value::TYPE_NULL:
+ if (value.data == Res_value::DATA_NULL_EMPTY) {
+ printer->Print("@empty");
} else {
- *out << "(null)";
+ printer->Print("@null");
}
break;
- case android::Res_value::TYPE_INT_DEC:
- *out << "(integer) " << static_cast<int32_t>(value.data);
+
+ case Res_value::TYPE_INT_DEC:
+ printer->Print(StringPrintf("%" PRIi32, static_cast<int32_t>(value.data)));
break;
- case android::Res_value::TYPE_INT_HEX:
- *out << "(integer) 0x" << std::hex << value.data << std::dec;
+
+ case Res_value::TYPE_INT_HEX:
+ printer->Print(StringPrintf("0x%08x", value.data));
break;
- case android::Res_value::TYPE_INT_BOOLEAN:
- *out << "(boolean) " << (value.data != 0 ? "true" : "false");
+
+ case Res_value::TYPE_INT_BOOLEAN:
+ printer->Print(value.data != 0 ? "true" : "false");
break;
- case android::Res_value::TYPE_INT_COLOR_ARGB8:
- case android::Res_value::TYPE_INT_COLOR_RGB8:
- case android::Res_value::TYPE_INT_COLOR_ARGB4:
- case android::Res_value::TYPE_INT_COLOR_RGB4:
- *out << "(color) #" << std::hex << value.data << std::dec;
+
+ case Res_value::TYPE_INT_COLOR_ARGB8:
+ case Res_value::TYPE_INT_COLOR_RGB8:
+ case Res_value::TYPE_INT_COLOR_ARGB4:
+ case Res_value::TYPE_INT_COLOR_RGB4:
+ printer->Print(StringPrintf("#%08x", value.data));
break;
+
+ case Res_value::TYPE_FLOAT:
+ printer->Print(StringPrintf("%g", *reinterpret_cast<const float*>(&value.data)));
+ break;
+
+ case Res_value::TYPE_DIMENSION:
+ printer->Print(ComplexToString(value.data, false /*fraction*/));
+ break;
+
+ case Res_value::TYPE_FRACTION:
+ printer->Print(ComplexToString(value.data, true /*fraction*/));
+ break;
+
default:
- *out << "(unknown 0x" << std::hex << (int)value.dataType << ") 0x"
- << std::hex << value.data << std::dec;
+ printer->Print(StringPrintf("(unknown 0x%02x) 0x%08x", value.dataType, value.data));
break;
}
}
@@ -424,107 +572,107 @@
return new Attribute(*this);
}
-void Attribute::PrintMask(std::ostream* out) const {
+std::string Attribute::MaskString() const {
if (type_mask == android::ResTable_map::TYPE_ANY) {
- *out << "any";
- return;
+ return "any";
}
+ std::ostringstream out;
bool set = false;
if ((type_mask & android::ResTable_map::TYPE_REFERENCE) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "reference";
+ out << "reference";
}
if ((type_mask & android::ResTable_map::TYPE_STRING) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "string";
+ out << "string";
}
if ((type_mask & android::ResTable_map::TYPE_INTEGER) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "integer";
+ out << "integer";
}
if ((type_mask & android::ResTable_map::TYPE_BOOLEAN) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "boolean";
+ out << "boolean";
}
if ((type_mask & android::ResTable_map::TYPE_COLOR) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "color";
+ out << "color";
}
if ((type_mask & android::ResTable_map::TYPE_FLOAT) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "float";
+ out << "float";
}
if ((type_mask & android::ResTable_map::TYPE_DIMENSION) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "dimension";
+ out << "dimension";
}
if ((type_mask & android::ResTable_map::TYPE_FRACTION) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "fraction";
+ out << "fraction";
}
if ((type_mask & android::ResTable_map::TYPE_ENUM) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "enum";
+ out << "enum";
}
if ((type_mask & android::ResTable_map::TYPE_FLAGS) != 0) {
if (!set) {
set = true;
} else {
- *out << "|";
+ out << "|";
}
- *out << "flags";
+ out << "flags";
}
+ return out.str();
}
void Attribute::Print(std::ostream* out) const {
- *out << "(attr) ";
- PrintMask(out);
+ *out << "(attr) " << MaskString();
if (!symbols.empty()) {
*out << " [" << util::Joiner(symbols, ", ") << "]";
diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h
index fd242a1..b2ec8bdd 100644
--- a/tools/aapt2/ResourceValues.h
+++ b/tools/aapt2/ResourceValues.h
@@ -29,6 +29,7 @@
#include "Resource.h"
#include "StringPool.h"
#include "io/File.h"
+#include "text/Printer.h"
#include "util/Maybe.h"
namespace aapt {
@@ -106,6 +107,10 @@
// Human readable printout of this value.
virtual void Print(std::ostream* out) const = 0;
+ // Human readable printout of this value that may omit some information for the sake
+ // of brevity and readability. Default implementation just calls Print().
+ virtual void PrettyPrint(text::Printer* printer) const;
+
friend std::ostream& operator<<(std::ostream& out, const Value& value);
protected:
@@ -162,6 +167,10 @@
bool Flatten(android::Res_value* out_value) const override;
Reference* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
+ void PrettyPrint(text::Printer* printer) const override;
+
+ // Prints the reference without a package name if the package name matches the one given.
+ void PrettyPrint(const android::StringPiece& package, text::Printer* printer) const;
};
bool operator<(const Reference&, const Reference&);
@@ -224,6 +233,7 @@
bool Flatten(android::Res_value* out_value) const override;
String* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
+ void PrettyPrint(text::Printer* printer) const override;
};
struct StyledString : public BaseItem<StyledString> {
@@ -274,6 +284,7 @@
bool Flatten(android::Res_value* out_value) const override;
BinaryPrimitive* Clone(StringPool* new_pool) const override;
void Print(std::ostream* out) const override;
+ void PrettyPrint(text::Printer* printer) const override;
};
struct Attribute : public BaseValue<Attribute> {
@@ -294,7 +305,7 @@
bool Equals(const Value* value) const override;
Attribute* Clone(StringPool* new_pool) const override;
- void PrintMask(std::ostream* out) const;
+ std::string MaskString() const;
void Print(std::ostream* out) const override;
bool Matches(const Item& item, DiagMessage* out_msg = nullptr) const;
};
diff --git a/tools/aapt2/Source.h b/tools/aapt2/Source.h
index d7f2a66..0f312d6 100644
--- a/tools/aapt2/Source.h
+++ b/tools/aapt2/Source.h
@@ -20,16 +20,14 @@
#include <ostream>
#include <string>
+#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
#include "util/Maybe.h"
namespace aapt {
-/**
- * Represents a file on disk. Used for logging and
- * showing errors.
- */
+// Represents a file on disk. Used for logging and showing errors.
struct Source {
std::string path;
Maybe<size_t> line;
@@ -42,7 +40,16 @@
inline Source(const android::StringPiece& path, size_t line)
: path(path.to_string()), line(line) {}
- inline Source WithLine(size_t line) const { return Source(path, line); }
+ inline Source WithLine(size_t line) const {
+ return Source(path, line);
+ }
+
+ std::string to_string() const {
+ if (line) {
+ return ::android::base::StringPrintf("%s:%zd", path.c_str(), line.value());
+ }
+ return path;
+ }
};
//
@@ -50,11 +57,7 @@
//
inline ::std::ostream& operator<<(::std::ostream& out, const Source& source) {
- out << source.path;
- if (source.line) {
- out << ":" << source.line.value();
- }
- return out;
+ return out << source.to_string();
}
inline bool operator==(const Source& lhs, const Source& rhs) {
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index bc8f1dc..bc7f5a8 100644
--- a/tools/aapt2/cmd/Dump.cpp
+++ b/tools/aapt2/cmd/Dump.cpp
@@ -14,8 +14,10 @@
* limitations under the License.
*/
+#include <cinttypes>
#include <vector>
+#include "android-base/stringprintf.h"
#include "androidfw/StringPiece.h"
#include "Debug.h"
@@ -27,9 +29,12 @@
#include "io/FileStream.h"
#include "io/ZipArchive.h"
#include "process/IResourceTableConsumer.h"
+#include "text/Printer.h"
#include "util/Files.h"
+using ::aapt::text::Printer;
using ::android::StringPiece;
+using ::android::base::StringPrintf;
namespace aapt {
@@ -48,16 +53,28 @@
}
static void DumpCompiledFile(const ResourceFile& file, const Source& source, off64_t offset,
- size_t len) {
- std::cout << "Resource: " << file.name << "\n"
- << "Config: " << file.config << "\n"
- << "Source: " << file.source << "\n"
- << "Type: " << ResourceFileTypeToString(file.type) << "\n"
- << "DataOff: " << offset << "\n"
- << "DataLen: " << len << "\n";
+ size_t len, Printer* printer) {
+ printer->Print("Resource: ");
+ printer->Println(file.name.to_string());
+
+ printer->Print("Config: ");
+ printer->Println(file.config.to_string());
+
+ printer->Print("Source: ");
+ printer->Println(file.source.to_string());
+
+ printer->Print("Type: ");
+ printer->Println(ResourceFileTypeToString(file.type));
+
+ printer->Println(StringPrintf("Data: offset=%" PRIi64 " length=%zd", offset, len));
}
static bool TryDumpFile(IAaptContext* context, const std::string& file_path) {
+ // Use a smaller buffer so that there is less latency for dumping to stdout.
+ constexpr size_t kStdOutBufferSize = 1024u;
+ io::FileOutputStream fout(STDOUT_FILENO, kStdOutBufferSize);
+ Printer printer(&fout);
+
DebugPrintTableOptions print_options;
print_options.show_sources = true;
@@ -83,6 +100,8 @@
<< "failed to parse table: " << err);
return false;
}
+
+ printer.Println("Proto APK");
} else if (io::IFile* file = zip->FindFile("resources.arsc")) {
std::unique_ptr<io::IData> data = file->OpenAsData();
if (!data) {
@@ -95,9 +114,11 @@
if (!parser.Parse()) {
return false;
}
+
+ printer.Println("Binary APK");
}
- Debug::PrintTable(table, print_options);
+ Debug::PrintTable(table, print_options, &printer);
return true;
}
@@ -118,9 +139,12 @@
return false;
}
+ printer.Println("AAPT2 Container (APC)");
ContainerReaderEntry* entry;
while ((entry = reader.Next()) != nullptr) {
if (entry->Type() == ContainerEntryType::kResTable) {
+ printer.Println("kResTable");
+
pb::ResourceTable pb_table;
if (!entry->GetResTable(&pb_table)) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
@@ -136,8 +160,11 @@
continue;
}
- Debug::PrintTable(table, print_options);
+ printer.Indent();
+ Debug::PrintTable(table, print_options, &printer);
+ printer.Undent();
} else if (entry->Type() == ContainerEntryType::kResFile) {
+ printer.Println("kResFile");
pb::internal::CompiledFile pb_compiled_file;
off64_t offset;
size_t length;
@@ -155,7 +182,9 @@
continue;
}
- DumpCompiledFile(file, Source(file_path), offset, length);
+ printer.Indent();
+ DumpCompiledFile(file, Source(file_path), offset, length, &printer);
+ printer.Undent();
}
}
return true;
diff --git a/tools/aapt2/compile/InlineXmlFormatParser.cpp b/tools/aapt2/compile/InlineXmlFormatParser.cpp
index 8b6c524..238e339 100644
--- a/tools/aapt2/compile/InlineXmlFormatParser.cpp
+++ b/tools/aapt2/compile/InlineXmlFormatParser.cpp
@@ -164,7 +164,7 @@
// Add the inline attribute to the parent.
parent_el->attributes.push_back(xml::Attribute{decl.attr_namespace_uri, decl.attr_name,
- "@" + new_doc->file.name.ToString()});
+ "@" + new_doc->file.name.to_string()});
// Delete the subtree.
for (auto iter = parent_el->children.begin(); iter != parent_el->children.end(); ++iter) {
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 66510b0..5078678 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -424,7 +424,7 @@
// We can ignore the value here.
return util::make_unique<Id>();
default:
- diag_->Error(DiagMessage() << "illegal map type '" << ToString(name.type) << "' ("
+ diag_->Error(DiagMessage() << "illegal map type '" << to_string(name.type) << "' ("
<< (int)name.type << ")");
break;
}
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 259f2e9..4a1b46c 100644
--- a/tools/aapt2/format/binary/TableFlattener.cpp
+++ b/tools/aapt2/format/binary/TableFlattener.cpp
@@ -472,7 +472,7 @@
expected_type_id++;
}
expected_type_id++;
- type_pool_.MakeRef(ToString(type->type));
+ type_pool_.MakeRef(to_string(type->type));
std::vector<ResourceEntry*> sorted_entries = CollectAndSortEntries(type);
if (sorted_entries.empty()) {
diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp
index 1d184fe..97ce01a 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -284,7 +284,7 @@
if (type->id) {
pb_type->mutable_type_id()->set_id(type->id.value());
}
- pb_type->set_name(ToString(type->type).to_string());
+ pb_type->set_name(to_string(type->type).to_string());
for (const std::unique_ptr<ResourceEntry>& entry : type->entries) {
pb::Entry* pb_entry = pb_type->add_entry();
@@ -328,7 +328,7 @@
pb_ref->set_id(ref.id.value_or_default(ResourceId(0x0)).id);
if (ref.name) {
- pb_ref->set_name(ref.name.value().ToString());
+ pb_ref->set_name(ref.name.value().to_string());
}
pb_ref->set_private_(ref.private_reference);
@@ -523,14 +523,14 @@
}
void SerializeCompiledFileToPb(const ResourceFile& file, pb::internal::CompiledFile* out_file) {
- out_file->set_resource_name(file.name.ToString());
+ out_file->set_resource_name(file.name.to_string());
out_file->set_source_path(file.source.path);
out_file->set_type(SerializeFileReferenceTypeToPb(file.type));
SerializeConfig(file.config, out_file->mutable_config());
for (const SourcedResourceName& exported : file.exported_symbols) {
pb::internal::CompiledFile_Symbol* pb_symbol = out_file->add_exported_symbol();
- pb_symbol->set_resource_name(exported.name.ToString());
+ pb_symbol->set_resource_name(exported.name.to_string());
pb_symbol->mutable_source()->set_line_number(exported.line);
}
}
diff --git a/tools/aapt2/io/FileStream.cpp b/tools/aapt2/io/FileStream.cpp
index 2f7a4b3..4ff6d78 100644
--- a/tools/aapt2/io/FileStream.cpp
+++ b/tools/aapt2/io/FileStream.cpp
@@ -26,6 +26,7 @@
#include "android-base/utf8.h"
using ::android::base::SystemErrorCodeToString;
+using ::android::base::unique_fd;
namespace aapt {
namespace io {
@@ -100,7 +101,13 @@
}
FileOutputStream::FileOutputStream(const std::string& path, int mode, size_t buffer_capacity)
- : FileOutputStream(::android::base::utf8::open(path.c_str(), mode), buffer_capacity) {
+ : FileOutputStream(unique_fd(::android::base::utf8::open(path.c_str(), mode)),
+ buffer_capacity) {
+}
+
+FileOutputStream::FileOutputStream(unique_fd fd, size_t buffer_capacity)
+ : FileOutputStream(fd.get(), buffer_capacity) {
+ owned_fd_ = std::move(fd);
}
FileOutputStream::FileOutputStream(int fd, size_t buffer_capacity)
@@ -118,7 +125,7 @@
}
bool FileOutputStream::Next(void** data, size_t* size) {
- if (fd_ == -1 || HadError()) {
+ if (HadError()) {
return false;
}
@@ -159,7 +166,8 @@
ssize_t n = TEMP_FAILURE_RETRY(write(fd_, buffer_.get(), buffer_offset_));
if (n < 0) {
error_ = SystemErrorCodeToString(errno);
- fd_.reset();
+ owned_fd_.reset();
+ fd_ = -1;
buffer_.reset();
return false;
}
diff --git a/tools/aapt2/io/FileStream.h b/tools/aapt2/io/FileStream.h
index 3b07667..4ed1ad5 100644
--- a/tools/aapt2/io/FileStream.h
+++ b/tools/aapt2/io/FileStream.h
@@ -29,12 +29,15 @@
namespace aapt {
namespace io {
+constexpr size_t kDefaultBufferCapacity = 4096u;
+
class FileInputStream : public InputStream {
public:
- explicit FileInputStream(const std::string& path, size_t buffer_capacity = 4096);
+ explicit FileInputStream(const std::string& path,
+ size_t buffer_capacity = kDefaultBufferCapacity);
- // Takes ownership of `fd`.
- explicit FileInputStream(int fd, size_t buffer_capacity = 4096);
+ // Take ownership of `fd`.
+ explicit FileInputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
bool Next(const void** data, size_t* size) override;
@@ -61,10 +64,14 @@
class FileOutputStream : public OutputStream {
public:
explicit FileOutputStream(const std::string& path, int mode = O_RDWR | O_CREAT | O_BINARY,
- size_t buffer_capacity = 4096);
+ size_t buffer_capacity = kDefaultBufferCapacity);
+
+ // Does not take ownership of `fd`.
+ explicit FileOutputStream(int fd, size_t buffer_capacity = kDefaultBufferCapacity);
// Takes ownership of `fd`.
- explicit FileOutputStream(int fd, size_t buffer_capacity = 4096);
+ explicit FileOutputStream(android::base::unique_fd fd,
+ size_t buffer_capacity = kDefaultBufferCapacity);
~FileOutputStream();
@@ -86,7 +93,8 @@
bool FlushImpl();
- android::base::unique_fd fd_;
+ android::base::unique_fd owned_fd_;
+ int fd_;
std::string error_;
std::unique_ptr<uint8_t[]> buffer_;
size_t buffer_capacity_;
diff --git a/tools/aapt2/io/FileStream_test.cpp b/tools/aapt2/io/FileStream_test.cpp
index 68c3cb1..a6d58ca 100644
--- a/tools/aapt2/io/FileStream_test.cpp
+++ b/tools/aapt2/io/FileStream_test.cpp
@@ -87,10 +87,8 @@
const std::string input = "this is a cool string";
TemporaryFile file;
- int fd = file.release();
- // FileOutputStream takes ownership.
- FileOutputStream out(fd, 10u);
+ FileOutputStream out(file.fd, 10u);
ASSERT_FALSE(out.HadError());
EXPECT_THAT(out.ByteCount(), Eq(0u));
@@ -118,10 +116,10 @@
ASSERT_TRUE(out.Flush());
- lseek64(fd, 0, SEEK_SET);
+ lseek64(file.fd, 0, SEEK_SET);
std::string actual;
- ASSERT_TRUE(android::base::ReadFdToString(fd, &actual));
+ ASSERT_TRUE(android::base::ReadFdToString(file.fd, &actual));
EXPECT_THAT(actual, StrEq(input));
}
diff --git a/tools/aapt2/io/Util.cpp b/tools/aapt2/io/Util.cpp
index d270340..7ee1016 100644
--- a/tools/aapt2/io/Util.cpp
+++ b/tools/aapt2/io/Util.cpp
@@ -18,6 +18,7 @@
#include "google/protobuf/io/zero_copy_stream_impl_lite.h"
+using ::android::StringPiece;
using ::google::protobuf::io::ZeroCopyOutputStream;
namespace aapt {
@@ -93,6 +94,25 @@
return !in->HadError();
}
+bool Copy(OutputStream* out, const StringPiece& in) {
+ const char* in_buffer = in.data();
+ size_t in_len = in.size();
+ while (in_len != 0) {
+ void* out_buffer;
+ size_t out_len;
+ if (!out->Next(&out_buffer, &out_len)) {
+ return false;
+ }
+
+ const size_t bytes_to_copy = in_len < out_len ? in_len : out_len;
+ memcpy(out_buffer, in_buffer, bytes_to_copy);
+ out->BackUp(out_len - bytes_to_copy);
+ in_buffer += bytes_to_copy;
+ in_len -= bytes_to_copy;
+ }
+ return true;
+}
+
bool Copy(ZeroCopyOutputStream* out, InputStream* in) {
OutputStreamAdaptor adaptor(out);
return Copy(&adaptor, in);
diff --git a/tools/aapt2/io/Util.h b/tools/aapt2/io/Util.h
index 1e48508..de2ab39 100644
--- a/tools/aapt2/io/Util.h
+++ b/tools/aapt2/io/Util.h
@@ -42,6 +42,7 @@
// Copies the data from in to out. Returns false if there was an error.
// If there was an error, check the individual streams' HadError/GetError methods.
bool Copy(OutputStream* out, InputStream* in);
+bool Copy(OutputStream* out, const ::android::StringPiece& in);
bool Copy(::google::protobuf::io::ZeroCopyOutputStream* out, InputStream* in);
class OutputStreamAdaptor : public io::OutputStream {
diff --git a/tools/aapt2/java/JavaClassGenerator.cpp b/tools/aapt2/java/JavaClassGenerator.cpp
index 3ba4dd8..91cef64 100644
--- a/tools/aapt2/java/JavaClassGenerator.cpp
+++ b/tools/aapt2/java/JavaClassGenerator.cpp
@@ -461,7 +461,7 @@
}
if (out_rewrite_method != nullptr) {
- const StringPiece& type_str = ToString(name.type);
+ const StringPiece& type_str = to_string(name.type);
out_rewrite_method->AppendStatement(StringPrintf("%s.%s = (%s.%s & 0x00ffffff) | (p << 24);",
type_str.data(), field_name.data(),
type_str.data(), field_name.data()));
@@ -584,7 +584,7 @@
(options_.types == JavaClassGeneratorOptions::SymbolTypes::kPublic);
std::unique_ptr<ClassDefinition> class_def = util::make_unique<ClassDefinition>(
- ToString(type->type), ClassQualifier::kStatic, force_creation_if_empty);
+ to_string(type->type), ClassQualifier::kStatic, force_creation_if_empty);
if (!ProcessType(package_name_to_generate, *package, *type, class_def.get(),
rewrite_method.get(), out_r_txt)) {
return false;
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 6fb1793..de4fb73 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -127,9 +127,9 @@
diag->Error(DiagMessage(el->line_number)
<< "attribute 'package' in <manifest> tag must not be a reference");
return false;
- } else if (!util::IsJavaPackageName(attr->value)) {
+ } else if (!util::IsAndroidPackageName(attr->value)) {
diag->Error(DiagMessage(el->line_number)
- << "attribute 'package' in <manifest> tag is not a valid Java package name: '"
+ << "attribute 'package' in <manifest> tag is not a valid Android package name: '"
<< attr->value << "'");
return false;
}
diff --git a/tools/aapt2/process/SymbolTable.cpp b/tools/aapt2/process/SymbolTable.cpp
index 882a85b..2d517c7 100644
--- a/tools/aapt2/process/SymbolTable.cpp
+++ b/tools/aapt2/process/SymbolTable.cpp
@@ -289,7 +289,7 @@
const android::ResTable& table = assets_.getResources(false);
const std::u16string package16 = util::Utf8ToUtf16(name.package);
- const std::u16string type16 = util::Utf8ToUtf16(ToString(name.type));
+ const std::u16string type16 = util::Utf8ToUtf16(to_string(name.type));
const std::u16string entry16 = util::Utf8ToUtf16(name.entry);
uint32_t type_spec_flags = 0;
diff --git a/tools/aapt2/text/Printer.cpp b/tools/aapt2/text/Printer.cpp
new file mode 100644
index 0000000..38b3585
--- /dev/null
+++ b/tools/aapt2/text/Printer.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2017 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 "text/Printer.h"
+
+#include <algorithm>
+
+#include "io/Util.h"
+
+using ::aapt::io::OutputStream;
+using ::android::StringPiece;
+
+namespace aapt {
+namespace text {
+
+void Printer::Println(const StringPiece& str) {
+ Print(str);
+ Print("\n");
+}
+
+void Printer::Println() {
+ Print("\n");
+}
+
+void Printer::Print(const StringPiece& str) {
+ if (error_) {
+ return;
+ }
+
+ auto remaining_str_begin = str.begin();
+ const auto remaining_str_end = str.end();
+ while (remaining_str_end != remaining_str_begin) {
+ // Find the next new-line.
+ const auto new_line_iter = std::find(remaining_str_begin, remaining_str_end, '\n');
+
+ // We will copy the string up until the next new-line (or end of string).
+ const StringPiece str_to_copy = str.substr(remaining_str_begin, new_line_iter);
+ if (!str_to_copy.empty()) {
+ if (needs_indent_) {
+ for (int i = 0; i < indent_level_; i++) {
+ if (!io::Copy(out_, " ")) {
+ error_ = true;
+ return;
+ }
+ }
+ needs_indent_ = false;
+ }
+
+ if (!io::Copy(out_, str_to_copy)) {
+ error_ = true;
+ return;
+ }
+ }
+
+ // If we found a new-line.
+ if (new_line_iter != remaining_str_end) {
+ if (!io::Copy(out_, "\n")) {
+ error_ = true;
+ return;
+ }
+ needs_indent_ = true;
+ // Ok to increment iterator here because we know that the '\n' character is one byte.
+ remaining_str_begin = new_line_iter + 1;
+ } else {
+ remaining_str_begin = new_line_iter;
+ }
+ }
+}
+
+void Printer::Indent() {
+ ++indent_level_;
+}
+
+void Printer::Undent() {
+ --indent_level_;
+}
+
+} // namespace text
+} // namespace aapt
diff --git a/tools/aapt2/text/Printer.h b/tools/aapt2/text/Printer.h
new file mode 100644
index 0000000..94b3c0b
--- /dev/null
+++ b/tools/aapt2/text/Printer.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef AAPT_TEXT_PRINTER_H
+#define AAPT_TEXT_PRINTER_H
+
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
+#include "io/Io.h"
+
+namespace aapt {
+namespace text {
+
+// An indenting Printer that helps write formatted text to the OutputStream.
+class Printer {
+ public:
+ explicit Printer(::aapt::io::OutputStream* out) : out_(out) {
+ }
+
+ void Print(const ::android::StringPiece& str);
+ void Println(const ::android::StringPiece& str);
+ void Println();
+
+ void Indent();
+ void Undent();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Printer);
+
+ ::aapt::io::OutputStream* out_;
+ int indent_level_ = 0;
+ bool needs_indent_ = false;
+ bool error_ = false;
+};
+
+} // namespace text
+} // namespace aapt
+
+#endif // AAPT_TEXT_PRINTER_H
diff --git a/tools/aapt2/text/Printer_test.cpp b/tools/aapt2/text/Printer_test.cpp
new file mode 100644
index 0000000..58beae7
--- /dev/null
+++ b/tools/aapt2/text/Printer_test.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2017 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 "text/Printer.h"
+
+#include "io/StringStream.h"
+#include "test/Test.h"
+
+using ::aapt::io::StringOutputStream;
+using ::android::StringPiece;
+using ::testing::StrEq;
+
+namespace aapt {
+namespace text {
+
+TEST(PrinterTest, PrintsToStreamWithIndents) {
+ std::string result;
+ StringOutputStream out(&result);
+ Printer printer(&out);
+
+ printer.Print("Hello");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello"));
+
+ printer.Println();
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n"));
+
+ // This shouldn't print anything yet.
+ printer.Indent();
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n"));
+
+ // Now we should see the indent.
+ printer.Print("world!");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world!"));
+
+ printer.Println(" What a\nlovely day.");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\n"));
+
+ // This shouldn't print anything yet.
+ printer.Undent();
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\n"));
+
+ printer.Println("Isn't it?");
+ out.Flush();
+ EXPECT_THAT(result, StrEq("Hello\n world! What a\n lovely day.\nIsn't it?\n"));
+}
+
+} // namespace text
+} // namespace aapt
diff --git a/tools/aapt2/text/Unicode.cpp b/tools/aapt2/text/Unicode.cpp
index 75eeb46..3735b3e 100644
--- a/tools/aapt2/text/Unicode.cpp
+++ b/tools/aapt2/text/Unicode.cpp
@@ -85,7 +85,8 @@
return false;
}
- if (!IsXidStart(iter.Next())) {
+ const char32_t first_codepoint = iter.Next();
+ if (!IsXidStart(first_codepoint) && first_codepoint != U'_' && first_codepoint != U'$') {
return false;
}
diff --git a/tools/aapt2/text/Unicode_test.cpp b/tools/aapt2/text/Unicode_test.cpp
index d47fb28..a8e797c 100644
--- a/tools/aapt2/text/Unicode_test.cpp
+++ b/tools/aapt2/text/Unicode_test.cpp
@@ -44,10 +44,11 @@
TEST(UnicodeTest, IsJavaIdentifier) {
EXPECT_TRUE(IsJavaIdentifier("FøøBar_12"));
EXPECT_TRUE(IsJavaIdentifier("Føø$Bar"));
+ EXPECT_TRUE(IsJavaIdentifier("_FøøBar"));
+ EXPECT_TRUE(IsJavaIdentifier("$Føø$Bar"));
EXPECT_FALSE(IsJavaIdentifier("12FøøBar"));
- EXPECT_FALSE(IsJavaIdentifier("_FøøBar"));
- EXPECT_FALSE(IsJavaIdentifier("$Føø$Bar"));
+ EXPECT_FALSE(IsJavaIdentifier(".Hello"));
}
TEST(UnicodeTest, IsValidResourceEntryName) {
diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp
index a9b49d9..e42145d 100644
--- a/tools/aapt2/util/Util.cpp
+++ b/tools/aapt2/util/Util.cpp
@@ -24,6 +24,7 @@
#include "androidfw/StringPiece.h"
#include "utils/Unicode.h"
+#include "text/Unicode.h"
#include "text/Utf8Iterator.h"
#include "util/BigBuffer.h"
#include "util/Maybe.h"
@@ -94,72 +95,55 @@
return StringPiece(start, end - start);
}
-StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
- const StringPiece& str, const StringPiece& allowed_chars) {
- const auto end_iter = str.end();
- for (auto iter = str.begin(); iter != end_iter; ++iter) {
- char c = *iter;
- if ((c >= u'a' && c <= u'z') || (c >= u'A' && c <= u'Z') ||
- (c >= u'0' && c <= u'9')) {
- continue;
- }
-
- bool match = false;
- for (char i : allowed_chars) {
- if (c == i) {
- match = true;
- break;
- }
- }
-
- if (!match) {
- return iter;
+static int IsJavaNameImpl(const StringPiece& str) {
+ int pieces = 0;
+ for (const StringPiece& piece : Tokenize(str, '.')) {
+ pieces++;
+ if (!text::IsJavaIdentifier(piece)) {
+ return -1;
}
}
- return end_iter;
+ return pieces;
}
bool IsJavaClassName(const StringPiece& str) {
- size_t pieces = 0;
- for (const StringPiece& piece : Tokenize(str, '.')) {
- pieces++;
- if (piece.empty()) {
- return false;
- }
-
- // Can't have starting or trailing $ character.
- if (piece.data()[0] == '$' || piece.data()[piece.size() - 1] == '$') {
- return false;
- }
-
- if (FindNonAlphaNumericAndNotInSet(piece, "$_") != piece.end()) {
- return false;
- }
- }
- return pieces >= 2;
+ return IsJavaNameImpl(str) >= 2;
}
bool IsJavaPackageName(const StringPiece& str) {
- if (str.empty()) {
- return false;
- }
+ return IsJavaNameImpl(str) >= 1;
+}
- size_t pieces = 0;
+static int IsAndroidNameImpl(const StringPiece& str) {
+ int pieces = 0;
for (const StringPiece& piece : Tokenize(str, '.')) {
- pieces++;
if (piece.empty()) {
- return false;
+ return -1;
}
- if (piece.data()[0] == '_' || piece.data()[piece.size() - 1] == '_') {
- return false;
+ const char first_character = piece.data()[0];
+ if (!::isalpha(first_character)) {
+ return -1;
}
- if (FindNonAlphaNumericAndNotInSet(piece, "_") != piece.end()) {
- return false;
+ bool valid = std::all_of(piece.begin() + 1, piece.end(), [](const char c) -> bool {
+ return ::isalnum(c) || c == '_';
+ });
+
+ if (!valid) {
+ return -1;
}
+ pieces++;
}
- return pieces >= 1;
+ return pieces;
+}
+
+bool IsAndroidPackageName(const StringPiece& str) {
+ return IsAndroidNameImpl(str) > 1 || str == "android";
+}
+
+bool IsAndroidSplitName(const StringPiece& str) {
+ return IsAndroidNameImpl(str) > 0;
}
Maybe<std::string> GetFullyQualifiedClassName(const StringPiece& package,
@@ -176,7 +160,7 @@
return {};
}
- std::string result(package.data(), package.size());
+ std::string result = package.to_string();
if (classname.data()[0] != '.') {
result += '.';
}
diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h
index c928458..7c949b90 100644
--- a/tools/aapt2/util/Util.h
+++ b/tools/aapt2/util/Util.h
@@ -53,48 +53,40 @@
std::vector<std::string> Split(const android::StringPiece& str, char sep);
std::vector<std::string> SplitAndLowercase(const android::StringPiece& str, char sep);
-/**
- * Returns true if the string starts with prefix.
- */
+// Returns true if the string starts with prefix.
bool StartsWith(const android::StringPiece& str, const android::StringPiece& prefix);
-/**
- * Returns true if the string ends with suffix.
- */
+// Returns true if the string ends with suffix.
bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix);
-/**
- * Creates a new StringPiece16 that points to a substring
- * of the original string without leading or trailing whitespace.
- */
+// Creates a new StringPiece16 that points to a substring of the original string without leading or
+// trailing whitespace.
android::StringPiece TrimWhitespace(const android::StringPiece& str);
-/**
- * Returns an iterator to the first character that is not alpha-numeric and that
- * is not in the allowedChars set.
- */
-android::StringPiece::const_iterator FindNonAlphaNumericAndNotInSet(
- const android::StringPiece& str, const android::StringPiece& allowed_chars);
-
-/**
- * Tests that the string is a valid Java class name.
- */
+// Tests that the string is a valid Java class name.
bool IsJavaClassName(const android::StringPiece& str);
-/**
- * Tests that the string is a valid Java package name.
- */
+// Tests that the string is a valid Java package name.
bool IsJavaPackageName(const android::StringPiece& str);
-/**
- * Converts the class name to a fully qualified class name from the given
- * `package`. Ex:
- *
- * asdf --> package.asdf
- * .asdf --> package.asdf
- * .a.b --> package.a.b
- * asdf.adsf --> asdf.adsf
- */
+// Tests that the string is a valid Android package name. More strict than a Java package name.
+// - First character of each component (separated by '.') must be an ASCII letter.
+// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
+// - Package must contain at least two components, unless it is 'android'.
+bool IsAndroidPackageName(const android::StringPiece& str);
+
+// Tests that the string is a valid Android split name.
+// - First character of each component (separated by '.') must be an ASCII letter.
+// - Subsequent characters of a component can be ASCII alphanumeric or an underscore.
+bool IsAndroidSplitName(const android::StringPiece& str);
+
+// Converts the class name to a fully qualified class name from the given
+// `package`. Ex:
+//
+// asdf --> package.asdf
+// .asdf --> package.asdf
+// .a.b --> package.a.b
+// asdf.adsf --> asdf.adsf
Maybe<std::string> GetFullyQualifiedClassName(const android::StringPiece& package,
const android::StringPiece& class_name);
@@ -108,23 +100,17 @@
return 0;
}
-/**
- * Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
- * This will be present in C++14 and can be removed then.
- */
+// Makes a std::unique_ptr<> with the template parameter inferred by the compiler.
+// This will be present in C++14 and can be removed then.
template <typename T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
}
-/**
- * Writes a set of items to the std::ostream, joining the times with the
- * provided
- * separator.
- */
+// Writes a set of items to the std::ostream, joining the times with the provided separator.
template <typename Container>
-::std::function<::std::ostream&(::std::ostream&)> Joiner(
- const Container& container, const char* sep) {
+::std::function<::std::ostream&(::std::ostream&)> Joiner(const Container& container,
+ const char* sep) {
using std::begin;
using std::end;
const auto begin_iter = begin(container);
@@ -140,32 +126,19 @@
};
}
-/**
- * Helper method to extract a UTF-16 string from a StringPool. If the string is
- * stored as UTF-8,
- * the conversion to UTF-16 happens within ResStringPool.
- */
+// Helper method to extract a UTF-16 string from a StringPool. If the string is stored as UTF-8,
+// the conversion to UTF-16 happens within ResStringPool.
android::StringPiece16 GetString16(const android::ResStringPool& pool, size_t idx);
-/**
- * Helper method to extract a UTF-8 string from a StringPool. If the string is
- * stored as UTF-16,
- * the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is
- * done by this method,
- * which maintains no state or cache. This means we must return an std::string
- * copy.
- */
+// Helper method to extract a UTF-8 string from a StringPool. If the string is stored as UTF-16,
+// the conversion from UTF-16 to UTF-8 does not happen in ResStringPool and is done by this method,
+// which maintains no state or cache. This means we must return an std::string copy.
std::string GetString(const android::ResStringPool& pool, size_t idx);
-/**
- * Checks that the Java string format contains no non-positional arguments
- * (arguments without
- * explicitly specifying an index) when there are more than one argument. This
- * is an error
- * because translations may rearrange the order of the arguments in the string,
- * which will
- * break the string interpolation.
- */
+// Checks that the Java string format contains no non-positional arguments (arguments without
+// explicitly specifying an index) when there are more than one argument. This is an error
+// because translations may rearrange the order of the arguments in the string, which will
+// break the string interpolation.
bool VerifyJavaStringFormat(const android::StringPiece& str);
class StringBuilder {
@@ -194,36 +167,38 @@
std::string error_;
};
-inline const std::string& StringBuilder::ToString() const { return str_; }
+inline const std::string& StringBuilder::ToString() const {
+ return str_;
+}
-inline const std::string& StringBuilder::Error() const { return error_; }
+inline const std::string& StringBuilder::Error() const {
+ return error_;
+}
-inline bool StringBuilder::IsEmpty() const { return str_.empty(); }
+inline bool StringBuilder::IsEmpty() const {
+ return str_.empty();
+}
-inline size_t StringBuilder::Utf16Len() const { return utf16_len_; }
+inline size_t StringBuilder::Utf16Len() const {
+ return utf16_len_;
+}
-inline StringBuilder::operator bool() const { return error_.empty(); }
+inline StringBuilder::operator bool() const {
+ return error_.empty();
+}
-/**
- * Converts a UTF8 string to a UTF16 string.
- */
+// Converts a UTF8 string to a UTF16 string.
std::u16string Utf8ToUtf16(const android::StringPiece& utf8);
std::string Utf16ToUtf8(const android::StringPiece16& utf16);
-/**
- * Writes the entire BigBuffer to the output stream.
- */
+// Writes the entire BigBuffer to the output stream.
bool WriteAll(std::ostream& out, const BigBuffer& buffer);
-/*
- * Copies the entire BigBuffer into a single buffer.
- */
+// Copies the entire BigBuffer into a single buffer.
std::unique_ptr<uint8_t[]> Copy(const BigBuffer& buffer);
-/**
- * A Tokenizer implemented as an iterable collection. It does not allocate
- * any memory on the heap nor use standard containers.
- */
+// A Tokenizer implemented as an iterable collection. It does not allocate any memory on the heap
+// nor use standard containers.
class Tokenizer {
public:
class iterator {
@@ -269,38 +244,42 @@
const iterator end_;
};
-inline Tokenizer Tokenize(const android::StringPiece& str, char sep) { return Tokenizer(str, sep); }
+inline Tokenizer Tokenize(const android::StringPiece& str, char sep) {
+ return Tokenizer(str, sep);
+}
-inline uint16_t HostToDevice16(uint16_t value) { return htods(value); }
+inline uint16_t HostToDevice16(uint16_t value) {
+ return htods(value);
+}
-inline uint32_t HostToDevice32(uint32_t value) { return htodl(value); }
+inline uint32_t HostToDevice32(uint32_t value) {
+ return htodl(value);
+}
-inline uint16_t DeviceToHost16(uint16_t value) { return dtohs(value); }
+inline uint16_t DeviceToHost16(uint16_t value) {
+ return dtohs(value);
+}
-inline uint32_t DeviceToHost32(uint32_t value) { return dtohl(value); }
+inline uint32_t DeviceToHost32(uint32_t value) {
+ return dtohl(value);
+}
-/**
- * Given a path like: res/xml-sw600dp/foo.xml
- *
- * Extracts "res/xml-sw600dp/" into outPrefix.
- * Extracts "foo" into outEntry.
- * Extracts ".xml" into outSuffix.
- *
- * Returns true if successful.
- */
+// Given a path like: res/xml-sw600dp/foo.xml
+//
+// Extracts "res/xml-sw600dp/" into outPrefix.
+// Extracts "foo" into outEntry.
+// Extracts ".xml" into outSuffix.
+//
+// Returns true if successful.
bool ExtractResFilePathParts(const android::StringPiece& path, android::StringPiece* out_prefix,
android::StringPiece* out_entry, android::StringPiece* out_suffix);
} // namespace util
-/**
- * Stream operator for functions. Calls the function with the stream as an
- * argument.
- * In the aapt namespace for lookup.
- */
-inline ::std::ostream& operator<<(
- ::std::ostream& out,
- const ::std::function<::std::ostream&(::std::ostream&)>& f) {
+// Stream operator for functions. Calls the function with the stream as an argument.
+// In the aapt namespace for lookup.
+inline ::std::ostream& operator<<(::std::ostream& out,
+ const ::std::function<::std::ostream&(::std::ostream&)>& f) {
return f(out);
}
diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp
index adb5291..2d1242a 100644
--- a/tools/aapt2/util/Util_test.cpp
+++ b/tools/aapt2/util/Util_test.cpp
@@ -117,24 +117,46 @@
EXPECT_TRUE(util::IsJavaClassName("android.test.Class$Inner"));
EXPECT_TRUE(util::IsJavaClassName("android_test.test.Class"));
EXPECT_TRUE(util::IsJavaClassName("_android_.test._Class_"));
- EXPECT_FALSE(util::IsJavaClassName("android.test.$Inner"));
- EXPECT_FALSE(util::IsJavaClassName("android.test.Inner$"));
+ EXPECT_TRUE(util::IsJavaClassName("android.test.$Inner"));
+ EXPECT_TRUE(util::IsJavaClassName("android.test.Inner$"));
+ EXPECT_TRUE(util::IsJavaClassName("com.foo.FøøBar"));
+
EXPECT_FALSE(util::IsJavaClassName(".test.Class"));
EXPECT_FALSE(util::IsJavaClassName("android"));
+ EXPECT_FALSE(util::IsJavaClassName("FooBar"));
}
TEST(UtilTest, IsJavaPackageName) {
EXPECT_TRUE(util::IsJavaPackageName("android"));
EXPECT_TRUE(util::IsJavaPackageName("android.test"));
EXPECT_TRUE(util::IsJavaPackageName("android.test_thing"));
- EXPECT_FALSE(util::IsJavaPackageName("_android"));
- EXPECT_FALSE(util::IsJavaPackageName("android_"));
+ EXPECT_TRUE(util::IsJavaPackageName("_android"));
+ EXPECT_TRUE(util::IsJavaPackageName("android_"));
+ EXPECT_TRUE(util::IsJavaPackageName("android._test"));
+ EXPECT_TRUE(util::IsJavaPackageName("cøm.foo"));
+
EXPECT_FALSE(util::IsJavaPackageName("android."));
EXPECT_FALSE(util::IsJavaPackageName(".android"));
- EXPECT_FALSE(util::IsJavaPackageName("android._test"));
EXPECT_FALSE(util::IsJavaPackageName(".."));
}
+TEST(UtilTest, IsAndroidPackageName) {
+ EXPECT_TRUE(util::IsAndroidPackageName("android"));
+ EXPECT_TRUE(util::IsAndroidPackageName("android.test"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo.test_thing"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo.testing_thing_"));
+ EXPECT_TRUE(util::IsAndroidPackageName("com.foo.test_99_"));
+
+ EXPECT_FALSE(util::IsAndroidPackageName("android._test"));
+ EXPECT_FALSE(util::IsAndroidPackageName("com"));
+ EXPECT_FALSE(util::IsAndroidPackageName("_android"));
+ EXPECT_FALSE(util::IsAndroidPackageName("android."));
+ EXPECT_FALSE(util::IsAndroidPackageName(".android"));
+ EXPECT_FALSE(util::IsAndroidPackageName(".."));
+ EXPECT_FALSE(util::IsAndroidPackageName("cøm.foo"));
+}
+
TEST(UtilTest, FullyQualifiedClassName) {
EXPECT_THAT(util::GetFullyQualifiedClassName("android", ".asdf"), Eq("android.asdf"));
EXPECT_THAT(util::GetFullyQualifiedClassName("android", ".a.b"), Eq("android.a.b"));
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index a367b23..bf8fed1 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -348,6 +348,9 @@
* quotation marks. Otherwise, it is returned as a string of hex digits. The
* SSID may be <unknown ssid> if there is no network currently connected,
* or if the caller has insufficient permissions to access the SSID.
+ *
+ * Prior to {@link android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}, this method
+ * always returned the SSID with no quotes around it.
* @return the SSID
*/
public String getSSID() {