Merge "Add DISALLOW_CONFIG_LOCALE user restriction"
diff --git a/Android.bp b/Android.bp
index c89cc40..5c1ccb7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,6 +47,7 @@
srcs: [
"core/proto/**/*.proto",
"libs/incident/**/*.proto",
+ "tools/streaming_proto/stream.proto",
],
},
android: {
@@ -61,7 +62,7 @@
"core/proto/android/os/pagetypeinfo.proto",
"core/proto/android/os/procrank.proto",
"core/proto/android/service/graphicsstats.proto",
- "libs/incident/proto/android/privacy.proto",
+ "tools/streaming_proto/stream.proto",
],
shared: {
enabled: false,
@@ -70,6 +71,27 @@
},
}
+gensrcs {
+ name: "gen-platform-proto-constants",
+ depfile: true,
+
+ tools: [
+ "aprotoc",
+ "protoc-gen-cppstream",
+ ],
+
+ srcs: [
+ "core/proto/android/os/kernelwake.proto",
+ "core/proto/android/os/pagetypeinfo.proto",
+ "core/proto/android/os/procrank.proto",
+ ],
+
+ // Append protoc-gen-cppstream tool's PATH otherwise aprotoc can't find the plugin tool
+ cmd: "PATH=$$PATH:$$(dirname $(location protoc-gen-cppstream)) $(location aprotoc) --plugin=protoc-gen-cpp-stream=$(location protoc-gen-cppstream) --dependency_out=$(depfile) --cppstream_out=$(genDir)/ -Iexternal/protobuf/src -I . $(in)",
+
+ output_extension = "proto.h",
+}
+
subdirs = [
"cmds/*",
"core/*",
diff --git a/Android.mk b/Android.mk
index 9843f17..c4f222e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -218,6 +218,7 @@
core/java/android/hardware/location/IGeofenceHardwareMonitorCallback.aidl \
core/java/android/hardware/location/IContextHubCallback.aidl \
core/java/android/hardware/location/IContextHubService.aidl \
+ core/java/android/hardware/location/IContextHubTransactionCallback.aidl \
core/java/android/hardware/radio/IRadioService.aidl \
core/java/android/hardware/radio/ITuner.aidl \
core/java/android/hardware/radio/ITunerCallback.aidl \
@@ -397,6 +398,7 @@
core/java/com/android/internal/backup/IObbBackupService.aidl \
core/java/com/android/internal/car/ICarServiceHelper.aidl \
core/java/com/android/internal/inputmethod/IInputContentUriToken.aidl \
+ core/java/com/android/internal/net/INetworkWatchlistManager.aidl \
core/java/com/android/internal/policy/IKeyguardDrawnCallback.aidl \
core/java/com/android/internal/policy/IKeyguardDismissCallback.aidl \
core/java/com/android/internal/policy/IKeyguardExitCallback.aidl \
@@ -1553,6 +1555,7 @@
-Iexternal/protobuf/src
LOCAL_SOURCE_FILES_ALL_GENERATED := true
LOCAL_SRC_FILES := \
+ tools/streaming_proto/stream.proto \
$(call all-proto-files-under, core/proto) \
$(call all-proto-files-under, libs/incident/proto)
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/api/current.txt b/api/current.txt
index dfd88f0..823cc3f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -484,6 +484,7 @@
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -6540,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
@@ -12016,6 +12018,7 @@
method public java.lang.String[] getColumnNames();
method public int getCount();
method public android.database.sqlite.SQLiteDatabase getDatabase();
+ method public void setFillWindowForwardOnly(boolean);
method public void setSelectionArguments(java.lang.String[]);
}
@@ -18270,13 +18273,11 @@
method public synchronized void applyLocalizedPattern(java.lang.String);
method public synchronized void applyPattern(java.lang.String);
method public synchronized boolean areSignificantDigitsUsed();
- method public synchronized boolean equals(java.lang.Object);
method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
- method public synchronized android.icu.util.Currency getCurrency();
method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -18284,12 +18285,8 @@
method public synchronized int getGroupingSize();
method public synchronized java.math.MathContext getMathContext();
method public synchronized android.icu.math.MathContext getMathContextICU();
- method public synchronized int getMaximumFractionDigits();
- method public synchronized int getMaximumIntegerDigits();
method public synchronized int getMaximumSignificantDigits();
method public synchronized byte getMinimumExponentDigits();
- method public synchronized int getMinimumFractionDigits();
- method public synchronized int getMinimumIntegerDigits();
method public synchronized int getMinimumSignificantDigits();
method public synchronized int getMultiplier();
method public synchronized java.lang.String getNegativePrefix();
@@ -18300,19 +18297,13 @@
method public synchronized java.lang.String getPositivePrefix();
method public synchronized java.lang.String getPositiveSuffix();
method public synchronized java.math.BigDecimal getRoundingIncrement();
- method public synchronized int getRoundingMode();
method public synchronized int getSecondaryGroupingSize();
- method public synchronized int hashCode();
method public synchronized boolean isDecimalPatternMatchRequired();
method public synchronized boolean isDecimalSeparatorAlwaysShown();
method public synchronized boolean isExponentSignAlwaysShown();
- method public synchronized boolean isGroupingUsed();
method public synchronized boolean isParseBigDecimal();
- method public synchronized boolean isParseIntegerOnly();
- method public synchronized boolean isParseStrict();
method public synchronized boolean isScientificNotation();
method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
- method public synchronized void setCurrency(android.icu.util.Currency);
method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -18321,15 +18312,10 @@
method public synchronized void setExponentSignAlwaysShown(boolean);
method public synchronized void setFormatWidth(int);
method public synchronized void setGroupingSize(int);
- method public synchronized void setGroupingUsed(boolean);
method public synchronized void setMathContext(java.math.MathContext);
method public synchronized void setMathContextICU(android.icu.math.MathContext);
- method public synchronized void setMaximumFractionDigits(int);
- method public synchronized void setMaximumIntegerDigits(int);
method public synchronized void setMaximumSignificantDigits(int);
method public synchronized void setMinimumExponentDigits(byte);
- method public synchronized void setMinimumFractionDigits(int);
- method public synchronized void setMinimumIntegerDigits(int);
method public synchronized void setMinimumSignificantDigits(int);
method public synchronized void setMultiplier(int);
method public synchronized void setNegativePrefix(java.lang.String);
@@ -18337,15 +18323,12 @@
method public synchronized void setPadCharacter(char);
method public synchronized void setPadPosition(int);
method public synchronized void setParseBigDecimal(boolean);
- method public synchronized void setParseIntegerOnly(boolean);
method public deprecated void setParseMaxDigits(int);
- method public synchronized void setParseStrict(boolean);
method public synchronized void setPositivePrefix(java.lang.String);
method public synchronized void setPositiveSuffix(java.lang.String);
method public synchronized void setRoundingIncrement(java.math.BigDecimal);
method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
method public synchronized void setRoundingIncrement(double);
- method public synchronized void setRoundingMode(int);
method public synchronized void setScientificNotation(boolean);
method public synchronized void setSecondaryGroupingSize(int);
method public synchronized void setSignificantDigitsUsed(boolean);
@@ -23026,8 +23009,9 @@
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer implements android.media.VolumeAutomation {
+ public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -23049,6 +23033,8 @@
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
method public android.media.MediaTimestamp getTimestamp();
@@ -23064,6 +23050,7 @@
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(long, int);
@@ -23100,6 +23087,7 @@
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackParams(android.media.PlaybackParams);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setSyncParams(android.media.SyncParams);
@@ -25834,7 +25822,6 @@
public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
method public void close();
- method protected void finalize();
method public int getSpi();
}
@@ -25989,6 +25976,7 @@
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -26019,7 +26007,7 @@
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
@@ -31028,6 +31016,7 @@
}
public final class Debug {
+ method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -32000,6 +31989,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
@@ -35190,6 +35180,7 @@
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
}
@@ -38441,6 +38432,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;
@@ -38510,7 +38511,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;
@@ -38535,7 +38537,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;
@@ -39924,6 +39927,7 @@
field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
+ field public static final java.lang.String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
@@ -40428,6 +40432,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";
@@ -40679,6 +40684,10 @@
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
+ field public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1
+ field public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2
+ field public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0
+ field public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff
field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4
field public static final int DATA_ACTIVITY_IN = 1; // 0x1
field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
@@ -44567,6 +44576,7 @@
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_ON_SUSPEND = 6; // 0x6
field public static final int STATE_UNKNOWN = 0; // 0x0
field public static final int STATE_VR = 5; // 0x5
}
@@ -48964,14 +48974,23 @@
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
+ public static final class TextClassification.Options {
+ ctor public TextClassification.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ }
+
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
- method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
- method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
+ 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;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
@@ -48980,6 +48999,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);
@@ -48994,6 +49043,12 @@
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
+ public static final class TextSelection.Options {
+ ctor public TextSelection.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+ }
+
}
package android.view.textservice {
diff --git a/api/system-current.txt b/api/system-current.txt
index 3f50dfde..76a12c5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -88,6 +88,7 @@
field public static final java.lang.String CAPTURE_SECURE_VIDEO_OUTPUT = "android.permission.CAPTURE_SECURE_VIDEO_OUTPUT";
field public static final java.lang.String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
field public static final java.lang.String CAPTURE_VIDEO_OUTPUT = "android.permission.CAPTURE_VIDEO_OUTPUT";
+ field public static final java.lang.String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
field public static final java.lang.String CHANGE_COMPONENT_ENABLED_STATE = "android.permission.CHANGE_COMPONENT_ENABLED_STATE";
field public static final java.lang.String CHANGE_CONFIGURATION = "android.permission.CHANGE_CONFIGURATION";
field public static final java.lang.String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
@@ -616,6 +617,7 @@
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -6786,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
@@ -7676,6 +7679,7 @@
method public java.util.List<android.app.usage.ConfigurationStats> queryConfigurations(int, long, long);
method public android.app.usage.UsageEvents queryEvents(long, long);
method public java.util.List<android.app.usage.UsageStats> queryUsageStats(int, long, long);
+ method public void setAppStandbyBucket(java.lang.String, int);
method public void whitelistAppTemporarily(java.lang.String, long, android.os.UserHandle);
field public static final int INTERVAL_BEST = 4; // 0x4
field public static final int INTERVAL_DAILY = 0; // 0x0
@@ -10234,6 +10238,7 @@
field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
field public static final java.lang.String EXTRA_QUICK_VIEW_FEATURES = "android.intent.extra.QUICK_VIEW_FEATURES";
field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
+ field public static final java.lang.String EXTRA_REASON = "android.intent.extra.REASON";
field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
@@ -12760,6 +12765,7 @@
method public java.lang.String[] getColumnNames();
method public int getCount();
method public android.database.sqlite.SQLiteDatabase getDatabase();
+ method public void setFillWindowForwardOnly(boolean);
method public void setSelectionArguments(java.lang.String[]);
}
@@ -19826,13 +19832,11 @@
method public synchronized void applyLocalizedPattern(java.lang.String);
method public synchronized void applyPattern(java.lang.String);
method public synchronized boolean areSignificantDigitsUsed();
- method public synchronized boolean equals(java.lang.Object);
method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
- method public synchronized android.icu.util.Currency getCurrency();
method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -19840,12 +19844,8 @@
method public synchronized int getGroupingSize();
method public synchronized java.math.MathContext getMathContext();
method public synchronized android.icu.math.MathContext getMathContextICU();
- method public synchronized int getMaximumFractionDigits();
- method public synchronized int getMaximumIntegerDigits();
method public synchronized int getMaximumSignificantDigits();
method public synchronized byte getMinimumExponentDigits();
- method public synchronized int getMinimumFractionDigits();
- method public synchronized int getMinimumIntegerDigits();
method public synchronized int getMinimumSignificantDigits();
method public synchronized int getMultiplier();
method public synchronized java.lang.String getNegativePrefix();
@@ -19856,19 +19856,13 @@
method public synchronized java.lang.String getPositivePrefix();
method public synchronized java.lang.String getPositiveSuffix();
method public synchronized java.math.BigDecimal getRoundingIncrement();
- method public synchronized int getRoundingMode();
method public synchronized int getSecondaryGroupingSize();
- method public synchronized int hashCode();
method public synchronized boolean isDecimalPatternMatchRequired();
method public synchronized boolean isDecimalSeparatorAlwaysShown();
method public synchronized boolean isExponentSignAlwaysShown();
- method public synchronized boolean isGroupingUsed();
method public synchronized boolean isParseBigDecimal();
- method public synchronized boolean isParseIntegerOnly();
- method public synchronized boolean isParseStrict();
method public synchronized boolean isScientificNotation();
method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
- method public synchronized void setCurrency(android.icu.util.Currency);
method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -19877,15 +19871,10 @@
method public synchronized void setExponentSignAlwaysShown(boolean);
method public synchronized void setFormatWidth(int);
method public synchronized void setGroupingSize(int);
- method public synchronized void setGroupingUsed(boolean);
method public synchronized void setMathContext(java.math.MathContext);
method public synchronized void setMathContextICU(android.icu.math.MathContext);
- method public synchronized void setMaximumFractionDigits(int);
- method public synchronized void setMaximumIntegerDigits(int);
method public synchronized void setMaximumSignificantDigits(int);
method public synchronized void setMinimumExponentDigits(byte);
- method public synchronized void setMinimumFractionDigits(int);
- method public synchronized void setMinimumIntegerDigits(int);
method public synchronized void setMinimumSignificantDigits(int);
method public synchronized void setMultiplier(int);
method public synchronized void setNegativePrefix(java.lang.String);
@@ -19893,15 +19882,12 @@
method public synchronized void setPadCharacter(char);
method public synchronized void setPadPosition(int);
method public synchronized void setParseBigDecimal(boolean);
- method public synchronized void setParseIntegerOnly(boolean);
method public deprecated void setParseMaxDigits(int);
- method public synchronized void setParseStrict(boolean);
method public synchronized void setPositivePrefix(java.lang.String);
method public synchronized void setPositiveSuffix(java.lang.String);
method public synchronized void setRoundingIncrement(java.math.BigDecimal);
method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
method public synchronized void setRoundingIncrement(double);
- method public synchronized void setRoundingMode(int);
method public synchronized void setScientificNotation(boolean);
method public synchronized void setSecondaryGroupingSize(int);
method public synchronized void setSignificantDigitsUsed(boolean);
@@ -24916,8 +24902,9 @@
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer implements android.media.VolumeAutomation {
+ public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -24939,6 +24926,8 @@
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
method public android.media.MediaTimestamp getTimestamp();
@@ -24954,6 +24943,7 @@
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(long, int);
@@ -24990,6 +24980,7 @@
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackParams(android.media.PlaybackParams);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setSyncParams(android.media.SyncParams);
@@ -28076,7 +28067,6 @@
public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
method public void close();
- method protected void finalize();
method public int getSpi();
}
@@ -28233,6 +28223,7 @@
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -28263,7 +28254,7 @@
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
@@ -33738,7 +33729,6 @@
field public static final java.lang.String ACTION_UPDATE_PINS = "android.intent.action.UPDATE_PINS";
field public static final java.lang.String ACTION_UPDATE_SMART_SELECTION = "android.intent.action.UPDATE_SMART_SELECTION";
field public static final java.lang.String ACTION_UPDATE_SMS_SHORT_CODES = "android.intent.action.UPDATE_SMS_SHORT_CODES";
- field public static final java.lang.String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
}
public abstract class CountDownTimer {
@@ -33767,6 +33757,7 @@
}
public final class Debug {
+ method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -34736,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 {
@@ -34850,6 +34842,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
@@ -38254,6 +38247,7 @@
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
}
@@ -41739,6 +41733,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;
@@ -41808,7 +41812,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;
@@ -41833,7 +41838,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;
@@ -43439,6 +43445,7 @@
field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
+ field public static final java.lang.String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
@@ -44301,6 +44308,10 @@
field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1
field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0
field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff
+ field public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1
+ field public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2
+ field public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0
+ field public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff
field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4
field public static final int DATA_ACTIVITY_IN = 1; // 0x1
field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
@@ -48300,6 +48311,7 @@
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_ON_SUSPEND = 6; // 0x6
field public static final int STATE_UNKNOWN = 0; // 0x0
field public static final int STATE_VR = 5; // 0x5
}
@@ -52701,14 +52713,23 @@
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
+ public static final class TextClassification.Options {
+ ctor public TextClassification.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ }
+
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
- method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
- method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
+ 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;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
@@ -52717,6 +52738,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);
@@ -52731,6 +52782,12 @@
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
+ public static final class TextSelection.Options {
+ ctor public TextSelection.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+ }
+
}
package android.view.textservice {
diff --git a/api/test-current.txt b/api/test-current.txt
index 0026bab..0cb6055 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -484,6 +484,7 @@
field public static final int detailSocialSummary = 16843428; // 0x10102a4
field public static final int detailsElementBackground = 16843598; // 0x101034e
field public static final int dial = 16843010; // 0x1010102
+ field public static final int dialogCornerRadius = 16844145; // 0x1010571
field public static final int dialogIcon = 16843252; // 0x10101f4
field public static final int dialogLayout = 16843255; // 0x10101f7
field public static final int dialogMessage = 16843251; // 0x10101f3
@@ -3873,6 +3874,7 @@
method public void resizeStack(int, android.graphics.Rect) throws java.lang.SecurityException;
method public deprecated void restartPackage(java.lang.String);
method public void setTaskWindowingMode(int, int, boolean) throws java.lang.SecurityException;
+ method public void setTaskWindowingModeSplitScreenPrimary(int, int, boolean, boolean, android.graphics.Rect) throws java.lang.SecurityException;
method public static void setVrThread(int);
method public void setWatchHeapLimit(long);
method public static boolean supportsMultiWindow(android.content.Context);
@@ -3886,6 +3888,8 @@
field public static final int MOVE_TASK_WITH_HOME = 1; // 0x1
field public static final int RECENT_IGNORE_UNAVAILABLE = 2; // 0x2
field public static final int RECENT_WITH_EXCLUDED = 1; // 0x1
+ field public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1; // 0x1
+ field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
}
public static class ActivityManager.AppTask {
@@ -6611,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
@@ -12103,6 +12108,7 @@
method public java.lang.String[] getColumnNames();
method public int getCount();
method public android.database.sqlite.SQLiteDatabase getDatabase();
+ method public void setFillWindowForwardOnly(boolean);
method public void setSelectionArguments(java.lang.String[]);
}
@@ -12303,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();
}
@@ -18412,13 +18419,11 @@
method public synchronized void applyLocalizedPattern(java.lang.String);
method public synchronized void applyPattern(java.lang.String);
method public synchronized boolean areSignificantDigitsUsed();
- method public synchronized boolean equals(java.lang.Object);
method public java.lang.StringBuffer format(double, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(long, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigInteger, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(java.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
method public java.lang.StringBuffer format(android.icu.math.BigDecimal, java.lang.StringBuffer, java.text.FieldPosition);
- method public synchronized android.icu.util.Currency getCurrency();
method public synchronized android.icu.text.CurrencyPluralInfo getCurrencyPluralInfo();
method public synchronized android.icu.util.Currency.CurrencyUsage getCurrencyUsage();
method public synchronized android.icu.text.DecimalFormatSymbols getDecimalFormatSymbols();
@@ -18426,12 +18431,8 @@
method public synchronized int getGroupingSize();
method public synchronized java.math.MathContext getMathContext();
method public synchronized android.icu.math.MathContext getMathContextICU();
- method public synchronized int getMaximumFractionDigits();
- method public synchronized int getMaximumIntegerDigits();
method public synchronized int getMaximumSignificantDigits();
method public synchronized byte getMinimumExponentDigits();
- method public synchronized int getMinimumFractionDigits();
- method public synchronized int getMinimumIntegerDigits();
method public synchronized int getMinimumSignificantDigits();
method public synchronized int getMultiplier();
method public synchronized java.lang.String getNegativePrefix();
@@ -18442,19 +18443,13 @@
method public synchronized java.lang.String getPositivePrefix();
method public synchronized java.lang.String getPositiveSuffix();
method public synchronized java.math.BigDecimal getRoundingIncrement();
- method public synchronized int getRoundingMode();
method public synchronized int getSecondaryGroupingSize();
- method public synchronized int hashCode();
method public synchronized boolean isDecimalPatternMatchRequired();
method public synchronized boolean isDecimalSeparatorAlwaysShown();
method public synchronized boolean isExponentSignAlwaysShown();
- method public synchronized boolean isGroupingUsed();
method public synchronized boolean isParseBigDecimal();
- method public synchronized boolean isParseIntegerOnly();
- method public synchronized boolean isParseStrict();
method public synchronized boolean isScientificNotation();
method public java.lang.Number parse(java.lang.String, java.text.ParsePosition);
- method public synchronized void setCurrency(android.icu.util.Currency);
method public synchronized void setCurrencyPluralInfo(android.icu.text.CurrencyPluralInfo);
method public synchronized void setCurrencyUsage(android.icu.util.Currency.CurrencyUsage);
method public synchronized void setDecimalFormatSymbols(android.icu.text.DecimalFormatSymbols);
@@ -18463,15 +18458,10 @@
method public synchronized void setExponentSignAlwaysShown(boolean);
method public synchronized void setFormatWidth(int);
method public synchronized void setGroupingSize(int);
- method public synchronized void setGroupingUsed(boolean);
method public synchronized void setMathContext(java.math.MathContext);
method public synchronized void setMathContextICU(android.icu.math.MathContext);
- method public synchronized void setMaximumFractionDigits(int);
- method public synchronized void setMaximumIntegerDigits(int);
method public synchronized void setMaximumSignificantDigits(int);
method public synchronized void setMinimumExponentDigits(byte);
- method public synchronized void setMinimumFractionDigits(int);
- method public synchronized void setMinimumIntegerDigits(int);
method public synchronized void setMinimumSignificantDigits(int);
method public synchronized void setMultiplier(int);
method public synchronized void setNegativePrefix(java.lang.String);
@@ -18479,15 +18469,12 @@
method public synchronized void setPadCharacter(char);
method public synchronized void setPadPosition(int);
method public synchronized void setParseBigDecimal(boolean);
- method public synchronized void setParseIntegerOnly(boolean);
method public deprecated void setParseMaxDigits(int);
- method public synchronized void setParseStrict(boolean);
method public synchronized void setPositivePrefix(java.lang.String);
method public synchronized void setPositiveSuffix(java.lang.String);
method public synchronized void setRoundingIncrement(java.math.BigDecimal);
method public synchronized void setRoundingIncrement(android.icu.math.BigDecimal);
method public synchronized void setRoundingIncrement(double);
- method public synchronized void setRoundingMode(int);
method public synchronized void setScientificNotation(boolean);
method public synchronized void setSecondaryGroupingSize(int);
method public synchronized void setSignificantDigitsUsed(boolean);
@@ -23226,8 +23213,9 @@
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
- public class MediaPlayer implements android.media.VolumeAutomation {
+ public class MediaPlayer implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public MediaPlayer();
+ method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(java.io.FileDescriptor, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -23249,6 +23237,8 @@
method public android.media.MediaDrm.KeyRequest getKeyRequest(byte[], byte[], java.lang.String, int, java.util.Map<java.lang.String, java.lang.String>) throws android.media.MediaPlayer.NoDrmSchemeException;
method public android.os.PersistableBundle getMetrics();
method public android.media.PlaybackParams getPlaybackParams();
+ method public android.media.AudioDeviceInfo getPreferredDevice();
+ method public android.media.AudioDeviceInfo getRoutedDevice();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.SyncParams getSyncParams();
method public android.media.MediaTimestamp getTimestamp();
@@ -23264,6 +23254,7 @@
method public byte[] provideKeyResponse(byte[], byte[]) throws android.media.DeniedByServerException, android.media.MediaPlayer.NoDrmSchemeException;
method public void release();
method public void releaseDrm() throws android.media.MediaPlayer.NoDrmSchemeException;
+ method public void removeOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener);
method public void reset();
method public void restoreKeys(byte[]) throws android.media.MediaPlayer.NoDrmSchemeException;
method public void seekTo(long, int);
@@ -23300,6 +23291,7 @@
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackParams(android.media.PlaybackParams);
+ method public boolean setPreferredDevice(android.media.AudioDeviceInfo);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setSyncParams(android.media.SyncParams);
@@ -26034,7 +26026,6 @@
public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
method public void close();
- method protected void finalize();
method public int getSpi();
}
@@ -26189,6 +26180,7 @@
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -26219,7 +26211,7 @@
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
@@ -31228,6 +31220,7 @@
}
public final class Debug {
+ method public static void attachJvmtiAgent(java.lang.String, java.lang.String) throws java.io.IOException;
method public static deprecated void changeDebugPort(int);
method public static void dumpHprofData(java.lang.String) throws java.io.IOException;
method public static boolean dumpService(java.lang.String, java.io.FileDescriptor, java.lang.String[]);
@@ -32097,13 +32090,13 @@
}
public static final class StrictMode.ViolationInfo implements android.os.Parcelable {
- ctor public StrictMode.ViolationInfo();
- ctor public StrictMode.ViolationInfo(java.lang.Throwable, int);
ctor public StrictMode.ViolationInfo(android.os.Parcel);
ctor public StrictMode.ViolationInfo(android.os.Parcel, boolean);
method public int describeContents();
method public void dump(android.util.Printer, java.lang.String);
+ method public int getPolicyMask();
method public java.lang.String getStackTrace();
+ method public int getViolationBit();
method public java.lang.String getViolationDetails();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.os.StrictMode.ViolationInfo> CREATOR;
@@ -32111,7 +32104,6 @@
field public int durationMillis;
field public int numAnimationsRunning;
field public long numInstances;
- field public final int policy;
field public java.lang.String[] tags;
field public int violationNumThisLoop;
field public long violationUptimeMillis;
@@ -32266,6 +32258,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
@@ -35460,6 +35453,7 @@
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_ENABLED = "android.settings.extra.do_not_disturb_mode_enabled";
field public static final java.lang.String EXTRA_DO_NOT_DISTURB_MODE_MINUTES = "android.settings.extra.do_not_disturb_mode_minutes";
field public static final java.lang.String EXTRA_INPUT_METHOD_ID = "input_method_id";
+ field public static final java.lang.String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final java.lang.String INTENT_CATEGORY_USAGE_ACCESS_CONFIG = "android.intent.category.USAGE_ACCESS_CONFIG";
field public static final java.lang.String METADATA_USAGE_ACCESS_REASON = "android.settings.metadata.USAGE_ACCESS_REASON";
}
@@ -35555,6 +35549,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";
@@ -37610,6 +37605,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);
@@ -37635,6 +37637,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();
@@ -37672,6 +37675,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);
@@ -38819,6 +38823,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;
@@ -38888,7 +38902,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;
@@ -38913,7 +38928,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;
@@ -40318,6 +40334,7 @@
field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array";
+ field public static final java.lang.String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_BOOL = "ci_action_on_sys_update_bool";
field public static final java.lang.String KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING = "ci_action_on_sys_update_extra_string";
@@ -40824,6 +40841,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";
@@ -41075,6 +41093,10 @@
field public static final int CALL_STATE_IDLE = 0; // 0x0
field public static final int CALL_STATE_OFFHOOK = 2; // 0x2
field public static final int CALL_STATE_RINGING = 1; // 0x1
+ field public static final int CDMA_ROAMING_MODE_AFFILIATED = 1; // 0x1
+ field public static final int CDMA_ROAMING_MODE_ANY = 2; // 0x2
+ field public static final int CDMA_ROAMING_MODE_HOME = 0; // 0x0
+ field public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1; // 0xffffffff
field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4
field public static final int DATA_ACTIVITY_IN = 1; // 0x1
field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3
@@ -41338,6 +41360,7 @@
}
public final class FileServiceInfo extends android.telephony.mbms.ServiceInfo implements android.os.Parcelable {
+ ctor public FileServiceInfo(java.util.Map<java.util.Locale, java.lang.String>, java.lang.String, java.util.List<java.util.Locale>, java.lang.String, java.util.Date, java.util.Date, java.util.List<android.telephony.mbms.FileInfo>);
method public int describeContents();
method public java.util.List<android.telephony.mbms.FileInfo> getFiles();
method public void writeToParcel(android.os.Parcel, int);
@@ -41446,6 +41469,22 @@
package android.telephony.mbms.vendor {
+ public class MbmsDownloadServiceBase extends android.os.Binder {
+ ctor public MbmsDownloadServiceBase();
+ method public int cancelDownload(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+ method public void dispose(int) throws android.os.RemoteException;
+ method public int download(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+ method public int getDownloadStatus(android.telephony.mbms.DownloadRequest, android.telephony.mbms.FileInfo) throws android.os.RemoteException;
+ method public int initialize(int, android.telephony.mbms.MbmsDownloadSessionCallback) throws android.os.RemoteException;
+ method public java.util.List<android.telephony.mbms.DownloadRequest> listPendingDownloads(int) throws android.os.RemoteException;
+ method public void onAppCallbackDied(int, int);
+ method public int registerStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
+ method public int requestUpdateFileServices(int, java.util.List<java.lang.String>) throws android.os.RemoteException;
+ method public int resetDownloadKnowledge(android.telephony.mbms.DownloadRequest) throws android.os.RemoteException;
+ method public int setTempFileRootDirectory(int, java.lang.String) throws android.os.RemoteException;
+ method public int unregisterStateCallback(android.telephony.mbms.DownloadRequest, android.telephony.mbms.DownloadStateCallback) throws android.os.RemoteException;
+ }
+
public class MbmsStreamingServiceBase extends android.os.Binder {
ctor public MbmsStreamingServiceBase();
method public void dispose(int) throws android.os.RemoteException;
@@ -44976,25 +45015,25 @@
field public static final long FIELD_COUNT_UNKNOWN = 0L; // 0x0L
field public static final int FIELD_ID_MASK = -8; // 0xfffffff8
field public static final int FIELD_ID_SHIFT = 3; // 0x3
- field public static final long FIELD_TYPE_BOOL = 55834574848L; // 0xd00000000L
- field public static final long FIELD_TYPE_BYTES = 64424509440L; // 0xf00000000L
+ field public static final long FIELD_TYPE_BOOL = 34359738368L; // 0x800000000L
+ field public static final long FIELD_TYPE_BYTES = 51539607552L; // 0xc00000000L
field public static final long FIELD_TYPE_DOUBLE = 4294967296L; // 0x100000000L
- field public static final long FIELD_TYPE_ENUM = 68719476736L; // 0x1000000000L
- field public static final long FIELD_TYPE_FIXED32 = 38654705664L; // 0x900000000L
- field public static final long FIELD_TYPE_FIXED64 = 42949672960L; // 0xa00000000L
+ field public static final long FIELD_TYPE_ENUM = 60129542144L; // 0xe00000000L
+ field public static final long FIELD_TYPE_FIXED32 = 30064771072L; // 0x700000000L
+ field public static final long FIELD_TYPE_FIXED64 = 25769803776L; // 0x600000000L
field public static final long FIELD_TYPE_FLOAT = 8589934592L; // 0x200000000L
- field public static final long FIELD_TYPE_INT32 = 12884901888L; // 0x300000000L
- field public static final long FIELD_TYPE_INT64 = 17179869184L; // 0x400000000L
+ field public static final long FIELD_TYPE_INT32 = 21474836480L; // 0x500000000L
+ field public static final long FIELD_TYPE_INT64 = 12884901888L; // 0x300000000L
field public static final long FIELD_TYPE_MASK = 1095216660480L; // 0xff00000000L
- field public static final long FIELD_TYPE_OBJECT = 73014444032L; // 0x1100000000L
- field public static final long FIELD_TYPE_SFIXED32 = 47244640256L; // 0xb00000000L
- field public static final long FIELD_TYPE_SFIXED64 = 51539607552L; // 0xc00000000L
+ field public static final long FIELD_TYPE_MESSAGE = 47244640256L; // 0xb00000000L
+ field public static final long FIELD_TYPE_SFIXED32 = 64424509440L; // 0xf00000000L
+ field public static final long FIELD_TYPE_SFIXED64 = 68719476736L; // 0x1000000000L
field public static final int FIELD_TYPE_SHIFT = 32; // 0x20
- field public static final long FIELD_TYPE_SINT32 = 30064771072L; // 0x700000000L
- field public static final long FIELD_TYPE_SINT64 = 34359738368L; // 0x800000000L
- field public static final long FIELD_TYPE_STRING = 60129542144L; // 0xe00000000L
- field public static final long FIELD_TYPE_UINT32 = 21474836480L; // 0x500000000L
- field public static final long FIELD_TYPE_UINT64 = 25769803776L; // 0x600000000L
+ field public static final long FIELD_TYPE_SINT32 = 73014444032L; // 0x1100000000L
+ field public static final long FIELD_TYPE_SINT64 = 77309411328L; // 0x1200000000L
+ field public static final long FIELD_TYPE_STRING = 38654705664L; // 0x900000000L
+ field public static final long FIELD_TYPE_UINT32 = 55834574848L; // 0xd00000000L
+ field public static final long FIELD_TYPE_UINT64 = 17179869184L; // 0x400000000L
field public static final long FIELD_TYPE_UNKNOWN = 0L; // 0x0L
field public static final java.lang.String TAG = "ProtoOutputStream";
field public static final int WIRE_TYPE_END_GROUP = 4; // 0x4
@@ -45160,6 +45199,7 @@
field public static final int STATE_DOZE_SUSPEND = 4; // 0x4
field public static final int STATE_OFF = 1; // 0x1
field public static final int STATE_ON = 2; // 0x2
+ field public static final int STATE_ON_SUSPEND = 6; // 0x6
field public static final int STATE_UNKNOWN = 0; // 0x0
field public static final int STATE_VR = 5; // 0x5
}
@@ -49582,14 +49622,23 @@
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
+ public static final class TextClassification.Options {
+ ctor public TextClassification.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextClassification.Options setDefaultLocales(android.os.LocaleList);
+ }
+
public final class TextClassificationManager {
method public android.view.textclassifier.TextClassifier getTextClassifier();
method public void setTextClassifier(android.view.textclassifier.TextClassifier);
}
public abstract interface TextClassifier {
- method public abstract android.view.textclassifier.TextClassification classifyText(java.lang.CharSequence, int, int, android.os.LocaleList);
- method public abstract android.view.textclassifier.TextSelection suggestSelection(java.lang.CharSequence, int, int, android.os.LocaleList);
+ 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;
field public static final java.lang.String TYPE_ADDRESS = "address";
field public static final java.lang.String TYPE_EMAIL = "email";
@@ -49598,6 +49647,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);
@@ -49612,6 +49691,12 @@
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
}
+ public static final class TextSelection.Options {
+ ctor public TextSelection.Options();
+ method public android.os.LocaleList getDefaultLocales();
+ method public android.view.textclassifier.TextSelection.Options setDefaultLocales(android.os.LocaleList);
+ }
+
}
package android.view.textservice {
diff --git a/cmds/am/proto/instrumentation_data.proto b/cmds/am/proto/instrumentation_data.proto
index 12a18a2..8e29f96 100644
--- a/cmds/am/proto/instrumentation_data.proto
+++ b/cmds/am/proto/instrumentation_data.proto
@@ -28,6 +28,7 @@
optional double value_double = 5;
optional sint64 value_long = 6;
optional ResultsBundle value_bundle = 7;
+ optional bytes value_bytes = 8;
}
message ResultsBundle {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 79e7fac..813335a 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -160,7 +160,11 @@
} else if (opt.equals("-r")) {
instrument.rawMode = true;
} else if (opt.equals("-m")) {
- instrument.proto = true;
+ instrument.protoStd = true;
+ } else if (opt.equals("-f")) {
+ instrument.protoFile = true;
+ if (peekNextArg() != null && !peekNextArg().startsWith("-"))
+ instrument.logPath = nextArg();
} else if (opt.equals("-e")) {
final String argKey = nextArgRequired();
final String argValue = nextArgRequired();
diff --git a/cmds/am/src/com/android/commands/am/Instrument.java b/cmds/am/src/com/android/commands/am/Instrument.java
index b69ef1c..93b9f58 100644
--- a/cmds/am/src/com/android/commands/am/Instrument.java
+++ b/cmds/am/src/com/android/commands/am/Instrument.java
@@ -25,23 +25,32 @@
import android.content.pm.InstrumentationInfo;
import android.os.Build;
import android.os.Bundle;
+import android.os.Environment;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.util.AndroidException;
import android.util.proto.ProtoOutputStream;
import android.view.IWindowManager;
+import java.io.File;
+import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.List;
+import java.util.Locale;
/**
* Runs the am instrument command
*/
public class Instrument {
+ public static final String DEFAULT_LOG_DIR = "instrument-logs";
+
private final IActivityManager mAm;
private final IPackageManager mPm;
private final IWindowManager mWm;
@@ -50,7 +59,9 @@
public String profileFile = null;
public boolean wait = false;
public boolean rawMode = false;
- public boolean proto = false;
+ boolean protoStd = false; // write proto to stdout
+ boolean protoFile = false; // write proto to a file
+ String logPath = null;
public boolean noWindowAnimation = false;
public String abi = null;
public int userId = UserHandle.USER_CURRENT;
@@ -178,18 +189,49 @@
* Printer for the protobuf based status reporting.
*/
private class ProtoStatusReporter implements StatusReporter {
+
+ private File mLog;
+
+ ProtoStatusReporter() {
+ if (protoFile) {
+ if (logPath == null) {
+ File logDir = new File(Environment.getLegacyExternalStorageDirectory(),
+ DEFAULT_LOG_DIR);
+ if (!logDir.exists() && !logDir.mkdirs()) {
+ System.err.format("Unable to create log directory: %s\n",
+ logDir.getAbsolutePath());
+ protoFile = false;
+ return;
+ }
+ SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd-hhmmss-SSS", Locale.US);
+ String fileName = String.format("log-%s.instrumentation_data_proto",
+ format.format(new Date()));
+ mLog = new File(logDir, fileName);
+ } else {
+ mLog = new File(Environment.getLegacyExternalStorageDirectory(), logPath);
+ File logDir = mLog.getParentFile();
+ if (!logDir.exists() && !logDir.mkdirs()) {
+ System.err.format("Unable to create log directory: %s\n",
+ logDir.getAbsolutePath());
+ protoFile = false;
+ return;
+ }
+ }
+ if (mLog.exists()) mLog.delete();
+ }
+ }
+
@Override
public void onInstrumentationStatusLocked(ComponentName name, int resultCode,
Bundle results) {
final ProtoOutputStream proto = new ProtoOutputStream();
- final long token = proto.startRepeatedObject(InstrumentationData.Session.TEST_STATUS);
-
- proto.writeSInt32(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
+ final long token = proto.start(InstrumentationData.Session.TEST_STATUS);
+ proto.write(InstrumentationData.TestStatus.RESULT_CODE, resultCode);
writeBundle(proto, InstrumentationData.TestStatus.RESULTS, results);
+ proto.end(token);
- proto.endRepeatedObject(token);
- writeProtoToStdout(proto);
+ outputProto(proto);
}
@Override
@@ -197,80 +239,87 @@
Bundle results) {
final ProtoOutputStream proto = new ProtoOutputStream();
- final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);
-
- proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
+ final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
+ proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
InstrumentationData.SESSION_FINISHED);
- proto.writeSInt32(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
+ proto.write(InstrumentationData.SessionStatus.RESULT_CODE, resultCode);
writeBundle(proto, InstrumentationData.SessionStatus.RESULTS, results);
+ proto.end(token);
- proto.endObject(token);
- writeProtoToStdout(proto);
+ outputProto(proto);
}
@Override
public void onError(String errorText, boolean commandError) {
final ProtoOutputStream proto = new ProtoOutputStream();
- final long token = proto.startObject(InstrumentationData.Session.SESSION_STATUS);
-
- proto.writeEnum(InstrumentationData.SessionStatus.STATUS_CODE,
+ final long token = proto.start(InstrumentationData.Session.SESSION_STATUS);
+ proto.write(InstrumentationData.SessionStatus.STATUS_CODE,
InstrumentationData.SESSION_ABORTED);
- proto.writeString(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
+ proto.write(InstrumentationData.SessionStatus.ERROR_TEXT, errorText);
+ proto.end(token);
- proto.endObject(token);
- writeProtoToStdout(proto);
+ outputProto(proto);
}
private void writeBundle(ProtoOutputStream proto, long fieldId, Bundle bundle) {
- final long bundleToken = proto.startObject(fieldId);
+ final long bundleToken = proto.start(fieldId);
for (final String key: sorted(bundle.keySet())) {
final long entryToken = proto.startRepeatedObject(
InstrumentationData.ResultsBundle.ENTRIES);
- proto.writeString(InstrumentationData.ResultsBundleEntry.KEY, key);
+ proto.write(InstrumentationData.ResultsBundleEntry.KEY, key);
final Object val = bundle.get(key);
if (val instanceof String) {
- proto.writeString(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_STRING,
(String)val);
} else if (val instanceof Byte) {
- proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT,
((Byte)val).intValue());
} else if (val instanceof Double) {
- proto.writeDouble(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE,
- ((Double)val).doubleValue());
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_DOUBLE, (double)val);
} else if (val instanceof Float) {
- proto.writeFloat(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT,
- ((Float)val).floatValue());
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_FLOAT, (float)val);
} else if (val instanceof Integer) {
- proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
- ((Integer)val).intValue());
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (int)val);
} else if (val instanceof Long) {
- proto.writeSInt64(InstrumentationData.ResultsBundleEntry.VALUE_LONG,
- ((Long)val).longValue());
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_LONG, (long)val);
} else if (val instanceof Short) {
- proto.writeSInt32(InstrumentationData.ResultsBundleEntry.VALUE_INT,
- ((Short)val).intValue());
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_INT, (short)val);
} else if (val instanceof Bundle) {
writeBundle(proto, InstrumentationData.ResultsBundleEntry.VALUE_BUNDLE,
(Bundle)val);
+ } else if (val instanceof byte[]) {
+ proto.write(InstrumentationData.ResultsBundleEntry.VALUE_BYTES, (byte[])val);
}
- proto.endRepeatedObject(entryToken);
+ proto.end(entryToken);
}
- proto.endObject(bundleToken);
+ proto.end(bundleToken);
}
- private void writeProtoToStdout(ProtoOutputStream proto) {
- try {
- System.out.write(proto.getBytes());
- System.out.flush();
- } catch (IOException ex) {
- System.err.println("Error writing finished response: ");
- ex.printStackTrace(System.err);
+ private void outputProto(ProtoOutputStream proto) {
+ byte[] out = proto.getBytes();
+ if (protoStd) {
+ try {
+ System.out.write(out);
+ System.out.flush();
+ } catch (IOException ex) {
+ System.err.println("Error writing finished response: ");
+ ex.printStackTrace(System.err);
+ }
+ }
+ if (protoFile) {
+ try (OutputStream os = new FileOutputStream(mLog, true)) {
+ os.write(proto.getBytes());
+ os.flush();
+ } catch (IOException ex) {
+ System.err.format("Cannot write to %s:\n", mLog.getAbsolutePath());
+ ex.printStackTrace();
+ }
}
}
}
@@ -374,7 +423,7 @@
try {
// Choose which output we will do.
- if (proto) {
+ if (protoFile || protoStd) {
reporter = new ProtoStatusReporter();
} else if (wait) {
reporter = new TextStatusReporter(rawMode);
@@ -396,7 +445,7 @@
mWm.setAnimationScale(2, 0.0f);
}
- // Figure out which component we are tring to do.
+ // Figure out which component we are trying to do.
final ComponentName cn = parseComponentName(componentNameArg);
// Choose an ABI if necessary
diff --git a/cmds/appwidget/appwidget b/cmds/appwidget/appwidget
index 6105009..26ab173 100755
--- a/cmds/appwidget/appwidget
+++ b/cmds/appwidget/appwidget
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "appwidget" on the device, which has a very rudimentary shell.
base=/system
export CLASSPATH=$base/framework/appwidget.jar
diff --git a/cmds/bmgr/bmgr b/cmds/bmgr/bmgr
index 6b4bbe2d..60b5833 100755
--- a/cmds/bmgr/bmgr
+++ b/cmds/bmgr/bmgr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "bmgr" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/bu/bu b/cmds/bu/bu
index e8dbc31..e50b53d 100755
--- a/cmds/bu/bu
+++ b/cmds/bu/bu
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "bu" on the device
#
base=/system
diff --git a/cmds/content/content b/cmds/content/content
index a8e056d..f1bfe17 100755
--- a/cmds/content/content
+++ b/cmds/content/content
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "content" on the device, which has a very rudimentary shell.
base=/system
export CLASSPATH=$base/framework/content.jar
diff --git a/cmds/dpm/dpm b/cmds/dpm/dpm
index c2e5cbb..e0efdc1 100755
--- a/cmds/dpm/dpm
+++ b/cmds/dpm/dpm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "dpm" on the device
#
base=/system
diff --git a/cmds/ime/ime b/cmds/ime/ime
index 96c56d3..1a1fdd9 100755
--- a/cmds/ime/ime
+++ b/cmds/ime/ime
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/incident_helper/Android.bp b/cmds/incident_helper/Android.bp
index 0532083..2ef0371 100644
--- a/cmds/incident_helper/Android.bp
+++ b/cmds/incident_helper/Android.bp
@@ -8,44 +8,53 @@
"-O0"
],
- srcs: [
- "IncidentHelper.cpp",
- "ih_util.cpp",
+ local_include_dirs: [
+ "src/",
+ "src/parsers/",
],
+ srcs: [
+ "src/parsers/*.cpp",
+ "src/TextParserBase.cpp",
+ "src/ih_util.cpp",
+ ],
+
+ generated_headers: ["gen-platform-proto-constants"],
+
shared_libs: [
"libbase",
"liblog",
- "libprotobuf-cpp-full",
+ "libprotoutil",
"libutils",
],
-
- static_libs: [
- "libplatformprotos",
- ],
}
cc_binary {
name: "incident_helper",
defaults: ["incident_helper_defaults"],
- srcs: ["main.cpp"],
+ srcs: ["src/main.cpp"],
}
cc_test {
name: "incident_helper_test",
defaults: ["incident_helper_defaults"],
+ local_include_dirs: ["src/"],
srcs: [
- "tests/IncidentHelper_test.cpp",
- "tests/ih_util_test.cpp",
+ "tests/*.cpp",
],
data: [
"testdata/*",
],
+ shared_libs: [
+ "libprotobuf-cpp-full",
+ ],
+
static_libs: [
"libgmock",
+ "libplatformprotos"
],
-}
\ No newline at end of file
+}
diff --git a/cmds/incident_helper/IncidentHelper.cpp b/cmds/incident_helper/IncidentHelper.cpp
deleted file mode 100644
index 7b06d42..0000000
--- a/cmds/incident_helper/IncidentHelper.cpp
+++ /dev/null
@@ -1,327 +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.
- */
-
-#define LOG_TAG "incident_helper"
-
-#include "IncidentHelper.h"
-#include "ih_util.h"
-
-#include "frameworks/base/core/proto/android/os/kernelwake.pb.h"
-#include "frameworks/base/core/proto/android/os/pagetypeinfo.pb.h"
-#include "frameworks/base/core/proto/android/os/procrank.pb.h"
-
-#include <android-base/file.h>
-#include <unistd.h>
-#include <string>
-#include <vector>
-
-using namespace android::base;
-using namespace android::os;
-using namespace google::protobuf;
-using namespace std;
-
-
-static const string TAB_DELIMITER = "\t";
-static const string COMMA_DELIMITER = ",";
-
-static inline int toInt(const string& s) {
- return atoi(s.c_str());
-}
-
-static inline long toLong(const string& s) {
- return atol(s.c_str());
-}
-
-/**
- * Sets the given protobuf message when the field name matches one of the
- * fields. It is useful to set values to proto from table-like plain texts.
- */
-static bool
-SetTableField(::google::protobuf::Message* message, string field_name, string field_value) {
- const Descriptor* descriptor = message->GetDescriptor();
- const Reflection* reflection = message->GetReflection();
-
- const FieldDescriptor* field = descriptor->FindFieldByName(field_name);
- switch (field->type()) {
- case FieldDescriptor::TYPE_STRING:
- reflection->SetString(message, field, field_value);
- return true;
- case FieldDescriptor::TYPE_INT64:
- reflection->SetInt64(message, field, toLong(field_value));
- return true;
- case FieldDescriptor::TYPE_UINT64:
- reflection->SetUInt64(message, field, toLong(field_value));
- return true;
- case FieldDescriptor::TYPE_INT32:
- reflection->SetInt32(message, field, toInt(field_value));
- return true;
- case FieldDescriptor::TYPE_UINT32:
- reflection->SetUInt32(message, field, toInt(field_value));
- return true;
- default:
- // Add new scalar types
- return false;
- }
-}
-
-// ================================================================================
-status_t NoopParser::Parse(const int in, const int out) const
-{
- string content;
- if (!ReadFdToString(in, &content)) {
- fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
- return -1;
- }
- if (!WriteStringToFd(content, out)) {
- fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
- return -1;
- }
- return NO_ERROR;
-}
-
-// ================================================================================
-status_t ReverseParser::Parse(const int in, const int out) const
-{
- string content;
- if (!ReadFdToString(in, &content)) {
- fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
- return -1;
- }
- // reverse the content
- reverse(content.begin(), content.end());
- if (!WriteStringToFd(content, out)) {
- fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
- return -1;
- }
- return NO_ERROR;
-}
-
-// ================================================================================
-status_t KernelWakesParser::Parse(const int in, const int out) const {
- Reader reader(in);
- string line;
- header_t header; // the header of /d/wakeup_sources
- record_t record; // retain each record
- int nline = 0;
-
- KernelWakeSources proto;
-
- // parse line by line
- while (reader.readLine(&line)) {
- if (line.empty()) continue;
- // parse head line
- if (nline++ == 0) {
- header = parseHeader(line, TAB_DELIMITER);
- continue;
- }
-
- // parse for each record, the line delimiter is \t only!
- record = parseRecord(line, TAB_DELIMITER);
-
- if (record.size() != header.size()) {
- // TODO: log this to incident report!
- fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline, line.c_str());
- continue;
- }
-
- WakeupSourceProto* source = proto.add_wakeup_sources();
- for (int i=0; i<(int)record.size(); i++) {
- if (!SetTableField(source, header[i], record[i])) {
- fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
- this->name.string(), nline, header[i].c_str(), record[i].c_str());
- }
- }
- }
-
- if (!reader.ok(&line)) {
- fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
- return -1;
- }
-
- if (!proto.SerializeToFileDescriptor(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
- return -1;
- }
- fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), proto.ByteSize());
- return NO_ERROR;
-}
-
-// ================================================================================
-status_t ProcrankParser::Parse(const int in, const int out) const {
- Reader reader(in);
- string line;
- header_t header; // the header of /d/wakeup_sources
- record_t record; // retain each record
- int nline = 0;
-
- Procrank proto;
-
- // parse line by line
- while (reader.readLine(&line)) {
- if (line.empty()) continue;
-
- // parse head line
- if (nline++ == 0) {
- header = parseHeader(line);
- continue;
- }
-
- if (hasPrefix(&line, "ZRAM:")) {
- proto.mutable_summary()->mutable_zram()->set_raw_text(line);
- continue;
- }
- if (hasPrefix(&line, "RAM:")) {
- proto.mutable_summary()->mutable_ram()->set_raw_text(line);
- continue;
- }
-
- record = parseRecord(line);
- if (record.size() != header.size()) {
- if (record[record.size() - 1] == "TOTAL") { // TOTAL record
- ProcessProto* total = proto.mutable_summary()->mutable_total();
- for (int i=1; i<=(int)record.size(); i++) {
- SetTableField(total, header[header.size() - i], record[record.size() - i]);
- }
- } else {
- fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline,
- line.c_str());
- }
- continue;
- }
-
- ProcessProto* process = proto.add_processes();
- for (int i=0; i<(int)record.size(); i++) {
- if (!SetTableField(process, header[i], record[i])) {
- fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
- this->name.string(), nline, header[i].c_str(), record[i].c_str());
- }
- }
- }
-
- if (!reader.ok(&line)) {
- fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
- return -1;
- }
-
- if (!proto.SerializeToFileDescriptor(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
- return -1;
- }
- fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), proto.ByteSize());
- return NO_ERROR;
-}
-
-// ================================================================================
-status_t PageTypeInfoParser::Parse(const int in, const int out) const {
- Reader reader(in);
- string line;
- bool migrateTypeSession = false;
- int pageBlockOrder;
- header_t blockHeader;
-
- PageTypeInfo pageTypeInfo;
-
- while (reader.readLine(&line)) {
- if (line.empty()) {
- migrateTypeSession = false;
- blockHeader.clear();
- continue;
- }
-
- if (hasPrefix(&line, "Page block order:")) {
- pageBlockOrder = toInt(line);
- pageTypeInfo.set_page_block_order(pageBlockOrder);
- continue;
- }
- if (hasPrefix(&line, "Pages per block:")) {
- pageTypeInfo.set_pages_per_block(toInt(line));
- continue;
- }
- if (hasPrefix(&line, "Free pages count per migrate type at order")) {
- migrateTypeSession = true;
- continue;
- }
- if (hasPrefix(&line, "Number of blocks type")) {
- blockHeader = parseHeader(line);
- continue;
- }
-
- record_t record = parseRecord(line, COMMA_DELIMITER);
- if (migrateTypeSession && record.size() == 3) {
- MigrateTypeProto* migrateType = pageTypeInfo.add_migrate_types();
- // expect part 0 starts with "Node"
- if (hasPrefix(&record[0], "Node")) {
- migrateType->set_node(toInt(record[0]));
- } else goto ERROR;
- // expect part 1 starts with "zone"
- if (hasPrefix(&record[1], "zone")) {
- migrateType->set_zone(record[1]);
- } else goto ERROR;
- // expect part 2 starts with "type"
- if (hasPrefix(&record[2], "type")) {
- // expect the rest of part 2 has number of (pageBlockOrder + 2) parts
- // An example looks like:
- // header line: type 0 1 2 3 4 5 6 7 8 9 10
- // record line: Unmovable 426 279 226 1 1 1 0 0 2 2 0
- // The pageBlockOrder = 10 and it's zero-indexed. so total parts
- // are 10 + 1(zero-indexed) + 1(the type part) = 12.
- record_t pageCounts = parseRecord(record[2]);
- int pageCountsSize = pageBlockOrder + 2;
- if ((int)pageCounts.size() != pageCountsSize) goto ERROR;
-
- migrateType->set_type(pageCounts[0]);
- for (auto i=1; i<pageCountsSize; i++) {
- migrateType->add_free_pages_count(toInt(pageCounts[i]));
- }
- } else goto ERROR;
- continue;
- }
-
- if (!blockHeader.empty() && record.size() == 2) {
- BlockProto* block = pageTypeInfo.add_blocks();
-
- if (hasPrefix(&record[0], "Node")) {
- block->set_node(toInt(record[0]));
- } else goto ERROR;
-
- if (hasPrefix(&record[1], "zone")) {
- record_t blockCounts = parseRecord(record[1]);
- block->set_zone(blockCounts[0]);
- for (size_t i=0; i<blockHeader.size(); i++) {
- if (!SetTableField(block, blockHeader[i], blockCounts[i+1])) goto ERROR;
- }
- } else goto ERROR;
-
- continue;
- }
-
-ERROR: // print out error for this single line and continue parsing
- fprintf(stderr, "[%s]Bad line: %s\n", this->name.string(), line.c_str());
- }
-
- if (!reader.ok(&line)) {
- fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
- return -1;
- }
-
- if (!pageTypeInfo.SerializeToFileDescriptor(out)) {
- fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
- return -1;
- }
-
- fprintf(stderr, "[%s]Proto size: %d bytes\n", this->name.string(), pageTypeInfo.ByteSize());
- return NO_ERROR;
-}
diff --git a/cmds/incident_helper/src/TextParserBase.cpp b/cmds/incident_helper/src/TextParserBase.cpp
new file mode 100644
index 0000000..a8f9968
--- /dev/null
+++ b/cmds/incident_helper/src/TextParserBase.cpp
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "incident_helper"
+
+#include "TextParserBase.h"
+
+#include <android-base/file.h>
+
+using namespace android::base;
+using namespace std;
+
+// ================================================================================
+status_t NoopParser::Parse(const int in, const int out) const
+{
+ string content;
+ if (!ReadFdToString(in, &content)) {
+ fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
+ return -1;
+ }
+ if (!WriteStringToFd(content, out)) {
+ fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
+ return -1;
+ }
+ return NO_ERROR;
+}
+
+// ================================================================================
+status_t ReverseParser::Parse(const int in, const int out) const
+{
+ string content;
+ if (!ReadFdToString(in, &content)) {
+ fprintf(stderr, "[%s]Failed to read data from incidentd\n", this->name.string());
+ return -1;
+ }
+ // reverse the content
+ reverse(content.begin(), content.end());
+ if (!WriteStringToFd(content, out)) {
+ fprintf(stderr, "[%s]Failed to write data to incidentd\n", this->name.string());
+ return -1;
+ }
+ return NO_ERROR;
+}
\ No newline at end of file
diff --git a/cmds/incident_helper/IncidentHelper.h b/cmds/incident_helper/src/TextParserBase.h
similarity index 64%
rename from cmds/incident_helper/IncidentHelper.h
rename to cmds/incident_helper/src/TextParserBase.h
index d24d717..c41612d 100644
--- a/cmds/incident_helper/IncidentHelper.h
+++ b/cmds/incident_helper/src/TextParserBase.h
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#ifndef INCIDENT_HELPER_H
-#define INCIDENT_HELPER_H
+#ifndef TEXT_PARSER_BASE_H
+#define TEXT_PARSER_BASE_H
#include <utils/Errors.h>
#include <utils/String8.h>
@@ -68,37 +68,4 @@
virtual status_t Parse(const int in, const int out) const;
};
-/**
- * Kernel wakeup sources parser, parses text to protobuf in /d/wakeup_sources
- */
-class KernelWakesParser : public TextParserBase {
-public:
- KernelWakesParser() : TextParserBase(String8("KernelWakeSources")) {};
- ~KernelWakesParser() {};
-
- virtual status_t Parse(const int in, const int out) const;
-};
-
-/**
- * PageTypeInfo parser, parses text to protobuf in /proc/pageinfotype
- */
-class PageTypeInfoParser : public TextParserBase {
-public:
- PageTypeInfoParser() : TextParserBase(String8("PageTypeInfo")) {};
- ~PageTypeInfoParser() {};
-
- virtual status_t Parse(const int in, const int out) const;
-};
-
-/**
- * Procrank parser, parses text produced by command procrank
- */
-class ProcrankParser : public TextParserBase {
-public:
- ProcrankParser() : TextParserBase(String8("ProcrankParser")) {};
- ~ProcrankParser() {};
-
- virtual status_t Parse(const int in, const int out) const;
-};
-
-#endif // INCIDENT_HELPER_H
+#endif // TEXT_PARSER_BASE_H
\ No newline at end of file
diff --git a/cmds/incident_helper/ih_util.cpp b/cmds/incident_helper/src/ih_util.cpp
similarity index 73%
rename from cmds/incident_helper/ih_util.cpp
rename to cmds/incident_helper/src/ih_util.cpp
index 2ab4b54..c7d1ca2 100644
--- a/cmds/incident_helper/ih_util.cpp
+++ b/cmds/incident_helper/src/ih_util.cpp
@@ -87,6 +87,15 @@
return true;
}
+int toInt(const std::string& s) {
+ return atoi(s.c_str());
+}
+
+long long toLongLong(const std::string& s) {
+ return atoll(s.c_str());
+}
+
+// ==============================================================================
Reader::Reader(const int fd) : Reader(fd, BUFFER_SIZE) {};
Reader::Reader(const int fd, const size_t capacity)
@@ -151,3 +160,57 @@
error->assign(mStatus);
return mStatus.empty();
}
+
+// ==============================================================================
+Table::Table(const char* names[], const uint64_t ids[], const int count)
+ :mFieldNames(names),
+ mFieldIds(ids),
+ mFieldCount(count)
+{
+}
+
+Table::~Table()
+{
+}
+
+bool
+Table::insertField(ProtoOutputStream& proto, const std::string& name, const std::string& value)
+{
+ uint64_t found = 0;
+ for (int i=0; i<mFieldCount; i++) {
+ if (strcmp(name.c_str(), mFieldNames[i]) == 0) {
+ found = mFieldIds[i];
+ break;
+ }
+ }
+
+ switch (found & FIELD_TYPE_MASK) {
+ case FIELD_TYPE_DOUBLE:
+ case FIELD_TYPE_FLOAT:
+ // TODO: support parse string to float/double
+ return false;
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_BYTES:
+ proto.write(found, value);
+ break;
+ case FIELD_TYPE_INT64:
+ case FIELD_TYPE_SINT64:
+ case FIELD_TYPE_UINT64:
+ case FIELD_TYPE_FIXED64:
+ case FIELD_TYPE_SFIXED64:
+ proto.write(found, toLongLong(value));
+ break;
+ case FIELD_TYPE_BOOL:
+ case FIELD_TYPE_ENUM:
+ case FIELD_TYPE_INT32:
+ case FIELD_TYPE_SINT32:
+ case FIELD_TYPE_UINT32:
+ case FIELD_TYPE_FIXED32:
+ case FIELD_TYPE_SFIXED32:
+ proto.write(found, toInt(value));
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
diff --git a/cmds/incident_helper/ih_util.h b/cmds/incident_helper/src/ih_util.h
similarity index 79%
rename from cmds/incident_helper/ih_util.h
rename to cmds/incident_helper/src/ih_util.h
index ce5baee..86761e9 100644
--- a/cmds/incident_helper/ih_util.h
+++ b/cmds/incident_helper/src/ih_util.h
@@ -21,6 +21,10 @@
#include <vector>
#include <sstream>
+#include <android/util/ProtoOutputStream.h>
+
+using namespace android::util;
+
typedef std::vector<std::string> header_t;
typedef std::vector<std::string> record_t;
typedef std::string (*trans_func) (const std::string&);
@@ -52,6 +56,12 @@
bool hasPrefix(std::string* line, const char* key);
/**
+ * Converts string to the desired type
+ */
+int toInt(const std::string& s);
+long long toLongLong(const std::string& s);
+
+/**
* Reader class reads data from given fd in streaming fashion.
* The buffer size is controlled by capacity parameter.
*/
@@ -78,4 +88,22 @@
inline bool EOR() { return mFd == -1 && mBufSize == 0; };
};
+/**
+ * The class contains a mapping between table headers to its field ids.
+ * And allow users to insert the field values to proto based on its header name.
+ */
+class Table
+{
+public:
+ Table(const char* names[], const uint64_t ids[], const int count);
+ ~Table();
+
+ bool insertField(ProtoOutputStream& proto, const std::string& name, const std::string& value);
+
+private:
+ const char** mFieldNames;
+ const uint64_t* mFieldIds;
+ const int mFieldCount;
+};
+
#endif // INCIDENT_HELPER_UTIL_H
diff --git a/cmds/incident_helper/main.cpp b/cmds/incident_helper/src/main.cpp
similarity index 96%
rename from cmds/incident_helper/main.cpp
rename to cmds/incident_helper/src/main.cpp
index 52ff777..3da87b9c 100644
--- a/cmds/incident_helper/main.cpp
+++ b/cmds/incident_helper/src/main.cpp
@@ -16,7 +16,9 @@
#define LOG_TAG "incident_helper"
-#include "IncidentHelper.h"
+#include "parsers/KernelWakesParser.h"
+#include "parsers/PageTypeInfoParser.h"
+#include "parsers/ProcrankParser.h"
#include <android-base/file.h>
#include <getopt.h>
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.cpp b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
new file mode 100644
index 0000000..cc4a1e1
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/kernelwake.proto.h"
+#include "ih_util.h"
+#include "KernelWakesParser.h"
+
+using namespace android::os;
+
+const std::string LINE_DELIMITER = "\t";
+
+status_t
+KernelWakesParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+ header_t header; // the header of /d/wakeup_sources
+ record_t record; // retain each record
+ int nline = 0;
+
+ ProtoOutputStream proto;
+ Table table(WakeupSourceProto::_FIELD_NAMES, WakeupSourceProto::_FIELD_IDS, WakeupSourceProto::_FIELD_COUNT);
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+ // parse head line
+ if (nline++ == 0) {
+ header = parseHeader(line, LINE_DELIMITER);
+ continue;
+ }
+
+ // parse for each record, the line delimiter is \t only!
+ record = parseRecord(line, LINE_DELIMITER);
+
+ if (record.size() != header.size()) {
+ // TODO: log this to incident report!
+ fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline, line.c_str());
+ continue;
+ }
+
+ long long token = proto.start(KernelWakeSources::WAKEUP_SOURCES);
+ for (int i=0; i<(int)record.size(); i++) {
+ if (!table.insertField(proto, header[i], record[i])) {
+ fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
+ this->name.string(), nline, header[i].c_str(), record[i].c_str());
+ }
+ }
+ proto.end(token);
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/src/parsers/KernelWakesParser.h b/cmds/incident_helper/src/parsers/KernelWakesParser.h
new file mode 100644
index 0000000..aabab7c
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/KernelWakesParser.h
@@ -0,0 +1,33 @@
+/*
+ * 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 KERNEL_WAKES_PARSER_H
+#define KERNEL_WAKES_PARSER_H
+
+#include "TextParserBase.h"
+
+/**
+ * Kernel wakeup sources parser, parses text to protobuf in /d/wakeup_sources
+ */
+class KernelWakesParser : public TextParserBase {
+public:
+ KernelWakesParser() : TextParserBase(String8("KernelWakeSources")) {};
+ ~KernelWakesParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // KERNEL_WAKES_PARSER_H
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
new file mode 100644
index 0000000..6047bd1
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/pagetypeinfo.proto.h"
+#include "ih_util.h"
+#include "PageTypeInfoParser.h"
+
+using namespace android::os;
+
+const std::string LINE_DELIMITER = ",";
+
+status_t
+PageTypeInfoParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+ bool migrateTypeSession = false;
+ int pageBlockOrder;
+ header_t blockHeader;
+
+ ProtoOutputStream proto;
+ Table table(BlockProto::_FIELD_NAMES, BlockProto::_FIELD_IDS, BlockProto::_FIELD_COUNT);
+
+ while (reader.readLine(&line)) {
+ if (line.empty()) {
+ migrateTypeSession = false;
+ blockHeader.clear();
+ continue;
+ }
+
+ if (hasPrefix(&line, "Page block order:")) {
+ pageBlockOrder = toInt(line);
+ proto.write(PageTypeInfo::PAGE_BLOCK_ORDER, pageBlockOrder);
+ continue;
+ }
+ if (hasPrefix(&line, "Pages per block:")) {
+ proto.write(PageTypeInfo::PAGES_PER_BLOCK, toInt(line));
+ continue;
+ }
+ if (hasPrefix(&line, "Free pages count per migrate type at order")) {
+ migrateTypeSession = true;
+ continue;
+ }
+ if (hasPrefix(&line, "Number of blocks type")) {
+ blockHeader = parseHeader(line);
+ continue;
+ }
+
+ record_t record = parseRecord(line, LINE_DELIMITER);
+ if (migrateTypeSession && record.size() == 3) {
+ long long token = proto.start(PageTypeInfo::MIGRATE_TYPES);
+ // expect part 0 starts with "Node"
+ if (hasPrefix(&record[0], "Node")) {
+ proto.write(MigrateTypeProto::NODE, toInt(record[0]));
+ } else return BAD_VALUE;
+ // expect part 1 starts with "zone"
+ if (hasPrefix(&record[1], "zone")) {
+ proto.write(MigrateTypeProto::ZONE, record[1]);
+ } else return BAD_VALUE;
+ // expect part 2 starts with "type"
+ if (hasPrefix(&record[2], "type")) {
+ // expect the rest of part 2 has number of (pageBlockOrder + 2) parts
+ // An example looks like:
+ // header line: type 0 1 2 3 4 5 6 7 8 9 10
+ // record line: Unmovable 426 279 226 1 1 1 0 0 2 2 0
+ // The pageBlockOrder = 10 and it's zero-indexed. so total parts
+ // are 10 + 1(zero-indexed) + 1(the type part) = 12.
+ record_t pageCounts = parseRecord(record[2]);
+ int pageCountsSize = pageBlockOrder + 2;
+ if ((int)pageCounts.size() != pageCountsSize) return BAD_VALUE;
+
+ proto.write(MigrateTypeProto::TYPE, pageCounts[0]);
+ for (auto i=1; i<pageCountsSize; i++) {
+ proto.write(MigrateTypeProto::FREE_PAGES_COUNT, toInt(pageCounts[i]));
+ }
+ } else return BAD_VALUE;
+
+ proto.end(token);
+ } else if (!blockHeader.empty() && record.size() == 2) {
+ long long token = proto.start(PageTypeInfo::BLOCKS);
+ if (hasPrefix(&record[0], "Node")) {
+ proto.write(BlockProto::NODE, toInt(record[0]));
+ } else return BAD_VALUE;
+
+ if (hasPrefix(&record[1], "zone")) {
+ record_t blockCounts = parseRecord(record[1]);
+ proto.write(BlockProto::ZONE, blockCounts[0]);
+
+ for (size_t i=0; i<blockHeader.size(); i++) {
+ if (!table.insertField(proto, blockHeader[i], blockCounts[i+1])) {
+ return BAD_VALUE;
+ }
+ }
+ } else return BAD_VALUE;
+ proto.end(token);
+ }
+ }
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
\ No newline at end of file
diff --git a/cmds/incident_helper/src/parsers/PageTypeInfoParser.h b/cmds/incident_helper/src/parsers/PageTypeInfoParser.h
new file mode 100644
index 0000000..fb84d91
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/PageTypeInfoParser.h
@@ -0,0 +1,35 @@
+/*
+ * 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 PAGE_TYPE_INFO_PARSER_H
+#define PAGE_TYPE_INFO_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * PageTypeInfo parser, parses text to protobuf in /proc/pageinfotype
+ */
+class PageTypeInfoParser : public TextParserBase {
+public:
+ PageTypeInfoParser() : TextParserBase(String8("PageTypeInfo")) {};
+ ~PageTypeInfoParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // PAGE_TYPE_INFO_PARSER_H
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.cpp b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
new file mode 100644
index 0000000..93f970f
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+#define LOG_TAG "incident_helper"
+
+#include <android/util/ProtoOutputStream.h>
+
+#include "frameworks/base/core/proto/android/os/procrank.proto.h"
+#include "ih_util.h"
+#include "ProcrankParser.h"
+
+using namespace android::os;
+
+status_t
+ProcrankParser::Parse(const int in, const int out) const
+{
+ Reader reader(in);
+ string line;
+ header_t header; // the header of /d/wakeup_sources
+ record_t record; // retain each record
+ int nline = 0;
+
+ ProtoOutputStream proto;
+ Table table(ProcessProto::_FIELD_NAMES, ProcessProto::_FIELD_IDS, ProcessProto::_FIELD_COUNT);
+ string zram, ram, total;
+
+ // parse line by line
+ while (reader.readLine(&line)) {
+ if (line.empty()) continue;
+
+ // parse head line
+ if (nline++ == 0) {
+ header = parseHeader(line);
+ continue;
+ }
+
+ if (hasPrefix(&line, "ZRAM:")) {
+ zram = line;
+ continue;
+ }
+ if (hasPrefix(&line, "RAM:")) {
+ ram = line;
+ continue;
+ }
+
+ record = parseRecord(line);
+ if (record.size() != header.size()) {
+ if (record[record.size() - 1] == "TOTAL") { // TOTAL record
+ total = line;
+ } else {
+ fprintf(stderr, "[%s]Line %d has missing fields\n%s\n", this->name.string(), nline,
+ line.c_str());
+ }
+ continue;
+ }
+
+ long long token = proto.start(Procrank::PROCESSES);
+ for (int i=0; i<(int)record.size(); i++) {
+ if (!table.insertField(proto, header[i], record[i])) {
+ fprintf(stderr, "[%s]Line %d has bad value %s of %s\n",
+ this->name.string(), nline, header[i].c_str(), record[i].c_str());
+ }
+ }
+ proto.end(token);
+ }
+
+ // add summary
+ long long token = proto.start(Procrank::SUMMARY);
+ if (!total.empty()) {
+ record = parseRecord(total);
+ long long token = proto.start(SummaryProto::TOTAL);
+ for (int i=(int)record.size(); i>0; i--) {
+ table.insertField(proto, header[header.size() - i].c_str(), record[record.size() - i].c_str());
+ }
+ proto.end(token);
+ }
+ if (!zram.empty()) {
+ long long token = proto.start(SummaryProto::ZRAM);
+ proto.write(ZramProto::RAW_TEXT, zram);
+ proto.end(token);
+ }
+ if (!ram.empty()) {
+ long long token = proto.start(SummaryProto::RAM);
+ proto.write(RamProto::RAW_TEXT, ram);
+ proto.end(token);
+ }
+ proto.end(token);
+
+ if (!reader.ok(&line)) {
+ fprintf(stderr, "Bad read from fd %d: %s\n", in, line.c_str());
+ return -1;
+ }
+
+ if (!proto.flush(out)) {
+ fprintf(stderr, "[%s]Error writing proto back\n", this->name.string());
+ return -1;
+ }
+ fprintf(stderr, "[%s]Proto size: %zu bytes\n", this->name.string(), proto.size());
+ return NO_ERROR;
+}
diff --git a/cmds/incident_helper/src/parsers/ProcrankParser.h b/cmds/incident_helper/src/parsers/ProcrankParser.h
new file mode 100644
index 0000000..5d0ee48
--- /dev/null
+++ b/cmds/incident_helper/src/parsers/ProcrankParser.h
@@ -0,0 +1,35 @@
+/*
+ * 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 PROCRANK_PARSER_H
+#define PROCRANK_PARSER_H
+
+#include "TextParserBase.h"
+
+using namespace android;
+
+/**
+ * Procrank parser, parses text produced by command procrank
+ */
+class ProcrankParser : public TextParserBase {
+public:
+ ProcrankParser() : TextParserBase(String8("ProcrankParser")) {};
+ ~ProcrankParser() {};
+
+ virtual status_t Parse(const int in, const int out) const;
+};
+
+#endif // PROCRANK_PARSER_H
diff --git a/cmds/incident_helper/testdata/kernel_wakeups_short.txt b/cmds/incident_helper/testdata/kernel_wakeups_short.txt
new file mode 100644
index 0000000..a51926e
--- /dev/null
+++ b/cmds/incident_helper/testdata/kernel_wakeups_short.txt
@@ -0,0 +1,3 @@
+name active_count last_change
+ab 8 123456123456
+df 143 0
diff --git a/cmds/incident_helper/tests/IncidentHelper_test.cpp b/cmds/incident_helper/tests/IncidentHelper_test.cpp
deleted file mode 100644
index c44a163..0000000
--- a/cmds/incident_helper/tests/IncidentHelper_test.cpp
+++ /dev/null
@@ -1,255 +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.
- */
-
-#include "IncidentHelper.h"
-
-#include "frameworks/base/core/proto/android/os/kernelwake.pb.h"
-#include "frameworks/base/core/proto/android/os/pagetypeinfo.pb.h"
-#include "frameworks/base/core/proto/android/os/procrank.pb.h"
-
-#include <android-base/file.h>
-#include <android-base/test_utils.h>
-#include <gmock/gmock.h>
-#include <google/protobuf/message.h>
-#include <gtest/gtest.h>
-#include <string.h>
-#include <fcntl.h>
-
-using namespace android::base;
-using namespace android::os;
-using namespace std;
-using ::testing::StrEq;
-using ::testing::Test;
-using ::testing::internal::CaptureStderr;
-using ::testing::internal::CaptureStdout;
-using ::testing::internal::GetCapturedStderr;
-using ::testing::internal::GetCapturedStdout;
-
-class IncidentHelperTest : public Test {
-public:
- virtual void SetUp() override {
- ASSERT_TRUE(tf.fd != -1);
- }
-
- string getSerializedString(::google::protobuf::Message& message) {
- string expectedStr;
- message.SerializeToFileDescriptor(tf.fd);
- ReadFileToString(tf.path, &expectedStr);
- return expectedStr;
- }
-
-protected:
- TemporaryFile tf;
-
- const string kTestPath = GetExecutableDirectory();
- const string kTestDataPath = kTestPath + "/testdata/";
-};
-
-TEST_F(IncidentHelperTest, ReverseParser) {
- ReverseParser parser;
- TemporaryFile tf;
-
- ASSERT_TRUE(tf.fd != -1);
- ASSERT_TRUE(WriteStringToFile("TestData", tf.path, false));
-
- CaptureStdout();
- ASSERT_EQ(NO_ERROR, parser.Parse(tf.fd, STDOUT_FILENO));
- EXPECT_THAT(GetCapturedStdout(), StrEq("ataDtseT"));
-}
-
-TEST_F(IncidentHelperTest, KernelWakesParser) {
- const string testFile = kTestDataPath + "kernel_wakeups.txt";
- KernelWakesParser parser;
- KernelWakeSources expected;
-
- WakeupSourceProto* record1 = expected.add_wakeup_sources();
- record1->set_name("ipc000000ab_ATFWD-daemon");
- record1->set_active_count(8);
- record1->set_event_count(8);
- record1->set_wakeup_count(0);
- record1->set_expire_count(0);
- record1->set_active_since(0l);
- record1->set_total_time(0l);
- record1->set_max_time(0l);
- record1->set_last_change(131348l);
- record1->set_prevent_suspend_time(0l);
-
- WakeupSourceProto* record2 = expected.add_wakeup_sources();
- record2->set_name("ipc000000aa_ATFWD-daemon");
- record2->set_active_count(143);
- record2->set_event_count(143);
- record2->set_wakeup_count(0);
- record2->set_expire_count(0);
- record2->set_active_since(0l);
- record2->set_total_time(123l);
- record2->set_max_time(3l);
- record2->set_last_change(2067286206l);
- record2->set_prevent_suspend_time(0l);
-
- int fd = open(testFile.c_str(), O_RDONLY);
- ASSERT_TRUE(fd != -1);
-
- CaptureStdout();
- ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
- close(fd);
-}
-
-TEST_F(IncidentHelperTest, ProcrankParser) {
- const string testFile = kTestDataPath + "procrank.txt";
- ProcrankParser parser;
- Procrank expected;
-
- ProcessProto* process1 = expected.add_processes();
- process1->set_pid(1119);
- process1->set_vss(2607640);
- process1->set_rss(339564);
- process1->set_pss(180278);
- process1->set_uss(114216);
- process1->set_swap(1584);
- process1->set_pswap(46);
- process1->set_uswap(0);
- process1->set_zswap(10);
- process1->set_cmdline("system_server");
-
- ProcessProto* process2 = expected.add_processes();
- process2->set_pid(649);
- process2->set_vss(11016);
- process2->set_rss(1448);
- process2->set_pss(98);
- process2->set_uss(48);
- process2->set_swap(472);
- process2->set_pswap(342);
- process2->set_uswap(212);
- process2->set_zswap(75);
- process2->set_cmdline("/vendor/bin/qseecomd");
-
- ProcessProto* total = expected.mutable_summary()->mutable_total();
- total->set_pss(1201993);
- total->set_uss(935300);
- total->set_swap(88164);
- total->set_pswap(31069);
- total->set_uswap(27612);
- total->set_zswap(6826);
- total->set_cmdline("TOTAL");
-
- expected.mutable_summary()->mutable_zram()
- ->set_raw_text("6828K physical used for 31076K in swap (524284K total swap)");
- expected.mutable_summary()->mutable_ram()
- ->set_raw_text("3843972K total, 281424K free, 116764K buffers, 1777452K cached, 1136K shmem, 217916K slab");
-
- int fd = open(testFile.c_str(), O_RDONLY);
- ASSERT_TRUE(fd != -1);
-
- CaptureStdout();
- ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
- close(fd);
-}
-
-TEST_F(IncidentHelperTest, ProcrankParserShortHeader) {
- const string testFile = kTestDataPath + "procrank_short.txt";
- ProcrankParser parser;
- Procrank expected;
-
- ProcessProto* process1 = expected.add_processes();
- process1->set_pid(1119);
- process1->set_vss(2607640);
- process1->set_rss(339564);
- process1->set_pss(180278);
- process1->set_uss(114216);
- process1->set_cmdline("system_server");
-
- ProcessProto* process2 = expected.add_processes();
- process2->set_pid(649);
- process2->set_vss(11016);
- process2->set_rss(1448);
- process2->set_pss(98);
- process2->set_uss(48);
- process2->set_cmdline("/vendor/bin/qseecomd");
-
- ProcessProto* total = expected.mutable_summary()->mutable_total();
- total->set_pss(1201993);
- total->set_uss(935300);
- total->set_cmdline("TOTAL");
-
- expected.mutable_summary()->mutable_ram()
- ->set_raw_text("3843972K total, 281424K free, 116764K buffers, 1777452K cached, 1136K shmem, 217916K slab");
-
- int fd = open(testFile.c_str(), O_RDONLY);
- ASSERT_TRUE(fd != -1);
-
- CaptureStdout();
- ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
- close(fd);
-}
-
-TEST_F(IncidentHelperTest, PageTypeInfoParser) {
- const string testFile = kTestDataPath + "pagetypeinfo.txt";
- PageTypeInfoParser parser;
- PageTypeInfo expected;
-
- expected.set_page_block_order(10);
- expected.set_pages_per_block(1024);
-
- MigrateTypeProto* mt1 = expected.add_migrate_types();
- mt1->set_node(0);
- mt1->set_zone("DMA");
- mt1->set_type("Unmovable");
- int arr1[] = { 426, 279, 226, 1, 1, 1, 0, 0, 2, 2, 0};
- for (auto i=0; i<11; i++) {
- mt1->add_free_pages_count(arr1[i]);
- }
-
- MigrateTypeProto* mt2 = expected.add_migrate_types();
- mt2->set_node(0);
- mt2->set_zone("Normal");
- mt2->set_type("Reclaimable");
- int arr2[] = { 953, 773, 437, 154, 92, 26, 15, 14, 12, 7, 0};
- for (auto i=0; i<11; i++) {
- mt2->add_free_pages_count(arr2[i]);
- }
-
- BlockProto* block1 = expected.add_blocks();
- block1->set_node(0);
- block1->set_zone("DMA");
- block1->set_unmovable(74);
- block1->set_reclaimable(9);
- block1->set_movable(337);
- block1->set_cma(41);
- block1->set_reserve(1);
- block1->set_isolate(0);
-
-
- BlockProto* block2 = expected.add_blocks();
- block2->set_node(0);
- block2->set_zone("Normal");
- block2->set_unmovable(70);
- block2->set_reclaimable(12);
- block2->set_movable(423);
- block2->set_cma(0);
- block2->set_reserve(1);
- block2->set_isolate(0);
-
- int fd = open(testFile.c_str(), O_RDONLY);
- ASSERT_TRUE(fd != -1);
-
- CaptureStdout();
- ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
- EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
- close(fd);
-}
\ No newline at end of file
diff --git a/cmds/incident_helper/tests/KernelWakesParser_test.cpp b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
new file mode 100644
index 0000000..a8fa6208
--- /dev/null
+++ b/cmds/incident_helper/tests/KernelWakesParser_test.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 "KernelWakesParser.h"
+
+#include "frameworks/base/core/proto/android/os/kernelwake.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class KernelWakesParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+ string getSerializedString(::google::protobuf::Message& message) {
+ string expectedStr;
+ message.SerializeToFileDescriptor(tf.fd);
+ ReadFileToString(tf.path, &expectedStr);
+ return expectedStr;
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(KernelWakesParserTest, Short) {
+ const string testFile = kTestDataPath + "kernel_wakeups_short.txt";
+ KernelWakesParser parser;
+ KernelWakeSources expected;
+
+ WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ record1->set_name("ab");
+ record1->set_active_count(8);
+ record1->set_last_change(123456123456LL);
+
+ WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ record2->set_name("df");
+ record2->set_active_count(143);
+ record2->set_last_change(0LL);
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ close(fd);
+}
+
+TEST_F(KernelWakesParserTest, Normal) {
+ const string testFile = kTestDataPath + "kernel_wakeups.txt";
+ KernelWakesParser parser;
+ KernelWakeSources expected;
+
+ WakeupSourceProto* record1 = expected.add_wakeup_sources();
+ record1->set_name("ipc000000ab_ATFWD-daemon");
+ record1->set_active_count(8);
+ record1->set_event_count(8);
+ record1->set_wakeup_count(0);
+ record1->set_expire_count(0);
+ record1->set_active_since(0l);
+ record1->set_total_time(0l);
+ record1->set_max_time(0l);
+ record1->set_last_change(131348LL);
+ record1->set_prevent_suspend_time(0LL);
+
+ WakeupSourceProto* record2 = expected.add_wakeup_sources();
+ record2->set_name("ipc000000aa_ATFWD-daemon");
+ record2->set_active_count(143);
+ record2->set_event_count(143);
+ record2->set_wakeup_count(0);
+ record2->set_expire_count(0);
+ record2->set_active_since(0l);
+ record2->set_total_time(123l);
+ record2->set_max_time(3l);
+ record2->set_last_change(2067286206LL);
+ record2->set_prevent_suspend_time(0LL);
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ close(fd);
+}
diff --git a/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
new file mode 100644
index 0000000..de64e70
--- /dev/null
+++ b/cmds/incident_helper/tests/PageTypeInfoParser_test.cpp
@@ -0,0 +1,113 @@
+/*
+ * 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 "PageTypeInfoParser.h"
+
+#include "frameworks/base/core/proto/android/os/pagetypeinfo.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class PageTypeInfoParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+ string getSerializedString(::google::protobuf::Message& message) {
+ string expectedStr;
+ message.SerializeToFileDescriptor(tf.fd);
+ ReadFileToString(tf.path, &expectedStr);
+ return expectedStr;
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(PageTypeInfoParserTest, Success) {
+ const string testFile = kTestDataPath + "pagetypeinfo.txt";
+ PageTypeInfoParser parser;
+ PageTypeInfo expected;
+
+ expected.set_page_block_order(10);
+ expected.set_pages_per_block(1024);
+
+ MigrateTypeProto* mt1 = expected.add_migrate_types();
+ mt1->set_node(0);
+ mt1->set_zone("DMA");
+ mt1->set_type("Unmovable");
+ int arr1[] = { 426, 279, 226, 1, 1, 1, 0, 0, 2, 2, 0};
+ for (auto i=0; i<11; i++) {
+ mt1->add_free_pages_count(arr1[i]);
+ }
+
+ MigrateTypeProto* mt2 = expected.add_migrate_types();
+ mt2->set_node(0);
+ mt2->set_zone("Normal");
+ mt2->set_type("Reclaimable");
+ int arr2[] = { 953, 773, 437, 154, 92, 26, 15, 14, 12, 7, 0};
+ for (auto i=0; i<11; i++) {
+ mt2->add_free_pages_count(arr2[i]);
+ }
+
+ BlockProto* block1 = expected.add_blocks();
+ block1->set_node(0);
+ block1->set_zone("DMA");
+ block1->set_unmovable(74);
+ block1->set_reclaimable(9);
+ block1->set_movable(337);
+ block1->set_cma(41);
+ block1->set_reserve(1);
+ block1->set_isolate(0);
+
+
+ BlockProto* block2 = expected.add_blocks();
+ block2->set_node(0);
+ block2->set_zone("Normal");
+ block2->set_unmovable(70);
+ block2->set_reclaimable(12);
+ block2->set_movable(423);
+ block2->set_cma(0);
+ block2->set_reserve(1);
+ block2->set_isolate(0);
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ close(fd);
+}
\ No newline at end of file
diff --git a/cmds/incident_helper/tests/ProcrankParser_test.cpp b/cmds/incident_helper/tests/ProcrankParser_test.cpp
new file mode 100644
index 0000000..e86647a
--- /dev/null
+++ b/cmds/incident_helper/tests/ProcrankParser_test.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "ProcrankParser.h"
+
+#include "frameworks/base/core/proto/android/os/procrank.pb.h"
+
+#include <android-base/file.h>
+#include <android-base/test_utils.h>
+#include <gmock/gmock.h>
+#include <google/protobuf/message.h>
+#include <gtest/gtest.h>
+#include <string.h>
+#include <fcntl.h>
+
+using namespace android::base;
+using namespace android::os;
+using namespace std;
+using ::testing::StrEq;
+using ::testing::Test;
+using ::testing::internal::CaptureStderr;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStderr;
+using ::testing::internal::GetCapturedStdout;
+
+class ProcrankParserTest : public Test {
+public:
+ virtual void SetUp() override {
+ ASSERT_TRUE(tf.fd != -1);
+ }
+
+ string getSerializedString(::google::protobuf::Message& message) {
+ string expectedStr;
+ message.SerializeToFileDescriptor(tf.fd);
+ ReadFileToString(tf.path, &expectedStr);
+ return expectedStr;
+ }
+
+protected:
+ TemporaryFile tf;
+
+ const string kTestPath = GetExecutableDirectory();
+ const string kTestDataPath = kTestPath + "/testdata/";
+};
+
+TEST_F(ProcrankParserTest, HasSwapInfo) {
+ const string testFile = kTestDataPath + "procrank.txt";
+ ProcrankParser parser;
+ Procrank expected;
+
+ ProcessProto* process1 = expected.add_processes();
+ process1->set_pid(1119);
+ process1->set_vss(2607640);
+ process1->set_rss(339564);
+ process1->set_pss(180278);
+ process1->set_uss(114216);
+ process1->set_swap(1584);
+ process1->set_pswap(46);
+ process1->set_uswap(0);
+ process1->set_zswap(10);
+ process1->set_cmdline("system_server");
+
+ ProcessProto* process2 = expected.add_processes();
+ process2->set_pid(649);
+ process2->set_vss(11016);
+ process2->set_rss(1448);
+ process2->set_pss(98);
+ process2->set_uss(48);
+ process2->set_swap(472);
+ process2->set_pswap(342);
+ process2->set_uswap(212);
+ process2->set_zswap(75);
+ process2->set_cmdline("/vendor/bin/qseecomd");
+
+ ProcessProto* total = expected.mutable_summary()->mutable_total();
+ total->set_pss(1201993);
+ total->set_uss(935300);
+ total->set_swap(88164);
+ total->set_pswap(31069);
+ total->set_uswap(27612);
+ total->set_zswap(6826);
+ total->set_cmdline("TOTAL");
+
+ expected.mutable_summary()->mutable_zram()
+ ->set_raw_text("6828K physical used for 31076K in swap (524284K total swap)");
+ expected.mutable_summary()->mutable_ram()
+ ->set_raw_text("3843972K total, 281424K free, 116764K buffers, 1777452K cached, 1136K shmem, 217916K slab");
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ close(fd);
+}
+
+TEST_F(ProcrankParserTest, NoSwapInfo) {
+ const string testFile = kTestDataPath + "procrank_short.txt";
+ ProcrankParser parser;
+ Procrank expected;
+
+ ProcessProto* process1 = expected.add_processes();
+ process1->set_pid(1119);
+ process1->set_vss(2607640);
+ process1->set_rss(339564);
+ process1->set_pss(180278);
+ process1->set_uss(114216);
+ process1->set_cmdline("system_server");
+
+ ProcessProto* process2 = expected.add_processes();
+ process2->set_pid(649);
+ process2->set_vss(11016);
+ process2->set_rss(1448);
+ process2->set_pss(98);
+ process2->set_uss(48);
+ process2->set_cmdline("/vendor/bin/qseecomd");
+
+ ProcessProto* total = expected.mutable_summary()->mutable_total();
+ total->set_pss(1201993);
+ total->set_uss(935300);
+ total->set_cmdline("TOTAL");
+
+ expected.mutable_summary()->mutable_ram()
+ ->set_raw_text("3843972K total, 281424K free, 116764K buffers, 1777452K cached, 1136K shmem, 217916K slab");
+
+ int fd = open(testFile.c_str(), O_RDONLY);
+ ASSERT_TRUE(fd != -1);
+
+ CaptureStdout();
+ ASSERT_EQ(NO_ERROR, parser.Parse(fd, STDOUT_FILENO));
+ EXPECT_EQ(GetCapturedStdout(), getSerializedString(expected));
+ close(fd);
+}
diff --git a/cmds/incidentd/src/PrivacyBuffer.cpp b/cmds/incidentd/src/PrivacyBuffer.cpp
index d926ea7..77ae1a7 100644
--- a/cmds/incidentd/src/PrivacyBuffer.cpp
+++ b/cmds/incidentd/src/PrivacyBuffer.cpp
@@ -87,12 +87,12 @@
// current field is message type and its sub-fields have extra privacy policies
uint32_t msgSize = mData.readRawVarint();
EncodedBuffer::Pointer start = mData.rp()->copy();
+ long long token = mProto.start(policy->EncodedFieldId());
while (mData.rp()->pos() - start.pos() != msgSize) {
- long long token = mProto.start(policy->EncodedFieldId());
status_t err = stripField(policy, spec);
if (err != NO_ERROR) return err;
- mProto.end(token);
}
+ mProto.end(token);
return NO_ERROR;
}
diff --git a/cmds/incidentd/src/section_list.h b/cmds/incidentd/src/section_list.h
index da82b00..dfd2312 100644
--- a/cmds/incidentd/src/section_list.h
+++ b/cmds/incidentd/src/section_list.h
@@ -30,7 +30,7 @@
* This is the mapping of section IDs to each section's privacy policy.
* The section IDs are guaranteed in ascending order, not NULL-terminated since size is provided.
*/
-extern const Privacy* PRIVACY_POLICY_LIST[];
+extern const Privacy** PRIVACY_POLICY_LIST;
extern const int PRIVACY_POLICY_COUNT;
diff --git a/cmds/incidentd/tests/PrivacyBuffer_test.cpp b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
index 8f6e355..84a2a82 100644
--- a/cmds/incidentd/tests/PrivacyBuffer_test.cpp
+++ b/cmds/incidentd/tests/PrivacyBuffer_test.cpp
@@ -260,3 +260,13 @@
PrivacySpec spec;
ASSERT_EQ(privacyBuf.strip(spec), BAD_VALUE);
}
+
+TEST_F(PrivacyBufferTest, SelfRecursionMessage) {
+ string input = "\x2a\"" + VARINT_FIELD_1 + STRING_FIELD_2 + MESSAGE_FIELD_5;
+ writeToFdBuffer(input);
+ Privacy* field5 = create_message_privacy(5, NULL);
+ Privacy* list[] = { create_privacy(1, OTHER_TYPE, LOCAL), field5, NULL };
+ field5->children = list;
+ string expected = "\x2a\x1c" + STRING_FIELD_2 + "\x2a\xd" + STRING_FIELD_2;
+ assertStrip(EXPLICIT, expected, field5);
+}
diff --git a/cmds/incidentd/tests/section_list.cpp b/cmds/incidentd/tests/section_list.cpp
index e47b61cf..4acc429 100644
--- a/cmds/incidentd/tests/section_list.cpp
+++ b/cmds/incidentd/tests/section_list.cpp
@@ -20,9 +20,11 @@
Privacy field_0 { 0, 11, list, EXPLICIT, NULL };
Privacy field_1 { 1, 9, NULL, AUTOMATIC, NULL };
-const Privacy* PRIVACY_POLICY_LIST[] = {
+Privacy* final_list[] = {
&field_0,
&field_1
};
-const int PRIVACY_POLICY_COUNT = 2;
\ No newline at end of file
+const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(final_list);
+
+const int PRIVACY_POLICY_COUNT = 2;
diff --git a/cmds/input/input b/cmds/input/input
index 7f1a18e..54ab947 100755
--- a/cmds/input/input
+++ b/cmds/input/input
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "input" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/locksettings/locksettings b/cmds/locksettings/locksettings
index c963b23..0ef4fa9 100755
--- a/cmds/locksettings/locksettings
+++ b/cmds/locksettings/locksettings
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "locksettings" on the device
#
base=/system
diff --git a/cmds/media/media b/cmds/media/media
index 1194442..5c0eb2f 100755
--- a/cmds/media/media
+++ b/cmds/media/media
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "media_cmd" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/pm/pm b/cmds/pm/pm
index 8183838..53f85b2 100755
--- a/cmds/pm/pm
+++ b/cmds/pm/pm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "pm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/requestsync/requestsync b/cmds/requestsync/requestsync
index 9315675..2d5d0e4 100755
--- a/cmds/requestsync/requestsync
+++ b/cmds/requestsync/requestsync
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "requestsync" on the device
#
base=/system
diff --git a/cmds/sm/sm b/cmds/sm/sm
index 8fba007..4bc859e0 100755
--- a/cmds/sm/sm
+++ b/cmds/sm/sm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "sm" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index a9a4118..699de94 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -20,6 +20,9 @@
import static android.os.storage.StorageManager.PROP_HAS_ADOPTABLE;
import static android.os.storage.StorageManager.PROP_VIRTUAL_DISK;
+import android.os.IBinder;
+import android.os.IVoldTaskListener;
+import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -29,6 +32,8 @@
import android.os.storage.VolumeInfo;
import android.util.Log;
+import java.util.concurrent.CompletableFuture;
+
public final class Sm {
private static final String TAG = "Sm";
@@ -221,9 +226,23 @@
mSm.format(volId);
}
- public void runBenchmark() throws RemoteException {
+ public void runBenchmark() throws Exception {
final String volId = nextArg();
- mSm.benchmark(volId);
+ final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+ mSm.benchmark(volId, new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ // Touch to unparcel
+ extras.size();
+ result.complete(extras);
+ }
+ });
+ System.out.println(result.get());
}
public void runForget() throws RemoteException {
@@ -235,8 +254,22 @@
}
}
- public void runFstrim() throws RemoteException {
- mSm.fstrim(0);
+ public void runFstrim() throws Exception {
+ final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+ mSm.fstrim(0, new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ // Touch to unparcel
+ extras.size();
+ result.complete(extras);
+ }
+ });
+ System.out.println(result.get());
}
public void runSetVirtualDisk() throws RemoteException {
diff --git a/cmds/statsd/.clang-format b/cmds/statsd/.clang-format
index 3d64bee..cead3a0 100644
--- a/cmds/statsd/.clang-format
+++ b/cmds/statsd/.clang-format
@@ -12,3 +12,6 @@
PointerAlignment: Left
TabWidth: 4
AccessModifierOffset: -4
+IncludeCategories:
+ - Regex: '^"Log\.h"'
+ Priority: -1
diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk
index db634d4..87d318b 100644
--- a/cmds/statsd/Android.mk
+++ b/cmds/statsd/Android.mk
@@ -29,7 +29,8 @@
src/config/ConfigKey.cpp \
src/config/ConfigListener.cpp \
src/config/ConfigManager.cpp \
- src/external/KernelWakelockPuller.cpp \
+ src/external/StatsCompanionServicePuller.cpp \
+ src/external/ResourcePowerManagerPuller.cpp \
src/external/StatsPullerManager.cpp \
src/logd/LogEvent.cpp \
src/logd/LogListener.cpp \
@@ -42,6 +43,10 @@
src/metrics/EventMetricProducer.cpp \
src/metrics/CountMetricProducer.cpp \
src/metrics/DurationMetricProducer.cpp \
+ src/metrics/duration_helper/OringDurationTracker.cpp \
+ src/metrics/duration_helper/MaxDurationTracker.cpp \
+ src/metrics/ValueMetricProducer.cpp \
+ src/metrics/GaugeMetricProducer.cpp \
src/metrics/MetricsManager.cpp \
src/metrics/metrics_manager_util.cpp \
src/packages/UidMap.cpp \
@@ -68,7 +73,15 @@
libutils \
libservices \
libandroidfw \
- libprotoutil
+ libprotoutil \
+ libstatslog \
+ libhardware \
+ libhardware_legacy \
+ libhidlbase \
+ libhidltransport \
+ libhwbinder \
+ android.hardware.power@1.0 \
+ android.hardware.power@1.1
# =========
# statsd
@@ -103,7 +116,8 @@
LOCAL_AIDL_INCLUDES := $(statsd_common_aidl_includes)
LOCAL_C_INCLUDES += $(statsd_common_c_includes)
-LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries)
+LOCAL_SHARED_LIBRARIES := $(statsd_common_shared_libraries) \
+ libgtest_prod
LOCAL_MODULE_CLASS := EXECUTABLES
@@ -142,7 +156,11 @@
tests/LogEntryMatcher_test.cpp \
tests/LogReader_test.cpp \
tests/MetricsManager_test.cpp \
- tests/UidMap_test.cpp
+ tests/UidMap_test.cpp \
+ tests/metrics/OringDurationTracker_test.cpp \
+ tests/metrics/MaxDurationTracker_test.cpp \
+ tests/metrics/CountMetricProducer_test.cpp \
+ tests/metrics/EventMetricProducer_test.cpp
LOCAL_STATIC_LIBRARIES := \
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index cdaca1b..8910523 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -60,6 +60,7 @@
unique_ptr<MetricsManager> newMetricsManager = std::make_unique<MetricsManager>(config);
if (newMetricsManager->isConfigValid()) {
+ mUidMap->OnConfigUpdated(key);
mMetricsManagers[key] = std::move(newMetricsManager);
// Why doesn't this work? mMetricsManagers.insert({key, std::move(newMetricsManager)});
ALOGD("StatsdConfig valid");
@@ -69,14 +70,27 @@
}
}
-vector<StatsLogReport> StatsLogProcessor::onDumpReport(const ConfigKey& key) {
+ConfigMetricsReport StatsLogProcessor::onDumpReport(const ConfigKey& key) {
+ ConfigMetricsReport report;
+
auto it = mMetricsManagers.find(key);
if (it == mMetricsManagers.end()) {
ALOGW("Config source %s does not exist", key.ToString().c_str());
- return vector<StatsLogReport>();
+ return report;
}
- return it->second->onDumpReport();
+ auto set_key = report.mutable_config_key();
+ set_key->set_uid(key.GetUid());
+ set_key->set_name(key.GetName());
+ for (auto m : it->second->onDumpReport()) {
+ // Transfer the vector of StatsLogReport into a field
+ // TODO: perhaps we just have bytes being returned from onDumpReport and transfer bytes
+ auto dest = report.add_metrics();
+ *dest = m;
+ }
+ auto temp = mUidMap->getOutput(key);
+ report.mutable_uid_map()->Swap(&temp);
+ return report;
}
void StatsLogProcessor::OnConfigRemoved(const ConfigKey& key) {
@@ -84,6 +98,7 @@
if (it != mMetricsManagers.end()) {
it->second->finish();
mMetricsManagers.erase(it);
+ mUidMap->OnConfigRemoved(key);
}
auto flushTime = mLastFlushTimes.find(key);
if (flushTime != mLastFlushTimes.end()) {
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index 6463441..0083827 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -42,7 +42,7 @@
void OnConfigRemoved(const ConfigKey& key);
// TODO: Once we have the ProtoOutputStream in c++, we can just return byte array.
- std::vector<StatsLogReport> onDumpReport(const ConfigKey& key);
+ ConfigMetricsReport onDumpReport(const ConfigKey& key);
/* Request a flush through a binder call. */
void flush();
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 604753e..11c5de1 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -65,7 +65,6 @@
StatsService::StatsService(const sp<Looper>& handlerLooper)
: mAnomalyMonitor(new AnomalyMonitor(2)) // TODO: Put this comment somewhere better
{
- mStatsPullerManager = new StatsPullerManager();
mUidMap = new UidMap();
mConfigManager = new ConfigManager();
mProcessor = new StatsLogProcessor(mUidMap, [this](const vector<uint8_t>& log) {
@@ -231,6 +230,14 @@
fprintf(out, " parameter on eng builds. If UID is omitted the calling\n");
fprintf(out, " uid is used.\n");
fprintf(out, " NAME The per-uid name to use\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "usage: adb shell cmd stats dump-report [UID] NAME\n");
+ fprintf(out, " Dump all metric data for a configuration.\n");
+ fprintf(out, " UID The uid of the configuration. It is only possible to pass\n");
+ fprintf(out, " the UID parameter on eng builds. If UID is omitted the\n");
+ fprintf(out, " calling uid is used.\n");
+ fprintf(out, " NAME The name of the configuration\n");
}
status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, Vector<String8>& args) {
@@ -312,7 +319,7 @@
// Automatically pick the UID
uid = IPCThreadState::self()->getCallingUid();
// TODO: What if this isn't a binder call? Should we fail?
- name.assign(args[2].c_str(), args[2].size());
+ name.assign(args[1].c_str(), args[1].size());
good = true;
} else if (argCount == 3) {
// If it's a userdebug or eng build, then the shell user can
@@ -366,12 +373,15 @@
status_t StatsService::cmd_print_pulled_metrics(FILE* out, const Vector<String8>& args) {
int s = atoi(args[1].c_str());
- auto stats = mStatsPullerManager->Pull(s);
- for (const auto& it : stats) {
- fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ vector<shared_ptr<LogEvent> > stats;
+ if (mStatsPullerManager.Pull(s, &stats)) {
+ for (const auto& it : stats) {
+ fprintf(out, "Pull from %d: %s\n", s, it->ToString().c_str());
+ }
+ fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
+ return NO_ERROR;
}
- fprintf(out, "Pull from %d: Received %zu elements\n", s, stats.size());
- return NO_ERROR;
+ return UNKNOWN_ERROR;
}
Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
@@ -433,8 +443,9 @@
"Only system uid can call informPollAlarmFired");
}
+ mStatsPullerManager.OnAlarmFired();
+
if (DEBUG) ALOGD("StatsService::informPollAlarmFired succeeded");
- // TODO: determine what services to poll and poll (or ask StatsCompanionService to poll) them.
return Status::ok();
}
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 7f04658..1d7e5a61 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -27,7 +27,6 @@
#include <android/os/IStatsCallbacks.h>
#include <android/os/IStatsCompanionService.h>
#include <binder/IResultReceiver.h>
-#include <binder/IShellCallback.h>
#include <utils/Looper.h>
#include <deque>
@@ -158,7 +157,7 @@
/**
* Fetches external metrics.
*/
- sp<StatsPullerManager> mStatsPullerManager;
+ StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance();
/**
* Tracks the configurations that have been passed to statsd.
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index f56c15a..953bcb3 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -16,7 +16,6 @@
#define DEBUG true // STOPSHIP if true
#include "Log.h"
-
#include "CombinationConditionTracker.h"
#include <log/logprint.h>
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index fc88a88..dbdb3b7 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -46,8 +46,6 @@
const std::vector<sp<ConditionTracker>>& allConditions,
std::vector<ConditionState>& conditionCache) override;
- void addDimensions(const std::vector<KeyMatcher>& keyMatchers) override{};
-
private:
LogicalOperation mLogicalOperation;
// Store index of the children Conditions.
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index 055b478..bb5ddeb 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -16,8 +16,6 @@
#pragma once
-#include "Log.h"
-
#include "condition/condition_util.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "matchers/LogMatchingTracker.h"
@@ -103,8 +101,6 @@
mSliced = mSliced | sliced;
}
- virtual void addDimensions(const std::vector<KeyMatcher>& keyMatchers) = 0;
-
protected:
// We don't really need the string name, but having a name here makes log messages
// easy to debug.
diff --git a/cmds/statsd/src/condition/ConditionWizard.h b/cmds/statsd/src/condition/ConditionWizard.h
index 4889b64..1a01afa 100644
--- a/cmds/statsd/src/condition/ConditionWizard.h
+++ b/cmds/statsd/src/condition/ConditionWizard.h
@@ -27,19 +27,23 @@
// Held by MetricProducer, to query a condition state with input defined in EventConditionLink.
class ConditionWizard : public virtual android::RefBase {
public:
+ ConditionWizard(){}; // for testing
ConditionWizard(std::vector<sp<ConditionTracker>>& conditionTrackers)
: mAllConditions(conditionTrackers){};
+ virtual ~ConditionWizard(){};
+
// Query condition state, for a ConditionTracker at [conditionIndex], with [conditionParameters]
// [conditionParameters] mapping from condition name to the HashableDimensionKey to query the
// condition.
// The ConditionTracker at [conditionIndex] can be a CombinationConditionTracker. In this case,
// the conditionParameters contains the parameters for it's children SimpleConditionTrackers.
- ConditionState query(const int conditionIndex,
- const std::map<std::string, HashableDimensionKey>& conditionParameters);
+ virtual ConditionState query(
+ const int conditionIndex,
+ const std::map<std::string, HashableDimensionKey>& conditionParameters);
private:
- std::vector<sp<ConditionTracker>>& mAllConditions;
+ std::vector<sp<ConditionTracker>> mAllConditions;
};
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index aff4768..b691faea 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -74,6 +74,13 @@
mStopAllLogMatcherIndex = -1;
}
+ mDimension.insert(mDimension.begin(), simpleCondition.dimension().begin(),
+ simpleCondition.dimension().end());
+
+ if (mDimension.size() > 0) {
+ mSliced = true;
+ }
+
mInitialized = true;
}
@@ -98,12 +105,6 @@
}
}
-void SimpleConditionTracker::addDimensions(const std::vector<KeyMatcher>& keyMatchers) {
- VLOG("Added dimensions size %lu", (unsigned long)keyMatchers.size());
- mDimensionsList.push_back(keyMatchers);
- mSliced = true;
-}
-
bool SimpleConditionTracker::evaluateCondition(const LogEvent& event,
const vector<MatchingState>& eventMatcherValues,
const vector<sp<ConditionTracker>>& mAllConditions,
@@ -157,18 +158,15 @@
// TODO: handle stop all; all dimension should be cleared.
}
- if (mDimensionsList.size() > 0) {
- for (size_t i = 0; i < mDimensionsList.size(); i++) {
- const auto& dim = mDimensionsList[i];
- vector<KeyValuePair> key = getDimensionKey(event, dim);
- HashableDimensionKey hashableKey = getHashableKey(key);
- if (mSlicedConditionState.find(hashableKey) == mSlicedConditionState.end() ||
- mSlicedConditionState[hashableKey] != newCondition) {
- slicedChanged = true;
- mSlicedConditionState[hashableKey] = newCondition;
- }
- VLOG("key: %s %d", hashableKey.c_str(), newCondition);
+
+ if (mDimension.size() > 0) {
+ HashableDimensionKey hashableKey = getHashableKey(getDimensionKey(event, mDimension));
+ if (mSlicedConditionState.find(hashableKey) == mSlicedConditionState.end() ||
+ mSlicedConditionState[hashableKey] != newCondition) {
+ slicedChanged = true;
+ mSlicedConditionState[hashableKey] = newCondition;
}
+ VLOG("key: %s %d", hashableKey.c_str(), newCondition);
// dump all dimensions for debugging
if (DEBUG) {
print(mSlicedConditionState, mName);
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index 1f357f0..b72157b 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -27,8 +27,6 @@
class SimpleConditionTracker : public virtual ConditionTracker {
public:
- // dimensions is a vector of vector because for one single condition, different metrics may be
- // interested in slicing in different ways. one vector<KeyMatcher> defines one type of slicing.
SimpleConditionTracker(const std::string& name, const int index,
const SimpleCondition& simpleCondition,
const std::unordered_map<std::string, int>& trackerNameIndexMap);
@@ -51,8 +49,6 @@
const std::vector<sp<ConditionTracker>>& allConditions,
std::vector<ConditionState>& conditionCache) override;
- void addDimensions(const std::vector<KeyMatcher>& keyMatchers) override;
-
private:
// The index of the LogEventMatcher which defines the start.
int mStartLogMatcherIndex;
@@ -66,8 +62,11 @@
// The index of the LogEventMatcher which defines the stop all.
int mStopAllLogMatcherIndex;
- // Different metrics may subscribe to different types of slicings. So it's a vector of vector.
- std::vector<std::vector<KeyMatcher>> mDimensionsList;
+ // The dimension defines at the atom level, how start and stop should match.
+ // e.g., APP_IN_FOREGROUND, the dimension should be the uid field. Each "start" and
+ // "stop" tells you the state change of a particular app. Without this dimension, this
+ // condition does not make sense.
+ std::vector<KeyMatcher> mDimension;
// Keep the map from the internal HashableDimensionKey to std::vector<KeyValuePair>
// that StatsLogReport wants.
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index c16971a..02e6903 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -118,9 +118,10 @@
StatsdConfig config;
config.set_config_id(12345L);
- int WAKE_LOCK_TAG_ID = 11;
+ int WAKE_LOCK_TAG_ID = 1111; // put a fake id here to make testing easier.
int WAKE_LOCK_UID_KEY_ID = 1;
- int WAKE_LOCK_STATE_KEY = 3;
+ int WAKE_LOCK_NAME_KEY = 3;
+ int WAKE_LOCK_STATE_KEY = 4;
int WAKE_LOCK_ACQUIRE_VALUE = 1;
int WAKE_LOCK_RELEASE_VALUE = 0;
@@ -138,6 +139,12 @@
int UID_PROCESS_STATE_TAG_ID = 27;
int UID_PROCESS_STATE_UID_KEY = 1;
+ int KERNEL_WAKELOCK_TAG_ID = 1004;
+ int KERNEL_WAKELOCK_NAME_KEY = 4;
+
+ int DEVICE_TEMPERATURE_TAG_ID = 33;
+ int DEVICE_TEMPERATURE_KEY = 1;
+
// Count Screen ON events.
CountMetric* metric = config.add_count_metric();
metric->set_metric_id(1);
@@ -180,27 +187,82 @@
link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
- // Duration of an app holding wl, while screen on and app in background
+ // Duration of an app holding any wl, while screen on and app in background, slice by uid
DurationMetric* durationMetric = config.add_duration_metric();
durationMetric->set_metric_id(5);
- durationMetric->set_start("APP_GET_WL");
- durationMetric->set_stop("APP_RELEASE_WL");
durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
keyMatcher = durationMetric->add_dimension();
keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
+ durationMetric->set_what("WL_STATE_PER_APP_PER_NAME");
durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
link = durationMetric->add_links();
link->set_condition("APP_IS_BACKGROUND");
link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
+ // max Duration of an app holding any wl, while screen on and app in background, slice by uid
+ durationMetric = config.add_duration_metric();
+ durationMetric->set_metric_id(6);
+ durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+ durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
+ keyMatcher = durationMetric->add_dimension();
+ keyMatcher->set_key(WAKE_LOCK_UID_KEY_ID);
+ durationMetric->set_what("WL_STATE_PER_APP_PER_NAME");
+ durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ link = durationMetric->add_links();
+ link->set_condition("APP_IS_BACKGROUND");
+ link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+ link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
+
+ // Duration of an app holding any wl, while screen on and app in background
+ durationMetric = config.add_duration_metric();
+ durationMetric->set_metric_id(7);
+ durationMetric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+ durationMetric->set_type(DurationMetric_AggregationType_DURATION_MAX_SPARSE);
+ durationMetric->set_what("WL_STATE_PER_APP_PER_NAME");
+ durationMetric->set_predicate("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ link = durationMetric->add_links();
+ link->set_condition("APP_IS_BACKGROUND");
+ link->add_key_in_main()->set_key(WAKE_LOCK_UID_KEY_ID);
+ link->add_key_in_condition()->set_key(APP_USAGE_UID_KEY_ID);
+
+ // Duration of screen on time.
+ durationMetric = config.add_duration_metric();
+ durationMetric->set_metric_id(8);
+ durationMetric->mutable_bucket()->set_bucket_size_millis(10 * 1000L);
+ durationMetric->set_type(DurationMetric_AggregationType_DURATION_SUM);
+ durationMetric->set_what("SCREEN_IS_ON");
+
+ // Value metric to count KERNEL_WAKELOCK when screen turned on
+ ValueMetric* valueMetric = config.add_value_metric();
+ valueMetric->set_metric_id(6);
+ valueMetric->set_what("KERNEL_WAKELOCK");
+ valueMetric->set_value_field(1);
+ valueMetric->set_condition("SCREEN_IS_ON");
+ keyMatcher = valueMetric->add_dimension();
+ keyMatcher->set_key(KERNEL_WAKELOCK_NAME_KEY);
+ // This is for testing easier. We should never set bucket size this small.
+ valueMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
+
// Add an EventMetric to log process state change events.
EventMetric* eventMetric = config.add_event_metric();
- eventMetric->set_metric_id(6);
+ eventMetric->set_metric_id(9);
eventMetric->set_what("SCREEN_TURNED_ON");
+ // Add an GaugeMetric.
+ GaugeMetric* gaugeMetric = config.add_gauge_metric();
+ gaugeMetric->set_metric_id(10);
+ gaugeMetric->set_what("DEVICE_TEMPERATURE");
+ gaugeMetric->set_gauge_field(DEVICE_TEMPERATURE_KEY);
+ gaugeMetric->mutable_bucket()->set_bucket_size_millis(60 * 1000L);
+
// Event matchers............
+ LogEntryMatcher* temperatureEntryMatcher = config.add_log_entry_matcher();
+ temperatureEntryMatcher->set_name("DEVICE_TEMPERATURE");
+ temperatureEntryMatcher->mutable_simple_log_entry_matcher()->set_tag(
+ DEVICE_TEMPERATURE_TAG_ID);
+
LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
eventMatcher->set_name("SCREEN_TURNED_ON");
SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
@@ -254,6 +316,12 @@
keyValueMatcher->mutable_key_matcher()->set_key(WAKE_LOCK_STATE_KEY);
keyValueMatcher->set_eq_int(WAKE_LOCK_RELEASE_VALUE);
+ // pulled events
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("KERNEL_WAKELOCK");
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->set_tag(KERNEL_WAKELOCK_TAG_ID);
+
// Conditions.............
Condition* condition = config.add_condition();
condition->set_name("SCREEN_IS_ON");
@@ -272,6 +340,8 @@
simpleCondition = condition->mutable_simple_condition();
simpleCondition->set_start("APP_GOES_BACKGROUND");
simpleCondition->set_stop("APP_GOES_FOREGROUND");
+ KeyMatcher* condition_dimension1 = simpleCondition->add_dimension();
+ condition_dimension1->set_key(APP_USAGE_UID_KEY_ID);
condition = config.add_condition();
condition->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
@@ -280,6 +350,16 @@
combination_condition->add_condition("APP_IS_BACKGROUND");
combination_condition->add_condition("SCREEN_IS_ON");
+ condition = config.add_condition();
+ condition->set_name("WL_STATE_PER_APP_PER_NAME");
+ simpleCondition = condition->mutable_simple_condition();
+ simpleCondition->set_start("APP_GET_WL");
+ simpleCondition->set_stop("APP_RELEASE_WL");
+ KeyMatcher* condition_dimension = simpleCondition->add_dimension();
+ condition_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
+ condition_dimension = simpleCondition->add_dimension();
+ condition_dimension->set_key(WAKE_LOCK_NAME_KEY);
+
return config;
}
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/PullDataReceiver.h
similarity index 66%
copy from cmds/statsd/src/external/KernelWakelockPuller.h
copy to cmds/statsd/src/external/PullDataReceiver.h
index c12806c..0d505cb 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/PullDataReceiver.h
@@ -13,27 +13,24 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#pragma once
#include <utils/String16.h>
-#include "external/StatsPuller.h"
+#include <unordered_map>
+#include <utils/RefBase.h>
+#include "StatsPuller.h"
+#include "logd/LogEvent.h"
namespace android {
namespace os {
namespace statsd {
-class KernelWakelockPuller : public StatsPuller {
-public:
- // a number of stats need to be pulled from StatsCompanionService
- //
- const static int PULL_CODE_KERNEL_WAKELOCKS;
- vector<StatsLogEventWrapper> pull() override;
+class PullDataReceiver : virtual public RefBase{
+ public:
+ virtual ~PullDataReceiver() {}
+ virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) = 0;
};
} // namespace statsd
} // namespace os
-} // namespace android
-
-#endif // STATSD_KERNELWAKELOCKPULLER_H
+} // namespace android
\ No newline at end of file
diff --git a/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
new file mode 100644
index 0000000..3608ee4
--- /dev/null
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
+#include <fcntl.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "external/ResourcePowerManagerPuller.h"
+#include "external/StatsPuller.h"
+
+#include "logd/LogEvent.h"
+
+using android::hardware::hidl_vec;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using android::hardware::power::V1_0::PowerStateVoter;
+using android::hardware::power::V1_0::Status;
+using android::hardware::power::V1_1::PowerStateSubsystem;
+using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
+using android::hardware::Return;
+using android::hardware::Void;
+
+using std::make_shared;
+using std::shared_ptr;
+
+namespace android {
+namespace os {
+namespace statsd {
+
+sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
+std::mutex gPowerHalMutex;
+bool gPowerHalExists = true;
+
+static const int power_state_platform_sleep_state_tag = 1011;
+static const int power_state_voter_tag = 1012;
+static const int power_state_subsystem_state_tag = 1013;
+
+bool getPowerHal() {
+ if (gPowerHalExists && gPowerHalV1_0 == nullptr) {
+ gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
+ if (gPowerHalV1_0 != nullptr) {
+ gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+ ALOGI("Loaded power HAL service");
+ } else {
+ ALOGW("Couldn't load power HAL service");
+ gPowerHalExists = false;
+ }
+ }
+ return gPowerHalV1_0 != nullptr;
+}
+
+bool ResourcePowerManagerPuller::Pull(const int tagId, vector<shared_ptr<LogEvent>>* data) {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if (!getPowerHal()) {
+ ALOGE("Power Hal not loaded");
+ return false;
+ }
+
+ uint64_t timestamp = time(nullptr) * NS_PER_SEC;
+
+ data->clear();
+ Return<void> ret = gPowerHalV1_0->getPlatformLowPowerStats(
+ [&data, timestamp](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+
+ if (status != Status::SUCCESS) return;
+
+ for (size_t i = 0; i < states.size(); i++) {
+ const PowerStatePlatformSleepState& state = states[i];
+
+ auto statePtr =
+ make_shared<LogEvent>(power_state_platform_sleep_state_tag, timestamp);
+ auto elemList = statePtr->GetAndroidLogEventList();
+ *elemList << state.name;
+ *elemList << state.residencyInMsecSinceBoot;
+ *elemList << state.totalTransitions;
+ *elemList << state.supportedOnlyInSuspend;
+ statePtr->init();
+ data->push_back(statePtr);
+ VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions, state.supportedOnlyInSuspend ? 1 : 0);
+ for (auto voter : state.voters) {
+ auto voterPtr = make_shared<LogEvent>(power_state_voter_tag, timestamp);
+ auto elemList = voterPtr->GetAndroidLogEventList();
+ *elemList << state.name;
+ *elemList << voter.name;
+ *elemList << voter.totalTimeInMsecVotedForSinceBoot;
+ *elemList << voter.totalNumberOfTimesVotedSinceBoot;
+ data->push_back(voterPtr);
+ VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
+ voter.name.c_str(), (long long)voter.totalTimeInMsecVotedForSinceBoot,
+ (long long)voter.totalNumberOfTimesVotedSinceBoot);
+ }
+ }
+ });
+ if (!ret.isOk()) {
+ ALOGE("getLowPowerStats() failed: power HAL service not available");
+ gPowerHalV1_0 = nullptr;
+ return false;
+ }
+
+ // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
+ sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
+ android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+ if (gPowerHal_1_1 != nullptr) {
+ ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ [&data, timestamp](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+
+ if (status != Status::SUCCESS) return;
+
+ if (subsystems.size() > 0) {
+ for (size_t i = 0; i < subsystems.size(); i++) {
+ const PowerStateSubsystem& subsystem = subsystems[i];
+ for (size_t j = 0; j < subsystem.states.size(); j++) {
+ const PowerStateSubsystemSleepState& state = subsystem.states[j];
+ auto subsystemStatePtr = make_shared<LogEvent>(
+ power_state_subsystem_state_tag, timestamp);
+ auto elemList = subsystemStatePtr->GetAndroidLogEventList();
+ *elemList << subsystem.name;
+ *elemList << state.name;
+ *elemList << state.residencyInMsecSinceBoot;
+ *elemList << state.totalTransitions;
+ *elemList << state.lastEntryTimestampMs;
+ *elemList << state.supportedOnlyInSuspend;
+ subsystemStatePtr->init();
+ data->push_back(subsystemStatePtr);
+ VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
+ subsystem.name.c_str(), state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions,
+ (long long)state.lastEntryTimestampMs);
+ }
+ }
+ }
+ });
+ }
+ return true;
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/ResourcePowerManagerPuller.h
similarity index 67%
rename from cmds/statsd/src/external/KernelWakelockPuller.h
rename to cmds/statsd/src/external/ResourcePowerManagerPuller.h
index c12806c..c396c12 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/ResourcePowerManagerPuller.h
@@ -14,26 +14,23 @@
* limitations under the License.
*/
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#pragma once
#include <utils/String16.h>
-#include "external/StatsPuller.h"
+#include "StatsPuller.h"
namespace android {
namespace os {
namespace statsd {
-class KernelWakelockPuller : public StatsPuller {
+/**
+ * Reads hal for sleep states
+ */
+class ResourcePowerManagerPuller : public StatsPuller {
public:
- // a number of stats need to be pulled from StatsCompanionService
- //
- const static int PULL_CODE_KERNEL_WAKELOCKS;
- vector<StatsLogEventWrapper> pull() override;
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) override;
};
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.cpp b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
similarity index 62%
rename from cmds/statsd/src/external/KernelWakelockPuller.cpp
rename to cmds/statsd/src/external/StatsCompanionServicePuller.cpp
index ee072f8..8e96399 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.cpp
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.cpp
@@ -14,43 +14,55 @@
* limitations under the License.
*/
+#define DEBUG true
#include "Log.h"
#include <android/os/IStatsCompanionService.h>
#include <binder/IPCThreadState.h>
#include <private/android_filesystem_config.h>
+#include "StatsCompanionServicePuller.h"
#include "StatsService.h"
-#include "external/KernelWakelockPuller.h"
-#include "external/StatsPuller.h"
using namespace android;
using namespace android::base;
using namespace android::binder;
using namespace android::os;
-using namespace std;
+using std::make_shared;
+using std::shared_ptr;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
-const int KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS = 20;
+const int kLogMsgHeaderSize = 28;
// The reading and parsing are implemented in Java. It is not difficult to port over. But for now
// let StatsCompanionService handle that and send the data back.
-vector<StatsLogEventWrapper> KernelWakelockPuller::pull() {
+bool StatsCompanionServicePuller::Pull(const int tagId, vector<shared_ptr<LogEvent> >* data) {
sp<IStatsCompanionService> statsCompanion = StatsService::getStatsCompanionService();
vector<StatsLogEventWrapper> returned_value;
if (statsCompanion != NULL) {
- Status status = statsCompanion->pullData(KernelWakelockPuller::PULL_CODE_KERNEL_WAKELOCKS,
- &returned_value);
+ Status status = statsCompanion->pullData(tagId, &returned_value);
if (!status.isOk()) {
ALOGW("error pulling kernel wakelock");
+ return false;
+ }
+ data->clear();
+ for (const StatsLogEventWrapper& it : returned_value) {
+ log_msg tmp;
+ tmp.entry_v1.len = it.bytes.size();
+ // Manually set the header size to 28 bytes to match the pushed log events.
+ tmp.entry.hdr_size = kLogMsgHeaderSize;
+ // And set the received bytes starting after the 28 bytes reserved for header.
+ std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + kLogMsgHeaderSize);
+ data->push_back(make_shared<LogEvent>(tmp));
}
ALOGD("KernelWakelockPuller::pull succeeded!");
- return returned_value;
+ return true;
} else {
ALOGW("statsCompanion not found!");
- return returned_value;
+ return false;
}
}
diff --git a/cmds/statsd/src/external/KernelWakelockPuller.h b/cmds/statsd/src/external/StatsCompanionServicePuller.h
similarity index 67%
copy from cmds/statsd/src/external/KernelWakelockPuller.h
copy to cmds/statsd/src/external/StatsCompanionServicePuller.h
index c12806c..3ff2274f 100644
--- a/cmds/statsd/src/external/KernelWakelockPuller.h
+++ b/cmds/statsd/src/external/StatsCompanionServicePuller.h
@@ -14,26 +14,20 @@
* limitations under the License.
*/
-#ifndef STATSD_KERNELWAKELOCKPULLER_H
-#define STATSD_KERNELWAKELOCKPULLER_H
+#pragma once
#include <utils/String16.h>
-#include "external/StatsPuller.h"
+#include "StatsPuller.h"
namespace android {
namespace os {
namespace statsd {
-class KernelWakelockPuller : public StatsPuller {
+class StatsCompanionServicePuller : public StatsPuller {
public:
- // a number of stats need to be pulled from StatsCompanionService
- //
- const static int PULL_CODE_KERNEL_WAKELOCKS;
- vector<StatsLogEventWrapper> pull() override;
+ bool Pull(const int tagId, vector<std::shared_ptr<LogEvent> >* data) override;
};
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // STATSD_KERNELWAKELOCKPULLER_H
diff --git a/cmds/statsd/src/external/StatsPuller.h b/cmds/statsd/src/external/StatsPuller.h
index 6655629..940ad9c 100644
--- a/cmds/statsd/src/external/StatsPuller.h
+++ b/cmds/statsd/src/external/StatsPuller.h
@@ -14,12 +14,12 @@
* limitations under the License.
*/
-#ifndef STATSD_STATSPULLER_H
-#define STATSD_STATSPULLER_H
+#pragma once
#include <android/os/StatsLogEventWrapper.h>
#include <utils/String16.h>
#include <vector>
+#include "logd/LogEvent.h"
using android::os::StatsLogEventWrapper;
using std::vector;
@@ -32,11 +32,9 @@
public:
virtual ~StatsPuller(){};
- virtual vector<StatsLogEventWrapper> pull() = 0;
+ virtual bool Pull(const int tagId, vector<std::shared_ptr<LogEvent>>* data) = 0;
};
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // STATSD_STATSPULLER_H
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 7f554d3..43543cc 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -18,49 +18,147 @@
#include "Log.h"
#include <android/os/IStatsCompanionService.h>
-#include "KernelWakelockPuller.h"
-#include "StatsService.h"
-#include "external/StatsPullerManager.h"
-#include "logd/LogEvent.h"
#include <cutils/log.h>
#include <algorithm>
+#include <climits>
+#include "ResourcePowerManagerPuller.h"
+#include "StatsCompanionServicePuller.h"
+#include "StatsPullerManager.h"
+#include "StatsService.h"
+#include "logd/LogEvent.h"
+#include "statslog.h"
#include <iostream>
-using namespace android;
+using std::make_shared;
+using std::map;
+using std::shared_ptr;
+using std::string;
+using std::vector;
namespace android {
namespace os {
namespace statsd {
-const int StatsPullerManager::KERNEL_WAKELOCKS = 1;
+StatsPullerManager::StatsPullerManager()
+ : mCurrentPullingInterval(LONG_MAX), mPullStartTimeMs(get_pull_start_time_ms()) {
+ shared_ptr<StatsPuller> statsCompanionServicePuller =
+ make_shared<StatsCompanionServicePuller>();
+ shared_ptr<StatsPuller> resourcePowerManagerPuller = make_shared<ResourcePowerManagerPuller>();
-StatsPullerManager::StatsPullerManager() {
- mStatsPullers.insert(
- {static_cast<int>(KERNEL_WAKELOCKS), std::make_unique<KernelWakelockPuller>()});
+ mPullers.insert({android::util::KERNEL_WAKELOCK_PULLED, statsCompanionServicePuller});
+ mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED, statsCompanionServicePuller});
+ mPullers.insert({android::util::MOBILE_BYTES_TRANSFERRED, statsCompanionServicePuller});
+ mPullers.insert({android::util::WIFI_BYTES_TRANSFERRED_BY_FG_BG, statsCompanionServicePuller});
+ mPullers.insert(
+ {android::util::MOBILE_BYTES_TRANSFERRED_BY_FG_BG, statsCompanionServicePuller});
+ mPullers.insert(
+ {android::util::POWER_STATE_PLATFORM_SLEEP_STATE_PULLED, resourcePowerManagerPuller});
+ mPullers.insert({android::util::POWER_STATE_VOTER_PULLED, resourcePowerManagerPuller});
+ mPullers.insert(
+ {android::util::POWER_STATE_SUBSYSTEM_SLEEP_STATE_PULLED, resourcePowerManagerPuller});
+
+ mStatsCompanionService = StatsService::getStatsCompanionService();
}
-vector<std::shared_ptr<LogEvent>> StatsPullerManager::Pull(int pullCode) {
- if (DEBUG) ALOGD("Initiating pulling %d", pullCode);
+bool StatsPullerManager::Pull(int tagId, vector<shared_ptr<LogEvent>>* data) {
+ if (DEBUG) ALOGD("Initiating pulling %d", tagId);
- vector<std::shared_ptr<LogEvent>> ret;
- if (mStatsPullers.find(pullCode) != mStatsPullers.end()) {
- vector<StatsLogEventWrapper> outputs = (mStatsPullers.find(pullCode)->second)->pull();
- for (const StatsLogEventWrapper& it : outputs) {
- log_msg tmp;
- tmp.entry_v1.len = it.bytes.size();
- // Manually set the header size to 28 bytes to match the pushed log events.
- tmp.entry.hdr_size = 28;
- // And set the received bytes starting after the 28 bytes reserved for header.
- std::copy(it.bytes.begin(), it.bytes.end(), tmp.buf + 28);
- std::shared_ptr<LogEvent> evt = std::make_shared<LogEvent>(tmp);
- ret.push_back(evt);
- // ret.emplace_back(tmp);
- }
- return ret;
+ if (mPullers.find(tagId) != mPullers.end()) {
+ return mPullers.find(tagId)->second->Pull(tagId, data);
} else {
- ALOGD("Unknown pull code %d", pullCode);
- return ret; // Return early since we don't know what to pull.
+ ALOGD("Unknown tagId %d", tagId);
+ return false; // Return early since we don't know what to pull.
+ }
+}
+
+StatsPullerManager& StatsPullerManager::GetInstance() {
+ static StatsPullerManager instance;
+ return instance;
+}
+
+bool StatsPullerManager::PullerForMatcherExists(int tagId) {
+ return mPullers.find(tagId) != mPullers.end();
+}
+
+long StatsPullerManager::get_pull_start_time_ms() {
+ // TODO: limit and align pull intervals to 10min boundaries if this turns out to be a problem
+ return time(nullptr) * 1000;
+}
+
+void StatsPullerManager::RegisterReceiver(int tagId, sp<PullDataReceiver> receiver,
+ long intervalMs) {
+ AutoMutex _l(mReceiversLock);
+ vector<ReceiverInfo>& receivers = mReceivers[tagId];
+ for (auto it = receivers.begin(); it != receivers.end(); it++) {
+ if (it->receiver.get() == receiver.get()) {
+ VLOG("Receiver already registered of %d", (int)receivers.size());
+ return;
+ }
+ }
+ ReceiverInfo receiverInfo;
+ receiverInfo.receiver = receiver;
+ receiverInfo.timeInfo.first = intervalMs;
+ receivers.push_back(receiverInfo);
+
+ // There is only one alarm for all pulled events. So only set it to the smallest denom.
+ if (intervalMs < mCurrentPullingInterval) {
+ VLOG("Updating pulling interval %ld", intervalMs);
+ mCurrentPullingInterval = intervalMs;
+ if (mStatsCompanionService != nullptr) {
+ mStatsCompanionService->setPullingAlarms(mPullStartTimeMs, mCurrentPullingInterval);
+ } else {
+ VLOG("Failed to update pulling interval");
+ }
+ }
+ VLOG("Puller for tagId %d registered of %d", tagId, (int)receivers.size());
+}
+
+void StatsPullerManager::UnRegisterReceiver(int tagId, sp<PullDataReceiver> receiver) {
+ AutoMutex _l(mReceiversLock);
+ if (mReceivers.find(tagId) == mReceivers.end()) {
+ VLOG("Unknown pull code or no receivers: %d", tagId);
+ return;
+ }
+ auto& receivers = mReceivers.find(tagId)->second;
+ for (auto it = receivers.begin(); it != receivers.end(); it++) {
+ if (receiver.get() == it->receiver.get()) {
+ receivers.erase(it);
+ VLOG("Puller for tagId %d unregistered of %d", tagId, (int)receivers.size());
+ return;
+ }
+ }
+}
+
+void StatsPullerManager::OnAlarmFired() {
+ AutoMutex _l(mReceiversLock);
+
+ uint64_t currentTimeMs = time(nullptr) * 1000;
+
+ vector<pair<int, vector<ReceiverInfo*>>> needToPull =
+ vector<pair<int, vector<ReceiverInfo*>>>();
+ for (auto& pair : mReceivers) {
+ vector<ReceiverInfo*> receivers = vector<ReceiverInfo*>();
+ if (pair.second.size() != 0) {
+ for (auto& receiverInfo : pair.second) {
+ if (receiverInfo.timeInfo.first + receiverInfo.timeInfo.second > currentTimeMs) {
+ receivers.push_back(&receiverInfo);
+ }
+ }
+ if (receivers.size() > 0) {
+ needToPull.push_back(make_pair(pair.first, receivers));
+ }
+ }
+ }
+
+ for (const auto& pullInfo : needToPull) {
+ vector<shared_ptr<LogEvent>> data;
+ if (Pull(pullInfo.first, &data)) {
+ for (const auto& receiverInfo : pullInfo.second) {
+ receiverInfo->receiver->onDataPulled(data);
+ receiverInfo->timeInfo.second = currentTimeMs;
+ }
+ }
}
}
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index e46aec1..67580d6 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -14,38 +14,75 @@
* limitations under the License.
*/
-#ifndef STATSD_STATSPULLERMANAGER_H
-#define STATSD_STATSPULLERMANAGER_H
+#pragma once
+#include <android/os/IStatsCompanionService.h>
+#include <binder/IServiceManager.h>
+#include <utils/RefBase.h>
#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/threads.h>
+#include <string>
#include <unordered_map>
-#include "external/StatsPuller.h"
+#include <vector>
+#include "PullDataReceiver.h"
+#include "StatsPuller.h"
#include "logd/LogEvent.h"
-#include "matchers/matcher_util.h"
namespace android {
namespace os {
namespace statsd {
-const static int KERNEL_WAKELOCKS = 1;
-
class StatsPullerManager : public virtual RefBase {
public:
- // Enums of pulled data types (pullCodes)
- // These values must be kept in sync with com/android/server/stats/StatsCompanionService.java.
- // TODO: pull the constant from stats_events.proto instead
- const static int KERNEL_WAKELOCKS;
- StatsPullerManager();
+ static StatsPullerManager& GetInstance();
- // We return a vector of shared_ptr since LogEvent's copy constructor is not available.
- vector<std::shared_ptr<LogEvent>> Pull(const int pullCode);
+ void RegisterReceiver(int tagId, sp<PullDataReceiver> receiver, long intervalMs);
+
+ void UnRegisterReceiver(int tagId, sp<PullDataReceiver> receiver);
+
+ // Verify if we know how to pull for this matcher
+ bool PullerForMatcherExists(int tagId);
+
+ void OnAlarmFired();
+
+ bool Pull(const int pullCode, vector<std::shared_ptr<LogEvent>>* data);
private:
- std::unordered_map<int, std::unique_ptr<StatsPuller>> mStatsPullers;
+ StatsPullerManager();
+
+ // use this to update alarm
+ sp<IStatsCompanionService> mStatsCompanionService = nullptr;
+
+ sp<IStatsCompanionService> get_stats_companion_service();
+
+ // mapping from simple matcher tagId to puller
+ std::map<int, std::shared_ptr<StatsPuller>> mPullers;
+
+ typedef struct {
+ // pull_interval_sec : last_pull_time_sec
+ std::pair<uint64_t, uint64_t> timeInfo;
+ sp<PullDataReceiver> receiver;
+ } ReceiverInfo;
+
+ // mapping from simple matcher tagId to receivers
+ std::map<int, std::vector<ReceiverInfo>> mReceivers;
+
+ Mutex mReceiversLock;
+
+ long mCurrentPullingInterval;
+
+ // for pulled metrics, it is important for the buckets to be aligned to multiple of smallest
+ // bucket size. All pulled metrics start pulling based on this time, so that they can be
+ // correctly attributed to the correct buckets. Pulled data attach a timestamp which is the
+ // request time.
+ const long mPullStartTimeMs;
+
+ long get_pull_start_time_ms();
+
+ LogEvent parse_pulled_data(String16 data);
};
} // namespace statsd
} // namespace os
} // namespace android
-
-#endif // STATSD_STATSPULLERMANAGER_H
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 1a039f6..913b906 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#define DEBUG true // STOPSHIP if true
#include "logd/LogEvent.h"
#include <sstream>
@@ -23,17 +24,18 @@
namespace os {
namespace statsd {
+using namespace android::util;
using std::ostringstream;
using std::string;
using android::util::ProtoOutputStream;
// We need to keep a copy of the android_log_event_list owned by this instance so that the char*
// for strings is not cleared before we can read them.
-LogEvent::LogEvent(log_msg msg) : mList(msg) {
+LogEvent::LogEvent(log_msg& msg) : mList(msg) {
init(msg.entry_v1.sec * NS_PER_SEC + msg.entry_v1.nsec, &mList);
}
-LogEvent::LogEvent(int tag) : mList(tag) {
+LogEvent::LogEvent(int tag, uint64_t timestampNs) : mList(tag), mTimestampNs(timestampNs) {
}
LogEvent::~LogEvent() {
@@ -206,20 +208,20 @@
}
void LogEvent::ToProto(ProtoOutputStream& proto) const {
- long long atomToken = proto.start(TYPE_MESSAGE + mTagId);
+ long long atomToken = proto.start(FIELD_TYPE_MESSAGE | mTagId);
const size_t N = mElements.size();
for (size_t i=0; i<N; i++) {
const int key = i + 1;
const android_log_list_element& elem = mElements[i];
if (elem.type == EVENT_TYPE_INT) {
- proto.write(TYPE_INT32 + key, elem.data.int32);
+ proto.write(FIELD_TYPE_INT32 | key, elem.data.int32);
} else if (elem.type == EVENT_TYPE_LONG) {
- proto.write(TYPE_INT64 + key, (long long)elem.data.int64);
+ proto.write(FIELD_TYPE_INT64 | key, (long long)elem.data.int64);
} else if (elem.type == EVENT_TYPE_FLOAT) {
- proto.write(TYPE_FLOAT + key, elem.data.float32);
+ proto.write(FIELD_TYPE_FLOAT | key, elem.data.float32);
} else if (elem.type == EVENT_TYPE_STRING) {
- proto.write(TYPE_STRING + key, elem.data.string);
+ proto.write(FIELD_TYPE_STRING | key, elem.data.string);
}
}
proto.end(atomToken);
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 9ef20ea..2984940 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -42,7 +42,7 @@
/**
* Read a LogEvent from a log_msg.
*/
- explicit LogEvent(log_msg msg);
+ explicit LogEvent(log_msg& msg);
/**
* Constructs a LogEvent with the specified tag and creates an android_log_event_list in write
@@ -50,7 +50,7 @@
* any of the values. This constructor is useful for unit-testing since we can't pass in an
* android_log_event_list since there is no copy constructor or assignment operator available.
*/
- explicit LogEvent(int tag);
+ explicit LogEvent(int tag, uint64_t timestampNs);
~LogEvent();
@@ -123,7 +123,9 @@
vector<android_log_list_element> mElements;
// Need a copy of the android_log_event_list so the strings are not cleared.
android_log_event_list mList;
- long mTimestampNs;
+
+ uint64_t mTimestampNs;
+
int mTagId;
};
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 69f336f..94f4adf 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -21,10 +21,15 @@
#include "CountMetricProducer.h"
#include "stats_util.h"
-#include <cutils/log.h>
#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;
@@ -34,12 +39,32 @@
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_COUNT_METRICS = 5;
+// for CountMetricDataWrapper
+const int FIELD_ID_DATA = 1;
+// for CountMetricData
+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 CountBucketInfo
+const int FIELD_ID_START_BUCKET_NANOS = 1;
+const int FIELD_ID_END_BUCKET_NANOS = 2;
+const int FIELD_ID_COUNT = 3;
+
// TODO: add back AnomalyTracker.
CountMetricProducer::CountMetricProducer(const CountMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard)
- // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
- : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
- mMetric(metric) {
+ const sp<ConditionWizard>& wizard,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
// TODO: evaluate initial conditions. and set mConditionMet.
if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
@@ -67,6 +92,8 @@
mConditionSliced = true;
}
+ startNewProtoOutputStream(mStartTimeNs);
+
VLOG("metric %lld created. bucket size %lld start_time: %lld", metric.metric_id(),
(long long)mBucketSizeNs, (long long)mStartTimeNs);
}
@@ -75,60 +102,89 @@
VLOG("~CountMetricProducer() called");
}
+void CountMetricProducer::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_COUNT_METRICS);
+}
+
void CountMetricProducer::finish() {
- // TODO: write the StatsLogReport to dropbox using
- // DropboxWriter.
}
-static void addSlicedCounterToReport(StatsLogReport_CountMetricDataWrapper& wrapper,
- const vector<KeyValuePair>& key,
- const vector<CountBucketInfo>& buckets) {
- CountMetricData* 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] count: %lld", bucket.start_bucket_nanos(),
- bucket.end_bucket_nanos(), bucket.count());
- }
-}
-
-void CountMetricProducer::onSlicedConditionMayChange() {
+void CountMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
}
StatsLogReport CountMetricProducer::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.
- flushCounterIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
- report.set_end_report_nanos(mCurrentBucketStartTimeNs);
+ flushCounterIfNeeded(endTime);
+ VLOG("metric %lld dump report now...", mMetric.metric_id());
- StatsLogReport_CountMetricDataWrapper* wrapper = report.mutable_count_metrics();
-
- for (const auto& pair : mPastBuckets) {
- const HashableDimensionKey& hashableKey = pair.first;
+ for (const auto& counter : mPastBuckets) {
+ const HashableDimensionKey& hashableKey = counter.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 (CountBucketInfo).
+ for (const auto& bucket : counter.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_COUNT, (long long)bucket.mCount);
+ mProto->end(bucketInfoToken);
+ VLOG("\t bucket [%lld - %lld] count: %lld", (long long)bucket.mBucketStartNs,
+ (long long)bucket.mBucketEndNs, (long long)bucket.mCount);
+ }
+ 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(endTime);
+ 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 CountMetricProducer::onConditionChanged(const bool conditionMet) {
+void CountMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
mCondition = conditionMet;
}
@@ -136,7 +192,7 @@
void CountMetricProducer::onMatchedLogEventInternal(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const map<string, HashableDimensionKey>& conditionKey, bool condition,
- const LogEvent& event) {
+ const LogEvent& event, bool scheduledPull) {
uint64_t eventTimeNs = event.GetTimestampNs();
flushCounterIfNeeded(eventTimeNs);
@@ -176,18 +232,16 @@
// adjust the bucket start time
int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
- CountBucketInfo info;
- info.set_start_bucket_nanos(mCurrentBucketStartTimeNs);
- info.set_end_bucket_nanos(mCurrentBucketStartTimeNs + mBucketSizeNs);
-
+ CountBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
for (const auto& counter : mCurrentSlicedCounter) {
- info.set_count(counter.second);
- // it will auto create new vector of CountbucketInfo if the key is not found.
+ info.mCount = counter.second;
auto& bucketList = mPastBuckets[counter.first];
bucketList.push_back(info);
-
VLOG("metric %lld, dump key value: %s -> %d", mMetric.metric_id(), counter.first.c_str(),
counter.second);
+ mByteSize += sizeof(info);
}
// TODO: Re-add anomaly detection (similar to):
@@ -203,11 +257,11 @@
(long long)mCurrentBucketStartTimeNs);
}
+// Rough estimate of CountMetricProducer buffer stored. This number will be
+// greater than actual data size as it contains each dimension of
+// CountMetricData is duplicated.
size_t CountMetricProducer::byteSize() {
-// TODO: return actual proto size when ProtoOutputStream is ready for use for
-// CountMetricsProducer.
-// return mProto->size();
- return 0;
+ return mByteSize;
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index be77e47..c3af006 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -19,6 +19,8 @@
#include <unordered_map>
+#include <android/util/ProtoOutputStream.h>
+#include <gtest/gtest_prod.h>
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "CountAnomalyTracker.h"
@@ -33,37 +35,51 @@
namespace os {
namespace statsd {
+struct CountBucket {
+ int64_t mBucketStartNs;
+ int64_t mBucketEndNs;
+ int64_t mCount;
+};
+
class CountMetricProducer : public MetricProducer {
public:
// TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
CountMetricProducer(const CountMetric& countMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard);
+ const sp<ConditionWizard>& wizard, const uint64_t startTimeNs);
virtual ~CountMetricProducer();
- void onConditionChanged(const bool conditionMet) override;
+ void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
- void onSlicedConditionMayChange() override;
+ void onSlicedConditionMayChange(const uint64_t eventTime) override;
size_t byteSize() override;
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ // TODO: Implement this later.
+ virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey,
- bool condition, const LogEvent& event) override;
+ bool condition, const LogEvent& event,
+ bool scheduledPull) override;
+
+ void startNewProtoOutputStream(long long timestamp) override;
private:
const CountMetric mMetric;
- // Save the past buckets and we can clear when the StatsLogReport is dumped.
- std::unordered_map<HashableDimensionKey, std::vector<CountBucketInfo>> mPastBuckets;
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<CountBucket>> mPastBuckets;
+
+ size_t mByteSize;
// The current bucket.
std::unordered_map<HashableDimensionKey, int> mCurrentSlicedCounter;
@@ -71,6 +87,10 @@
vector<unique_ptr<CountAnomalyTracker>> mAnomalyTrackers;
void flushCounterIfNeeded(const uint64_t newEventTime);
+
+ FRIEND_TEST(CountMetricProducerTest, TestNonDimensionalEvents);
+ FRIEND_TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition);
+ FRIEND_TEST(CountMetricProducerTest, TestEventsWithSlicedCondition);
};
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index a590bc8..c0a0d98 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -15,14 +15,20 @@
*/
#define DEBUG true
-#include "DurationMetricProducer.h"
+
#include "Log.h"
+#include "DurationMetricProducer.h"
#include "stats_util.h"
-#include <cutils/log.h>
#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,16 +37,39 @@
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,
- const sp<ConditionWizard>& wizard)
- // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
- : MetricProducer(time(nullptr) * NANO_SECONDS_IN_A_SECOND, conditionIndex, wizard),
+ const sp<ConditionWizard>& wizard,
+ const vector<KeyMatcher>& internalDimension,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard),
mMetric(metric),
mStartIndex(startIndex),
mStopIndex(stopIndex),
- mStopAllIndex(stopAllIndex) {
+ mStopAllIndex(stopAllIndex),
+ mInternalDimension(internalDimension) {
// TODO: The following boiler plate code appears in all MetricProducers, but we can't abstract
// them in the base class, because the proto generated CountMetric, and DurationMetric are
// not related. Maybe we should add a template in the future??
@@ -59,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);
}
@@ -67,34 +98,50 @@
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<DurationBucket>& bucket) {
+ switch (mMetric.type()) {
+ case DurationMetric_AggregationType_DURATION_SUM:
+ return make_unique<OringDurationTracker>(mWizard, mConditionTrackerIndex,
+ mCurrentBucketStartTimeNs, mBucketSizeNs,
+ bucket);
+ case DurationMetric_AggregationType_DURATION_MAX_SPARSE:
+ return make_unique<MaxDurationTracker>(mWizard, mConditionTrackerIndex,
+ mCurrentBucketStartTimeNs, mBucketSizeNs,
+ bucket);
+ }
+}
+
void DurationMetricProducer::finish() {
// TODO: write the StatsLogReport to dropbox using
// DropboxWriter.
}
-void DurationMetricProducer::onSlicedConditionMayChange() {
+void DurationMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
// Now for each of the on-going event, check if the condition has changed for them.
+ flushIfNeeded(eventTime);
for (auto& pair : mCurrentSlicedDuration) {
- VLOG("Metric %lld current %s state: %d", mMetric.metric_id(), pair.first.c_str(),
- pair.second.state);
- if (pair.second.state == kStopped) {
- continue;
- }
- bool conditionMet = mWizard->query(mConditionTrackerIndex, pair.second.conditionKeys) ==
- ConditionState::kTrue;
- VLOG("key: %s, condition: %d", pair.first.c_str(), conditionMet);
- noteConditionChanged(pair.first, conditionMet, time(nullptr) * 1000000000);
+ pair.second->onSlicedConditionMayChange(eventTime);
}
}
-void DurationMetricProducer::onConditionChanged(const bool conditionMet) {
+void DurationMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
mCondition = conditionMet;
// TODO: need to populate the condition change time from the event which triggers the condition
// change, instead of using current time.
+
+ flushIfNeeded(eventTime);
for (auto& pair : mCurrentSlicedDuration) {
- noteConditionChanged(pair.first, conditionMet, time(nullptr) * 1000000000);
+ pair.second->onConditionChanged(conditionMet, eventTime);
}
}
@@ -107,253 +154,127 @@
}
for (const auto& bucket : buckets) {
data->add_bucket_info()->CopyFrom(bucket);
- VLOG("\t bucket [%lld - %lld] count: %lld", bucket.start_bucket_nanos(),
+ VLOG("\t bucket [%lld - %lld] duration(ns): %lld", bucket.start_bucket_nanos(),
bucket.end_bucket_nanos(), bucket.duration_nanos());
}
}
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.
- flushDurationIfNeeded(time(nullptr) * NANO_SECONDS_IN_A_SECOND);
- 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);
- }
- return report;
-};
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
-void DurationMetricProducer::onMatchedLogEventInternal(
- const size_t matcherIndex, const HashableDimensionKey& eventKey,
- const map<string, HashableDimensionKey>& conditionKeys, bool condition,
- const LogEvent& event) {
- flushDurationIfNeeded(event.GetTimestampNs());
-
- if (matcherIndex == mStopAllIndex) {
- noteStopAll(event.GetTimestampNs());
- return;
- }
-
- if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end() && mConditionSliced) {
- // add the durationInfo for the current bucket.
- auto& durationInfo = mCurrentSlicedDuration[eventKey];
- durationInfo.conditionKeys = conditionKeys;
- }
-
- if (matcherIndex == mStartIndex) {
- VLOG("Metric %lld Key: %s Start, Condition %d", mMetric.metric_id(), eventKey.c_str(),
- condition);
- noteStart(eventKey, condition, event.GetTimestampNs());
- } else if (matcherIndex == mStopIndex) {
- VLOG("Metric %lld Key: %s Stop, Condition %d", mMetric.metric_id(), eventKey.c_str(),
- condition);
- noteStop(eventKey, event.GetTimestampNs());
- }
-}
-
-void DurationMetricProducer::noteConditionChanged(const HashableDimensionKey& key,
- const bool conditionMet,
- const uint64_t eventTime) {
- flushDurationIfNeeded(eventTime);
-
- auto it = mCurrentSlicedDuration.find(key);
- if (it == mCurrentSlicedDuration.end()) {
- return;
- }
-
- switch (it->second.state) {
- case kStarted:
- // if condition becomes false, kStarted -> kPaused. Record the current duration.
- if (!conditionMet) {
- it->second.state = DurationState::kPaused;
- it->second.lastDuration =
- updateDuration(it->second.lastDuration,
- eventTime - it->second.lastStartTime, mMetric.type());
- VLOG("Metric %lld Key: %s Paused because condition is false ", mMetric.metric_id(),
- key.c_str());
+ // 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());
}
- break;
- case kStopped:
- // nothing to do if it's stopped.
- break;
- case kPaused:
- // if condition becomes true, kPaused -> kStarted. and the start time is the condition
- // change time.
- if (conditionMet) {
- it->second.state = DurationState::kStarted;
- it->second.lastStartTime = eventTime;
- VLOG("Metric %lld Key: %s Paused->Started", mMetric.metric_id(), key.c_str());
- }
- break;
- }
-}
-
-void DurationMetricProducer::noteStart(const HashableDimensionKey& key, const bool conditionMet,
- const uint64_t eventTime) {
- // this will add an empty bucket for this key if it didn't exist before.
- DurationInfo& duration = mCurrentSlicedDuration[key];
-
- switch (duration.state) {
- case kStarted:
- // It's safe to do nothing here. even if condition is not true, it means we are about
- // to receive the condition change event.
- break;
- case kPaused:
- // Safe to do nothing here. kPaused is waiting for the condition change.
- break;
- case kStopped:
- if (!conditionMet) {
- // event started, but we need to wait for the condition to become true.
- duration.state = DurationState::kPaused;
- break;
- }
- duration.state = DurationState::kStarted;
- duration.lastStartTime = eventTime;
- break;
- }
-}
-
-void DurationMetricProducer::noteStop(const HashableDimensionKey& key, const uint64_t eventTime) {
- if (mCurrentSlicedDuration.find(key) == mCurrentSlicedDuration.end()) {
- // we didn't see a start event before. do nothing.
- return;
- }
- DurationInfo& duration = mCurrentSlicedDuration[key];
-
- switch (duration.state) {
- case DurationState::kStopped:
- // already stopped, do nothing.
- break;
- case DurationState::kStarted: {
- duration.state = DurationState::kStopped;
- int64_t durationTime = eventTime - duration.lastStartTime;
- VLOG("Metric %lld, key %s, Stop %lld %lld %lld", mMetric.metric_id(), key.c_str(),
- (long long)duration.lastStartTime, (long long)eventTime, (long long)durationTime);
- duration.lastDuration =
- updateDuration(duration.lastDuration, durationTime, mMetric.type());
- VLOG(" record duration: %lld ", (long long)duration.lastDuration);
- break;
+ mProto->end(dimensionToken);
}
- case DurationState::kPaused: {
- duration.state = DurationState::kStopped;
- break;
+
+ // 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);
}
+
+ 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();
}
-int64_t DurationMetricProducer::updateDuration(const int64_t lastDuration,
- const int64_t durationTime,
- const DurationMetric_AggregationType type) {
- int64_t result = lastDuration;
- switch (type) {
- case DurationMetric_AggregationType_DURATION_SUM:
- result += durationTime;
- break;
- case DurationMetric_AggregationType_DURATION_MAX_SPARSE:
- if (lastDuration < durationTime) {
- result = durationTime;
- }
- break;
- case DurationMetric_AggregationType_DURATION_MIN_SPARSE:
- if (lastDuration > durationTime) {
- result = durationTime;
- }
- break;
- }
- return result;
-}
-
-void DurationMetricProducer::noteStopAll(const uint64_t eventTime) {
- for (auto& duration : mCurrentSlicedDuration) {
- noteStop(duration.first, eventTime);
- }
-}
-
-// When a new matched event comes in, we check if event falls into the current
-// bucket. If not, flush the old counter to past buckets and initialize the current buckt.
-void DurationMetricProducer::flushDurationIfNeeded(const uint64_t eventTime) {
+void DurationMetricProducer::flushIfNeeded(uint64_t eventTime) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
return;
}
- // 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);
-
- uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
- mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
- VLOG("Metric %lld: new bucket start time: %lld", mMetric.metric_id(),
- (long long)mCurrentBucketStartTimeNs);
-
+ VLOG("flushing...........");
for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end(); ++it) {
- int64_t finalDuration = it->second.lastDuration;
- if (it->second.state == kStarted) {
- // the event is still on-going, duration needs to be updated.
- int64_t durationTime = endTime - it->second.lastStartTime;
- finalDuration = updateDuration(it->second.lastDuration, durationTime, mMetric.type());
- }
-
- VLOG(" final duration for last bucket: %lld", (long long)finalDuration);
-
- // Don't record empty bucket.
- if (finalDuration != 0) {
- info.set_duration_nanos(finalDuration);
- // it will auto create new vector of CountbucketInfo if the key is not found.
- auto& bucketList = mPastBuckets[it->first];
- bucketList.push_back(info);
- }
-
- // if the event is still on-going, add the buckets between previous bucket and now. Because
- // the event has been going on across all the buckets in between.
- // |prev_bucket|...|..|...|now_bucket|
- if (it->second.state == kStarted) {
- 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);
- auto& bucketList = mPastBuckets[it->first];
- bucketList.push_back(info);
- VLOG(" add filling bucket with duration %lld", (long long)mBucketSizeNs);
- }
- }
-
- if (it->second.state == DurationState::kStopped) {
- // No need to keep buckets for events that were stopped before. If the event starts
- // again, we will add it back.
+ if (it->second->flushIfNeeded(eventTime)) {
+ VLOG("erase bucket for key %s", it->first.c_str());
mCurrentSlicedDuration.erase(it);
- } else {
- // for kPaused, and kStarted event, we will keep the buckets, and reset the start time
- // and duration.
- it->second.lastStartTime = mCurrentBucketStartTimeNs;
- it->second.lastDuration = 0;
}
}
+
+ int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+ mCurrentBucketStartTimeNs += numBucketsForward * mBucketSizeNs;
+}
+
+void DurationMetricProducer::onMatchedLogEventInternal(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const map<string, HashableDimensionKey>& conditionKeys, bool condition,
+ const LogEvent& event, bool scheduledPull) {
+ flushIfNeeded(event.GetTimestampNs());
+
+ if (matcherIndex == mStopAllIndex) {
+ for (auto& pair : mCurrentSlicedDuration) {
+ pair.second->noteStopAll(event.GetTimestampNs());
+ }
+ return;
+ }
+
+ HashableDimensionKey atomKey = getHashableKey(getDimensionKey(event, mInternalDimension));
+
+ if (mCurrentSlicedDuration.find(eventKey) == mCurrentSlicedDuration.end()) {
+ mCurrentSlicedDuration[eventKey] = createDurationTracker(mPastBuckets[eventKey]);
+ }
+
+ auto it = mCurrentSlicedDuration.find(eventKey);
+
+ 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 8820403..8fdd0d4 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -19,9 +19,13 @@
#include <unordered_map>
+#include <android/util/ProtoOutputStream.h>
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "MetricProducer.h"
+#include "duration_helper/DurationTracker.h"
+#include "duration_helper/MaxDurationTracker.h"
+#include "duration_helper/OringDurationTracker.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "stats_util.h"
@@ -32,52 +36,38 @@
namespace os {
namespace statsd {
-enum DurationState {
- kStopped = 0, // The event is stopped.
- kStarted = 1, // The event is on going.
- kPaused = 2, // The event is started, but condition is false, clock is paused. When condition
- // turns to true, kPaused will become kStarted.
-};
-
-// Hold duration information for current on-going bucket.
-struct DurationInfo {
- DurationState state;
- // most recent start time.
- int64_t lastStartTime;
- // existing duration in current bucket. Eventually, the duration will be aggregated in
- // the way specified in AggregateType (Sum, Max, or Min).
- int64_t lastDuration;
- // cache the HashableDimensionKeys we need to query the condition for this duration event.
- std::map<string, HashableDimensionKey> conditionKeys;
-
- DurationInfo() : state(kStopped), lastStartTime(0), lastDuration(0){};
-};
-
class DurationMetricProducer : public MetricProducer {
public:
DurationMetricProducer(const DurationMetric& durationMetric, const int conditionIndex,
const size_t startIndex, const size_t stopIndex,
- const size_t stopAllIndex, const sp<ConditionWizard>& wizard);
+ const size_t stopAllIndex, const sp<ConditionWizard>& wizard,
+ const vector<KeyMatcher>& internalDimension, const uint64_t startTimeNs);
virtual ~DurationMetricProducer();
- void onConditionChanged(const bool conditionMet) override;
+ void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
- void onSlicedConditionMayChange() override;
+ void onSlicedConditionMayChange(const uint64_t eventTime) override;
size_t byteSize() override;
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ // TODO: Implement this later.
+ virtual void notifyAppRemoved(const string& apk, const int uid) override{};
protected:
void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKeys,
- bool condition, const LogEvent& event) override;
+ bool condition, const LogEvent& event,
+ bool scheduledPull) override;
+
+ void startNewProtoOutputStream(long long timestamp) override;
private:
const DurationMetric mMetric;
@@ -91,26 +81,24 @@
// Index of the SimpleLogEntryMatcher which defines the stop all for all dimensions.
const size_t mStopAllIndex;
+ // The dimension from the atom predicate. e.g., uid, wakelock name.
+ 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, DurationInfo> mCurrentSlicedDuration;
+ std::unordered_map<HashableDimensionKey, std::unique_ptr<DurationTracker>>
+ mCurrentSlicedDuration;
void flushDurationIfNeeded(const uint64_t newEventTime);
- void noteStart(const HashableDimensionKey& key, const bool conditionMet,
- const uint64_t eventTime);
+ std::unique_ptr<DurationTracker> createDurationTracker(std::vector<DurationBucket>& bucket);
- void noteStop(const HashableDimensionKey& key, const uint64_t eventTime);
+ void flushIfNeeded(uint64_t timestamp);
- void noteStopAll(const uint64_t eventTime);
-
- static int64_t updateDuration(const int64_t lastDuration, const int64_t durationTime,
- const DurationMetric_AggregationType type);
-
- void noteConditionChanged(const HashableDimensionKey& key, const bool conditionMet,
- const uint64_t eventTime);
+ 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 7e06105..ee0bfde 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -20,10 +20,14 @@
#include "EventMetricProducer.h"
#include "stats_util.h"
-#include <cutils/log.h>
#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;
@@ -37,19 +41,18 @@
// for StatsLogReport
const int FIELD_ID_METRIC_ID = 1;
const int FIELD_ID_START_REPORT_NANOS = 2;
-const int FIELD_ID_END_REPORT_NANOS = 2;
+const int FIELD_ID_END_REPORT_NANOS = 3;
const int FIELD_ID_EVENT_METRICS = 4;
+// for EventMetricDataWrapper
+const int FIELD_ID_DATA = 1;
// for EventMetricData
const int FIELD_ID_TIMESTAMP_NANOS = 1;
const int FIELD_ID_STATS_EVENTS = 2;
-// for CountMetricDataWrapper
-const int FIELD_ID_DATA = 1;
EventMetricProducer::EventMetricProducer(const EventMetric& metric, const int conditionIndex,
- const sp<ConditionWizard>& wizard)
- // TODO: Pass in the start time from MetricsManager, instead of calling time() here.
- : MetricProducer((time(nullptr) * NANO_SECONDS_IN_A_SECOND), conditionIndex, wizard),
- mMetric(metric) {
+ const sp<ConditionWizard>& wizard,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric) {
if (metric.links().size() > 0) {
mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
metric.links().end());
@@ -70,33 +73,25 @@
mProto = std::make_unique<ProtoOutputStream>();
// TODO: We need to auto-generate the field IDs for StatsLogReport, EventMetricData,
// and StatsEvent.
- mProto->write(TYPE_INT32 + FIELD_ID_METRIC_ID, mMetric.metric_id());
- mProto->write(TYPE_INT64 + FIELD_ID_START_REPORT_NANOS, startTime);
- mProtoToken = mProto->start(TYPE_MESSAGE + FIELD_ID_EVENT_METRICS);
+ 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_EVENT_METRICS);
}
void EventMetricProducer::finish() {
}
-void EventMetricProducer::onSlicedConditionMayChange() {
+void EventMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
}
StatsLogReport EventMetricProducer::onDumpReport() {
- long long endTime = time(nullptr) * NANO_SECONDS_IN_A_SECOND;
+ long long endTime = time(nullptr) * NS_PER_SEC;
mProto->end(mProtoToken);
- mProto->write(TYPE_INT64 + FIELD_ID_END_REPORT_NANOS, endTime);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_END_REPORT_NANOS, endTime);
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);
@@ -105,7 +100,7 @@
return StatsLogReport();
}
-void EventMetricProducer::onConditionChanged(const bool conditionMet) {
+void EventMetricProducer::onConditionChanged(const bool conditionMet, const uint64_t eventTime) {
VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
mCondition = conditionMet;
}
@@ -113,22 +108,21 @@
void EventMetricProducer::onMatchedLogEventInternal(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
- const LogEvent& event) {
-
+ const LogEvent& event, bool scheduledPull) {
if (!condition) {
return;
}
- long long wrapperToken = mProto->start(TYPE_MESSAGE + FIELD_ID_DATA);
- mProto->write(TYPE_INT64 + FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
- long long eventToken = mProto->start(TYPE_MESSAGE + FIELD_ID_STATS_EVENTS);
+ long long wrapperToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_DATA);
+ mProto->write(FIELD_TYPE_INT64 | FIELD_ID_TIMESTAMP_NANOS, (long long)event.GetTimestampNs());
+ long long eventToken = mProto->start(FIELD_TYPE_MESSAGE | FIELD_ID_STATS_EVENTS);
event.ToProto(*mProto);
mProto->end(eventToken);
mProto->end(wrapperToken);
}
size_t EventMetricProducer::byteSize() {
- return mProto->size();
+ return mProto->size();
}
} // namespace statsd
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index 14fa31c..2ca8181 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -20,6 +20,7 @@
#include <unordered_map>
#include <android/util/ProtoOutputStream.h>
+
#include "../condition/ConditionTracker.h"
#include "../matchers/matcher_util.h"
#include "MetricProducer.h"
@@ -35,35 +36,36 @@
public:
// TODO: Pass in the start time from MetricsManager, it should be consistent for all metrics.
EventMetricProducer(const EventMetric& eventMetric, const int conditionIndex,
- const sp<ConditionWizard>& wizard);
+ const sp<ConditionWizard>& wizard, const uint64_t startTimeNs);
virtual ~EventMetricProducer();
void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey,
- bool condition, const LogEvent& event) override;
+ bool condition, const LogEvent& event,
+ bool scheduledPull) override;
- void onConditionChanged(const bool conditionMet) override;
+ void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
void finish() override;
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
StatsLogReport onDumpReport() override;
- void onSlicedConditionMayChange() override;
+ void onSlicedConditionMayChange(const uint64_t eventTime) override;
size_t byteSize() override;
// TODO: Implement this later.
virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ // 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
new file mode 100644
index 0000000..dcfcc19
--- /dev/null
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -0,0 +1,295 @@
+/*
+* 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.
+*/
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "GaugeMetricProducer.h"
+#include "stats_util.h"
+
+#include <cutils/log.h>
+#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;
+using std::vector;
+
+namespace android {
+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),
+ mMetric(metric),
+ mPullTagId(pullTagId) {
+ if (metric.has_bucket() && metric.bucket().has_bucket_size_millis()) {
+ mBucketSizeNs = metric.bucket().bucket_size_millis() * 1000 * 1000;
+ } else {
+ mBucketSizeNs = kDefaultGaugemBucketSizeNs;
+ }
+
+ // TODO: use UidMap if uid->pkg_name is required
+ mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+
+ if (metric.links().size() > 0) {
+ mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+ metric.links().end());
+ mConditionSliced = true;
+ }
+
+ // Kicks off the puller immediately.
+ if (mPullTagId != -1) {
+ mStatsPullerManager.RegisterReceiver(mPullTagId, this,
+ 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);
+}
+
+GaugeMetricProducer::~GaugeMetricProducer() {
+ VLOG("~GaugeMetricProducer() called");
+}
+
+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);
+}
+
+void GaugeMetricProducer::finish() {
+}
+
+StatsLogReport GaugeMetricProducer::onDumpReport() {
+ VLOG("gauge metric %lld dump report now...", mMetric.metric_id());
+
+ // 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);
+
+ for (const auto& pair : mPastBuckets) {
+ const HashableDimensionKey& hashableKey = pair.first;
+ auto it = mDimensionKeyMap.find(hashableKey);
+ if (it == mDimensionKeyMap.end()) {
+ ALOGE("Dimension key %s not found?!?! skip...", hashableKey.c_str());
+ continue;
+ }
+
+ VLOG(" dimension key %s", hashableKey.c_str());
+ 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);
+ }
+ 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) {
+ AutoMutex _l(mLock);
+ VLOG("Metric %lld onConditionChanged", mMetric.metric_id());
+ mCondition = conditionMet;
+
+ // Push mode. Nothing to do.
+ if (mPullTagId == -1) {
+ return;
+ }
+ // If (1) the condition is not met or (2) we already pulled the gauge metric in the current
+ // bucket, do not pull gauge again.
+ if (!mCondition || mCurrentSlicedBucket.size() > 0) {
+ return;
+ }
+ vector<std::shared_ptr<LogEvent>> allData;
+ if (!mStatsPullerManager.Pull(mPullTagId, &allData)) {
+ ALOGE("Stats puller failed for tag: %d", mPullTagId);
+ return;
+ }
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, false /*scheduledPull*/);
+ }
+ flushGaugeIfNeededLocked(eventTime);
+}
+
+void GaugeMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+ VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+}
+
+long GaugeMetricProducer::getGauge(const LogEvent& event) {
+ status_t err = NO_ERROR;
+ long val = event.GetLong(mMetric.gauge_field(), &err);
+ if (err == NO_ERROR) {
+ return val;
+ } else {
+ VLOG("Can't find value in message.");
+ return -1;
+ }
+}
+
+void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
+ AutoMutex mutex(mLock);
+ if (allData.size() == 0) {
+ return;
+ }
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, true /*scheduledPull*/);
+ }
+ uint64_t eventTime = allData.at(0)->GetTimestampNs();
+ flushGaugeIfNeededLocked(eventTime);
+}
+
+void GaugeMetricProducer::onMatchedLogEventInternal(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const map<string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) {
+ if (condition == false) {
+ return;
+ }
+ uint64_t eventTimeNs = event.GetTimestampNs();
+ if (eventTimeNs < mCurrentBucketStartTimeNs) {
+ VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+ (long long)mCurrentBucketStartTimeNs);
+ return;
+ }
+
+ // For gauge metric, we just simply use the latest guage in the given bucket.
+ const long gauge = getGauge(event);
+ if (gauge < 0) {
+ VLOG("Invalid gauge at event Time: %lld", (long long)eventTimeNs);
+ return;
+ }
+ mCurrentSlicedBucket[eventKey] = gauge;
+ if (mPullTagId < 0) {
+ flushGaugeIfNeededLocked(eventTimeNs);
+ }
+}
+
+// When a new matched event comes in, we check if event falls into the current
+// bucket. If not, flush the old counter to past buckets and initialize the new
+// bucket.
+// if data is pushed, onMatchedLogEvent will only be called through onConditionChanged() inside
+// the GaugeMetricProducer while holding the lock.
+void GaugeMetricProducer::flushGaugeIfNeededLocked(const uint64_t eventTimeNs) {
+ if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
+ VLOG("event time is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
+ (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
+ return;
+ }
+
+ // Adjusts the bucket start time
+ int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+
+ GaugeBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = mCurrentBucketStartTimeNs + mBucketSizeNs;
+
+ for (const auto& slice : mCurrentSlicedBucket) {
+ 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);
+ }
+ // Reset counters
+ mCurrentSlicedBucket.clear();
+
+ mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
+ VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+ (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
new file mode 100644
index 0000000..3757174
--- /dev/null
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -0,0 +1,107 @@
+/*
+ * 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 <unordered_map>
+
+#include <android/util/ProtoOutputStream.h>
+#include "../condition/ConditionTracker.h"
+#include "../external/PullDataReceiver.h"
+#include "../external/StatsPullerManager.h"
+#include "../matchers/matcher_util.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+#include "stats_util.h"
+
+namespace android {
+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
+// producer always reports the guage at the earliest time of the bucket when the condition is met.
+class GaugeMetricProducer : public virtual MetricProducer, public virtual PullDataReceiver {
+public:
+ // TODO: Pass in the start time from MetricsManager, it should be consistent
+ // for all metrics.
+ GaugeMetricProducer(const GaugeMetric& countMetric, const int conditionIndex,
+ const sp<ConditionWizard>& wizard, const int pullTagId);
+
+ virtual ~GaugeMetricProducer();
+
+ // Handles when the pulled data arrives.
+ void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
+
+ void onConditionChanged(const bool conditionMet, const uint64_t eventTime) override;
+ void onSlicedConditionMayChange(const uint64_t eventTime) override;
+
+ void finish() override;
+
+ // TODO: Pass a timestamp as a parameter in onDumpReport.
+ StatsLogReport onDumpReport() override;
+
+ size_t byteSize() override;
+
+ // TODO: Implement this later.
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ // TODO: Implement this later.
+ virtual void notifyAppRemoved(const string& apk, const int uid) override{};
+
+protected:
+ void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKey,
+ 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;
+ const GaugeMetric mMetric;
+
+ StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance();
+ // tagId for pulled data. -1 if this is not pulled
+ const int mPullTagId;
+
+ Mutex mLock;
+
+ // Save the past buckets and we can clear when the StatsLogReport is dumped.
+ // TODO: Add a lock to mPastBuckets.
+ std::unordered_map<HashableDimensionKey, std::vector<GaugeBucket>> mPastBuckets;
+
+ // The current bucket.
+ std::unordered_map<HashableDimensionKey, long> mCurrentSlicedBucket;
+
+ void flushGaugeIfNeededLocked(const uint64_t newEventTime);
+
+ long getGauge(const LogEvent& event);
+
+ size_t mByteSize;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 3c8ce6e..5ca83b2 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -21,7 +21,8 @@
using std::map;
-void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event) {
+void MetricProducer::onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event,
+ bool scheduledPull) {
uint64_t eventTimeNs = event.GetTimestampNs();
// this is old event, maybe statsd restarted?
if (eventTimeNs < mStartTimeNs) {
@@ -59,9 +60,27 @@
condition = mCondition;
}
- onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event);
+ onMatchedLogEventInternal(matcherIndex, eventKey, conditionKeys, condition, event,
+ 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 80eb527..7ac97a8 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -40,6 +40,7 @@
: mStartTimeNs(startTimeNs),
mCurrentBucketStartTimeNs(startTimeNs),
mCondition(conditionIndex >= 0 ? false : true),
+ mConditionSliced(false),
mWizard(wizard),
mConditionTrackerIndex(conditionIndex) {
// reuse the same map for non-sliced metrics too. this way, we avoid too many if-else.
@@ -48,16 +49,18 @@
virtual ~MetricProducer(){};
// Consume the parsed stats log entry that already matched the "what" of the metric.
- void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event);
+ void onMatchedLogEvent(const size_t matcherIndex, const LogEvent& event, bool scheduledPull);
- virtual void onConditionChanged(const bool condition) = 0;
+ virtual void onConditionChanged(const bool condition, const uint64_t eventTime) = 0;
- virtual void onSlicedConditionMayChange() = 0;
+ virtual void onSlicedConditionMayChange(const uint64_t eventTime) = 0;
// This is called when the metric collecting is done, e.g., when there is a new configuration
// 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 {
@@ -107,7 +110,15 @@
virtual void onMatchedLogEventInternal(
const size_t matcherIndex, const HashableDimensionKey& eventKey,
const std::map<std::string, HashableDimensionKey>& conditionKey, bool condition,
- const LogEvent& event) = 0;
+ 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/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 4fa3965..80b325f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -15,17 +15,17 @@
*/
#define DEBUG true // STOPSHIP if true
#include "Log.h"
-
#include "MetricsManager.h"
-#include <log/logprint.h>
-#include "../condition/CombinationConditionTracker.h"
-#include "../condition/SimpleConditionTracker.h"
-#include "../matchers/CombinationLogMatchingTracker.h"
-#include "../matchers/SimpleLogMatchingTracker.h"
+
#include "CountMetricProducer.h"
+#include "condition/CombinationConditionTracker.h"
+#include "condition/SimpleConditionTracker.h"
+#include "matchers/CombinationLogMatchingTracker.h"
+#include "matchers/SimpleLogMatchingTracker.h"
#include "metrics_manager_util.h"
#include "stats_util.h"
+#include <log/logprint.h>
using std::make_unique;
using std::set;
using std::string;
@@ -74,6 +74,7 @@
}
int tagId = event.GetTagId();
+ uint64_t eventTime = event.GetTimestampNs();
if (mTagIds.find(tagId) == mTagIds.end()) {
// not interesting...
return;
@@ -124,13 +125,14 @@
// metric cares about non sliced condition, and it's changed.
// Push the new condition to it directly.
if (!mAllMetricProducers[metricIndex]->isConditionSliced() && changedCache[i]) {
- mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i]);
+ mAllMetricProducers[metricIndex]->onConditionChanged(conditionCache[i],
+ eventTime);
// metric cares about sliced conditions, and it may have changed. Send
// notification, and the metric can query the sliced conditions that are
// interesting to it.
} else if (mAllMetricProducers[metricIndex]->isConditionSliced() &&
slicedChangedCache[i]) {
- mAllMetricProducers[metricIndex]->onSlicedConditionMayChange();
+ mAllMetricProducers[metricIndex]->onSlicedConditionMayChange(eventTime);
}
}
}
@@ -143,7 +145,9 @@
if (pair != mTrackerToMetricMap.end()) {
auto& metricList = pair->second;
for (const int metricIndex : metricList) {
- mAllMetricProducers[metricIndex]->onMatchedLogEvent(i, event);
+ // pushed metrics are never scheduled pulls
+ mAllMetricProducers[metricIndex]->onMatchedLogEvent(
+ i, event, false /* schedulePull */);
}
}
}
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index 44cd637..63e2c33 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -96,4 +96,3 @@
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
new file mode 100644
index 0000000..41b7a5d
--- /dev/null
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -0,0 +1,303 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true // STOPSHIP if true
+#include "Log.h"
+
+#include "ValueMetricProducer.h"
+
+#include <cutils/log.h>
+#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;
+using std::shared_ptr;
+using std::unique_ptr;
+using std::unordered_map;
+
+namespace android {
+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,
+ const uint64_t startTimeNs)
+ : MetricProducer(startTimeNs, conditionIndex, wizard), mMetric(metric), mPullTagId(pullTagId) {
+ // TODO: valuemetric for pushed events may need unlimited bucket length
+ mBucketSizeNs = mMetric.bucket().bucket_size_millis() * 1000 * 1000;
+
+ mDimension.insert(mDimension.begin(), metric.dimension().begin(), metric.dimension().end());
+
+ if (metric.links().size() > 0) {
+ mConditionLinks.insert(mConditionLinks.begin(), metric.links().begin(),
+ metric.links().end());
+ mConditionSliced = true;
+ }
+
+ if (!metric.has_condition() && mPullTagId != -1) {
+ mStatsPullerManager.RegisterReceiver(mPullTagId, this,
+ 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);
+}
+
+ValueMetricProducer::~ValueMetricProducer() {
+ 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.
+}
+
+void ValueMetricProducer::onSlicedConditionMayChange(const uint64_t eventTime) {
+ VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+}
+
+StatsLogReport ValueMetricProducer::onDumpReport() {
+ VLOG("metric %lld dump report now...", mMetric.metric_id());
+
+ 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);
+
+ // 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);
+ }
+ 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) {
+ mCondition = condition;
+
+ if (mPullTagId != -1) {
+ if (mCondition == true) {
+ mStatsPullerManager.RegisterReceiver(mPullTagId, this,
+ mMetric.bucket().bucket_size_millis());
+ } else if (mCondition == ConditionState::kFalse) {
+ mStatsPullerManager.UnRegisterReceiver(mPullTagId, this);
+ }
+
+ vector<shared_ptr<LogEvent>> allData;
+ if (mStatsPullerManager.Pull(mPullTagId, &allData)) {
+ if (allData.size() == 0) {
+ return;
+ }
+ AutoMutex _l(mLock);
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, false);
+ }
+ flush_if_needed(eventTime);
+ }
+ return;
+ }
+}
+
+void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
+ if (mCondition == ConditionState::kTrue || !mMetric.has_condition()) {
+ AutoMutex _l(mLock);
+ if (allData.size() == 0) {
+ return;
+ }
+ uint64_t eventTime = allData.at(0)->GetTimestampNs();
+ for (const auto& data : allData) {
+ onMatchedLogEvent(0, *data, true);
+ }
+ flush_if_needed(eventTime);
+ }
+}
+
+void ValueMetricProducer::onMatchedLogEventInternal(
+ const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const map<string, HashableDimensionKey>& conditionKey, bool condition,
+ const LogEvent& event, bool scheduledPull) {
+ uint64_t eventTimeNs = event.GetTimestampNs();
+ if (eventTimeNs < mCurrentBucketStartTimeNs) {
+ VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
+ (long long)mCurrentBucketStartTimeNs);
+ return;
+ }
+
+ Interval& interval = mCurrentSlicedBucket[eventKey];
+
+ long value = get_value(event);
+
+ if (scheduledPull) {
+ if (interval.raw.size() > 0) {
+ interval.raw.back().second = value;
+ } else {
+ interval.raw.push_back(std::make_pair(value, value));
+ }
+ mNextSlicedBucket[eventKey].raw[0].first = value;
+ } else {
+ if (mCondition == ConditionState::kTrue) {
+ interval.raw.push_back(std::make_pair(value, 0));
+ } else {
+ if (interval.raw.size() != 0) {
+ interval.raw.back().second = value;
+ }
+ }
+ }
+ if (mPullTagId == -1) {
+ flush_if_needed(eventTimeNs);
+ }
+}
+
+long ValueMetricProducer::get_value(const LogEvent& event) {
+ status_t err = NO_ERROR;
+ long val = event.GetLong(mMetric.value_field(), &err);
+ if (err == NO_ERROR) {
+ return val;
+ } else {
+ VLOG("Can't find value in message.");
+ return 0;
+ }
+}
+
+void ValueMetricProducer::flush_if_needed(const uint64_t eventTimeNs) {
+ if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTimeNs) {
+ VLOG("eventTime is %lld, less than next bucket start time %lld", (long long)eventTimeNs,
+ (long long)(mCurrentBucketStartTimeNs + mBucketSizeNs));
+ return;
+ }
+
+ VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
+ (int)mCurrentSlicedBucket.size());
+ 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.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
+ mCurrentSlicedBucket.swap(mNextSlicedBucket);
+ mNextSlicedBucket.clear();
+ int64_t numBucketsForward = (eventTimeNs - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+ if (numBucketsForward > 1) {
+ VLOG("Skipping forward %lld buckets", (long long)numBucketsForward);
+ }
+ mCurrentBucketStartTimeNs = mCurrentBucketStartTimeNs + numBucketsForward * mBucketSizeNs;
+ VLOG("metric %lld: new bucket start time: %lld", mMetric.metric_id(),
+ (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
new file mode 100644
index 0000000..8437665
--- /dev/null
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -0,0 +1,106 @@
+/*
+ * 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 <utils/threads.h>
+#include <list>
+#include "../condition/ConditionTracker.h"
+#include "../external/PullDataReceiver.h"
+#include "../external/StatsPullerManager.h"
+#include "CountAnomalyTracker.h"
+#include "MetricProducer.h"
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
+
+namespace android {
+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,
+ const sp<ConditionWizard>& wizard, const int pullTagId,
+ const uint64_t startTimeNs);
+
+ virtual ~ValueMetricProducer();
+
+ void onConditionChanged(const bool condition, const uint64_t eventTime) override;
+
+ 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;
+
+ size_t byteSize() override;
+
+ // TODO: Implement this later.
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ // TODO: Implement this later.
+ virtual void notifyAppRemoved(const string& apk, const int uid) override{};
+
+protected:
+ void onMatchedLogEventInternal(const size_t matcherIndex, const HashableDimensionKey& eventKey,
+ const std::map<std::string, HashableDimensionKey>& conditionKey,
+ bool condition, const LogEvent& event,
+ bool scheduledPull) override;
+
+ void startNewProtoOutputStream(long long timestamp) override;
+
+private:
+ const ValueMetric mMetric;
+
+ StatsPullerManager& mStatsPullerManager = StatsPullerManager::GetInstance();
+
+ Mutex mLock;
+
+ // tagId for pulled data. -1 if this is not pulled
+ const int mPullTagId;
+
+ // internal state of a bucket.
+ typedef struct {
+ std::vector<std::pair<long, long>> raw;
+ } Interval;
+
+ std::unordered_map<HashableDimensionKey, Interval> mCurrentSlicedBucket;
+ // If condition is true and pulling on schedule, the previous bucket value needs to be carried
+ // over to the next bucket.
+ std::unordered_map<HashableDimensionKey, Interval> mNextSlicedBucket;
+
+ // Save the past buckets and we can clear when the StatsLogReport is dumped.
+ // 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
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
new file mode 100644
index 0000000..aeb234d
--- /dev/null
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -0,0 +1,95 @@
+/*
+ * 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 DURATION_TRACKER_H
+#define DURATION_TRACKER_H
+
+#include "condition/ConditionWizard.h"
+#include "stats_util.h"
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+enum DurationState {
+ kStopped = 0, // The event is stopped.
+ kStarted = 1, // The event is on going.
+ kPaused = 2, // The event is started, but condition is false, clock is paused. When condition
+ // turns to true, kPaused will become kStarted.
+};
+
+// Hold duration information for one atom level duration in current on-going bucket.
+struct DurationInfo {
+ DurationState state;
+ // most recent start time.
+ int64_t lastStartTime;
+ // existing duration in current bucket.
+ int64_t lastDuration;
+ // TODO: Optimize the way we track sliced condition in duration metrics.
+ // cache the HashableDimensionKeys we need to query the condition for this duration event.
+ ConditionKey conditionKeys;
+
+ 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<DurationBucket>& bucket)
+ : mWizard(wizard),
+ mConditionTrackerIndex(conditionIndex),
+ mCurrentBucketStartTimeNs(currentBucketStartNs),
+ mBucketSizeNs(bucketSizeNs),
+ mBucket(bucket),
+ mDuration(0){};
+ virtual ~DurationTracker(){};
+ virtual void noteStart(const HashableDimensionKey& key, bool condition,
+ const uint64_t eventTime, const ConditionKey& conditionKey) = 0;
+ virtual void noteStop(const HashableDimensionKey& key, const uint64_t eventTime) = 0;
+ virtual void noteStopAll(const uint64_t eventTime) = 0;
+ virtual void onSlicedConditionMayChange(const uint64_t timestamp) = 0;
+ virtual void onConditionChanged(bool condition, const uint64_t timestamp) = 0;
+ // Flush stale buckets if needed, and return true if the tracker has no on-going duration
+ // events, so that the owner can safely remove the tracker.
+ virtual bool flushIfNeeded(uint64_t timestampNs) = 0;
+
+protected:
+ sp<ConditionWizard> mWizard;
+
+ int mConditionTrackerIndex;
+
+ uint64_t mCurrentBucketStartTimeNs;
+
+ int64_t mBucketSizeNs;
+
+ std::vector<DurationBucket>& mBucket; // where to write output
+
+ int64_t mDuration; // current recorded duration result
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
new file mode 100644
index 0000000..a4d3098
--- /dev/null
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#define DEBUG true
+
+#include "Log.h"
+#include "MaxDurationTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+MaxDurationTracker::MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+ uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+ std::vector<DurationBucket>& bucket)
+ : DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket) {
+}
+
+void MaxDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
+ const uint64_t eventTime, const ConditionKey& conditionKey) {
+ // this will construct a new DurationInfo if this key didn't exist.
+ DurationInfo& duration = mInfos[key];
+ duration.conditionKeys = conditionKey;
+ VLOG("MaxDuration: key %s start condition %d", key.c_str(), condition);
+
+ switch (duration.state) {
+ case kStarted:
+ // The same event is already started. Because we are not counting nesting, so ignore.
+ break;
+ case kPaused:
+ // Safe to do nothing here. Paused means started but condition is false.
+ break;
+ case kStopped:
+ if (!condition) {
+ // event started, but we need to wait for the condition to become true.
+ duration.state = DurationState::kPaused;
+ } else {
+ duration.state = DurationState::kStarted;
+ duration.lastStartTime = eventTime;
+ }
+ break;
+ }
+}
+
+void MaxDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t eventTime) {
+ VLOG("MaxDuration: key %s stop", key.c_str());
+ if (mInfos.find(key) == mInfos.end()) {
+ // we didn't see a start event before. do nothing.
+ return;
+ }
+ DurationInfo& duration = mInfos[key];
+
+ switch (duration.state) {
+ case DurationState::kStopped:
+ // already stopped, do nothing.
+ break;
+ case DurationState::kStarted: {
+ duration.state = DurationState::kStopped;
+ int64_t durationTime = eventTime - duration.lastStartTime;
+ VLOG("Max, key %s, Stop %lld %lld %lld", key.c_str(), (long long)duration.lastStartTime,
+ (long long)eventTime, (long long)durationTime);
+ duration.lastDuration = duration.lastDuration + durationTime;
+ VLOG(" record duration: %lld ", (long long)duration.lastDuration);
+ break;
+ }
+ case DurationState::kPaused: {
+ duration.state = DurationState::kStopped;
+ break;
+ }
+ }
+
+ if (duration.lastDuration > mDuration) {
+ mDuration = duration.lastDuration;
+ VLOG("Max: new max duration: %lld", (long long)mDuration);
+ }
+ // Once an atom duration ends, we erase it. Next time, if we see another atom event with the
+ // same name, they are still considered as different atom durations.
+ mInfos.erase(key);
+}
+void MaxDurationTracker::noteStopAll(const uint64_t eventTime) {
+ for (auto& pair : mInfos) {
+ noteStop(pair.first, eventTime);
+ }
+}
+
+bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
+ if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
+ return false;
+ }
+
+ VLOG("MaxDurationTracker flushing.....");
+
+ // adjust the bucket start time
+ int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+
+ uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
+
+ DurationBucket info;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = endTime;
+
+
+ uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
+ mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
+
+ bool hasOnGoingStartedEvent = false; // a kStarted event last across bucket boundaries.
+ bool hasPendingEvent =
+ false; // has either a kStarted or kPaused event across bucket boundaries
+ // meaning we need to carry them over to the new bucket.
+ for (auto it = mInfos.begin(); it != mInfos.end(); ++it) {
+ int64_t finalDuration = it->second.lastDuration;
+ if (it->second.state == kStarted) {
+ // the event is still on-going, duration needs to be updated.
+ // |..lastDurationTime_recorded...last_start -----|bucket_end. We need to record the
+ // duration between lastStartTime and bucketEnd.
+ int64_t durationTime = endTime - it->second.lastStartTime;
+
+ finalDuration += durationTime;
+ VLOG(" unrecorded %lld -> %lld", (long long)(durationTime), (long long)finalDuration);
+ // if the event is still on-going, we need to fill the buckets between prev_bucket and
+ // now_bucket. |prev_bucket|...|..|...|now_bucket|
+ hasOnGoingStartedEvent = true;
+ }
+
+ if (finalDuration > mDuration) {
+ mDuration = finalDuration;
+ }
+
+ if (it->second.state == DurationState::kStopped) {
+ // No need to keep buckets for events that were stopped before.
+ mInfos.erase(it);
+ } else {
+ hasPendingEvent = true;
+ // for kPaused, and kStarted event, we will keep track of them, and reset the start time
+ // and duration.
+ it->second.lastStartTime = mCurrentBucketStartTimeNs;
+ it->second.lastDuration = 0;
+ }
+ }
+
+ if (mDuration != 0) {
+ info.mDuration = mDuration;
+ mBucket.push_back(info);
+ VLOG(" final duration for last bucket: %lld", (long long)mDuration);
+ }
+
+ mDuration = 0;
+ if (hasOnGoingStartedEvent) {
+ for (int i = 1; i < numBucketsForward; i++) {
+ 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);
+ }
+ }
+ // If this tracker has no pending events, tell owner to remove.
+ return !hasPendingEvent;
+}
+
+void MaxDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
+ // VLOG("Metric %lld onSlicedConditionMayChange", mMetric.metric_id());
+ // Now for each of the on-going event, check if the condition has changed for them.
+ for (auto& pair : mInfos) {
+ if (pair.second.state == kStopped) {
+ continue;
+ }
+ bool conditionMet = mWizard->query(mConditionTrackerIndex, pair.second.conditionKeys) ==
+ ConditionState::kTrue;
+ VLOG("key: %s, condition: %d", pair.first.c_str(), conditionMet);
+ noteConditionChanged(pair.first, conditionMet, timestamp);
+ }
+}
+
+void MaxDurationTracker::onConditionChanged(bool condition, const uint64_t timestamp) {
+ for (auto& pair : mInfos) {
+ noteConditionChanged(pair.first, condition, timestamp);
+ }
+}
+
+void MaxDurationTracker::noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
+ const uint64_t timestamp) {
+ auto it = mInfos.find(key);
+ if (it == mInfos.end()) {
+ return;
+ }
+
+ switch (it->second.state) {
+ case kStarted:
+ // if condition becomes false, kStarted -> kPaused. Record the current duration.
+ if (!conditionMet) {
+ it->second.state = DurationState::kPaused;
+ it->second.lastDuration += (timestamp - it->second.lastStartTime);
+
+ VLOG("MaxDurationTracker Key: %s Started->Paused ", key.c_str());
+ }
+ break;
+ case kStopped:
+ // nothing to do if it's stopped.
+ break;
+ case kPaused:
+ // if condition becomes true, kPaused -> kStarted. and the start time is the condition
+ // change time.
+ if (conditionMet) {
+ it->second.state = DurationState::kStarted;
+ it->second.lastStartTime = timestamp;
+ VLOG("MaxDurationTracker Key: %s Paused->Started", key.c_str());
+ }
+ break;
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
new file mode 100644
index 0000000..de53d62
--- /dev/null
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -0,0 +1,55 @@
+/*
+ * 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 MAX_DURATION_TRACKER_H
+#define MAX_DURATION_TRACKER_H
+
+#include "DurationTracker.h"
+
+#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+// Tracks a pool of atom durations, and output the max duration for each bucket.
+// To get max duration, we need to keep track of each individual durations, and compare them when
+// they stop or bucket expires.
+class MaxDurationTracker : public DurationTracker {
+public:
+ MaxDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+ uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+ 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;
+ void noteStopAll(const uint64_t eventTime) override;
+ bool flushIfNeeded(uint64_t timestampNs) override;
+ void onSlicedConditionMayChange(const uint64_t timestamp) override;
+ void onConditionChanged(bool condition, const uint64_t timestamp) override;
+
+private:
+ std::map<HashableDimensionKey, DurationInfo> mInfos;
+
+ void noteConditionChanged(const HashableDimensionKey& key, bool conditionMet,
+ const uint64_t timestamp);
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // MAX_DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
new file mode 100644
index 0000000..e4f1d21
--- /dev/null
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -0,0 +1,195 @@
+/*
+ * 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.
+ */
+#define DEBUG true
+#include "Log.h"
+#include "OringDurationTracker.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+OringDurationTracker::OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+ uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+ std::vector<DurationBucket>& bucket)
+ : DurationTracker(wizard, conditionIndex, currentBucketStartNs, bucketSizeNs, bucket),
+ mStarted(),
+ mPaused() {
+ mLastStartTime = 0;
+}
+
+void OringDurationTracker::noteStart(const HashableDimensionKey& key, bool condition,
+ const uint64_t eventTime, const ConditionKey& conditionKey) {
+ if (condition) {
+ if (mStarted.size() == 0) {
+ mLastStartTime = eventTime;
+ VLOG("record first start....");
+ }
+ mStarted.insert(key);
+ } else {
+ mPaused.insert(key);
+ }
+
+ if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
+ mConditionKeyMap[key] = conditionKey;
+ }
+
+ VLOG("Oring: %s start, condition %d", key.c_str(), condition);
+}
+
+void OringDurationTracker::noteStop(const HashableDimensionKey& key, const uint64_t timestamp) {
+ VLOG("Oring: %s stop", key.c_str());
+ auto it = mStarted.find(key);
+ if (it != mStarted.end()) {
+ mStarted.erase(it);
+ if (mStarted.empty()) {
+ mDuration += (timestamp - mLastStartTime);
+ VLOG("record duration %lld, total %lld ", (long long)timestamp - mLastStartTime,
+ (long long)mDuration);
+ }
+ }
+
+ mPaused.erase(key);
+ mConditionKeyMap.erase(key);
+}
+void OringDurationTracker::noteStopAll(const uint64_t timestamp) {
+ if (!mStarted.empty()) {
+ mDuration += (timestamp - mLastStartTime);
+ VLOG("Oring Stop all: record duration %lld %lld ", (long long)timestamp - mLastStartTime,
+ (long long)mDuration);
+ }
+
+ mStarted.clear();
+ mPaused.clear();
+ mConditionKeyMap.clear();
+}
+
+bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
+ if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
+ return false;
+ }
+ VLOG("OringDurationTracker Flushing.............");
+ // adjust the bucket start time
+ int numBucketsForward = (eventTime - mCurrentBucketStartTimeNs) / mBucketSizeNs;
+ DurationBucket info;
+ uint64_t endTime = mCurrentBucketStartTimeNs + mBucketSizeNs;
+ info.mBucketStartNs = mCurrentBucketStartTimeNs;
+ info.mBucketEndNs = endTime;
+
+ uint64_t oldBucketStartTimeNs = mCurrentBucketStartTimeNs;
+ mCurrentBucketStartTimeNs += (numBucketsForward)*mBucketSizeNs;
+
+ if (mStarted.size() > 0) {
+ mDuration += (endTime - mLastStartTime);
+ }
+ if (mDuration != 0) {
+ 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);
+ }
+
+ if (mStarted.size() > 0) {
+ for (int i = 1; i < numBucketsForward; i++) {
+ 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);
+ }
+ }
+ mLastStartTime = mCurrentBucketStartTimeNs;
+ mDuration = 0;
+
+ // if all stopped, then tell owner it's safe to remove this tracker.
+ return mStarted.empty() && mPaused.empty();
+}
+
+void OringDurationTracker::onSlicedConditionMayChange(const uint64_t timestamp) {
+ vector<HashableDimensionKey> startedToPaused;
+ vector<HashableDimensionKey> pausedToStarted;
+ if (!mStarted.empty()) {
+ for (auto it = mStarted.begin(); it != mStarted.end();) {
+ auto key = *it;
+ if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
+ VLOG("Key %s dont have condition key", key.c_str());
+ ++it;
+ continue;
+ }
+ if (mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key]) !=
+ ConditionState::kTrue) {
+ it = mStarted.erase(it);
+ startedToPaused.push_back(key);
+ VLOG("Key %s started -> paused", key.c_str());
+ } else {
+ ++it;
+ }
+ }
+
+ if (mStarted.empty()) {
+ mDuration += (timestamp - mLastStartTime);
+ VLOG("Duration add %lld , to %lld ", (long long)(timestamp - mLastStartTime),
+ (long long)mDuration);
+ }
+ }
+
+ if (!mPaused.empty()) {
+ for (auto it = mPaused.begin(); it != mPaused.end();) {
+ auto key = *it;
+ if (mConditionKeyMap.find(key) == mConditionKeyMap.end()) {
+ VLOG("Key %s dont have condition key", key.c_str());
+ ++it;
+ continue;
+ }
+ if (mWizard->query(mConditionTrackerIndex, mConditionKeyMap[key]) ==
+ ConditionState::kTrue) {
+ it = mPaused.erase(it);
+ pausedToStarted.push_back(key);
+ VLOG("Key %s paused -> started", key.c_str());
+ } else {
+ ++it;
+ }
+ }
+
+ if (mStarted.empty() && pausedToStarted.size() > 0) {
+ mLastStartTime = timestamp;
+ }
+ }
+
+ mStarted.insert(pausedToStarted.begin(), pausedToStarted.end());
+ mPaused.insert(startedToPaused.begin(), startedToPaused.end());
+}
+
+void OringDurationTracker::onConditionChanged(bool condition, const uint64_t timestamp) {
+ if (condition) {
+ if (!mPaused.empty()) {
+ VLOG("Condition true, all started");
+ if (mStarted.empty()) {
+ mLastStartTime = timestamp;
+ }
+ mStarted.insert(mPaused.begin(), mPaused.end());
+ }
+ } else {
+ if (!mStarted.empty()) {
+ VLOG("Condition false, all paused");
+ mDuration += (timestamp - mLastStartTime);
+ mPaused.insert(mStarted.begin(), mStarted.end());
+ }
+ }
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
new file mode 100644
index 0000000..b54dafa
--- /dev/null
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -0,0 +1,57 @@
+/*
+ * 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 ORING_DURATION_TRACKER_H
+#define ORING_DURATION_TRACKER_H
+
+#include "DurationTracker.h"
+
+#include <set>
+namespace android {
+namespace os {
+namespace statsd {
+
+// Tracks the "Or'd" duration -- if 2 durations are overlapping, they won't be double counted.
+class OringDurationTracker : public DurationTracker {
+public:
+ OringDurationTracker(sp<ConditionWizard> wizard, int conditionIndex,
+ uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
+ 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;
+ void noteStopAll(const uint64_t eventTime) override;
+ void onSlicedConditionMayChange(const uint64_t timestamp) override;
+ void onConditionChanged(bool condition, const uint64_t timestamp) override;
+ bool flushIfNeeded(uint64_t timestampNs) override;
+
+private:
+ // We don't need to keep track of individual durations. The information that's needed is:
+ // 1) which keys are started. We record the first start time.
+ // 2) which keys are paused (started but condition was false)
+ // 3) whenever a key stops, we remove it from the started set. And if the set becomes empty,
+ // it means everything has stopped, we then record the end time.
+ std::set<HashableDimensionKey> mStarted;
+ std::set<HashableDimensionKey> mPaused;
+ int64_t mLastStartTime;
+ std::map<HashableDimensionKey, ConditionKey> mConditionKeyMap;
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+
+#endif // ORING_DURATION_TRACKER_H
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index e90f998..ca9cdfb 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -16,11 +16,14 @@
#include "../condition/CombinationConditionTracker.h"
#include "../condition/SimpleConditionTracker.h"
+#include "../external/StatsPullerManager.h"
#include "../matchers/CombinationLogMatchingTracker.h"
#include "../matchers/SimpleLogMatchingTracker.h"
#include "CountMetricProducer.h"
#include "DurationMetricProducer.h"
#include "EventMetricProducer.h"
+#include "GaugeMetricProducer.h"
+#include "ValueMetricProducer.h"
#include "stats_util.h"
using std::set;
@@ -33,6 +36,8 @@
namespace statsd {
bool handleMetricWithLogTrackers(const string what, const int metricIndex,
+ const bool usedForDimension,
+ const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
const unordered_map<string, int>& logTrackerMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap,
int& logTrackerIndex) {
@@ -41,6 +46,12 @@
ALOGW("cannot find the LogEntryMatcher %s in config", what.c_str());
return false;
}
+ if (usedForDimension && allLogEntryMatchers[logTrackerIt->second]->getTagIds().size() > 1) {
+ ALOGE("LogEntryMatcher %s has more than one tag ids. When a metric has dimension, the "
+ "\"what\" can only about one atom type.",
+ what.c_str());
+ return false;
+ }
logTrackerIndex = logTrackerIt->second;
auto& metric_list = trackerToMetricMap[logTrackerIndex];
metric_list.push_back(metricIndex);
@@ -68,8 +79,7 @@
}
allConditionTrackers[condition_it->second]->setSliced(true);
allConditionTrackers[it->second]->setSliced(true);
- allConditionTrackers[it->second]->addDimensions(
- vector<KeyMatcher>(link.key_in_condition().begin(), link.key_in_condition().end()));
+ // TODO: We need to verify the link is valid.
}
conditionIndex = condition_it->second;
@@ -176,17 +186,20 @@
bool initMetrics(const StatsdConfig& config, const unordered_map<string, int>& logTrackerMap,
const unordered_map<string, int>& conditionTrackerMap,
+ const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
vector<sp<MetricProducer>>& allMetricProducers,
unordered_map<int, std::vector<int>>& conditionToMetricMap,
unordered_map<int, std::vector<int>>& trackerToMetricMap) {
sp<ConditionWizard> wizard = new ConditionWizard(allConditionTrackers);
- const int allMetricsCount =
- config.count_metric_size() + config.duration_metric_size() + config.event_metric_size();
+ const int allMetricsCount = config.count_metric_size() + config.duration_metric_size() +
+ config.event_metric_size() + config.value_metric_size();
allMetricProducers.reserve(allMetricsCount);
+ StatsPullerManager& statsPullerManager = StatsPullerManager::GetInstance();
+ uint64_t startTimeNs = time(nullptr) * NS_PER_SEC;
// Build MetricProducers for each metric defined in config.
- // (1) build CountMetricProducer
+ // build CountMetricProducer
for (int i = 0; i < config.count_metric_size(); i++) {
const CountMetric& metric = config.count_metric(i);
if (!metric.has_what()) {
@@ -196,8 +209,9 @@
int metricIndex = allMetricProducers.size();
int trackerIndex;
- if (!handleMetricWithLogTrackers(metric.what(), metricIndex, logTrackerMap,
- trackerToMetricMap, trackerIndex)) {
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
+ allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ trackerIndex)) {
return false;
}
@@ -208,33 +222,58 @@
conditionToMetricMap);
}
- sp<MetricProducer> countProducer = new CountMetricProducer(metric, conditionIndex, wizard);
+ sp<MetricProducer> countProducer =
+ new CountMetricProducer(metric, conditionIndex, wizard, startTimeNs);
allMetricProducers.push_back(countProducer);
}
+ // build DurationMetricProducer
for (int i = 0; i < config.duration_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const DurationMetric& metric = config.duration_metric(i);
+
+ auto what_it = conditionTrackerMap.find(metric.what());
+ if (what_it == conditionTrackerMap.end()) {
+ ALOGE("DurationMetric's \"what\" is invalid");
+ return false;
+ }
+
+ const Condition& durationWhat = config.condition(what_it->second);
+
+ if (durationWhat.contents_case() != Condition::ContentsCase::kSimpleCondition) {
+ ALOGE("DurationMetric's \"what\" must be a simple condition");
+ return false;
+ }
+
+ const auto& simpleCondition = durationWhat.simple_condition();
+
int trackerIndices[3] = {-1, -1, -1};
- if (!metric.has_start() ||
- !handleMetricWithLogTrackers(metric.start(), metricIndex, logTrackerMap,
- trackerToMetricMap, trackerIndices[0])) {
+ if (!simpleCondition.has_start() ||
+ !handleMetricWithLogTrackers(simpleCondition.start(), metricIndex,
+ metric.dimension_size() > 0, allLogEntryMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndices[0])) {
ALOGE("Duration metrics must specify a valid the start event matcher");
return false;
}
- if (metric.has_stop() &&
- !handleMetricWithLogTrackers(metric.stop(), metricIndex, logTrackerMap,
- trackerToMetricMap, trackerIndices[1])) {
+ if (simpleCondition.has_stop() &&
+ !handleMetricWithLogTrackers(simpleCondition.stop(), metricIndex,
+ metric.dimension_size() > 0, allLogEntryMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndices[1])) {
return false;
}
- if (metric.has_stop_all() &&
- !handleMetricWithLogTrackers(metric.stop_all(), metricIndex, logTrackerMap,
- trackerToMetricMap, trackerIndices[2])) {
+ if (simpleCondition.has_stop_all() &&
+ !handleMetricWithLogTrackers(simpleCondition.stop_all(), metricIndex,
+ metric.dimension_size() > 0, allLogEntryMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndices[2])) {
return false;
}
+ vector<KeyMatcher> internalDimension;
+ internalDimension.insert(internalDimension.begin(), simpleCondition.dimension().begin(),
+ simpleCondition.dimension().end());
+
int conditionIndex = -1;
if (metric.has_predicate()) {
@@ -243,13 +282,14 @@
conditionToMetricMap);
}
- sp<MetricProducer> durationMetric =
- new DurationMetricProducer(metric, conditionIndex, trackerIndices[0],
- trackerIndices[1], trackerIndices[2], wizard);
+ sp<MetricProducer> durationMetric = new DurationMetricProducer(
+ metric, conditionIndex, trackerIndices[0], trackerIndices[1], trackerIndices[2],
+ wizard, internalDimension, startTimeNs);
allMetricProducers.push_back(durationMetric);
}
+ // build EventMetricProducer
for (int i = 0; i < config.event_metric_size(); i++) {
int metricIndex = allMetricProducers.size();
const EventMetric& metric = config.event_metric(i);
@@ -258,8 +298,8 @@
return false;
}
int trackerIndex;
- if (!handleMetricWithLogTrackers(metric.what(), metricIndex, logTrackerMap,
- trackerToMetricMap, trackerIndex)) {
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, false, allLogEntryMatchers,
+ logTrackerMap, trackerToMetricMap, trackerIndex)) {
return false;
}
@@ -270,11 +310,91 @@
conditionToMetricMap);
}
- sp<MetricProducer> eventMetric = new EventMetricProducer(metric, conditionIndex, wizard);
+ sp<MetricProducer> eventMetric =
+ new EventMetricProducer(metric, conditionIndex, wizard, startTimeNs);
allMetricProducers.push_back(eventMetric);
}
+ // build ValueMetricProducer
+ for (int i = 0; i < config.value_metric_size(); i++) {
+ const ValueMetric& metric = config.value_metric(i);
+ if (!metric.has_what()) {
+ ALOGW("cannot find what in ValueMetric %lld", metric.metric_id());
+ return false;
+ }
+
+ int metricIndex = allMetricProducers.size();
+ int trackerIndex;
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
+ allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ trackerIndex)) {
+ return false;
+ }
+
+ sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ // If it is pulled atom, it should be simple matcher with one tagId.
+ int pullTagId = -1;
+ for (int tagId : atomMatcher->getTagIds()) {
+ if (statsPullerManager.PullerForMatcherExists(tagId)) {
+ if (atomMatcher->getTagIds().size() != 1) {
+ return false;
+ }
+ pullTagId = tagId;
+ }
+ }
+
+ int conditionIndex = -1;
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+ metric.links(), allConditionTrackers, conditionIndex,
+ conditionToMetricMap);
+ }
+
+ sp<MetricProducer> valueProducer =
+ new ValueMetricProducer(metric, conditionIndex, wizard, pullTagId, startTimeNs);
+ allMetricProducers.push_back(valueProducer);
+ }
+
+ // Gauge metrics.
+ for (int i = 0; i < config.gauge_metric_size(); i++) {
+ const GaugeMetric& metric = config.gauge_metric(i);
+ if (!metric.has_what()) {
+ ALOGW("cannot find what in ValueMetric %lld", metric.metric_id());
+ return false;
+ }
+
+ int metricIndex = allMetricProducers.size();
+ int trackerIndex;
+ if (!handleMetricWithLogTrackers(metric.what(), metricIndex, metric.dimension_size() > 0,
+ allLogEntryMatchers, logTrackerMap, trackerToMetricMap,
+ trackerIndex)) {
+ return false;
+ }
+
+ sp<LogMatchingTracker> atomMatcher = allLogEntryMatchers.at(trackerIndex);
+ // If it is pulled atom, it should be simple matcher with one tagId.
+ int pullTagId = -1;
+ for (int tagId : atomMatcher->getTagIds()) {
+ if (statsPullerManager.PullerForMatcherExists(tagId)) {
+ if (atomMatcher->getTagIds().size() != 1) {
+ return false;
+ }
+ pullTagId = tagId;
+ }
+ }
+
+ int conditionIndex = -1;
+ if (metric.has_condition()) {
+ handleMetricWithConditions(metric.condition(), metricIndex, conditionTrackerMap,
+ metric.links(), allConditionTrackers, conditionIndex,
+ conditionToMetricMap);
+ }
+
+ sp<MetricProducer> gaugeProducer =
+ new GaugeMetricProducer(metric, conditionIndex, wizard, pullTagId);
+ allMetricProducers.push_back(gaugeProducer);
+ }
return true;
}
@@ -292,6 +412,7 @@
ALOGE("initLogMatchingTrackers failed");
return false;
}
+ ALOGD("initLogMatchingTrackers succeed...");
if (!initConditions(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
trackerToConditionMap)) {
@@ -299,8 +420,9 @@
return false;
}
- if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allConditionTrackers,
- allMetricProducers, conditionToMetricMap, trackerToMetricMap)) {
+ if (!initMetrics(config, logTrackerMap, conditionTrackerMap, allLogEntryMatchers,
+ allConditionTrackers, allMetricProducers, conditionToMetricMap,
+ trackerToMetricMap)) {
ALOGE("initMetricProducers failed");
return false;
}
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 6722eb3..e089d065 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -21,6 +21,7 @@
#include <vector>
#include "../condition/ConditionTracker.h"
+#include "../external/StatsPullerManager.h"
#include "../matchers/LogMatchingTracker.h"
namespace android {
@@ -75,6 +76,7 @@
const StatsdConfig& config, const std::unordered_map<std::string, int>& logTrackerMap,
const std::unordered_map<std::string, int>& conditionTrackerMap,
const std::unordered_map<int, std::vector<EventConditionLink>>& eventConditionLinks,
+ const vector<sp<LogMatchingTracker>>& allLogEntryMatchers,
vector<sp<ConditionTracker>>& allConditionTrackers,
std::vector<sp<MetricProducer>>& allMetricProducers,
std::unordered_map<int, std::vector<int>>& conditionToMetricMap,
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 8b948de..13e776f 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -29,6 +29,9 @@
// Uid map will notify this listener that the app with apk name and uid has been upgraded to
// the specified version.
virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int version) = 0;
+
+ // Notify interested listeners that the given apk and uid combination no longer exits.
+ virtual void notifyAppRemoved(const std::string& apk, const int uid) = 0;
};
} // namespace statsd
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index f4621ee..d83c3a4 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -52,25 +52,35 @@
void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
const vector<String16>& packageName) {
+ updateMap(time(nullptr) * 1000000000, uid, versionCode, packageName);
+}
+
+void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
+ const vector<int32_t>& versionCode, const vector<String16>& packageName) {
lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
mMap.clear();
- for (unsigned long j = 0; j < uid.size(); j++) {
+ for (size_t j = 0; j < uid.size(); j++) {
mMap.insert(make_pair(uid[j],
AppData(string(String8(packageName[j]).string()), versionCode[j])));
}
- if (mOutput.initial_size() == 0) { // Provide the initial states in the mOutput proto
- for (unsigned long j = 0; j < uid.size(); j++) {
- auto t = mOutput.add_initial();
- t->set_app(string(String8(packageName[j]).string()));
- t->set_version(int(versionCode[j]));
- t->set_uid(uid[j]);
- }
+ auto snapshot = mOutput.add_snapshots();
+ snapshot->set_timestamp_nanos(timestamp);
+ for (size_t j = 0; j < uid.size(); j++) {
+ auto t = snapshot->add_package_info();
+ t->set_name(string(String8(packageName[j]).string()));
+ t->set_version(int(versionCode[j]));
+ t->set_uid(uid[j]);
}
}
void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
+ updateApp(time(nullptr) * 1000000000, app_16, uid, versionCode);
+}
+
+void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
+ const int32_t& versionCode) {
lock_guard<mutex> lock(mMutex);
string app = string(String8(app_16).string());
@@ -82,7 +92,7 @@
auto log = mOutput.add_changes();
log->set_deletion(false);
- // log.timestamp = TODO: choose how timestamps are computed
+ log->set_timestamp_nanos(timestamp);
log->set_app(app);
log->set_uid(uid);
log->set_version(versionCode);
@@ -102,13 +112,20 @@
}
void UidMap::removeApp(const String16& app_16, const int32_t& uid) {
+ removeApp(time(nullptr) * 1000000000, app_16, uid);
+}
+void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid) {
lock_guard<mutex> lock(mMutex);
string app = string(String8(app_16).string());
+ for (auto it : mSubscribers) {
+ it->notifyAppRemoved(app, uid);
+ }
+
auto log = mOutput.add_changes();
log->set_deletion(true);
- // log.timestamp = TODO: choose how timestamps are computed
+ log->set_timestamp_nanos(timestamp);
log->set_app(app);
log->set_uid(uid);
@@ -133,21 +150,67 @@
mSubscribers.erase(producer);
}
-UidMapping UidMap::getAndClearOutput() {
- lock_guard<mutex> lock(mMutex); // Lock for updates
-
- auto ret = UidMapping(mOutput); // Copy that will be returned.
+void UidMap::clearOutput() {
mOutput.Clear();
// Re-initialize the initial state for the outputs. This results in extra data being uploaded
- // but helps ensure we can't re-construct the UID->app name, versionCode mapping in server.
+ // but helps ensure we can re-construct the UID->app name, versionCode mapping in server.
+ auto snapshot = mOutput.add_snapshots();
for (auto it : mMap) {
- auto t = mOutput.add_initial();
- t->set_app(it.second.packageName);
+ auto t = snapshot->add_package_info();
+ t->set_name(it.second.packageName);
t->set_version(it.second.versionCode);
t->set_uid(it.first);
}
+}
+int64_t UidMap::getMinimumTimestampNs() {
+ int64_t m = 0;
+ for (auto it : mLastUpdatePerConfigKey) {
+ if (m == 0) {
+ m = it.second;
+ } else if (it.second < m) {
+ m = it.second;
+ }
+ }
+ return m;
+}
+
+UidMapping UidMap::getOutput(const ConfigKey& key) {
+ return getOutput(time(nullptr) * 1000000000, key);
+}
+
+UidMapping UidMap::getOutput(const int64_t& timestamp, const ConfigKey& key) {
+ lock_guard<mutex> lock(mMutex); // Lock for updates
+
+ auto ret = UidMapping(mOutput); // Copy that will be returned.
+ int64_t prevMin = getMinimumTimestampNs();
+ mLastUpdatePerConfigKey[key] = timestamp;
+ int64_t newMin = getMinimumTimestampNs();
+
+ if (newMin > prevMin) {
+ int64_t cutoff_nanos = newMin;
+ auto snapshots = mOutput.mutable_snapshots();
+ auto it_snapshots = snapshots->cbegin();
+ while (it_snapshots != snapshots->cend()) {
+ if (it_snapshots->timestamp_nanos() < cutoff_nanos) {
+ // it_snapshots now points to the following element.
+ it_snapshots = snapshots->erase(it_snapshots);
+ } else {
+ ++it_snapshots;
+ }
+ }
+ auto deltas = mOutput.mutable_changes();
+ auto it_deltas = deltas->cbegin();
+ while (it_deltas != deltas->cend()) {
+ if (it_deltas->timestamp_nanos() < cutoff_nanos) {
+ // it_deltas now points to the following element.
+ it_deltas = deltas->erase(it_deltas);
+ } else {
+ ++it_deltas;
+ }
+ }
+ }
return ret;
}
@@ -160,6 +223,14 @@
}
}
+void UidMap::OnConfigUpdated(const ConfigKey& key) {
+ mLastUpdatePerConfigKey[key] = -1;
+}
+
+void UidMap::OnConfigRemoved(const ConfigKey& key) {
+ mLastUpdatePerConfigKey.erase(key);
+}
+
} // namespace statsd
} // namespace os
} // namespace android
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index d550372..bf120e0 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -17,11 +17,14 @@
#ifndef STATSD_UIDMAP_H
#define STATSD_UIDMAP_H
+#include "config/ConfigKey.h"
+#include "config/ConfigListener.h"
#include "frameworks/base/cmds/statsd/src/stats_log.pb.h"
#include "packages/PackageInfoListener.h"
#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
+#include <gtest/gtest_prod.h>
#include <log/logprint.h>
#include <stdio.h>
#include <utils/RefBase.h>
@@ -51,17 +54,19 @@
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
*/
+ // TODO: Add safeguards to call clearOutput if there's too much data already stored.
void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
const vector<String16>& packageName);
+ // TODO: Add safeguards to call clearOutput if there's too much data already stored.
+ void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
+ void removeApp(const String16& packageName, const int32_t& uid);
+
// Returns true if the given uid contains the specified app (eg. com.google.android.gms).
bool hasApp(int uid, const string& packageName) const;
int getAppVersion(int uid, const string& packageName) const;
- void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
- void removeApp(const String16& packageName, const int32_t& uid);
-
// Helper for debugging contents of this uid map. Can be triggered with:
// adb shell cmd stats print-uid-map
void printUidMap(FILE* out);
@@ -73,13 +78,36 @@
// Remove the listener from the set of metric producers that subscribe to updates.
void removeListener(sp<PackageInfoListener> producer);
- // Grabs the current output contents and then clears it.
- UidMapping getAndClearOutput();
+ // Informs uid map that a config is added/updated. Used for keeping mConfigKeys up to date.
+ void OnConfigUpdated(const ConfigKey& key);
+
+ // Informs uid map that a config is removed. Used for keeping mConfigKeys up to date.
+ void OnConfigRemoved(const ConfigKey& key);
+
+ // Gets the output. If every config key has received the output, then the output is cleared.
+ UidMapping getOutput(const ConfigKey& key);
+
+ // Forces the output to be cleared. We still generate a snapshot based on the current state.
+ // This results in extra data uploaded but helps us reconstruct the uid mapping on the server
+ // in case we lose a previous upload.
+ void clearOutput();
private:
+ void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
+ const vector<int32_t>& versionCode, const vector<String16>& packageName);
+
+ // TODO: Add safeguards to call clearOutput if there's too much data already stored.
+ void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
+ const int32_t& versionCode);
+ void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
+
+ UidMapping getOutput(const int64_t& timestamp, const ConfigKey& key);
+
// TODO: Use shared_mutex for improved read-locking if a library can be found in Android.
mutable mutex mMutex;
+ // Maps uid to application data. This must be multimap since there is a feature in Android for
+ // multiple apps to share the same uid.
std::unordered_multimap<int, AppData> mMap;
// We prepare the output proto as apps are updated, so that we can grab the current output.
@@ -87,6 +115,17 @@
// Metric producers that should be notified if there's an upgrade in any app.
set<sp<PackageInfoListener>> mSubscribers;
+
+ // Mapping of config keys we're aware of to the epoch time they last received an update. This
+ // lets us know it's safe to delete events older than the oldest update. The value is nanosec.
+ // Value of -1 denotes this config key has never received an upload.
+ std::unordered_map<ConfigKey, int64_t> mLastUpdatePerConfigKey;
+
+ // Returns the minimum value from mConfigKeys.
+ int64_t getMinimumTimestampNs();
+
+ // Allows unit-test to access private methods.
+ FRIEND_TEST(UidMapTest, TestClearingOutput);
};
} // namespace statsd
diff --git a/cmds/statsd/src/stats_events.proto b/cmds/statsd/src/stats_events.proto
index 74ee332..82d9759 100644
--- a/cmds/statsd/src/stats_events.proto
+++ b/cmds/statsd/src/stats_events.proto
@@ -35,7 +35,8 @@
* in the format defined here and in stats_log.proto.
*/
message StatsEvent {
- oneof event {
+ // Pushed events start at 2.
+ oneof pushed {
// For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
BleScanStateChanged ble_scan_state_changed = 2;
BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
@@ -69,9 +70,23 @@
WifiSignalStrengthChanged wifi_signal_strength_changed = 38;
WifiScanStateChanged wifi_scan_state_changed = 39;
PhoneSignalStrengthChanged phone_signal_strength_changed = 40;
+ SettingChanged setting_changed = 41;
+ ActivityForegroundStateChanged activity_foreground_state_changed = 42;
// TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
+
+ // Pulled events will start at field 1000.
+ oneof pulled {
+ WifiBytesTransferred wifi_bytes_transferred = 1000;
+ WifiBytesTransferredByFgBg wifi_bytes_transferred_by_fg_bg = 1001;
+ MobileBytesTransferred mobile_bytes_transferred = 1002;
+ MobileBytesTransferredByFgBg mobile_bytes_transferred_by_fg_bg = 1003;
+ KernelWakelockPulled kernel_wakelock_pulled = 1004;
+ PowerStatePlatformSleepStatePulled power_state_platform_sleep_state_pulled = 1005;
+ PowerStateVoterPulled power_state_voter_pulled = 1006;
+ PowerStateSubsystemSleepStatePulled power_state_subsystem_sleep_state_pulled = 1007;
+ }
}
/**
@@ -479,7 +494,7 @@
* Logs battery level (percent full, from 0 to 100).
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message BatteryLevelChanged {
// Battery level. Should be in [0, 100].
@@ -490,7 +505,7 @@
* Logs change in charging status of the device.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message ChargingStateChanged {
// TODO: Link directly to BatteryManager.java's constants (via a proto).
@@ -508,7 +523,7 @@
* Logs whether the device is plugged in, and what power source it is using.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message PluggedStateChanged {
// TODO: Link directly to BatteryManager.java's constants (via a proto).
@@ -529,7 +544,7 @@
* Logs the temperature of the device, in tenths of a degree Celsius.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message DeviceTemperatureReported {
// Temperature in tenths of a degree C.
@@ -542,7 +557,7 @@
* Logs when the device turns off or on.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
*/
message DeviceOnStatusChanged {
enum State {
@@ -556,7 +571,7 @@
* Logs when an app's wakeup alarm fires.
*
* Logged from:
- * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
+ * frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
*/
message WakeupAlarmOccurred {
// TODO: Add attribution instead of uid?
@@ -581,7 +596,7 @@
* Logs wifi locks held by an app.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message WifiLockStateChanged {
// TODO: Add attribution instead of uid.
@@ -598,7 +613,7 @@
* Logs wifi signal strength changes.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message WifiSignalStrengthChanged {
// TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
@@ -616,7 +631,7 @@
* Logs wifi scans performed by an app.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message WifiScanStateChanged {
// TODO: Add attribution instead of uid.
@@ -633,7 +648,7 @@
* Logs phone signal strength changes.
*
* Logged from:
- * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
*/
message PhoneSignalStrengthChanged {
// TODO: Reference the actual telephony/java/android/telephony/SignalStrength.java states.
@@ -645,4 +660,191 @@
SIGNAL_STRENGTH_GREAT = 4;
}
optional SignalStrength signal_strength = 1;
-}
\ No newline at end of file
+}
+
+/**
+ * Logs that a setting was updated.
+ * Logged from:
+ * frameworks/base/core/java/android/provider/Settings.java
+ * The tag and is_default allow resetting of settings to default values based on the specified
+ * tag. See Settings#putString(ContentResolver, String, String, String, boolean) for more details.
+ */
+message SettingChanged {
+ // The name of the setting.
+ optional string setting = 1;
+
+ // The change being imposed on this setting. May represent a number, eg "3".
+ optional string value = 2;
+
+ // The new value of this setting. For most settings, this is same as value. For some settings,
+ // value is +X or -X where X represents an element in a set. For example, if the previous value
+ // is A,B,C and value is -B, then new_value is A,C and prev_value is A,B,C.
+ // The +/- feature is currently only used for location_providers_allowed.
+ optional string new_value = 3;
+
+ // The previous value of this setting.
+ optional string prev_value = 4;
+
+ // The tag used with the is_default for resetting sets of settings. This is generally null.
+ optional string tag = 5;
+
+ // 1 indicates that this setting with tag should be resettable.
+ optional int32 is_default = 6;
+
+ // The user ID associated. Defined in android/os/UserHandle.java
+ optional int32 user = 7;
+}
+
+
+/*
+ * Logs activity going to foreground or background
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/ActivityRecord.java
+ */
+message ActivityForegroundStateChanged {
+ enum Activity {
+ MOVE_TO_BACKGROUND = 0;
+ MOVE_TO_FOREGROUND = 1;
+ }
+ optional int32 uid = 1;
+ optional string pkg_name = 2;
+ optional string class_name = 3;
+ optional Activity activity = 4;
+}
+
+/**
+ * Pulls bytes transferred via wifi (Sum of foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are wifi)
+ */
+message WifiBytesTransferred {
+ optional int32 uid = 1;
+
+ optional int64 rx_bytes = 2;
+
+ optional int64 rx_packets = 3;
+
+ optional int64 tx_bytes = 4;
+
+ optional int64 tx_packets = 5;
+}
+
+/**
+ * Pulls bytes transferred via wifi (separated by foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are wifi)
+ */
+message WifiBytesTransferredByFgBg {
+ optional int32 uid = 1;
+
+ // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ optional int32 is_foreground = 2;
+
+ optional int64 rx_bytes = 3;
+
+ optional int64 rx_packets = 4;
+
+ optional int64 tx_bytes = 5;
+
+ optional int64 tx_packets = 6;
+}
+
+/**
+ * Pulls bytes transferred via mobile networks (Sum of foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
+ */
+message MobileBytesTransferred {
+ optional int32 uid = 1;
+
+ optional int64 rx_bytes = 2;
+
+ optional int64 rx_packets = 3;
+
+ optional int64 tx_bytes = 4;
+
+ optional int64 tx_packets = 5;
+}
+
+/**
+ * Pulls bytes transferred via mobile networks (separated by foreground and background usage).
+ *
+ * Pulled from:
+ * StatsCompanionService (using BatteryStats to get which interfaces are mobile data)
+ */
+message MobileBytesTransferredByFgBg {
+ optional int32 uid = 1;
+
+ // 1 denotes foreground and 0 denotes background. This is called Set in NetworkStats.
+ optional int32 is_foreground = 2;
+
+ optional int64 rx_bytes = 3;
+
+ optional int64 rx_packets = 4;
+
+ optional int64 tx_bytes = 5;
+
+ optional int64 tx_packets = 6;
+}
+
+/**
+ * Pulls the kernel wakelock durations. This atom is adapted from
+ * android/internal/os/KernelWakelockStats.java
+ *
+ * Pulled from:
+ * StatsCompanionService using KernelWakelockReader.
+ */
+message KernelWakelockPulled {
+ optional string name = 1;
+
+ optional int32 count = 2;
+
+ optional int32 version = 3;
+
+ optional int64 time = 4;
+}
+
+/*
+ * Pulls PowerStatePlatformSleepState.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.0/types.hal
+ */
+message PowerStatePlatformSleepStatePulled {
+ optional string name = 1;
+ optional uint64 residency_in_msec_since_boot = 2;
+ optional uint64 total_transitions = 3;
+ optional bool supported_only_in_suspend = 4;
+}
+
+/**
+ * Pulls PowerStateVoter.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.0/types.hal
+ */
+message PowerStateVoterPulled {
+ optional string power_state_platform_sleep_state_name = 1;
+ optional string power_state_voter_name = 2;
+ optional uint64 total_time_in_msec_voted_for_since_boot = 3;
+ optional uint64 total_number_of_times_voted_since_boot = 4;
+}
+
+/**
+ * Pulls PowerStateSubsystemSleepState.
+ *
+ * Definition here:
+ * hardware/interfaces/power/1.1/types.hal
+ */
+message PowerStateSubsystemSleepStatePulled {
+ optional string power_state_subsystem_name = 1;
+ optional string power_state_subsystem_sleep_state_name = 2;
+ optional uint64 residency_in_msec_since_boot = 3;
+ optional uint64 total_transitions = 4;
+ optional uint64 last_entry_timestamp_ms = 5;
+ optional bool supported_only_in_suspend = 6;
+}
diff --git a/cmds/statsd/src/stats_events_copy.proto b/cmds/statsd/src/stats_events_copy.proto
index 5e8ef24..898856b 100644
--- a/cmds/statsd/src/stats_events_copy.proto
+++ b/cmds/statsd/src/stats_events_copy.proto
@@ -40,9 +40,29 @@
*/
message StatsEvent {
oneof event {
- ScreenStateChanged screen_state_changed = 1;
- ProcessStateChanged process_state_changed = 2;
- WakeLockChanged wakelock_changed = 3;
+ // For StatsLog reasons, 1 is illegal and will not work. Must start at 2.
+ BleScanStateChanged ble_scan_state_changed = 2;
+ BleUnoptimizedScanStateChanged ble_unoptimized_scan_state_changed = 3;
+ BleScanResultReceived ble_scan_result_received = 4;
+ SensorStateChanged sensor_state_changed = 5;
+ GpsScanStateChanged gps_scan_state_changed = 6; // TODO: untested
+ SyncStateChanged sync_state_changed = 7;
+ ScheduledJobStateChanged scheduled_job_state_changed = 8;
+ ScreenBrightnessChanged screen_brightness_changed = 9;
+ // 10-20 are temporarily reserved for wakelocks etc.
+ UidWakelockStateChanged uid_wakelock_state_changed = 11;
+ LongPartialWakelockStateChanged long_partial_wakelock_state_changed = 12;
+ BatterySaverModeStateChanged battery_saver_mode_state_changed = 21;
+ DeviceIdleModeStateChanged device_idle_mode_state_changed = 22;
+ AudioStateChanged audio_state_changed = 23;
+ MediaCodecActivityChanged media_codec_activity_changed = 24;
+ CameraStateChanged camera_state_changed = 25;
+ FlashlightStateChanged flashlight_state_changed = 26;
+ UidProcessStateChanged uid_process_state_changed = 27;
+ ProcessLifeCycleStateChanged process_life_cycle_state_changed = 28;
+ ScreenStateChanged screen_state_changed = 29;
+ DeviceTemperatureReported device_temperature_reported = 33;
+ // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15.
}
}
@@ -76,12 +96,23 @@
* and those UIDs will be translated in xxx to those strings.
*
* CONVENTIONS:
- * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange
+ * - Events are past tense. e.g. ScreenStateChanged, not ScreenStateChange.
* - If there is a UID, it goes first. Think in an object-oriented fashion.
* *****************************************************************************
*/
/**
+ * Logs the temperature of the device, in tenths of a degree Celsius.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message DeviceTemperatureReported {
+ // Temperature in tenths of a degree C.
+ optional int32 temperature = 1;
+}
+
+/**
* Logs when the screen state changes.
*
* Logged from:
@@ -102,33 +133,347 @@
}
/**
- * Logs that the state of a process state, as per the activity manager has changed.
+ * Logs that the state of a process state, as per the activity manager, has changed.
*
* Logged from:
* frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
*/
-message ProcessStateChanged {
- // TODO: Use the real (mapped) process states.
+message UidProcessStateChanged {
optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
// The state.
+ // TODO: Use the real (mapped) process states.
optional int32 state = 2;
}
/**
- * Logs that the state of a wakelock has changed.
+ * Logs that a process started, finished, crashed, or ANRed.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ProcessLifeCycleStateChanged {
+ // TODO: Use the real (mapped) process states.
+ optional int32 uid = 1; // TODO: should be a string tagged w/ uid annotation
+
+ // TODO: What is this?
+ optional string name = 2;
+
+ // The state.
+ // TODO: Use an enum.
+ optional int32 event = 3;
+}
+
+
+
+/**
+ * Logs when the ble scan state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message BleScanStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs when an unoptimized ble scan state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
+message BleUnoptimizedScanStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs reporting of a ble scan finding results.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+// TODO: Consider changing to tracking per-scanner-id (log from AppScanStats).
+message BleScanResultReceived {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // Number of ble scan results returned.
+ optional int32 num_of_results = 2;
+}
+
+/**
+ * Logs when a sensor state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message SensorStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // TODO: Is there a way to get the actual name of the sensor?
+ // The id (int) of the sensor.
+ optional int32 sensor_id = 2;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 3;
+}
+
+
+/**
+ * Logs when GPS state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message GpsScanStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+
+/**
+ * Logs when a sync manager sync state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message SyncStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // Name of the sync (as named in the app)
+ optional string name = 2;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 3;
+}
+
+/**
+ * Logs when a job scheduler job state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message ScheduledJobStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // Name of the job (as named in the app)
+ optional string name = 2;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 3;
+
+ // TODO: Consider adding the stopReason (int)
+}
+
+/**
+ * Logs when the audio state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message AudioStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs when the video codec state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message MediaCodecActivityChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs when the flashlight state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message FlashlightStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs when the camera state changes.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message CameraStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 2;
+}
+
+/**
+ * Logs that the state of a wakelock (per app and per wakelock name) has changed.
*
* Logged from:
* TODO
*/
-message WakeLockChanged {
+message WakelockChanged {
// TODO: Add attribution instead of uid.
optional int32 uid = 1;
+ // Type of wakelock.
+ enum Type {
+ PARTIAL = 0;
+ FULL = 1;
+ WINDOW = 2;
+ }
+ optional int32 type = 2;
+
+ // The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
+ optional string tag = 3;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 4;
+}
+
+/**
+ * Logs when an app is holding a wakelock, regardless of the wakelock's name.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message UidWakelockStateChanged {
+ // TODO: Add attribution instead of uid.
+ optional int32 uid = 1;
+
+ // Type of wakelock.
+ enum Type {
+ PARTIAL = 0;
+ FULL = 1;
+ WINDOW = 2;
+ }
+ optional int32 type = 2;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 3;
+}
+
+/**
+ * Logs when a partial wakelock is considered 'long' (over 1 min).
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message LongPartialWakelockStateChanged {
+ // TODO: Add attribution instead of uid?
+ optional int32 uid = 1;
+
// The wakelock tag (Called tag in the Java API, sometimes name elsewhere).
optional string tag = 2;
- // TODO: Use a constant instead of boolean?
- optional bool state = 3;
+ // TODO: I have no idea what this is.
+ optional string history_tag = 3;
+
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 4;
}
+/**
+ * Logs Battery Saver state change.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java
+ */
+message BatterySaverModeStateChanged {
+ enum State {
+ OFF = 0;
+ ON = 1;
+ }
+ optional State state = 1;
+}
+
+/**
+ * Logs Doze mode state change.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message DeviceIdleModeStateChanged {
+ // TODO: Use the enum matching BatteryStats.DEVICE_IDLE_MODE_.
+ optional int32 state = 1;
+}
+
+/**
+ * Logs screen brightness level.
+ *
+ * Logged from:
+ * frameworks/base/services/core/java/com/android/server/am/BatteryStatsService.java
+ */
+message ScreenBrightnessChanged {
+ // Screen brightness level. Should be in [-1, 255] according to PowerManager.java.
+ optional int32 level = 1;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index ec91509..1e37ff8 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -98,15 +98,19 @@
}
message UidMapping {
- message AppInfo {
- optional string app = 1;
+ message PackageInfoSnapshot {
+ message PackageInfo {
+ optional string name = 1;
- optional int32 version = 2;
+ optional int32 version = 2;
- optional int32 uid = 3;
+ optional int32 uid = 3;
+ }
+ optional int64 timestamp_nanos = 1;
+
+ repeated PackageInfo package_info = 2;
}
-
- repeated AppInfo initial = 1;
+ repeated PackageInfoSnapshot snapshots = 1;
message Change {
optional bool deletion = 1;
@@ -139,9 +143,11 @@
message ValueMetricDataWrapper {
repeated ValueMetricData data = 1;
}
+
message GaugeMetricDataWrapper {
repeated GaugeMetricData data = 1;
}
+
oneof data {
EventMetricDataWrapper event_metrics = 4;
CountMetricDataWrapper count_metrics = 5;
diff --git a/cmds/statsd/src/stats_util.h b/cmds/statsd/src/stats_util.h
index 39c1d59..a9507bf 100644
--- a/cmds/statsd/src/stats_util.h
+++ b/cmds/statsd/src/stats_util.h
@@ -28,18 +28,11 @@
#define DEFAULT_DIMENSION_KEY ""
#define MATCHER_NOT_FOUND -2
-#define NANO_SECONDS_IN_A_SECOND (1000 * 1000 * 1000)
-
-// TODO: Remove the following constants once they are exposed in ProtOutputStream.h
-const uint64_t FIELD_TYPE_SHIFT = 32;
-const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT;
-const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT;
typedef std::string HashableDimensionKey;
+typedef std::map<std::string, HashableDimensionKey> ConditionKey;
+
EventMetricData parse(log_msg msg);
int getTagId(log_msg msg);
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index a4d2421..f3e6894 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -82,6 +82,8 @@
optional bool count_nesting = 3 [default = true];
optional string stop_all = 4;
+
+ repeated KeyMatcher dimension = 5;
}
message Condition {
@@ -148,29 +150,24 @@
message DurationMetric {
optional int64 metric_id = 1;
- optional string start = 2;
-
- optional string stop = 3;
-
- optional string stop_all = 4;
+ optional string what = 2;
enum AggregationType {
DURATION_SUM = 1;
DURATION_MAX_SPARSE = 2;
- DURATION_MIN_SPARSE = 3;
}
- optional AggregationType type = 5;
+ optional AggregationType type = 3;
- optional string predicate = 6;
+ optional string predicate = 4;
- repeated KeyMatcher dimension = 7;
+ repeated KeyMatcher dimension = 5;
- optional Bucket bucket = 8;
+ optional Bucket bucket = 6;
- repeated Alert alerts = 9;
+ repeated Alert alerts = 7;
- repeated EventConditionLink links = 10;
+ repeated EventConditionLink links = 8;
}
@@ -210,14 +207,7 @@
repeated EventConditionLink links = 8;
enum Operation {
- SUM_DIFF = 1;
- MIN_DIFF = 2;
- MAX_DIFF = 3;
- SUM = 4;
- MIN = 5;
- MAX = 6;
- FIRST = 7;
- LAST = 8;
+ SUM = 1;
}
optional Operation operation = 9 [default = SUM];
}
@@ -240,7 +230,9 @@
repeated DurationMetric duration_metric = 5;
- repeated LogEntryMatcher log_entry_matcher = 6;
+ repeated GaugeMetric gauge_metric = 6;
- repeated Condition condition = 7;
+ repeated LogEntryMatcher log_entry_matcher = 7;
+
+ repeated Condition condition = 8;
}
diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp
index fdfe8ef..d0898b0 100644
--- a/cmds/statsd/tests/LogEntryMatcher_test.cpp
+++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp
@@ -42,7 +42,7 @@
auto simpleMatcher = matcher.mutable_simple_log_entry_matcher();
simpleMatcher->set_tag(TAG_ID);
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
// Convert to a LogEvent
event.init();
@@ -62,7 +62,7 @@
keyValue2->mutable_key_matcher()->set_key(FIELD_ID_2);
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << true;
*list << false;
@@ -98,7 +98,7 @@
keyValue->set_eq_string("some value");
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << "some value";
@@ -119,7 +119,7 @@
keyValue->mutable_key_matcher()->set_key(FIELD_ID_1);
// Set up the event
- LogEvent event(TAG_ID);
+ LogEvent event(TAG_ID, 0);
auto list = event.GetAndroidLogEventList();
*list << 11;
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index b000e13..7333785 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -17,7 +17,9 @@
#include "src/condition/ConditionTracker.h"
#include "src/matchers/LogMatchingTracker.h"
#include "src/metrics/CountMetricProducer.h"
+#include "src/metrics/GaugeMetricProducer.h"
#include "src/metrics/MetricProducer.h"
+#include "src/metrics/ValueMetricProducer.h"
#include "src/metrics/metrics_manager_util.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -124,6 +126,39 @@
return config;
}
+StatsdConfig buildDimensionMetricsWithMultiTags() {
+ StatsdConfig config;
+ config.set_config_id(12345L);
+
+ LogEntryMatcher* eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("BATTERY_VERY_LOW");
+ SimpleLogEntryMatcher* simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->set_tag(2);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("BATTERY_VERY_VERY_LOW");
+ simpleLogEntryMatcher = eventMatcher->mutable_simple_log_entry_matcher();
+ simpleLogEntryMatcher->set_tag(3);
+
+ eventMatcher = config.add_log_entry_matcher();
+ eventMatcher->set_name("BATTERY_LOW");
+
+ LogEntryMatcher_Combination* combination = eventMatcher->mutable_combination();
+ combination->set_operation(LogicalOperation::OR);
+ combination->add_matcher("BATTERY_VERY_LOW");
+ combination->add_matcher("BATTERY_VERY_VERY_LOW");
+
+ // Count process state changes, slice by uid, while SCREEN_IS_OFF
+ CountMetric* metric = config.add_count_metric();
+ metric->set_metric_id(3);
+ metric->set_what("BATTERY_LOW");
+ metric->mutable_bucket()->set_bucket_size_millis(30 * 1000L);
+ KeyMatcher* keyMatcher = metric->add_dimension();
+ keyMatcher->set_key(1);
+
+ return config;
+}
+
StatsdConfig buildCircleConditions() {
StatsdConfig config;
config.set_config_id(12345L);
@@ -180,6 +215,21 @@
trackerToConditionMap));
}
+TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) {
+ StatsdConfig config = buildDimensionMetricsWithMultiTags();
+ set<int> allTagIds;
+ vector<sp<LogMatchingTracker>> allLogEntryMatchers;
+ vector<sp<ConditionTracker>> allConditionTrackers;
+ vector<sp<MetricProducer>> allMetricProducers;
+ unordered_map<int, std::vector<int>> conditionToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToMetricMap;
+ unordered_map<int, std::vector<int>> trackerToConditionMap;
+
+ EXPECT_FALSE(initStatsdConfig(config, allTagIds, allLogEntryMatchers, allConditionTrackers,
+ allMetricProducers, conditionToMetricMap, trackerToMetricMap,
+ trackerToConditionMap));
+}
+
TEST(MetricsManagerTest, TestCircleLogMatcherDependency) {
StatsdConfig config = buildCircleMatchers();
set<int> allTagIds;
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index f9a90e4..671f6d4 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -13,13 +13,17 @@
// limitations under the License.
#include "packages/UidMap.h"
+#include "config/ConfigKey.h"
#include <gtest/gtest.h>
#include <stdio.h>
using namespace android;
-using namespace android::os::statsd;
+
+namespace android {
+namespace os {
+namespace statsd {
#ifdef __ANDROID__
const string kApp1 = "app1.sharing.1";
@@ -64,6 +68,57 @@
EXPECT_FALSE(m.hasApp(1000, kApp1));
EXPECT_TRUE(m.hasApp(1000, kApp2));
}
+
+TEST(UidMapTest, TestClearingOutput) {
+ UidMap m;
+
+ ConfigKey config1(1, "config1");
+ ConfigKey config2(1, "config2");
+
+ m.OnConfigUpdated(config1);
+
+ vector<int32_t> uids;
+ vector<int32_t> versions;
+ vector<String16> apps;
+ uids.push_back(1000);
+ uids.push_back(1000);
+ apps.push_back(String16(kApp1.c_str()));
+ apps.push_back(String16(kApp2.c_str()));
+ versions.push_back(4);
+ versions.push_back(5);
+ m.updateMap(1, uids, versions, apps);
+
+ UidMapping results = m.getOutput(2, config1);
+ EXPECT_EQ(1, results.snapshots_size());
+
+ // It should be cleared now
+ results = m.getOutput(3, config1);
+ EXPECT_EQ(0, results.snapshots_size());
+
+ // Now add another configuration.
+ m.OnConfigUpdated(config2);
+ m.updateApp(5, String16(kApp1.c_str()), 1000, 40);
+ results = m.getOutput(6, config1);
+ EXPECT_EQ(0, results.snapshots_size());
+ EXPECT_EQ(1, results.changes_size());
+
+ // Now we still haven't been able to delete anything
+ m.updateApp(7, String16(kApp2.c_str()), 1001, 41);
+ results = m.getOutput(8, config1);
+ EXPECT_EQ(0, results.snapshots_size());
+ EXPECT_EQ(2, results.changes_size());
+
+ results = m.getOutput(9, config2);
+ EXPECT_EQ(0, results.snapshots_size());
+ EXPECT_EQ(2, results.changes_size());
+ // At this point both should be cleared.
+ EXPECT_EQ(0, m.mOutput.snapshots_size());
+ EXPECT_EQ(0, m.mOutput.changes_size());
+}
#else
GTEST_LOG_(INFO) << "This test does nothing.\n";
#endif
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
new file mode 100644
index 0000000..5a4ee73
--- /dev/null
+++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp
@@ -0,0 +1,183 @@
+// 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 "metrics_test_helper.h"
+#include "src/metrics/CountMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(CountMetricProducerTest, TestNonDimensionalEvents) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+ int64_t bucket2StartTimeNs = bucketStartTimeNs + bucketSizeNs;
+ int64_t bucket3StartTimeNs = bucketStartTimeNs + 2 * bucketSizeNs;
+ int tagId = 1;
+
+ CountMetric metric;
+ metric.set_metric_id(1);
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+
+ LogEvent event1(tagId, bucketStartTimeNs + 1);
+ LogEvent event2(tagId, bucketStartTimeNs + 2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs);
+
+ // 2 events in bucket 1.
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(2LL, bucketInfo.mCount);
+
+ // 1 matched event happens in bucket 2.
+ LogEvent event3(tagId, bucketStartTimeNs + bucketSizeNs + 2);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event3, false);
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + 2 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ EXPECT_EQ(2UL, countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY].size());
+ const auto& bucketInfo2 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY][1];
+ EXPECT_EQ(bucket2StartTimeNs, bucketInfo2.mBucketStartNs);
+ EXPECT_EQ(bucket2StartTimeNs + bucketSizeNs, bucketInfo2.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo2.mCount);
+
+ // nothing happens in bucket 3. we should not record anything for bucket 3.
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 1);
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets3 = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(2UL, buckets3.size());
+}
+
+TEST(CountMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ CountMetric metric;
+ metric.set_metric_id(1);
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_condition("SCREEN_ON");
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ LogEvent event2(1, bucketStartTimeNs + 10);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ CountMetricProducer countProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ countProducer.onConditionChanged(true, bucketStartTimeNs);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.onConditionChanged(false /*new condition*/, bucketStartTimeNs + 2);
+ countProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+ EXPECT_EQ(0UL, countProducer.mPastBuckets.size());
+
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) {
+ int64_t bucketStartTimeNs = 10000000000;
+ int64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ CountMetric metric;
+ metric.set_metric_id(1);
+ metric.mutable_bucket()->set_bucket_size_millis(bucketSizeNs / 1000000);
+ metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ EventConditionLink* link = metric.add_links();
+ link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->add_key_in_main()->set_key(1);
+ link->add_key_in_condition()->set_key(2);
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ auto list = event1.GetAndroidLogEventList();
+ *list << "111"; // uid
+ event1.init();
+ ConditionKey key1;
+ key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+
+ LogEvent event2(1, bucketStartTimeNs + 10);
+ auto list2 = event2.GetAndroidLogEventList();
+ *list2 << "222"; // uid
+ event2.init();
+ ConditionKey key2;
+ key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
+
+ EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
+
+ CountMetricProducer countProducer(metric, 1 /*condition tracker index*/, wizard,
+ bucketStartTimeNs);
+
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event1, false);
+ countProducer.onMatchedLogEvent(1 /*log matcher index*/, event2, false);
+
+ countProducer.flushCounterIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+
+ EXPECT_EQ(1UL, countProducer.mPastBuckets.size());
+ EXPECT_TRUE(countProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
+ countProducer.mPastBuckets.end());
+ const auto& buckets = countProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
+ EXPECT_EQ(1UL, buckets.size());
+ const auto& bucketInfo = buckets[0];
+ EXPECT_EQ(bucketStartTimeNs, bucketInfo.mBucketStartNs);
+ EXPECT_EQ(bucketStartTimeNs + bucketSizeNs, bucketInfo.mBucketEndNs);
+ EXPECT_EQ(1LL, bucketInfo.mCount);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
new file mode 100644
index 0000000..76dbc73
--- /dev/null
+++ b/cmds/statsd/tests/metrics/EventMetricProducer_test.cpp
@@ -0,0 +1,130 @@
+// 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 "metrics_test_helper.h"
+#include "src/metrics/EventMetricProducer.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(EventMetricProducerTest, TestNoCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_metric_id(1);
+
+ LogEvent event1(1 /*tag id*/, bucketStartTimeNs + 1);
+ LogEvent event2(1 /*tag id*/, bucketStartTimeNs + 2);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ EventMetricProducer eventProducer(metric, -1 /*-1 meaning no condition*/, wizard,
+ bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+TEST(EventMetricProducerTest, TestEventsWithNonSlicedCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_metric_id(1);
+ metric.set_condition("SCREEN_ON");
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ LogEvent event2(1, bucketStartTimeNs + 10);
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onConditionChanged(true /*condition*/, bucketStartTimeNs);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+
+ eventProducer.onConditionChanged(false /*condition*/, bucketStartTimeNs + 2);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+TEST(EventMetricProducerTest, TestEventsWithSlicedCondition) {
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ EventMetric metric;
+ metric.set_metric_id(1);
+ metric.set_condition("APP_IN_BACKGROUND_PER_UID_AND_SCREEN_ON");
+ EventConditionLink* link = metric.add_links();
+ link->set_condition("APP_IN_BACKGROUND_PER_UID");
+ link->add_key_in_main()->set_key(1);
+ link->add_key_in_condition()->set_key(2);
+
+ LogEvent event1(1, bucketStartTimeNs + 1);
+ auto list = event1.GetAndroidLogEventList();
+ *list << "111"; // uid
+ event1.init();
+ ConditionKey key1;
+ key1["APP_IN_BACKGROUND_PER_UID"] = "2:111|";
+
+ LogEvent event2(1, bucketStartTimeNs + 10);
+ auto list2 = event2.GetAndroidLogEventList();
+ *list2 << "222"; // uid
+ event2.init();
+ ConditionKey key2;
+ key2["APP_IN_BACKGROUND_PER_UID"] = "2:222|";
+
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+ EXPECT_CALL(*wizard, query(_, key1)).WillOnce(Return(ConditionState::kFalse));
+
+ EXPECT_CALL(*wizard, query(_, key2)).WillOnce(Return(ConditionState::kTrue));
+
+ EventMetricProducer eventProducer(metric, 1, wizard, bucketStartTimeNs);
+
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event1, false /*pulled*/);
+ eventProducer.onMatchedLogEvent(1 /*matcher index*/, event2, false /*pulled*/);
+
+ // TODO: get the report and check the content after the ProtoOutputStream change is done.
+ // eventProducer.onDumpReport();
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
new file mode 100644
index 0000000..58bf1b3
--- /dev/null
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -0,0 +1,114 @@
+// 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 "metrics_test_helper.h"
+#include "src/condition/ConditionWizard.h"
+#include "src/metrics/duration_helper/MaxDurationTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+using namespace android::os::statsd;
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ vector<DurationBucket> buckets;
+ ConditionKey key1;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ MaxDurationTracker tracker(wizard, -1, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("", true, bucketStartTimeNs, key1);
+ tracker.noteStop("", bucketStartTimeNs + 10);
+
+ tracker.noteStart("", true, bucketStartTimeNs + 20, key1);
+ tracker.noteStop("", bucketStartTimeNs + 40);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1u, buckets.size());
+ EXPECT_EQ(20, buckets[0].mDuration);
+}
+
+TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ vector<DurationBucket> buckets;
+ ConditionKey key1;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+
+ MaxDurationTracker tracker(wizard, -1, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
+ tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
+
+ EXPECT_EQ(2u, buckets.size());
+ EXPECT_EQ((long long)(bucketSizeNs - 1), buckets[0].mDuration);
+ EXPECT_EQ((long long)bucketSizeNs, buckets[1].mDuration);
+}
+
+TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ ConditionKey key1;
+ key1["APP_BACKGROUND"] = "1:maps|";
+
+ EXPECT_CALL(*wizard, query(_, key1)) // #4
+ .WillOnce(Return(ConditionState::kFalse));
+
+ vector<DurationBucket> buckets;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+ int64_t durationTimeNs = 2 * 1000;
+
+ MaxDurationTracker tracker(wizard, 1, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+
+ tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
+
+ tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1u, buckets.size());
+ EXPECT_EQ(5, buckets[0].mDuration);
+}
+
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
new file mode 100644
index 0000000..74a6f11
--- /dev/null
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -0,0 +1,95 @@
+// 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 "metrics_test_helper.h"
+#include "src/condition/ConditionWizard.h"
+#include "src/metrics/duration_helper/OringDurationTracker.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <stdio.h>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+using namespace testing;
+using android::sp;
+using std::set;
+using std::unordered_map;
+using std::vector;
+
+#ifdef __ANDROID__
+namespace android {
+namespace os {
+namespace statsd {
+
+TEST(OringDurationTrackerTest, TestDurationOverlap) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ ConditionKey key1;
+ key1["APP_BACKGROUND"] = "1:maps|";
+
+ vector<DurationBucket> buckets;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+ int64_t durationTimeNs = 2 * 1000;
+
+ OringDurationTracker tracker(wizard, 1, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+ tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
+
+ tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1u, buckets.size());
+ EXPECT_EQ(durationTimeNs, buckets[0].mDuration);
+}
+
+TEST(OringDurationTrackerTest, TestDurationConditionChange) {
+ sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+
+ ConditionKey key1;
+ key1["APP_BACKGROUND"] = "1:maps|";
+
+ EXPECT_CALL(*wizard, query(_, key1)) // #4
+ .WillOnce(Return(ConditionState::kFalse));
+
+ vector<DurationBucket> buckets;
+
+ uint64_t bucketStartTimeNs = 10000000000;
+ uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
+ uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
+ int64_t durationTimeNs = 2 * 1000;
+
+ OringDurationTracker tracker(wizard, 1, bucketStartTimeNs, bucketSizeNs, buckets);
+
+ tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
+
+ tracker.onSlicedConditionMayChange(eventStartTimeNs + 5);
+
+ tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
+ EXPECT_EQ(1u, buckets.size());
+ EXPECT_EQ(5, buckets[0].mDuration);
+}
+} // namespace statsd
+} // namespace os
+} // namespace android
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
diff --git a/cmds/statsd/tests/metrics/metrics_test_helper.h b/cmds/statsd/tests/metrics/metrics_test_helper.h
new file mode 100644
index 0000000..5fd7d62
--- /dev/null
+++ b/cmds/statsd/tests/metrics/metrics_test_helper.h
@@ -0,0 +1,35 @@
+// 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 "src/condition/ConditionWizard.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+class MockConditionWizard : public ConditionWizard {
+public:
+ MOCK_METHOD2(
+ query,
+ ConditionState(const int conditionIndex,
+ const std::map<std::string, HashableDimensionKey>& conditionParameters));
+};
+
+} // namespace statsd
+} // namespace os
+} // namespace android
diff --git a/cmds/svc/svc b/cmds/svc/svc
index 27111cd..07b50fe 100755
--- a/cmds/svc/svc
+++ b/cmds/svc/svc
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "am" on the device, which has a very rudimentary
# shell.
#
diff --git a/cmds/telecom/telecom b/cmds/telecom/telecom
index 9efdcfd..a19036b 100755
--- a/cmds/telecom/telecom
+++ b/cmds/telecom/telecom
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "telecom" on the device
#
base=/system
diff --git a/cmds/uiautomator/cmds/uiautomator/uiautomator b/cmds/uiautomator/cmds/uiautomator/uiautomator
index 86a1dba..889c2b5 100755
--- a/cmds/uiautomator/cmds/uiautomator/uiautomator
+++ b/cmds/uiautomator/cmds/uiautomator/uiautomator
@@ -1,3 +1,4 @@
+#!/system/bin/sh
#
# Copyright (C) 2012 The Android Open Source Project
#
diff --git a/cmds/vr/vr b/cmds/vr/vr
index a279007..dbde02a 100755
--- a/cmds/vr/vr
+++ b/cmds/vr/vr
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "vr" on the device
#
base=/system
diff --git a/cmds/wm/wm b/cmds/wm/wm
index f7a5bc7..16d6bd6 100755
--- a/cmds/wm/wm
+++ b/cmds/wm/wm
@@ -1,3 +1,4 @@
+#!/system/bin/sh
# Script to start "wm" on the device, which has a very rudimentary
# shell.
#
diff --git a/config/compiled-classes-phone b/config/compiled-classes-phone
index 47e148d..bc344d7 100644
--- a/config/compiled-classes-phone
+++ b/config/compiled-classes-phone
@@ -3340,14 +3340,8 @@
android.os.StrictMode$AndroidBlockGuardPolicy
android.os.StrictMode$AndroidBlockGuardPolicy$1
android.os.StrictMode$AndroidCloseGuardReporter
-android.os.StrictMode$InstanceCountViolation
android.os.StrictMode$InstanceTracker
-android.os.StrictMode$LogStackTrace
android.os.StrictMode$Span
-android.os.StrictMode$StrictModeCustomViolation
-android.os.StrictMode$StrictModeDiskReadViolation
-android.os.StrictMode$StrictModeDiskWriteViolation
-android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
@@ -3949,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/config/preloaded-classes b/config/preloaded-classes
index 1b86724..a9e90de 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -1865,9 +1865,6 @@
android.os.StrictMode$InstanceTracker
android.os.StrictMode$LogStackTrace
android.os.StrictMode$Span
-android.os.StrictMode$StrictModeDiskReadViolation
-android.os.StrictMode$StrictModeDiskWriteViolation
-android.os.StrictMode$StrictModeViolation
android.os.StrictMode$ThreadPolicy
android.os.StrictMode$ThreadPolicy$Builder
android.os.StrictMode$ThreadSpanState
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 076c2bc..a8863bf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,8 +16,6 @@
package android.app;
-import static android.os.Build.VERSION_CODES.O_MR1;
-
import static java.lang.Character.MIN_VALUE;
import android.annotation.CallSuper;
@@ -136,6 +134,7 @@
import java.util.HashMap;
import java.util.List;
+
/**
* An activity is a single, focused thing that the user can do. Almost all
* activities interact with the user, so the Activity class takes care of
@@ -991,17 +990,6 @@
protected void onCreate(@Nullable Bundle savedInstanceState) {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
- if (getApplicationInfo().targetSdkVersion >= O_MR1 && mActivityInfo.isFixedOrientation()) {
- final TypedArray ta = obtainStyledAttributes(com.android.internal.R.styleable.Window);
- final boolean isTranslucentOrFloating = ActivityInfo.isTranslucentOrFloating(ta);
- ta.recycle();
-
- if (isTranslucentOrFloating) {
- throw new IllegalStateException(
- "Only fullscreen opaque activities can request orientation");
- }
- }
-
if (mLastNonConfigurationInstances != null) {
mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
}
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2305957..064e978 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -687,6 +687,7 @@
* in portrait mode or at the left half of the screen if in landscape mode.
* @hide
*/
+ @TestApi
public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0;
/**
@@ -696,6 +697,7 @@
* in portrait mode or at the right half of the screen if in landscape mode.
* @hide
*/
+ @TestApi
public static final int SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT = 1;
/**
@@ -1926,6 +1928,33 @@
}
/**
+ * Moves the input task to the primary-split-screen stack.
+ * @param taskId Id of task to move.
+ * @param createMode The mode the primary split screen stack should be created in if it doesn't
+ * exist already. See
+ * {@link android.app.ActivityManager#SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT}
+ * and
+ * {@link android.app.ActivityManager
+ * #SPLIT_SCREEN_CREATE_MODE_BOTTOM_OR_RIGHT}
+ * @param toTop If the task and stack should be moved to the top.
+ * @param animate Whether we should play an animation for the moving the task
+ * @param initialBounds If the primary stack gets created, it will use these bounds for the
+ * docked stack. Pass {@code null} to use default bounds.
+ * @hide
+ */
+ @TestApi
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public void setTaskWindowingModeSplitScreenPrimary(int taskId, int createMode, boolean toTop,
+ boolean animate, Rect initialBounds) throws SecurityException {
+ try {
+ getService().setTaskWindowingModeSplitScreenPrimary(taskId, createMode, toTop, animate,
+ initialBounds);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Resizes the input stack id to the given bounds.
* @param stackId Id of the stack to resize.
* @param bounds Bounds to resize the stack to or {@code null} for fullscreen.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 2516a3e..21e454f 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -5533,32 +5533,8 @@
View.mDebugViewAttributes =
mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
- /**
- * For system applications on userdebug/eng builds, log stack
- * traces of disk and network access to dropbox for analysis.
- */
- if ((data.appInfo.flags &
- (ApplicationInfo.FLAG_SYSTEM |
- ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
- StrictMode.conditionallyEnableDebugLogging();
- }
-
- /**
- * For apps targetting Honeycomb or later, we don't allow network usage
- * on the main event loop / UI thread. This is what ultimately throws
- * {@link NetworkOnMainThreadException}.
- */
- if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
- StrictMode.enableDeathOnNetwork();
- }
-
- /**
- * For apps targetting N or later, we don't allow file:// Uri exposure.
- * This is what ultimately throws {@link FileUriExposedException}.
- */
- if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
- StrictMode.enableDeathOnFileUriExposure();
- }
+ StrictMode.initThreadDefaults(data.appInfo);
+ StrictMode.initVmDefaults(data.appInfo);
// We deprecated Build.SERIAL and only apps that target pre NMR1
// SDK can see it. Since access to the serial is now behind a
@@ -5655,7 +5631,12 @@
mResourcesManager.getConfiguration().getLocales());
if (!Process.isIsolated()) {
- setupGraphicsSupport(appContext);
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try {
+ setupGraphicsSupport(appContext);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
}
// If we use profiles, setup the dex reporter to notify package manager
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 4b31b80..bbc90c8 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -450,9 +450,8 @@
int checkPermissionWithToken(in String permission, int pid, int uid,
in IBinder callerToken);
void registerTaskStackListener(in ITaskStackListener listener);
+ void unregisterTaskStackListener(in ITaskStackListener listener);
-
- // Start of M transactions
void notifyCleartextNetwork(int uid, in byte[] firstPacket);
int createStackOnDisplay(int displayId);
void setTaskResizeable(int taskId, int resizeableMode);
@@ -618,7 +617,6 @@
* @return Returns true if the configuration was updated.
*/
boolean updateDisplayOverrideConfiguration(in Configuration values, int displayId);
- void unregisterTaskStackListener(ITaskStackListener listener);
void moveStackToDisplay(int stackId, int displayId);
boolean requestAutofillData(in IAssistDataReceiver receiver, in Bundle receiverExtras,
in IBinder activityToken, int flags);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8226e0f..d5d95fb 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -22,6 +22,7 @@
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
@@ -3900,7 +3901,7 @@
final Bundle ex = mN.extras;
updateBackgroundColor(contentView);
bindNotificationHeader(contentView, p.ambient);
- bindLargeIcon(contentView);
+ bindLargeIcon(contentView, p.hideLargeIcon, p.alwaysShowReply);
boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
if (p.title != null) {
contentView.setViewVisibility(R.id.title, View.VISIBLE);
@@ -4110,11 +4111,13 @@
}
}
- private void bindLargeIcon(RemoteViews contentView) {
+ private void bindLargeIcon(RemoteViews contentView, boolean hideLargeIcon,
+ boolean alwaysShowReply) {
if (mN.mLargeIcon == null && mN.largeIcon != null) {
mN.mLargeIcon = Icon.createWithBitmap(mN.largeIcon);
}
- if (mN.mLargeIcon != null) {
+ boolean showLargeIcon = mN.mLargeIcon != null && !hideLargeIcon;
+ if (showLargeIcon) {
contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
contentView.setImageViewIcon(R.id.right_icon, mN.mLargeIcon);
processLargeLegacyIcon(mN.mLargeIcon, contentView);
@@ -4122,32 +4125,45 @@
contentView.setViewLayoutMarginEndDimen(R.id.line1, endMargin);
contentView.setViewLayoutMarginEndDimen(R.id.text, endMargin);
contentView.setViewLayoutMarginEndDimen(R.id.progress, endMargin);
- // Bind the reply action
- Action action = findReplyAction();
- contentView.setViewVisibility(R.id.reply_icon_action, action != null
- ? View.VISIBLE
- : View.GONE);
+ }
+ // Bind the reply action
+ Action action = findReplyAction();
- if (action != null) {
- int contrastColor = resolveContrastColor();
+ boolean actionVisible = action != null && (showLargeIcon || alwaysShowReply);
+ int replyId = showLargeIcon ? R.id.reply_icon_action : R.id.right_icon;
+ if (actionVisible) {
+ // We're only showing the icon as big if we're hiding the large icon
+ int contrastColor = resolveContrastColor();
+ int iconColor;
+ if (showLargeIcon) {
contentView.setDrawableTint(R.id.reply_icon_action,
true /* targetBackground */,
contrastColor, PorterDuff.Mode.SRC_ATOP);
- int iconColor = NotificationColorUtil.isColorLight(contrastColor)
- ? Color.BLACK : Color.WHITE;
- contentView.setDrawableTint(R.id.reply_icon_action,
- false /* targetBackground */,
- iconColor, PorterDuff.Mode.SRC_ATOP);
contentView.setOnClickPendingIntent(R.id.right_icon,
action.actionIntent);
- contentView.setOnClickPendingIntent(R.id.reply_icon_action,
- action.actionIntent);
contentView.setRemoteInputs(R.id.right_icon, action.mRemoteInputs);
- contentView.setRemoteInputs(R.id.reply_icon_action, action.mRemoteInputs);
-
+ iconColor = NotificationColorUtil.isColorLight(contrastColor)
+ ? Color.BLACK : Color.WHITE;
+ } else {
+ contentView.setImageViewResource(R.id.right_icon,
+ R.drawable.ic_reply_notification_large);
+ contentView.setViewVisibility(R.id.right_icon, View.VISIBLE);
+ iconColor = contrastColor;
}
+ contentView.setDrawableTint(replyId,
+ false /* targetBackground */,
+ iconColor,
+ PorterDuff.Mode.SRC_ATOP);
+ contentView.setOnClickPendingIntent(replyId,
+ action.actionIntent);
+ contentView.setRemoteInputs(replyId, action.mRemoteInputs);
+ } else {
+ contentView.setRemoteInputs(R.id.right_icon, null);
}
- contentView.setViewVisibility(R.id.right_icon_container, mN.mLargeIcon != null
+ contentView.setViewVisibility(R.id.reply_icon_action, actionVisible && showLargeIcon
+ ? View.VISIBLE
+ : View.GONE);
+ contentView.setViewVisibility(R.id.right_icon_container, actionVisible || showLargeIcon
? View.VISIBLE
: View.GONE);
}
@@ -6055,18 +6071,12 @@
protected void restoreFromExtras(Bundle extras) {
super.restoreFromExtras(extras);
- mMessages.clear();
- mHistoricMessages.clear();
mUserDisplayName = extras.getCharSequence(EXTRA_SELF_DISPLAY_NAME);
mConversationTitle = extras.getCharSequence(EXTRA_CONVERSATION_TITLE);
Parcelable[] messages = extras.getParcelableArray(EXTRA_MESSAGES);
- if (messages != null && messages instanceof Parcelable[]) {
- mMessages = Message.getMessagesFromBundleArray(messages);
- }
+ mMessages = Message.getMessagesFromBundleArray(messages);
Parcelable[] histMessages = extras.getParcelableArray(EXTRA_HISTORIC_MESSAGES);
- if (histMessages != null && histMessages instanceof Parcelable[]) {
- mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
- }
+ mHistoricMessages = Message.getMessagesFromBundleArray(histMessages);
}
/**
@@ -6074,38 +6084,34 @@
*/
@Override
public RemoteViews makeContentView(boolean increasedHeight) {
- if (!increasedHeight) {
- Message m = findLatestIncomingMessage();
- CharSequence title = mConversationTitle != null
- ? mConversationTitle
- : (m == null) ? null : m.mSender;
- CharSequence text = (m == null)
- ? null
- : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
-
- return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
- } else {
- mBuilder.mOriginalActions = mBuilder.mActions;
- mBuilder.mActions = new ArrayList<>();
- RemoteViews remoteViews = makeBigContentView();
- mBuilder.mActions = mBuilder.mOriginalActions;
- mBuilder.mOriginalActions = null;
- return remoteViews;
- }
+ mBuilder.mOriginalActions = mBuilder.mActions;
+ mBuilder.mActions = new ArrayList<>();
+ RemoteViews remoteViews = makeBigContentView();
+ mBuilder.mActions = mBuilder.mOriginalActions;
+ mBuilder.mOriginalActions = null;
+ return remoteViews;
}
private Message findLatestIncomingMessage() {
- for (int i = mMessages.size() - 1; i >= 0; i--) {
- Message m = mMessages.get(i);
+ return findLatestIncomingMessage(mMessages);
+ }
+
+ /**
+ * @hide
+ */
+ @Nullable
+ public static Message findLatestIncomingMessage(
+ List<Message> messages) {
+ for (int i = messages.size() - 1; i >= 0; i--) {
+ Message m = messages.get(i);
// Incoming messages have a non-empty sender.
if (!TextUtils.isEmpty(m.mSender)) {
return m;
}
}
- if (!mMessages.isEmpty()) {
+ if (!messages.isEmpty()) {
// No incoming messages, fall back to outgoing message
- return mMessages.get(mMessages.size() - 1);
+ return messages.get(messages.size() - 1);
}
return null;
}
@@ -6115,118 +6121,82 @@
*/
@Override
public RemoteViews makeBigContentView() {
- CharSequence title = !TextUtils.isEmpty(super.mBigContentTitle)
+ CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
? super.mBigContentTitle
: mConversationTitle;
- boolean hasTitle = !TextUtils.isEmpty(title);
-
- if (mMessages.size() == 1) {
- // Special case for a single message: Use the big text style
- // so the collapsed and expanded versions match nicely.
- CharSequence bigTitle;
- CharSequence text;
- if (hasTitle) {
- bigTitle = title;
- text = makeMessageLine(mMessages.get(0), mBuilder);
- } else {
- bigTitle = mMessages.get(0).mSender;
- text = mMessages.get(0).mText;
- }
- RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
- mBuilder.getBigTextLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(bigTitle).text(null));
- BigTextStyle.applyBigTextContentView(mBuilder, contentView, text);
- return contentView;
+ boolean isOneToOne = TextUtils.isEmpty(conversationTitle);
+ if (isOneToOne) {
+ // Let's add the conversationTitle in case we didn't have one before and all
+ // messages are from the same sender
+ conversationTitle = createConversationTitleFromMessages();
+ } else if (hasOnlyWhiteSpaceSenders()) {
+ isOneToOne = true;
}
-
+ boolean hasTitle = !TextUtils.isEmpty(conversationTitle);
RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
mBuilder.getMessagingLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(null));
-
- int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
- R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
-
- // Make sure all rows are gone in case we reuse a view.
- for (int rowId : rowIds) {
- contentView.setViewVisibility(rowId, View.GONE);
- }
-
- int i=0;
- contentView.setViewLayoutMarginBottomDimen(R.id.line1,
- hasTitle ? R.dimen.notification_messaging_spacing : 0);
- contentView.setInt(R.id.notification_messaging, "setNumIndentLines",
- !mBuilder.mN.hasLargeIcon() ? 0 : (hasTitle ? 1 : 2));
-
- int contractedChildId = View.NO_ID;
- Message contractedMessage = findLatestIncomingMessage();
- int firstHistoricMessage = Math.max(0, mHistoricMessages.size()
- - (rowIds.length - mMessages.size()));
- while (firstHistoricMessage + i < mHistoricMessages.size() && i < rowIds.length) {
- Message m = mHistoricMessages.get(firstHistoricMessage + i);
- int rowId = rowIds[i];
-
- contentView.setTextViewText(rowId, makeMessageLine(m, mBuilder));
-
- if (contractedMessage == m) {
- contractedChildId = rowId;
- }
-
- i++;
- }
-
- int firstMessage = Math.max(0, mMessages.size() - rowIds.length);
- while (firstMessage + i < mMessages.size() && i < rowIds.length) {
- Message m = mMessages.get(firstMessage + i);
- int rowId = rowIds[i];
-
- contentView.setViewVisibility(rowId, View.VISIBLE);
- contentView.setTextViewText(rowId, mBuilder.processTextSpans(
- makeMessageLine(m, mBuilder)));
- mBuilder.setTextViewColorSecondary(contentView, rowId);
-
- if (contractedMessage == m) {
- contractedChildId = rowId;
- }
-
- i++;
- }
- // Clear the remaining views for reapply. Ensures that historic message views can
- // reliably be identified as being GONE and having non-null text.
- while (i < rowIds.length) {
- int rowId = rowIds[i];
- contentView.setTextViewText(rowId, null);
- i++;
- }
-
- // Record this here to allow transformation between the contracted and expanded views.
- contentView.setInt(R.id.notification_messaging, "setContractedChildId",
- contractedChildId);
+ mBuilder.mParams.reset().hasProgress(false).title(conversationTitle).text(null)
+ .hideLargeIcon(isOneToOne).alwaysShowReply(true));
+ addExtras(mBuilder.mN.extras);
+ contentView.setInt(R.id.status_bar_latest_event_content, "setLayoutColor",
+ mBuilder.resolveContrastColor());
+ contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
+ mBuilder.mN.mLargeIcon);
+ contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsOneToOne",
+ isOneToOne);
+ contentView.setBundle(R.id.status_bar_latest_event_content, "setData",
+ mBuilder.mN.extras);
return contentView;
}
- private CharSequence makeMessageLine(Message m, Builder builder) {
- BidiFormatter bidi = BidiFormatter.getInstance();
- SpannableStringBuilder sb = new SpannableStringBuilder();
- boolean colorize = builder.isColorized();
- TextAppearanceSpan colorSpan;
- CharSequence messageName;
- if (TextUtils.isEmpty(m.mSender)) {
- CharSequence replyName = mUserDisplayName == null ? "" : mUserDisplayName;
- sb.append(bidi.unicodeWrap(replyName),
- makeFontColorSpan(colorize
- ? builder.getPrimaryTextColor()
- : mBuilder.resolveContrastColor()),
- 0 /* flags */);
- } else {
- sb.append(bidi.unicodeWrap(m.mSender),
- makeFontColorSpan(colorize
- ? builder.getPrimaryTextColor()
- : Color.BLACK),
- 0 /* flags */);
+ private boolean hasOnlyWhiteSpaceSenders() {
+ for (int i = 0; i < mMessages.size(); i++) {
+ Message m = mMessages.get(i);
+ CharSequence sender = m.getSender();
+ if (!isWhiteSpace(sender)) {
+ return false;
+ }
}
- CharSequence text = m.mText == null ? "" : m.mText;
- sb.append(" ").append(bidi.unicodeWrap(text));
- return sb;
+ return true;
+ }
+
+ private boolean isWhiteSpace(CharSequence sender) {
+ if (TextUtils.isEmpty(sender)) {
+ return true;
+ }
+ if (sender.toString().matches("^\\s*$")) {
+ return true;
+ }
+ // Let's check if we only have 0 whitespace chars. Some apps did this as a workaround
+ // For the presentation that we had.
+ for (int i = 0; i < sender.length(); i++) {
+ char c = sender.charAt(i);
+ if (c != '\u200B') {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private CharSequence createConversationTitleFromMessages() {
+ ArraySet<CharSequence> names = new ArraySet<>();
+ for (int i = 0; i < mMessages.size(); i++) {
+ Message m = mMessages.get(i);
+ CharSequence sender = m.getSender();
+ if (sender != null) {
+ names.add(sender);
+ }
+ }
+ SpannableStringBuilder title = new SpannableStringBuilder();
+ int size = names.size();
+ for (int i = 0; i < size; i++) {
+ CharSequence name = names.valueAt(i);
+ if (!TextUtils.isEmpty(title)) {
+ title.append(", ");
+ }
+ title.append(BidiFormatter.getInstance().unicodeWrap(name));
+ }
+ return title;
}
/**
@@ -6234,19 +6204,9 @@
*/
@Override
public RemoteViews makeHeadsUpContentView(boolean increasedHeight) {
- if (increasedHeight) {
- return makeBigContentView();
- }
- Message m = findLatestIncomingMessage();
- CharSequence title = mConversationTitle != null
- ? mConversationTitle
- : (m == null) ? null : m.mSender;
- CharSequence text = (m == null)
- ? null
- : mConversationTitle != null ? makeMessageLine(m, mBuilder) : m.mText;
-
- return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
- mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
+ RemoteViews remoteViews = makeBigContentView();
+ remoteViews.setInt(R.id.notification_messaging, "setMaxDisplayedLines", 1);
+ return remoteViews;
}
private static TextAppearanceSpan makeFontColorSpan(int color) {
@@ -6394,7 +6354,15 @@
return bundles;
}
- static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) {
+ /**
+ * @return A list of messages read from the bundles.
+ *
+ * @hide
+ */
+ public static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) {
+ if (bundles == null) {
+ return new ArrayList<>();
+ }
List<Message> messages = new ArrayList<>(bundles.length);
for (int i = 0; i < bundles.length; i++) {
if (bundles[i] instanceof Bundle) {
@@ -8487,6 +8455,8 @@
boolean ambient = false;
CharSequence title;
CharSequence text;
+ boolean hideLargeIcon;
+ public boolean alwaysShowReply;
final StandardTemplateParams reset() {
hasProgress = true;
@@ -8511,6 +8481,16 @@
return this;
}
+ final StandardTemplateParams alwaysShowReply(boolean alwaysShowReply) {
+ this.alwaysShowReply = alwaysShowReply;
+ return this;
+ }
+
+ final StandardTemplateParams hideLargeIcon(boolean hideLargeIcon) {
+ this.hideLargeIcon = hideLargeIcon;
+ return this;
+ }
+
final StandardTemplateParams ambient(boolean ambient) {
Preconditions.checkState(title == null && text == null, "must set ambient before text");
this.ambient = ambient;
@@ -8527,7 +8507,6 @@
text = extras.getCharSequence(EXTRA_TEXT);
}
this.text = b.processLegacyText(text, ambient);
-
return this;
}
}
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 50f1f36..4efc2c7 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -81,6 +81,7 @@
import android.net.IpSecManager;
import android.net.NetworkPolicyManager;
import android.net.NetworkScoreManager;
+import android.net.NetworkWatchlistManager;
import android.net.lowpan.ILowpanManager;
import android.net.lowpan.LowpanManager;
import android.net.nsd.INsdManager;
@@ -150,6 +151,7 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.app.ISoundTriggerService;
import com.android.internal.appwidget.IAppWidgetService;
+import com.android.internal.net.INetworkWatchlistManager;
import com.android.internal.os.IDropBoxManagerService;
import com.android.internal.policy.PhoneLayoutInflater;
@@ -304,14 +306,14 @@
}});
registerService(Context.BATTERY_SERVICE, BatteryManager.class,
- new StaticServiceFetcher<BatteryManager>() {
+ new CachedServiceFetcher<BatteryManager>() {
@Override
- public BatteryManager createService() throws ServiceNotFoundException {
+ public BatteryManager createService(ContextImpl ctx) throws ServiceNotFoundException {
IBatteryStats stats = IBatteryStats.Stub.asInterface(
ServiceManager.getServiceOrThrow(BatteryStats.SERVICE_NAME));
IBatteryPropertiesRegistrar registrar = IBatteryPropertiesRegistrar.Stub
.asInterface(ServiceManager.getServiceOrThrow("batteryproperties"));
- return new BatteryManager(stats, registrar);
+ return new BatteryManager(ctx, stats, registrar);
}});
registerService(Context.NFC_SERVICE, NfcManager.class,
@@ -862,6 +864,17 @@
return new ShortcutManager(ctx, IShortcutService.Stub.asInterface(b));
}});
+ registerService(Context.NETWORK_WATCHLIST_SERVICE, NetworkWatchlistManager.class,
+ new CachedServiceFetcher<NetworkWatchlistManager>() {
+ @Override
+ public NetworkWatchlistManager createService(ContextImpl ctx)
+ throws ServiceNotFoundException {
+ IBinder b =
+ ServiceManager.getServiceOrThrow(Context.NETWORK_WATCHLIST_SERVICE);
+ return new NetworkWatchlistManager(ctx,
+ INetworkWatchlistManager.Stub.asInterface(b));
+ }});
+
registerService(Context.SYSTEM_HEALTH_SERVICE, SystemHealthManager.class,
new CachedServiceFetcher<SystemHealthManager>() {
@Override
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 5c6ffa3..392387a 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -198,4 +198,20 @@
e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+ * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+ *
+ * @param standby True if the device is entering standby, false if it's exiting standby.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.ACCESS_VR_MANAGER)
+ public void setStandbyEnabled(boolean standby) {
+ try {
+ mService.setStandbyEnabled(standby);
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/WindowConfiguration.java b/core/java/android/app/WindowConfiguration.java
index de27b4f..2c1fad1 100644
--- a/core/java/android/app/WindowConfiguration.java
+++ b/core/java/android/app/WindowConfiguration.java
@@ -500,15 +500,12 @@
* @hide
*/
public boolean supportSplitScreenWindowingMode() {
- return supportSplitScreenWindowingMode(mWindowingMode, mActivityType);
+ return supportSplitScreenWindowingMode(mActivityType);
}
/** @hide */
- public static boolean supportSplitScreenWindowingMode(int windowingMode, int activityType) {
- if (activityType == ACTIVITY_TYPE_ASSISTANT) {
- return false;
- }
- return windowingMode != WINDOWING_MODE_FREEFORM && windowingMode != WINDOWING_MODE_PINNED;
+ public static boolean supportSplitScreenWindowingMode(int activityType) {
+ return activityType != ACTIVITY_TYPE_ASSISTANT;
}
/** @hide */
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/app/slice/Slice.java b/core/java/android/app/slice/Slice.java
index f6b6b86..1ce89d2 100644
--- a/core/java/android/app/slice/Slice.java
+++ b/core/java/android/app/slice/Slice.java
@@ -21,6 +21,7 @@
import android.annotation.StringDef;
import android.app.PendingIntent;
import android.app.RemoteInput;
+import android.app.slice.widget.SliceView;
import android.content.ContentResolver;
import android.content.IContentProvider;
import android.graphics.drawable.Icon;
@@ -54,7 +55,12 @@
public @interface SliceHint{ }
/**
- * Hint that this content is a title of other content in the slice.
+ * Hint that this content is a title of other content in the slice. This can also indicate that
+ * the content should be used in the shortcut representation of the slice (icon, label, action),
+ * normally this should be indicated by adding the hint on the action containing that content.
+ *
+ * @see SliceView#MODE_SHORTCUT
+ * @see SliceItem#TYPE_ACTION
*/
public static final String HINT_TITLE = "title";
/**
@@ -100,6 +106,13 @@
*/
public static final String HINT_NO_TINT = "no_tint";
/**
+ * Hint to indicate that this content should not be shown in the {@link SliceView#MODE_SMALL}
+ * and {@link SliceView#MODE_LARGE} modes of SliceView. This content may be used to populate
+ * the {@link SliceView#MODE_SHORTCUT} format of the slice.
+ * @hide
+ */
+ public static final String HINT_HIDDEN = "hidden";
+ /**
* Hint to indicate that this slice is incomplete and an update will be sent once
* loading is complete. Slices which contain HINT_PARTIAL will not be cached by the
* OS and should not be cached by apps.
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 33825b4..da718dc 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -19,15 +19,19 @@
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
+import android.content.Intent;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Binder;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
+import android.os.Process;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
+import android.os.UserHandle;
import android.util.Log;
import java.util.concurrent.CountDownLatch;
@@ -143,9 +147,13 @@
@Override
public Bundle call(String method, String arg, Bundle extras) {
if (method.equals(METHOD_SLICE)) {
- getContext().enforceCallingPermission(permission.BIND_SLICE,
- "Slice binding requires the permission BIND_SLICE");
Uri uri = extras.getParcelable(EXTRA_BIND_URI);
+ if (!UserHandle.isSameApp(Binder.getCallingUid(), Process.myUid())) {
+ getContext().enforceUriPermission(uri, permission.BIND_SLICE,
+ permission.BIND_SLICE, Binder.getCallingPid(), Binder.getCallingUid(),
+ Intent.FLAG_GRANT_WRITE_URI_PERMISSION,
+ "Slice binding requires the permission BIND_SLICE");
+ }
Slice s = handleBindSlice(uri);
Bundle b = new Bundle();
diff --git a/core/java/android/app/slice/widget/GridView.java b/core/java/android/app/slice/widget/GridView.java
index 67a3c67..793abc0 100644
--- a/core/java/android/app/slice/widget/GridView.java
+++ b/core/java/android/app/slice/widget/GridView.java
@@ -126,6 +126,9 @@
* Returns true if this item is just an image.
*/
private boolean addItem(SliceItem item) {
+ if (item.hasHint(Slice.HINT_HIDDEN)) {
+ return false;
+ }
if (item.getType() == SliceItem.TYPE_IMAGE) {
ImageView v = new ImageView(getContext());
v.setImageIcon(item.getIcon());
@@ -145,6 +148,9 @@
items.addAll(item.getSlice().getItems());
}
items.forEach(i -> {
+ if (i.hasHint(Slice.HINT_HIDDEN)) {
+ return;
+ }
Context context = getContext();
switch (i.getType()) {
case SliceItem.TYPE_TEXT:
diff --git a/core/java/android/app/slice/widget/LargeTemplateView.java b/core/java/android/app/slice/widget/LargeTemplateView.java
index f45b2a8..788f6fb 100644
--- a/core/java/android/app/slice/widget/LargeTemplateView.java
+++ b/core/java/android/app/slice/widget/LargeTemplateView.java
@@ -85,9 +85,14 @@
addList(slice, items);
} else {
slice.getItems().forEach(item -> {
- if (item.hasHint(Slice.HINT_ACTIONS)) {
+ if (item.hasHint(Slice.HINT_HIDDEN)) {
+ // If it's hidden we don't show it
+ return;
+ } else if (item.hasHint(Slice.HINT_ACTIONS)) {
+ // Action groups don't show in lists
return;
} else if (item.getType() == SliceItem.TYPE_COLOR) {
+ // A color is not a list item
return;
} else if (item.getType() == SliceItem.TYPE_SLICE
&& item.hasHint(Slice.HINT_LIST)) {
@@ -108,8 +113,12 @@
private void addList(Slice slice, List<SliceItem> items) {
List<SliceItem> sliceItems = slice.getItems();
- sliceItems.forEach(i -> i.addHint(Slice.HINT_LIST_ITEM));
- items.addAll(sliceItems);
+ sliceItems.forEach(i -> {
+ if (!i.hasHint(Slice.HINT_HIDDEN) && i.getType() != SliceItem.TYPE_COLOR) {
+ i.addHint(Slice.HINT_LIST_ITEM);
+ items.add(i);
+ }
+ });
}
/**
diff --git a/core/java/android/app/slice/widget/ShortcutView.java b/core/java/android/app/slice/widget/ShortcutView.java
index 0bca8ce..0b7ad0d 100644
--- a/core/java/android/app/slice/widget/ShortcutView.java
+++ b/core/java/android/app/slice/widget/ShortcutView.java
@@ -24,13 +24,20 @@
import android.app.slice.widget.SliceView.SliceModeView;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.res.Resources;
import android.graphics.Color;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.net.Uri;
import com.android.internal.R;
+import java.util.List;
+
/**
* @hide
*/
@@ -38,27 +45,26 @@
private static final String TAG = "ShortcutView";
- private PendingIntent mAction;
private Uri mUri;
+ private PendingIntent mAction;
+ private SliceItem mLabel;
+ private SliceItem mIcon;
+
private int mLargeIconSize;
private int mSmallIconSize;
public ShortcutView(Context context) {
super(context);
- mSmallIconSize = getContext().getResources().getDimensionPixelSize(R.dimen.slice_icon_size);
+ final Resources res = getResources();
+ mSmallIconSize = res.getDimensionPixelSize(R.dimen.slice_icon_size);
+ mLargeIconSize = res.getDimensionPixelSize(R.dimen.slice_shortcut_size);
}
@Override
public void setSlice(Slice slice) {
removeAllViews();
- SliceItem sliceItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
- SliceItem iconItem = SliceQuery.getPrimaryIcon(slice);
- SliceItem textItem = sliceItem != null
- ? SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT)
- : SliceQuery.find(slice, SliceItem.TYPE_TEXT);
- SliceItem colorItem = sliceItem != null
- ? SliceQuery.find(sliceItem, SliceItem.TYPE_COLOR)
- : SliceQuery.find(slice, SliceItem.TYPE_COLOR);
+ determineShortcutItems(getContext(), slice);
+ SliceItem colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
if (colorItem == null) {
colorItem = SliceQuery.find(slice, SliceItem.TYPE_COLOR);
}
@@ -67,13 +73,11 @@
ShapeDrawable circle = new ShapeDrawable(new OvalShape());
circle.setTint(color);
setBackground(circle);
- if (iconItem != null) {
- final boolean isLarge = iconItem.hasHint(Slice.HINT_LARGE);
+ if (mIcon != null) {
+ final boolean isLarge = mIcon.hasHint(Slice.HINT_LARGE);
final int iconSize = isLarge ? mLargeIconSize : mSmallIconSize;
- SliceViewUtil.createCircledIcon(getContext(), color, iconSize, iconItem.getIcon(),
+ SliceViewUtil.createCircledIcon(getContext(), color, iconSize, mIcon.getIcon(),
isLarge, this /* parent */);
- mAction = sliceItem != null ? sliceItem.getAction()
- : null;
mUri = slice.getUri();
setClickable(true);
} else {
@@ -103,4 +107,69 @@
}
return true;
}
+
+ /**
+ * Looks at the slice and determines which items are best to use to compose the shortcut.
+ */
+ private void determineShortcutItems(Context context, Slice slice) {
+ List<String> h = slice.getHints();
+ SliceItem sliceItem = new SliceItem(slice, SliceItem.TYPE_SLICE,
+ h.toArray(new String[h.size()]));
+ SliceItem titleItem = SliceQuery.find(slice, SliceItem.TYPE_ACTION,
+ Slice.HINT_TITLE, null);
+
+ if (titleItem != null) {
+ // Preferred case: hinted action containing hinted image and text
+ mAction = titleItem.getAction();
+ mIcon = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_IMAGE, Slice.HINT_TITLE,
+ null);
+ mLabel = SliceQuery.find(titleItem.getSlice(), SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+ null);
+ } else {
+ // No hinted action; just use the first one
+ SliceItem actionItem = SliceQuery.find(sliceItem, SliceItem.TYPE_ACTION, (String) null,
+ null);
+ mAction = (actionItem != null) ? actionItem.getAction() : null;
+ }
+ // First fallback: any hinted image and text
+ if (mIcon == null) {
+ mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, Slice.HINT_TITLE,
+ null);
+ }
+ if (mLabel == null) {
+ mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+ null);
+ }
+ // Second fallback: first image and text
+ if (mIcon == null) {
+ mIcon = SliceQuery.find(sliceItem, SliceItem.TYPE_IMAGE, (String) null,
+ null);
+ }
+ if (mLabel == null) {
+ mLabel = SliceQuery.find(sliceItem, SliceItem.TYPE_TEXT, (String) null,
+ null);
+ }
+ // Final fallback: use app info
+ if (mIcon == null || mLabel == null || mAction == null) {
+ PackageManager pm = context.getPackageManager();
+ ProviderInfo providerInfo = pm.resolveContentProvider(
+ slice.getUri().getAuthority(), 0);
+ ApplicationInfo appInfo = providerInfo.applicationInfo;
+ if (appInfo != null) {
+ if (mIcon == null) {
+ Drawable icon = appInfo.loadDefaultIcon(pm);
+ mIcon = new SliceItem(SliceViewUtil.createIconFromDrawable(icon),
+ SliceItem.TYPE_IMAGE, new String[] {Slice.HINT_LARGE});
+ }
+ if (mLabel == null) {
+ mLabel = new SliceItem(pm.getApplicationLabel(appInfo),
+ SliceItem.TYPE_TEXT, null);
+ }
+ if (mAction == null) {
+ mAction = PendingIntent.getActivity(context, 0,
+ pm.getLaunchIntentForPackage(appInfo.packageName), 0);
+ }
+ }
+ }
+ }
}
diff --git a/core/java/android/app/slice/widget/SliceView.java b/core/java/android/app/slice/widget/SliceView.java
index 5bafbc0..cc13ba3 100644
--- a/core/java/android/app/slice/widget/SliceView.java
+++ b/core/java/android/app/slice/widget/SliceView.java
@@ -115,7 +115,9 @@
*/
public static final String MODE_LARGE = "SLICE_LARGE";
/**
- * Mode indicating this slice should be presented as an icon.
+ * Mode indicating this slice should be presented as an icon. A shortcut requires an intent,
+ * icon, and label. This can be indicated by using {@link Slice#HINT_TITLE} on an action in a
+ * slice.
*/
public static final String MODE_SHORTCUT = "SLICE_ICON";
@@ -210,11 +212,15 @@
validate(sliceUri);
Slice s = Slice.bindSlice(mContext.getContentResolver(), sliceUri);
if (s != null) {
+ if (mObserver != null) {
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ }
mObserver = new SliceObserver(new Handler(Looper.getMainLooper()));
if (isAttachedToWindow()) {
registerSlice(sliceUri);
}
- showSlice(s);
+ mCurrentSlice = s;
+ reinflate();
}
return s != null;
}
diff --git a/core/java/android/app/slice/widget/SliceViewUtil.java b/core/java/android/app/slice/widget/SliceViewUtil.java
index 0366998..1cf0055 100644
--- a/core/java/android/app/slice/widget/SliceViewUtil.java
+++ b/core/java/android/app/slice/widget/SliceViewUtil.java
@@ -28,6 +28,7 @@
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.Icon;
import android.view.Gravity;
@@ -141,6 +142,21 @@
/**
* @hide
*/
+ public static Icon createIconFromDrawable(Drawable d) {
+ if (d instanceof BitmapDrawable) {
+ return Icon.createWithBitmap(((BitmapDrawable) d).getBitmap());
+ }
+ Bitmap b = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+ Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(b);
+ d.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
+ d.draw(canvas);
+ return Icon.createWithBitmap(b);
+ }
+
+ /**
+ * @hide
+ */
public static void createCircledIcon(Context context, int color, int iconSize, Icon icon,
boolean isLarge, ViewGroup parent) {
ImageView v = new ImageView(context);
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index c827432..3a3e16e 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -261,7 +261,10 @@
/**
* @hide
+ * Changes the app standby state to the provided bucket.
*/
+ @SystemApi
+ @RequiresPermission(android.Manifest.permission.CHANGE_APP_IDLE_STATE)
public void setAppStandbyBucket(String packageName, @StandbyBuckets int bucket) {
try {
mService.setAppStandbyBucket(packageName, bucket, mContext.getUserId());
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index dbaace2..29e7439 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -118,7 +118,15 @@
AppIdleStateChangeListener listener);
public static abstract class AppIdleStateChangeListener {
- public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle);
+
+ /** Callback to inform listeners that the idle state has changed to a new bucket. */
+ public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle,
+ int bucket);
+
+ /**
+ * Callback to inform listeners that the parole state has changed. This means apps are
+ * allowed to do work even if they're idle or in a low bucket.
+ */
public abstract void onParoleStateChanged(boolean isParoleOn);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index c165fb3..01ad3ad 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3413,6 +3413,8 @@
public static final String NETWORK_STATS_SERVICE = "netstats";
/** {@hide} */
public static final String NETWORK_POLICY_SERVICE = "netpolicy";
+ /** {@hide} */
+ public static final String NETWORK_WATCHLIST_SERVICE = "network_watchlist";
/**
* Use with {@link #getSystemService} to retrieve a {@link
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index e47de75..dd729a3 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3444,11 +3444,12 @@
/**
* A broadcast action to trigger a factory reset.
*
- * <p> The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission.
+ * <p>The sender must hold the {@link android.Manifest.permission#MASTER_CLEAR} permission. The
+ * reason for the factory reset should be specified as {@link #EXTRA_REASON}.
*
* <p>Not for use by third-party applications.
*
- * @see #EXTRA_FORCE_MASTER_CLEAR
+ * @see #EXTRA_FORCE_FACTORY_RESET
*
* {@hide}
*/
@@ -4827,7 +4828,13 @@
/** @hide */
public static final int EXTRA_TIME_PREF_VALUE_USE_LOCALE_DEFAULT = 2;
- /** {@hide} */
+ /**
+ * Intent extra: the reason that the operation associated with this intent is being performed.
+ *
+ * <p>Type: String
+ * @hide
+ */
+ @SystemApi
public static final String EXTRA_REASON = "android.intent.extra.REASON";
/**
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 41667c4..837c00a 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -455,7 +455,6 @@
*/
public static final int FLAG_TURN_SCREEN_ON = 0x1000000;
-
/**
* @hide Bit in {@link #flags}: If set, this component will only be seen
* by the system user. Only works with broadcast receivers. Set from the
@@ -1001,20 +1000,12 @@
* Returns true if the activity's orientation is fixed.
* @hide
*/
- public boolean isFixedOrientation() {
+ boolean isFixedOrientation() {
return isFixedOrientationLandscape() || isFixedOrientationPortrait()
|| screenOrientation == SCREEN_ORIENTATION_LOCKED;
}
/**
- * Returns true if the specified orientation is considered fixed.
- * @hide
- */
- static public boolean isFixedOrientation(int orientation) {
- return isFixedOrientationLandscape(orientation) || isFixedOrientationPortrait(orientation);
- }
-
- /**
* Returns true if the activity's orientation is fixed to landscape.
* @hide
*/
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index b94a410..05c5556 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -671,9 +671,13 @@
}
/**
- * Returns whether the caller can access the shortcut information.
+ * Returns whether the caller can access the shortcut information. Access is currently
+ * available to:
*
- * <p>Only the default launcher can access the shortcut information.
+ * <ul>
+ * <li>The current launcher (or default launcher if there is no set current launcher).</li>
+ * <li>The currently active voice interaction service.</li>
+ * </ul>
*
* <p>Note when this method returns {@code false}, it may be a temporary situation because
* the user is trying a new launcher application. The user may decide to change the default
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/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java
index 7fc25d8..dadfaa9 100644
--- a/core/java/android/content/pm/ShortcutServiceInternal.java
+++ b/core/java/android/content/pm/ShortcutServiceInternal.java
@@ -73,6 +73,9 @@
public abstract boolean hasShortcutHostPermission(int launcherUserId,
@NonNull String callingPackage, int callingPid, int callingUid);
+ public abstract void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+ int userId);
+
public abstract boolean requestPinAppWidget(@NonNull String callingPackage,
@NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
@Nullable IntentSender resultIntent, int userId);
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 386239c..3239212 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -49,6 +49,8 @@
import android.util.Xml;
import android.view.DisplayAdjustments;
+import com.android.internal.util.GrowingArrayUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -117,6 +119,13 @@
private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
new ConfigurationBoundResourceCache<>();
+ // A stack of all the resourceIds already referenced when parsing a resource. This is used to
+ // detect circular references in the xml.
+ // Using a ThreadLocal variable ensures that we have different stacks for multiple parallel
+ // calls to ResourcesImpl
+ private final ThreadLocal<LookupStack> mLookupStack =
+ ThreadLocal.withInitial(() -> new LookupStack());
+
/** Size of the cyclical cache used to map XML files to blocks. */
private static final int XML_BLOCK_CACHE_SIZE = 4;
@@ -784,19 +793,29 @@
final Drawable dr;
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+ LookupStack stack = mLookupStack.get();
try {
- if (file.endsWith(".xml")) {
- final XmlResourceParser rp = loadXmlResourceParser(
- file, id, value.assetCookie, "drawable");
- dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
- rp.close();
- } else {
- final InputStream is = mAssets.openNonAsset(
- value.assetCookie, file, AssetManager.ACCESS_STREAMING);
- dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
- is.close();
+ // Perform a linear search to check if we have already referenced this resource before.
+ if (stack.contains(id)) {
+ throw new Exception("Recursive reference in drawable");
}
- } catch (Exception | StackOverflowError e) {
+ stack.push(id);
+ try {
+ if (file.endsWith(".xml")) {
+ final XmlResourceParser rp = loadXmlResourceParser(
+ file, id, value.assetCookie, "drawable");
+ dr = Drawable.createFromXmlForDensity(wrapper, rp, density, theme);
+ rp.close();
+ } else {
+ final InputStream is = mAssets.openNonAsset(
+ value.assetCookie, file, AssetManager.ACCESS_STREAMING);
+ dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+ is.close();
+ }
+ } finally {
+ stack.pop();
+ }
+ } catch (Exception e) {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
final NotFoundException rnf = new NotFoundException(
"File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
@@ -1377,4 +1396,29 @@
}
}
}
+
+ private static class LookupStack {
+
+ // Pick a reasonable default size for the array, it is grown as needed.
+ private int[] mIds = new int[4];
+ private int mSize = 0;
+
+ public void push(int id) {
+ mIds = GrowingArrayUtils.append(mIds, mSize, id);
+ mSize++;
+ }
+
+ public boolean contains(int id) {
+ for (int i = 0; i < mSize; i++) {
+ if (mIds[i] == id) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void pop() {
+ mSize--;
+ }
+ }
}
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index c28583e..b692039 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -289,7 +289,9 @@
private void setWalModeFromConfiguration() {
if (!mConfiguration.isInMemoryDb() && !mIsReadOnlyConnection) {
- if ((mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0) {
+ boolean walEnabled =
+ (mConfiguration.openFlags & SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING) != 0;
+ if (walEnabled || mConfiguration.useCompatibilityWal) {
setJournalMode("WAL");
setSyncMode(SQLiteGlobal.getWALSyncMode());
} else {
@@ -414,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/SQLiteCursor.java b/core/java/android/database/sqlite/SQLiteCursor.java
index 2dc5ca4..13e6f71 100644
--- a/core/java/android/database/sqlite/SQLiteCursor.java
+++ b/core/java/android/database/sqlite/SQLiteCursor.java
@@ -22,6 +22,8 @@
import android.os.StrictMode;
import android.util.Log;
+import com.android.internal.util.Preconditions;
+
import java.util.HashMap;
import java.util.Map;
@@ -60,6 +62,9 @@
/** Used to find out where a cursor was allocated in case it never got released. */
private final Throwable mStackTrace;
+ /** Controls fetching of rows relative to requested position **/
+ private boolean mFillWindowForwardOnly;
+
/**
* Execute a query and provide access to its result set through a Cursor
* interface. For a query such as: {@code SELECT name, birth, phone FROM
@@ -136,18 +141,19 @@
private void fillWindow(int requiredPos) {
clearOrCreateWindow(getDatabase().getPath());
-
try {
+ Preconditions.checkArgumentNonnegative(requiredPos,
+ "requiredPos cannot be negative, but was " + requiredPos);
+
if (mCount == NO_COUNT) {
- int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos, 0);
- mCount = mQuery.fillWindow(mWindow, startPos, requiredPos, true);
+ mCount = mQuery.fillWindow(mWindow, requiredPos, requiredPos, true);
mCursorWindowCapacity = mWindow.getNumRows();
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "received count(*) from native_fill_window: " + mCount);
}
} else {
- int startPos = DatabaseUtils.cursorPickFillWindowStartPosition(requiredPos,
- mCursorWindowCapacity);
+ int startPos = mFillWindowForwardOnly ? requiredPos : DatabaseUtils
+ .cursorPickFillWindowStartPosition(requiredPos, mCursorWindowCapacity);
mQuery.fillWindow(mWindow, startPos, requiredPos, false);
}
} catch (RuntimeException ex) {
@@ -252,6 +258,20 @@
}
/**
+ * Controls fetching of rows relative to requested position.
+ *
+ * <p>Calling this method defines how rows will be loaded, but it doesn't affect rows that
+ * are already in the window. This setting is preserved if a new window is
+ * {@link #setWindow(CursorWindow) set}
+ *
+ * @param fillWindowForwardOnly if true, rows will be fetched starting from requested position
+ * up to the window's capacity. Default value is false.
+ */
+ public void setFillWindowForwardOnly(boolean fillWindowForwardOnly) {
+ mFillWindowForwardOnly = fillWindowForwardOnly;
+ }
+
+ /**
* Release the native resources, if they haven't been released yet.
*/
@Override
diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java
index df0e262..83b8dc7 100644
--- a/core/java/android/database/sqlite/SQLiteDatabase.java
+++ b/core/java/android/database/sqlite/SQLiteDatabase.java
@@ -285,6 +285,7 @@
}
}
mConfigurationLocked.idleConnectionTimeoutMs = effectiveTimeoutMs;
+ mConfigurationLocked.useCompatibilityWal = SQLiteGlobal.isCompatibilityWalSupported();
}
@Override
@@ -2070,15 +2071,21 @@
synchronized (mLock) {
throwIfNotOpenLocked();
- if ((mConfigurationLocked.openFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
+ final boolean oldUseCompatibilityWal = mConfigurationLocked.useCompatibilityWal;
+ final int oldFlags = mConfigurationLocked.openFlags;
+ if (!oldUseCompatibilityWal && (oldFlags & ENABLE_WRITE_AHEAD_LOGGING) == 0) {
return;
}
mConfigurationLocked.openFlags &= ~ENABLE_WRITE_AHEAD_LOGGING;
+ // If an app explicitly disables WAL, do not even use compatibility mode
+ mConfigurationLocked.useCompatibilityWal = false;
+
try {
mConnectionPoolLocked.reconfigure(mConfigurationLocked);
} catch (RuntimeException ex) {
- mConfigurationLocked.openFlags |= ENABLE_WRITE_AHEAD_LOGGING;
+ mConfigurationLocked.openFlags = oldFlags;
+ mConfigurationLocked.useCompatibilityWal = oldUseCompatibilityWal;
throw ex;
}
}
diff --git a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
index 34c9b33..905da724 100644
--- a/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
+++ b/core/java/android/database/sqlite/SQLiteDatabaseConfiguration.java
@@ -111,6 +111,15 @@
public long idleConnectionTimeoutMs = Long.MAX_VALUE;
/**
+ * Enables compatibility WAL mode. Applications cannot explicitly choose compatibility WAL mode,
+ * therefore it is not exposed as a flag.
+ *
+ * <p>In this mode, only database journal mode will be changed, connection pool
+ * size will still be limited to a single connection.
+ */
+ public boolean useCompatibilityWal;
+
+ /**
* Creates a database configuration with the required parameters for opening a
* database and default values for all other parameters.
*
@@ -170,6 +179,7 @@
lookasideSlotSize = other.lookasideSlotSize;
lookasideSlotCount = other.lookasideSlotCount;
idleConnectionTimeoutMs = other.idleConnectionTimeoutMs;
+ useCompatibilityWal = other.useCompatibilityWal;
}
/**
diff --git a/core/java/android/database/sqlite/SQLiteGlobal.java b/core/java/android/database/sqlite/SQLiteGlobal.java
index 94d5555..d6d9764 100644
--- a/core/java/android/database/sqlite/SQLiteGlobal.java
+++ b/core/java/android/database/sqlite/SQLiteGlobal.java
@@ -81,6 +81,16 @@
}
/**
+ * 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.
+ */
+ public static boolean isCompatibilityWalSupported() {
+ return SystemProperties.getBoolean("debug.sqlite.compatibility_wal_supported",
+ Resources.getSystem().getBoolean(
+ com.android.internal.R.bool.db_compatibility_wal_supported));
+ }
+
+ /**
* Gets the journal size limit in bytes.
*/
public static int getJournalSizeLimit() {
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 7cbb436..2411727 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -271,6 +271,59 @@
throw new UnsupportedOperationException("TODO: Implement this");
}
+ /*
+ * Helper function to generate a stub for a non-query transaction callback.
+ *
+ * @param transaction the transaction to unblock when complete
+ *
+ * @return the callback
+ *
+ * @hide
+ */
+ private IContextHubTransactionCallback createTransactionCallback(
+ ContextHubTransaction<Void> transaction) {
+ return new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ Log.e(TAG, "Received a query callback on a non-query request");
+ transaction.setResponse(new ContextHubTransaction.Response<Void>(
+ ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ transaction.setResponse(new ContextHubTransaction.Response<Void>(result, null));
+ }
+ };
+ }
+
+ /*
+ * Helper function to generate a stub for a query transaction callback.
+ *
+ * @param transaction the transaction to unblock when complete
+ *
+ * @return the callback
+ *
+ * @hide
+ */
+ private IContextHubTransactionCallback createQueryCallback(
+ ContextHubTransaction<List<NanoAppState>> transaction) {
+ return new IContextHubTransactionCallback.Stub() {
+ @Override
+ public void onQueryResponse(int result, List<NanoAppState> nanoappList) {
+ transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+ result, nanoappList));
+ }
+
+ @Override
+ public void onTransactionComplete(int result) {
+ Log.e(TAG, "Received a non-query callback on a query request");
+ transaction.setResponse(new ContextHubTransaction.Response<List<NanoAppState>>(
+ ContextHubTransaction.TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE, null));
+ }
+ };
+ }
+
/**
* Loads a nanoapp at the specified Context Hub.
*
@@ -411,7 +464,7 @@
*
* @param callback the notification callback to register
* @param hubInfo the hub to attach this client to
- * @param handler the handler to invoke the callback, if null uses the current thread Looper
+ * @param handler the handler to invoke the callback, if null uses the main thread's Looper
*
* @return the registered client object
*
diff --git a/core/java/android/hardware/location/ContextHubTransaction.java b/core/java/android/hardware/location/ContextHubTransaction.java
index 4877d38..a8569ef 100644
--- a/core/java/android/hardware/location/ContextHubTransaction.java
+++ b/core/java/android/hardware/location/ContextHubTransaction.java
@@ -16,11 +16,16 @@
package android.hardware.location;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.os.Handler;
+import android.os.Looper;
+import android.util.Log;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
/**
* A class describing a request sent to the Context Hub Service.
@@ -29,17 +34,15 @@
* through the ContextHubManager APIs. The caller can either retrieve the result
* synchronously through a blocking call ({@link #waitForResponse(long, TimeUnit)}) or
* asynchronously through a user-defined callback
- * ({@link #onComplete(ContextHubTransaction.Callback<T>, Handler)}).
- *
- * A transaction can be invalidated if the caller of the transaction is no longer active
- * and the reference to this object is lost, or if timeout period has passed in
- * {@link #waitForResponse(long, TimeUnit)}.
+ * ({@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}).
*
* @param <T> the type of the contents in the transaction response
*
* @hide
*/
public class ContextHubTransaction<T> {
+ private static final String TAG = "ContextHubTransaction";
+
/**
* Constants describing the type of a transaction through the Context Hub Service.
*/
@@ -68,7 +71,8 @@
TRANSACTION_FAILED_UNINITIALIZED,
TRANSACTION_FAILED_PENDING,
TRANSACTION_FAILED_AT_HUB,
- TRANSACTION_FAILED_TIMEOUT})
+ TRANSACTION_FAILED_TIMEOUT,
+ TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE})
public @interface Result {}
public static final int TRANSACTION_SUCCESS = 0;
/**
@@ -95,6 +99,10 @@
* Failure mode when the transaction has timed out.
*/
public static final int TRANSACTION_FAILED_TIMEOUT = 6;
+ /**
+ * Failure mode when the transaction has failed internally at the service.
+ */
+ public static final int TRANSACTION_FAILED_SERVICE_INTERNAL_FAILURE = 7;
/**
* A class describing the response for a ContextHubTransaction.
@@ -146,11 +154,6 @@
}
/*
- * The unique identifier representing the transaction.
- */
- private int mTransactionId;
-
- /*
* The type of the transaction.
*/
@Type
@@ -171,8 +174,17 @@
*/
private ContextHubTransaction.Callback<T> mCallback = null;
- ContextHubTransaction(int id, @Type int type) {
- mTransactionId = id;
+ /*
+ * Synchronization latch used to block on response.
+ */
+ private final CountDownLatch mDoneSignal = new CountDownLatch(1);
+
+ /*
+ * true if the response has been set throught setResponse, false otherwise.
+ */
+ private boolean mIsResponseSet = false;
+
+ ContextHubTransaction(@Type int type) {
mTransactionType = type;
}
@@ -191,17 +203,26 @@
* for the transaction represented by this object by the Context Hub, or a
* specified timeout period has elapsed.
*
- * If the specified timeout has passed, the transaction represented by this object
- * is invalidated by the Context Hub Service (resulting in a timeout failure in the
- * response).
+ * If the specified timeout has passed, a TimeoutException will be thrown and the caller may
+ * retry the invocation of this method at a later time.
*
* @param timeout the timeout duration
* @param unit the unit of the timeout
*
* @return the transaction response
+ *
+ * @throws InterruptedException if the current thread is interrupted while waiting for response
+ * @throws TimeoutException if the timeout period has passed
*/
- public ContextHubTransaction.Response<T> waitForResponse(long timeout, TimeUnit unit) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ public ContextHubTransaction.Response<T> waitForResponse(
+ long timeout, TimeUnit unit) throws InterruptedException, TimeoutException {
+ boolean success = mDoneSignal.await(timeout, unit);
+
+ if (!success) {
+ throw new TimeoutException("Timed out while waiting for transaction");
+ }
+
+ return mResponse;
}
/**
@@ -215,15 +236,100 @@
* will be immediately posted by the handler. If the transaction has been invalidated,
* the callback will never be invoked.
*
+ * A transaction can be invalidated if the process owning the transaction is no longer active
+ * and the reference to this object is lost.
+ *
+ * This method or {@link #setCallbackOnCompletecan(ContextHubTransaction.Callback)} can only be
+ * invoked once, or an IllegalStateException will be thrown.
+ *
* @param callback the callback to be invoked upon completion
* @param handler the handler to post the callback
+ *
+ * @throws IllegalStateException if this method is called multiple times
+ * @throws NullPointerException if the callback or handler is null
*/
- public void onComplete(ContextHubTransaction.Callback<T> callback, Handler handler) {
- throw new UnsupportedOperationException("TODO: Implement this");
+ public void setCallbackOnComplete(
+ @NonNull ContextHubTransaction.Callback<T> callback, @NonNull Handler handler) {
+ synchronized (this) {
+ if (callback == null) {
+ throw new NullPointerException("Callback cannot be null");
+ }
+ if (handler == null) {
+ throw new NullPointerException("Handler cannot be null");
+ }
+ if (mCallback != null) {
+ throw new IllegalStateException(
+ "Cannot set ContextHubTransaction callback multiple times");
+ }
+
+ mCallback = callback;
+ mHandler = handler;
+
+ if (mDoneSignal.getCount() == 0) {
+ boolean callbackPosted = mHandler.post(() -> {
+ mCallback.onComplete(this, mResponse);
+ });
+
+ if (!callbackPosted) {
+ Log.e(TAG, "Failed to post callback to Handler");
+ }
+ }
+ }
}
- private void setResponse(ContextHubTransaction.Response<T> response) {
- mResponse = response;
- throw new UnsupportedOperationException("TODO: Unblock waitForResponse");
+ /**
+ * Sets a callback to be invoked when the transaction completes.
+ *
+ * Equivalent to {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+ * with the handler being that of the main thread's Looper.
+ *
+ * This method or {@link #setCallbackOnComplete(ContextHubTransaction.Callback, Handler)}
+ * can only be invoked once, or an IllegalStateException will be thrown.
+ *
+ * @param callback the callback to be invoked upon completion
+ *
+ * @throws IllegalStateException if this method is called multiple times
+ * @throws NullPointerException if the callback is null
+ */
+ public void setCallbackOnComplete(@NonNull ContextHubTransaction.Callback<T> callback) {
+ setCallbackOnComplete(callback, new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Sets the response of the transaction.
+ *
+ * This method should only be invoked by ContextHubManager as a result of a callback from
+ * the Context Hub Service indicating the response from a transaction. This method should not be
+ * invoked more than once.
+ *
+ * @param response the response to set
+ *
+ * @throws IllegalStateException if this method is invoked multiple times
+ * @throws NullPointerException if the response is null
+ */
+ void setResponse(ContextHubTransaction.Response<T> response) {
+ synchronized (this) {
+ if (response == null) {
+ throw new NullPointerException("Response cannot be null");
+ }
+ if (mIsResponseSet) {
+ throw new IllegalStateException(
+ "Cannot set response of ContextHubTransaction multiple times");
+ }
+
+ mResponse = response;
+ mIsResponseSet = true;
+
+ mDoneSignal.countDown();
+ if (mCallback != null) {
+ boolean callbackPosted = mHandler.post(() -> {
+ mCallback.onComplete(this, mResponse);
+ });
+
+ if (!callbackPosted) {
+ Log.e(TAG, "Failed to post callback to Handler");
+ }
+ }
+ }
}
}
diff --git a/core/java/android/hardware/location/IContextHubTransactionCallback.aidl b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
new file mode 100644
index 0000000..5419cd7
--- /dev/null
+++ b/core/java/android/hardware/location/IContextHubTransactionCallback.aidl
@@ -0,0 +1,35 @@
+/*
+ * 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.hardware.location;
+
+import android.hardware.location.NanoAppState;
+
+/**
+ * An interface used by the Context Hub Service to invoke callbacks notifying the complete of a
+ * transaction. The callbacks are unique for each type of transaction, and the service is
+ * responsible for invoking the correct callback.
+ *
+ * @hide
+ */
+oneway interface IContextHubTransactionCallback {
+
+ // Callback to be invoked when a query request completes
+ void onQueryResponse(int result, in List<NanoAppState> nanoappList);
+
+ // Callback to be invoked when a non-query request completes
+ void onTransactionComplete(int result);
+}
diff --git a/core/java/android/hardware/location/NanoAppBinary.java b/core/java/android/hardware/location/NanoAppBinary.java
index 5454227..934e9e4 100644
--- a/core/java/android/hardware/location/NanoAppBinary.java
+++ b/core/java/android/hardware/location/NanoAppBinary.java
@@ -22,6 +22,7 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
/**
* @hide
@@ -57,7 +58,7 @@
private static final int EXPECTED_HEADER_VERSION = 1;
/*
- * The magic value expected in the header.
+ * The magic value expected in the header as defined in context_hub.h.
*/
private static final int EXPECTED_MAGIC_VALUE =
(((int) 'N' << 0) | ((int) 'A' << 8) | ((int) 'N' << 16) | ((int) 'O' << 24));
@@ -67,6 +68,17 @@
*/
private static final ByteOrder HEADER_ORDER = ByteOrder.LITTLE_ENDIAN;
+ /*
+ * The size of the header in bytes as defined in context_hub.h.
+ */
+ private static final int HEADER_SIZE_BYTES = 40;
+
+ /*
+ * The bit fields for mFlags as defined in context_hub.h.
+ */
+ private static final int NANOAPP_SIGNED_FLAG_BIT = 0x1;
+ private static final int NANOAPP_ENCRYPTED_FLAG_BIT = 0x2;
+
public NanoAppBinary(byte[] appBinary) {
mNanoAppBinary = appBinary;
parseBinaryHeader();
@@ -111,11 +123,26 @@
/**
* @return the app binary byte array
*/
- public byte[] getNanoAppBinary() {
+ public byte[] getBinary() {
return mNanoAppBinary;
}
/**
+ * @return the app binary byte array without the leading header
+ *
+ * @throws IndexOutOfBoundsException if the nanoapp binary size is smaller than the header size
+ * @throws NullPointerException if the nanoapp binary is null
+ */
+ public byte[] getBinaryNoHeader() {
+ if (mNanoAppBinary.length < HEADER_SIZE_BYTES) {
+ throw new IndexOutOfBoundsException("NanoAppBinary binary byte size ("
+ + mNanoAppBinary.length + ") is less than header size (" + HEADER_SIZE_BYTES + ")");
+ }
+
+ return Arrays.copyOfRange(mNanoAppBinary, HEADER_SIZE_BYTES, mNanoAppBinary.length);
+ }
+
+ /**
* @return {@code true} if the header is valid, {@code false} otherwise
*/
public boolean hasValidHeader() {
@@ -164,6 +191,31 @@
return mTargetChreApiMinorVersion;
}
+ /**
+ * Returns the flags for the nanoapp as defined in context_hub.h.
+ *
+ * This method is meant to be used by the Context Hub Service.
+ *
+ * @return the flags for the nanoapp
+ */
+ public int getFlags() {
+ return mFlags;
+ }
+
+ /**
+ * @return {@code true} if the nanoapp binary is signed, {@code false} otherwise
+ */
+ public boolean isSigned() {
+ return (mFlags & NANOAPP_SIGNED_FLAG_BIT) != 0;
+ }
+
+ /**
+ * @return {@code true} if the nanoapp binary is encrypted, {@code false} otherwise
+ */
+ public boolean isEncrypted() {
+ return (mFlags & NANOAPP_ENCRYPTED_FLAG_BIT) != 0;
+ }
+
private NanoAppBinary(Parcel in) {
int binaryLength = in.readInt();
mNanoAppBinary = new byte[binaryLength];
diff --git a/core/java/android/hardware/sidekick/SidekickInternal.java b/core/java/android/hardware/sidekick/SidekickInternal.java
new file mode 100644
index 0000000..fe3550b
--- /dev/null
+++ b/core/java/android/hardware/sidekick/SidekickInternal.java
@@ -0,0 +1,56 @@
+/*
+ * 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.hardware.sidekick;
+
+
+/**
+ * Sidekick local system service interface.
+ *
+ * @hide Only for use within the system server, and maybe by Clockwork Home.
+ */
+public abstract class SidekickInternal {
+
+ /**
+ * Tell Sidekick to reset back to newly-powered-on state.
+ *
+ * @return true on success (Sidekick is reset), false if Sidekick is not
+ * available (failed or not present). Either way, upon return Sidekick is
+ * guaranteed not to be controlling the display.
+ */
+ public abstract boolean reset();
+
+ /**
+ * Tell Sidekick it can start controlling the display.
+ *
+ * SidekickServer may choose not to actually control the display, if it's been told
+ * via other channels to leave the previous image on the display (same as SUSPEND in
+ * a non-Sidekick system).
+ *
+ * @param displayState - one of Display.STATE_DOZE_SUSPEND, Display.STATE_ON_SUSPEND
+ * @return true on success, false on failure (no sidekick available)
+ */
+ public abstract boolean startDisplayControl(int displayState);
+
+ /**
+ * Tell Sidekick it must stop controlling the display.
+ *
+ * No return code because this must always succeed - after return, Sidekick
+ * is guaranteed to not be controlling the display.
+ */
+ public abstract void endDisplayControl();
+
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index d7ecc81..8071e8b 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -619,6 +619,35 @@
*/
public static final int NETID_UNSET = 0;
+ /**
+ * Private DNS Mode values.
+ *
+ * The "private_dns_mode" global setting stores a String value which is
+ * expected to be one of the following.
+ */
+
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE_OFF = "off";
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
+ /**
+ * The default Private DNS mode.
+ *
+ * This may change from release to release or may become dependent upon
+ * the capabilities of the underlying platform.
+ *
+ * @hide
+ */
+ public static final String PRIVATE_DNS_DEFAULT_MODE = PRIVATE_DNS_MODE_OPPORTUNISTIC;
+
private final IConnectivityManager mService;
/**
* A kludge to facilitate static access where a Context pointer isn't available, like in the
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/IIpConnectivityMetrics.aidl b/core/java/android/net/IIpConnectivityMetrics.aidl
index 6f07b31..aeaf09d 100644
--- a/core/java/android/net/IIpConnectivityMetrics.aidl
+++ b/core/java/android/net/IIpConnectivityMetrics.aidl
@@ -30,11 +30,11 @@
int logEvent(in ConnectivityMetricsEvent event);
/**
- * At most one callback can be registered (by DevicePolicyManager).
+ * Callback can be registered by DevicePolicyManager or NetworkWatchlistService only.
* @return status {@code true} if registering/unregistering of the callback was successful,
* {@code false} otherwise (might happen if IIpConnectivityMetrics is not available,
* if it happens make sure you call it when the service is up in the caller)
*/
- boolean registerNetdEventCallback(in INetdEventCallback callback);
- boolean unregisterNetdEventCallback();
+ boolean addNetdEventCallback(in int callerType, in INetdEventCallback callback);
+ boolean removeNetdEventCallback(in int callerType);
}
diff --git a/core/java/android/net/INetdEventCallback.aidl b/core/java/android/net/INetdEventCallback.aidl
index 49436be..1fd9423 100644
--- a/core/java/android/net/INetdEventCallback.aidl
+++ b/core/java/android/net/INetdEventCallback.aidl
@@ -19,6 +19,10 @@
/** {@hide} */
oneway interface INetdEventCallback {
+ // Possible addNetdEventCallback callers.
+ const int CALLBACK_CALLER_DEVICE_POLICY = 0;
+ const int CALLBACK_CALLER_NETWORK_WATCHLIST = 1;
+
/**
* Reports a single DNS lookup function call.
* This method must not block or perform long-running operations.
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..f6a69ba
--- /dev/null
+++ b/core/java/android/net/MacAddress.java
@@ -0,0 +1,274 @@
+/*
+ * 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 android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.BitUtils;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.StringJoiner;
+
+/**
+ * Represents a mac address.
+ *
+ * @hide
+ */
+public final class MacAddress implements Parcelable {
+
+ private static final int ETHER_ADDR_LEN = 6;
+ private static final byte[] ETHER_ADDR_BROADCAST = addr(0xff, 0xff, 0xff, 0xff, 0xff, 0xff);
+
+ /** The broadcast mac address. */
+ public static final MacAddress BROADCAST_ADDRESS = new MacAddress(ETHER_ADDR_BROADCAST);
+
+ /** The zero mac address. */
+ public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
+
+ /** Represents categories of mac addresses. */
+ public enum MacAddressType {
+ UNICAST,
+ MULTICAST,
+ BROADCAST;
+ }
+
+ private static final long VALID_LONG_MASK = BROADCAST_ADDRESS.mAddr;
+ private static final long LOCALLY_ASSIGNED_MASK = new MacAddress("2:0:0:0:0:0").mAddr;
+ private static final long MULTICAST_MASK = new MacAddress("1:0:0:0:0:0").mAddr;
+ private static final long OUI_MASK = new MacAddress("ff:ff:ff:0:0:0").mAddr;
+ private static final long NIC_MASK = new MacAddress("0:0:0:ff:ff:ff").mAddr;
+ private static final MacAddress BASE_ANDROID_MAC = new MacAddress("da:a1:19:0:0:0");
+
+ // Internal representation of the mac address as a single 8 byte long.
+ // The encoding scheme sets the two most significant bytes to 0. The 6 bytes of the
+ // mac address are encoded in the 6 least significant bytes of the long, where the first
+ // byte of the array is mapped to the 3rd highest logical byte of the long, the second
+ // byte of the array is mapped to the 4th highest logical byte of the long, and so on.
+ private final long mAddr;
+
+ private MacAddress(long addr) {
+ mAddr = addr;
+ }
+
+ /** Creates a MacAddress for the given byte representation. */
+ public MacAddress(byte[] addr) {
+ this(longAddrFromByteAddr(addr));
+ }
+
+ /** Creates a MacAddress for the given string representation. */
+ public MacAddress(String addr) {
+ this(longAddrFromByteAddr(byteAddrFromStringAddr(addr)));
+ }
+
+ /** Returns the MacAddressType of this MacAddress. */
+ public MacAddressType addressType() {
+ if (equals(BROADCAST_ADDRESS)) {
+ return MacAddressType.BROADCAST;
+ }
+ if (isMulticastAddress()) {
+ return MacAddressType.MULTICAST;
+ }
+ return MacAddressType.UNICAST;
+ }
+
+ /** Returns true if this MacAddress corresponds to a multicast address. */
+ public boolean isMulticastAddress() {
+ return (mAddr & MULTICAST_MASK) != 0;
+ }
+
+ /** Returns true if this MacAddress corresponds to a locally assigned address. */
+ public boolean isLocallyAssigned() {
+ return (mAddr & LOCALLY_ASSIGNED_MASK) != 0;
+ }
+
+ /** Returns a byte array representation of this MacAddress. */
+ public byte[] toByteArray() {
+ return byteAddrFromLongAddr(mAddr);
+ }
+
+ @Override
+ public String toString() {
+ return stringAddrFromByteAddr(byteAddrFromLongAddr(mAddr));
+ }
+
+ @Override
+ public int hashCode() {
+ return (int) ((mAddr >> 32) ^ mAddr);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return (o instanceof MacAddress) && ((MacAddress) o).mAddr == mAddr;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(mAddr);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<MacAddress> CREATOR =
+ new Parcelable.Creator<MacAddress>() {
+ public MacAddress createFromParcel(Parcel in) {
+ return new MacAddress(in.readLong());
+ }
+
+ public MacAddress[] newArray(int size) {
+ return new MacAddress[size];
+ }
+ };
+
+ /** 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;
+ }
+ return new MacAddress(addr).addressType();
+ }
+
+ /** DOCME */
+ public static byte[] byteAddrFromStringAddr(String addr) {
+ if (addr == null) {
+ throw new IllegalArgumentException("cannot convert the null String");
+ }
+ String[] parts = addr.split(":");
+ if (parts.length != ETHER_ADDR_LEN) {
+ throw new IllegalArgumentException(addr + " was not a valid MAC address");
+ }
+ byte[] bytes = new byte[ETHER_ADDR_LEN];
+ for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+ int x = Integer.valueOf(parts[i], 16);
+ if (x < 0 || 0xff < x) {
+ throw new IllegalArgumentException(addr + "was not a valid MAC address");
+ }
+ bytes[i] = (byte) x;
+ }
+ return bytes;
+ }
+
+ /** DOCME */
+ public static String stringAddrFromByteAddr(byte[] addr) {
+ if (!isMacAddress(addr)) {
+ return null;
+ }
+ StringJoiner j = new StringJoiner(":");
+ for (byte b : addr) {
+ j.add(Integer.toHexString(BitUtils.uint8(b)));
+ }
+ return j.toString();
+ }
+
+ /** @hide */
+ public static byte[] byteAddrFromLongAddr(long addr) {
+ byte[] bytes = new byte[ETHER_ADDR_LEN];
+ int index = ETHER_ADDR_LEN;
+ while (index-- > 0) {
+ bytes[index] = (byte) addr;
+ addr = addr >> 8;
+ }
+ return bytes;
+ }
+
+ /** @hide */
+ public static long longAddrFromByteAddr(byte[] addr) {
+ if (!isMacAddress(addr)) {
+ throw new IllegalArgumentException(
+ Arrays.toString(addr) + " was not a valid MAC address");
+ }
+ long longAddr = 0;
+ for (byte b : addr) {
+ longAddr = (longAddr << 8) + BitUtils.uint8(b);
+ }
+ return longAddr;
+ }
+
+ /** @hide */
+ public static long longAddrFromStringAddr(String addr) {
+ if (addr == null) {
+ throw new IllegalArgumentException("cannot convert the null String");
+ }
+ String[] parts = addr.split(":");
+ if (parts.length != ETHER_ADDR_LEN) {
+ throw new IllegalArgumentException(addr + " was not a valid MAC address");
+ }
+ long longAddr = 0;
+ int index = ETHER_ADDR_LEN;
+ while (index-- > 0) {
+ int x = Integer.valueOf(parts[index], 16);
+ if (x < 0 || 0xff < x) {
+ throw new IllegalArgumentException(addr + "was not a valid MAC address");
+ }
+ longAddr = x + (longAddr << 8);
+ }
+ return longAddr;
+ }
+
+ /** @hide */
+ public static String stringAddrFromLongAddr(long addr) {
+ addr = Long.reverseBytes(addr) >> 16;
+ StringJoiner j = new StringJoiner(":");
+ for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+ j.add(Integer.toHexString((byte) addr));
+ addr = addr >> 8;
+ }
+ return j.toString();
+ }
+
+ /**
+ * Returns a randomely generated mac address with the Android OUI value "DA-A1-19".
+ * The locally assigned bit is always set to 1.
+ */
+ public static MacAddress getRandomAddress() {
+ return getRandomAddress(BASE_ANDROID_MAC, new Random());
+ }
+
+ /**
+ * Returns a randomely generated mac address using the given Random object and the same
+ * OUI values as the given MacAddress. The locally assigned bit is always set to 1.
+ */
+ public static MacAddress getRandomAddress(MacAddress base, Random r) {
+ long longAddr = (base.mAddr & OUI_MASK) | (NIC_MASK & r.nextLong()) | LOCALLY_ASSIGNED_MASK;
+ return new MacAddress(longAddr);
+ }
+
+ // Convenience function for working around the lack of byte literals.
+ private static byte[] addr(int... in) {
+ if (in.length != ETHER_ADDR_LEN) {
+ throw new IllegalArgumentException(Arrays.toString(in)
+ + " was not an array with length equal to " + ETHER_ADDR_LEN);
+ }
+ byte[] out = new byte[ETHER_ADDR_LEN];
+ for (int i = 0; i < ETHER_ADDR_LEN; i++) {
+ out[i] = (byte) in[i];
+ }
+ return out;
+ }
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index db12dd9..ee75fd4 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,15 +31,24 @@
import java.util.StringJoiner;
/**
- * This class represents the capabilities of a network. This is used both to specify
- * needs to {@link ConnectivityManager} and when inspecting a network.
- *
- * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
- * of network selection. Rather than indicate a need for Wi-Fi because an application
- * needs high bandwidth and risk obsolescence when a new, fast network appears (like LTE),
- * the application should specify it needs high bandwidth. Similarly if an application
- * needs an unmetered network for a bulk transfer it can specify that rather than assuming
- * all cellular based connections are metered and all Wi-Fi based connections are not.
+ * Representation of the capabilities of a network. This object serves two
+ * purposes:
+ * <ul>
+ * <li>An expression of the current capabilities of an active network, typically
+ * expressed through
+ * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
+ * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
+ * <li>An expression of the future capabilities of a desired network, typically
+ * expressed through {@link NetworkRequest}.
+ * </ul>
+ * <p>
+ * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
+ * network selection. Rather than indicate a need for Wi-Fi because an
+ * application needs high bandwidth and risk obsolescence when a new, fast
+ * network appears (like LTE), the application should specify it needs high
+ * bandwidth. Similarly if an application needs an unmetered network for a bulk
+ * transfer it can specify that rather than assuming all cellular based
+ * connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
@@ -101,6 +111,7 @@
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_VALIDATED,
NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_FOREGROUND,
})
public @interface NetCapability { }
@@ -218,11 +229,16 @@
public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
/**
+ * Indicates that this network is not roaming.
+ */
+ public static final int NET_CAPABILITY_NOT_ROAMING = 18;
+
+ /**
* Indicates that this network is available for use by apps, and not a network that is being
* kept up in the background to facilitate fast network switching.
* @hide
*/
- public static final int NET_CAPABILITY_FOREGROUND = 18;
+ public static final int NET_CAPABILITY_FOREGROUND = 19;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
@@ -237,6 +253,7 @@
(1 << NET_CAPABILITY_TRUSTED) |
(1 << NET_CAPABILITY_VALIDATED) |
(1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
+ (1 << NET_CAPABILITY_NOT_ROAMING) |
(1 << NET_CAPABILITY_FOREGROUND);
/**
@@ -316,6 +333,21 @@
}
/**
+ * Sets (or clears) the given capability on this {@link NetworkCapabilities}
+ * instance.
+ *
+ * @hide
+ */
+ public NetworkCapabilities setCapability(@NetCapability int capability, boolean value) {
+ if (value) {
+ addCapability(capability);
+ } else {
+ removeCapability(capability);
+ }
+ return this;
+ }
+
+ /**
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
* @return an array of capability values for this instance.
@@ -326,6 +358,15 @@
}
/**
+ * Sets all the capabilities set on this {@code NetworkCapability} instance.
+ *
+ * @hide
+ */
+ public void setCapabilities(@NetCapability int[] capabilities) {
+ mNetworkCapabilities = BitUtils.packBits(capabilities);
+ }
+
+ /**
* Tests for the presence of a capabilitity on this instance.
*
* @param capability the capabilities to be tested for.
@@ -515,6 +556,21 @@
}
/**
+ * Sets (or clears) the given transport on this {@link NetworkCapabilities}
+ * instance.
+ *
+ * @hide
+ */
+ public NetworkCapabilities setTransportType(@Transport int transportType, boolean value) {
+ if (value) {
+ addTransportType(transportType);
+ } else {
+ removeTransportType(transportType);
+ }
+ return this;
+ }
+
+ /**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
* @return an array of transport type values for this instance.
@@ -525,6 +581,15 @@
}
/**
+ * Sets all the transports set on this {@code NetworkCapability} instance.
+ *
+ * @hide
+ */
+ public void setTransportTypes(@Transport int[] transportTypes) {
+ mTransportTypes = BitUtils.packBits(transportTypes);
+ }
+
+ /**
* Tests for the presence of a transport on this instance.
*
* @param transportType the transport type to be tested for.
@@ -549,12 +614,18 @@
}
/**
+ * Value indicating that link bandwidth is unspecified.
+ * @hide
+ */
+ public static final int LINK_BANDWIDTH_UNSPECIFIED = 0;
+
+ /**
* Passive link bandwidth. This is a rough guide of the expected peak bandwidth
* for the first hop on the given transport. It is not measured, but may take into account
* link parameters (Radio technology, allocated channels, etc).
*/
- private int mLinkUpBandwidthKbps;
- private int mLinkDownBandwidthKbps;
+ private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
+ private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
/**
* Sets the upstream bandwidth for this network in Kbps. This always only refers to
@@ -571,8 +642,9 @@
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
* @hide
*/
- public void setLinkUpstreamBandwidthKbps(int upKbps) {
+ public NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
+ return this;
}
/**
@@ -600,8 +672,9 @@
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
* @hide
*/
- public void setLinkDownstreamBandwidthKbps(int downKbps) {
+ public NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
+ return this;
}
/**
@@ -628,6 +701,20 @@
return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
}
+ /** @hide */
+ public static int minBandwidth(int a, int b) {
+ if (a == LINK_BANDWIDTH_UNSPECIFIED) {
+ return b;
+ } else if (b == LINK_BANDWIDTH_UNSPECIFIED) {
+ return a;
+ } else {
+ return Math.min(a, b);
+ }
+ }
+ /** @hide */
+ public static int maxBandwidth(int a, int b) {
+ return Math.max(a, b);
+ }
private NetworkSpecifier mNetworkSpecifier = null;
@@ -708,8 +795,9 @@
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
- public void setSignalStrength(int signalStrength) {
+ public NetworkCapabilities setSignalStrength(int signalStrength) {
mSignalStrength = signalStrength;
+ return this;
}
/**
@@ -968,6 +1056,7 @@
case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
case NET_CAPABILITY_VALIDATED: return "VALIDATED";
case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
+ case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
default: return Integer.toString(capability);
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index acd7b560..d3b3599 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -189,7 +189,8 @@
String subscriberId = null;
String networkId = null;
- boolean roaming = false;
+ boolean roaming = !state.networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
boolean metered = !state.networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
@@ -203,7 +204,6 @@
}
subscriberId = state.subscriberId;
- roaming = state.networkInfo.isRoaming();
} else if (type == TYPE_WIFI) {
if (state.networkId != null) {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 818aa21..e6ad89a 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -305,11 +305,17 @@
}
/**
- * Indicates whether the device is currently roaming on this network.
- * When {@code true}, it suggests that use of data on this network
- * may incur extra costs.
+ * Indicates whether the device is currently roaming on this network. When
+ * {@code true}, it suggests that use of data on this network may incur
+ * extra costs.
+ *
* @return {@code true} if roaming is in effect, {@code false} otherwise.
+ * @deprecated Callers should switch to checking
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}
+ * instead, since that handles more complex situations, such as
+ * VPNs.
*/
+ @Deprecated
public boolean isRoaming() {
synchronized (this) {
return mIsRoaming;
@@ -318,6 +324,7 @@
/** {@hide} */
@VisibleForTesting
+ @Deprecated
public void setRoaming(boolean isRoaming) {
synchronized (this) {
mIsRoaming = isRoaming;
diff --git a/core/java/android/net/NetworkWatchlistManager.java b/core/java/android/net/NetworkWatchlistManager.java
new file mode 100644
index 0000000..42e43c8
--- /dev/null
+++ b/core/java/android/net/NetworkWatchlistManager.java
@@ -0,0 +1,75 @@
+/*
+ * 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.net;
+
+import android.annotation.SystemService;
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import com.android.internal.net.INetworkWatchlistManager;
+import com.android.internal.util.Preconditions;
+
+/**
+ * Class that manage network watchlist in system.
+ * @hide
+ */
+@SystemService(Context.NETWORK_WATCHLIST_SERVICE)
+public class NetworkWatchlistManager {
+
+ private static final String TAG = "NetworkWatchlistManager";
+ private static final String SHARED_MEMORY_TAG = "NETWORK_WATCHLIST_SHARED_MEMORY";
+
+ private final Context mContext;
+ private final INetworkWatchlistManager mNetworkWatchlistManager;
+
+ /**
+ * @hide
+ */
+ public NetworkWatchlistManager(Context context, INetworkWatchlistManager manager) {
+ mContext = context;
+ mNetworkWatchlistManager = manager;
+ }
+
+ /**
+ * @hide
+ */
+ public NetworkWatchlistManager(Context context) {
+ mContext = Preconditions.checkNotNull(context, "missing context");
+ mNetworkWatchlistManager = (INetworkWatchlistManager)
+ INetworkWatchlistManager.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_WATCHLIST_SERVICE));
+ }
+
+ /**
+ * Report network watchlist records if necessary.
+ *
+ * Watchlist report process will run summarize records into a single report, then the
+ * report will be processed by differential privacy framework and store it on disk.
+ *
+ * @hide
+ */
+ public void reportWatchlistIfNecessary() {
+ try {
+ mNetworkWatchlistManager.reportWatchlistIfNecessary();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Cannot report records", e);
+ e.rethrowFromSystemServer();
+ }
+ }
+}
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/DefaultNetworkEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
index eb61c153..8ff8e4f 100644
--- a/core/java/android/net/metrics/DefaultNetworkEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -20,44 +20,72 @@
import android.net.NetworkCapabilities;
+import com.android.internal.util.BitUtils;
+
+import java.util.StringJoiner;
+
/**
* An event recorded by ConnectivityService when there is a change in the default network.
* {@hide}
*/
public class DefaultNetworkEvent {
- // The ID of the network that has become the new default or NETID_UNSET if none.
+ // The creation time in milliseconds of this DefaultNetworkEvent.
+ public final long creationTimeMs;
+ // The network ID of the network or NETID_UNSET if none.
public int netId = NETID_UNSET;
- // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
- // defined in NetworkCapabilities.java.
- public int[] transportTypes = new int[0];
- // The ID of the network that was the default before or NETID_UNSET if none.
- public int prevNetId = NETID_UNSET;
- // Whether the previous network had IPv4/IPv6 connectivity.
- public boolean prevIPv4;
- public boolean prevIPv6;
+ // The list of transport types, as defined in NetworkCapabilities.java.
+ public int transports;
+ // The list of transport types of the last previous default network.
+ public int previousTransports;
+ // Whether the network has IPv4/IPv6 connectivity.
+ public boolean ipv4;
+ public boolean ipv6;
+ // The initial network score when this network became the default network.
+ public int initialScore;
+ // The initial network score when this network stopped being the default network.
+ public int finalScore;
+ // The total duration in milliseconds this network was the default network.
+ public long durationMs;
+ // The total duration in milliseconds this network was the default network and was validated.
+ public long validatedMs;
+
+ public DefaultNetworkEvent(long timeMs) {
+ creationTimeMs = timeMs;
+ }
+
+ /** Update the durationMs of this DefaultNetworkEvent for the given current time. */
+ public void updateDuration(long timeMs) {
+ durationMs = timeMs - creationTimeMs;
+ }
@Override
public String toString() {
- String prevNetwork = String.valueOf(prevNetId);
- String newNetwork = String.valueOf(netId);
- if (prevNetId != 0) {
- prevNetwork += ":" + ipSupport();
+ StringJoiner j = new StringJoiner(", ", "DefaultNetworkEvent(", ")");
+ j.add("netId=" + netId);
+ for (int t : BitUtils.unpackBits(transports)) {
+ j.add(NetworkCapabilities.transportNameOf(t));
}
- if (netId != 0) {
- newNetwork += ":" + NetworkCapabilities.transportNamesOf(transportTypes);
+ j.add("ip=" + ipSupport());
+ if (initialScore > 0) {
+ j.add("initial_score=" + initialScore);
}
- return String.format("DefaultNetworkEvent(%s -> %s)", prevNetwork, newNetwork);
+ if (finalScore > 0) {
+ j.add("final_score=" + finalScore);
+ }
+ j.add(String.format("duration=%.0fs", durationMs / 1000.0));
+ j.add(String.format("validation=%4.1f%%", (validatedMs * 100.0) / durationMs));
+ return j.toString();
}
private String ipSupport() {
- if (prevIPv4 && prevIPv6) {
+ if (ipv4 && ipv6) {
return "IPv4v6";
}
- if (prevIPv6) {
+ if (ipv6) {
return "IPv6";
}
- if (prevIPv4) {
+ if (ipv4) {
return "IPv4";
}
return "NONE";
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/BatteryManager.java b/core/java/android/os/BatteryManager.java
index f715f50..6e0f70c1 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -19,6 +19,7 @@
import android.annotation.SystemService;
import android.content.Context;
import android.hardware.health.V1_0.Constants;
+
import com.android.internal.app.IBatteryStats;
/**
@@ -33,39 +34,39 @@
* integer containing the current status constant.
*/
public static final String EXTRA_STATUS = "status";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the current health constant.
*/
public static final String EXTRA_HEALTH = "health";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* boolean indicating whether a battery is present.
*/
public static final String EXTRA_PRESENT = "present";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer field containing the current battery level, from 0 to
* {@link #EXTRA_SCALE}.
*/
public static final String EXTRA_LEVEL = "level";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the maximum battery level.
*/
public static final String EXTRA_SCALE = "scale";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the resource ID of a small status bar icon
* indicating the current battery state.
*/
public static final String EXTRA_ICON_SMALL = "icon-small";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer indicating whether the device is plugged in to a power
@@ -73,19 +74,19 @@
* types of power sources.
*/
public static final String EXTRA_PLUGGED = "plugged";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the current battery voltage level.
*/
public static final String EXTRA_VOLTAGE = "voltage";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* integer containing the current battery temperature.
*/
public static final String EXTRA_TEMPERATURE = "temperature";
-
+
/**
* Extra for {@link android.content.Intent#ACTION_BATTERY_CHANGED}:
* String describing the technology of the current battery.
@@ -216,6 +217,7 @@
*/
public static final int BATTERY_PROPERTY_STATUS = 6;
+ private final Context mContext;
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
@@ -223,6 +225,7 @@
* @removed Was previously made visible by accident.
*/
public BatteryManager() {
+ mContext = null;
mBatteryStats = IBatteryStats.Stub.asInterface(
ServiceManager.getService(BatteryStats.SERVICE_NAME));
mBatteryPropertiesRegistrar = IBatteryPropertiesRegistrar.Stub.asInterface(
@@ -230,8 +233,10 @@
}
/** {@hide} */
- public BatteryManager(IBatteryStats batteryStats,
+ public BatteryManager(Context context,
+ IBatteryStats batteryStats,
IBatteryPropertiesRegistrar batteryPropertiesRegistrar) {
+ mContext = context;
mBatteryStats = batteryStats;
mBatteryPropertiesRegistrar = batteryPropertiesRegistrar;
}
@@ -278,16 +283,23 @@
}
/**
- * Return the value of a battery property of integer type. If the
- * platform does not provide the property queried, this value will
- * be Integer.MIN_VALUE.
+ * Return the value of a battery property of integer type.
*
* @param id identifier of the requested property
*
- * @return the property value, or Integer.MIN_VALUE if not supported.
+ * @return the property value. If the property is not supported or there is any other error,
+ * return (a) 0 if {@code targetSdkVersion < VERSION_CODES.P} or (b) Integer.MIN_VALUE
+ * if {@code targetSdkVersion >= VERSION_CODES.P}.
*/
public int getIntProperty(int id) {
- return (int)queryProperty(id);
+ long value = queryProperty(id);
+ if (value == Long.MIN_VALUE && mContext != null
+ && mContext.getApplicationInfo().targetSdkVersion
+ >= android.os.Build.VERSION_CODES.P) {
+ return Integer.MIN_VALUE;
+ }
+
+ return (int) value;
}
/**
diff --git a/core/java/android/os/BatteryStatsInternal.java b/core/java/android/os/BatteryStatsInternal.java
new file mode 100644
index 0000000..b0436eb
--- /dev/null
+++ b/core/java/android/os/BatteryStatsInternal.java
@@ -0,0 +1,35 @@
+/*
+ * 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.os;
+
+/**
+ * Battery stats local system service interface. This is used to pass internal data out of
+ * BatteryStatsImpl.
+ *
+ * @hide Only for use within Android OS.
+ */
+public abstract class BatteryStatsInternal {
+ /**
+ * Returns the wifi interfaces.
+ */
+ public abstract String[] getWifiIfaces();
+
+ /**
+ * Returns the mobile data interfaces.
+ */
+ public abstract String[] getMobileIfaces();
+}
diff --git a/core/java/android/os/ConfigUpdate.java b/core/java/android/os/ConfigUpdate.java
index 1396877..94a44ec 100644
--- a/core/java/android/os/ConfigUpdate.java
+++ b/core/java/android/os/ConfigUpdate.java
@@ -68,13 +68,6 @@
= "android.intent.action.UPDATE_CT_LOGS";
/**
- * Update system wide timezone data.
- * @hide
- */
- @SystemApi
- public static final String ACTION_UPDATE_TZDATA = "android.intent.action.UPDATE_TZDATA";
-
- /**
* Update language detection model file.
* @hide
*/
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 017c213..2acf36f 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -16,14 +16,16 @@
package android.os;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.AppGlobals;
import android.content.Context;
import android.util.Log;
import com.android.internal.util.FastPrintWriter;
+import com.android.internal.util.Preconditions;
import com.android.internal.util.TypedProperties;
-import dalvik.bytecode.OpcodeInfo;
import dalvik.system.VMDebug;
import org.apache.harmony.dalvik.ddmc.Chunk;
@@ -48,8 +50,6 @@
import java.util.Map;
-
-
/**
* Provides various debugging methods for Android applications, including
* tracing and allocation counts.
@@ -1959,13 +1959,7 @@
*/
@Deprecated
public static class InstructionCount {
- private static final int NUM_INSTR =
- OpcodeInfo.MAXIMUM_PACKED_VALUE + 1;
-
- private int[] mCounts;
-
public InstructionCount() {
- mCounts = new int[NUM_INSTR];
}
/**
@@ -1975,13 +1969,7 @@
* @return true if counting was started
*/
public boolean resetAndStart() {
- try {
- VMDebug.startInstructionCounting();
- VMDebug.resetInstructionCount();
- } catch (UnsupportedOperationException uoe) {
- return false;
- }
- return true;
+ return false;
}
/**
@@ -1989,13 +1977,7 @@
* counting process.
*/
public boolean collect() {
- try {
- VMDebug.stopInstructionCounting();
- VMDebug.getInstructionCount(mCounts);
- } catch (UnsupportedOperationException uoe) {
- return false;
- }
- return true;
+ return false;
}
/**
@@ -2003,13 +1985,7 @@
* all threads).
*/
public int globalTotal() {
- int count = 0;
-
- for (int i = 0; i < NUM_INSTR; i++) {
- count += mCounts[i];
- }
-
- return count;
+ return 0;
}
/**
@@ -2017,15 +1993,7 @@
* executed globally.
*/
public int globalMethodInvocations() {
- int count = 0;
-
- for (int i = 0; i < NUM_INSTR; i++) {
- if (OpcodeInfo.isInvoke(i)) {
- count += mCounts[i];
- }
- }
-
- return count;
+ return 0;
}
}
@@ -2382,4 +2350,24 @@
public static String getCaller() {
return getCaller(Thread.currentThread().getStackTrace(), 0);
}
+
+ /**
+ * Attach a library as a jvmti agent to the current runtime.
+ *
+ * @param library library containing the agent
+ * @param options options passed to the agent
+ *
+ * @throws IOException If the agent could not be attached
+ */
+ public static void attachJvmtiAgent(@NonNull String library, @Nullable String options)
+ throws IOException {
+ Preconditions.checkNotNull(library);
+ Preconditions.checkArgument(!library.contains("="));
+
+ if (options == null) {
+ VMDebug.attachAgent(library);
+ } else {
+ VMDebug.attachAgent(library + "=" + options);
+ }
+ }
}
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 5b0e5bbc..f977c1d 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -836,7 +836,6 @@
* physically removed.
*/
public static boolean isExternalStorageRemovable() {
- if (isStorageDisabled()) return false;
final File externalDir = sCurrentUser.getExternalDirs()[0];
return isExternalStorageRemovable(externalDir);
}
@@ -875,7 +874,6 @@
* boolean)
*/
public static boolean isExternalStorageEmulated() {
- if (isStorageDisabled()) return false;
final File externalDir = sCurrentUser.getExternalDirs()[0];
return isExternalStorageEmulated(externalDir);
}
@@ -951,9 +949,6 @@
return cur;
}
- private static boolean isStorageDisabled() {
- return SystemProperties.getBoolean("config.disable_storage", false);
- }
/**
* If the given path exists on emulated external storage, return the
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 56d6e0a..7c53ec1 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -320,8 +320,17 @@
* is {@code filename}.
*/
public static void bytesToFile(String filename, byte[] content) throws IOException {
- try (FileOutputStream fos = new FileOutputStream(filename)) {
- fos.write(content);
+ if (filename.startsWith("/proc/")) {
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try (FileOutputStream fos = new FileOutputStream(filename)) {
+ fos.write(content);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ } else {
+ try (FileOutputStream fos = new FileOutputStream(filename)) {
+ fos.write(content);
+ }
}
}
diff --git a/core/java/android/os/HidlSupport.java b/core/java/android/os/HidlSupport.java
index 7dec4d7..3544ea1 100644
--- a/core/java/android/os/HidlSupport.java
+++ b/core/java/android/os/HidlSupport.java
@@ -156,4 +156,27 @@
// Should not reach here.
throw new UnsupportedOperationException();
}
+
+ /**
+ * Test that two interfaces are equal. This is the Java equivalent to C++
+ * interfacesEqual function.
+ * This essentially calls .equals on the internal binder objects (via Binder()).
+ * - If both interfaces are proxies, asBinder() returns a {@link HwRemoteBinder}
+ * object, and they are compared in {@link HwRemoteBinder#equals}.
+ * - If both interfaces are stubs, asBinder() returns the object itself. By default,
+ * auto-generated IFoo.Stub does not override equals(), but an implementation can
+ * optionally override it, and {@code interfacesEqual} will use it here.
+ */
+ public static boolean interfacesEqual(IHwInterface lft, Object rgt) {
+ if (lft == rgt) {
+ return true;
+ }
+ if (lft == null || rgt == null) {
+ return false;
+ }
+ if (!(rgt instanceof IHwInterface)) {
+ return false;
+ }
+ return Objects.equals(lft.asBinder(), ((IHwInterface) rgt).asBinder());
+ }
}
diff --git a/core/java/android/os/HwBinder.java b/core/java/android/os/HwBinder.java
index 270e63f..5e2a081 100644
--- a/core/java/android/os/HwBinder.java
+++ b/core/java/android/os/HwBinder.java
@@ -16,10 +16,10 @@
package android.os;
-import java.util.ArrayList;
-import java.util.NoSuchElementException;
import libcore.util.NativeAllocationRegistry;
+import java.util.NoSuchElementException;
+
/** @hide */
public abstract class HwBinder implements IHwBinder {
private static final String TAG = "HwBinder";
@@ -46,9 +46,16 @@
public native final void registerService(String serviceName)
throws RemoteException;
- public static native final IHwBinder getService(
+ public static final IHwBinder getService(
String iface,
String serviceName)
+ throws RemoteException, NoSuchElementException {
+ return getService(iface, serviceName, false /* retry */);
+ }
+ public static native final IHwBinder getService(
+ String iface,
+ String serviceName,
+ boolean retry)
throws RemoteException, NoSuchElementException;
public static native final void configureRpcThreadpool(
diff --git a/core/java/android/os/HwBlob.java b/core/java/android/os/HwBlob.java
index 88226f0..5e9b9ae3 100644
--- a/core/java/android/os/HwBlob.java
+++ b/core/java/android/os/HwBlob.java
@@ -43,6 +43,18 @@
public native final double getDouble(long offset);
public native final String getString(long offset);
+ /**
+ The copyTo... methods copy the blob's data, starting from the given
+ byte offset, into the array. A total of "size" _elements_ are copied.
+ */
+ public native final void copyToBoolArray(long offset, boolean[] array, int size);
+ public native final void copyToInt8Array(long offset, byte[] array, int size);
+ public native final void copyToInt16Array(long offset, short[] array, int size);
+ public native final void copyToInt32Array(long offset, int[] array, int size);
+ public native final void copyToInt64Array(long offset, long[] array, int size);
+ public native final void copyToFloatArray(long offset, float[] array, int size);
+ public native final void copyToDoubleArray(long offset, double[] array, int size);
+
public native final void putBool(long offset, boolean x);
public native final void putInt8(long offset, byte x);
public native final void putInt16(long offset, short x);
@@ -52,6 +64,14 @@
public native final void putDouble(long offset, double x);
public native final void putString(long offset, String x);
+ public native final void putBoolArray(long offset, boolean[] x);
+ public native final void putInt8Array(long offset, byte[] x);
+ public native final void putInt16Array(long offset, short[] x);
+ public native final void putInt32Array(long offset, int[] x);
+ public native final void putInt64Array(long offset, long[] x);
+ public native final void putFloatArray(long offset, float[] x);
+ public native final void putDoubleArray(long offset, double[] x);
+
public native final void putBlob(long offset, HwBlob blob);
public native final long handle();
diff --git a/core/java/android/os/HwRemoteBinder.java b/core/java/android/os/HwRemoteBinder.java
index 2f89ce6..a07e42c 100644
--- a/core/java/android/os/HwRemoteBinder.java
+++ b/core/java/android/os/HwRemoteBinder.java
@@ -63,4 +63,9 @@
}
private long mNativeContext;
+
+ @Override
+ public final native boolean equals(Object other);
+ @Override
+ public final native int hashCode();
}
diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl
index 20f6c8e..c0a95cc 100644
--- a/core/java/android/os/IStatsCompanionService.aidl
+++ b/core/java/android/os/IStatsCompanionService.aidl
@@ -46,10 +46,10 @@
* Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately,
* and alarm is inexact.
*/
- oneway void setPollingAlarms(long timestampMs, long intervalMs);
+ oneway void setPullingAlarms(long timestampMs, long intervalMs);
/** Cancel any repeating polling alarm. */
- oneway void cancelPollingAlarms();
+ oneway void cancelPullingAlarms();
/** Pull the specified data. Results will be sent to statsd when complete. */
StatsLogEventWrapper[] pullData(int pullCode);
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index c2cf3967..10adb5a 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -2020,8 +2020,6 @@
@Deprecated
static native void closeFileDescriptor(FileDescriptor desc) throws IOException;
- static native void clearFileDescriptor(FileDescriptor desc);
-
/**
* Read a byte value from the parcel at the current dataPosition().
*/
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 7f588ad..7556f09 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -683,7 +683,7 @@
throw new IllegalStateException("Already closed");
}
final int fd = getFd();
- Parcel.clearFileDescriptor(mFd);
+ mFd.setInt$(-1);
writeCommStatusAndClose(Status.DETACHED, null);
mClosed = true;
mGuard.close();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 7f4dee6..dd4825e 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -513,6 +513,53 @@
*/
public static final int SHUTDOWN_REASON_BATTERY_THERMAL = 6;
+ /**
+ * @hide
+ */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({ServiceType.GPS,
+ ServiceType.VIBRATION,
+ ServiceType.ANIMATION,
+ ServiceType.FULL_BACKUP,
+ ServiceType.KEYVALUE_BACKUP,
+ ServiceType.NETWORK_FIREWALL,
+ ServiceType.SCREEN_BRIGHTNESS,
+ ServiceType.SOUND,
+ ServiceType.BATTERY_STATS,
+ ServiceType.DATA_SAVER,
+ ServiceType.FORCE_ALL_APPS_STANDBY_JOBS,
+ ServiceType.FORCE_ALL_APPS_STANDBY_ALARMS,
+ ServiceType.OPTIONAL_SENSORS,
+ })
+ public @interface ServiceType {
+ int NULL = 0;
+ int GPS = 1;
+ int VIBRATION = 2;
+ int ANIMATION = 3;
+ int FULL_BACKUP = 4;
+ int KEYVALUE_BACKUP = 5;
+ int NETWORK_FIREWALL = 6;
+ int SCREEN_BRIGHTNESS = 7;
+ int SOUND = 8;
+ int BATTERY_STATS = 9;
+ int DATA_SAVER = 10;
+
+ /**
+ * Whether the job scheduler should force app standby on all apps on battery saver or not.
+ */
+ int FORCE_ALL_APPS_STANDBY_JOBS = 11;
+
+ /**
+ * Whether the alarm manager should force app standby on all apps on battery saver or not.
+ */
+ int FORCE_ALL_APPS_STANDBY_ALARMS = 12;
+
+ /**
+ * Whether to disable non-essential sensors. (e.g. edge sensors.)
+ */
+ int OPTIONAL_SENSORS = 13;
+ }
+
final Context mContext;
final IPowerManager mService;
final Handler mHandler;
@@ -1055,15 +1102,14 @@
/**
* Get data about the battery saver mode for a specific service
- * @param serviceType unique key for the service, one of
- * {@link com.android.server.power.BatterySaverPolicy.ServiceType}
+ * @param serviceType unique key for the service, one of {@link ServiceType}
* @return Battery saver state data.
*
* @hide
* @see com.android.server.power.BatterySaverPolicy
* @see PowerSaveState
*/
- public PowerSaveState getPowerSaveState(int serviceType) {
+ public PowerSaveState getPowerSaveState(@ServiceType int serviceType) {
try {
return mService.getPowerSaveState(serviceType);
} catch (RemoteException e) {
diff --git a/core/java/android/os/PowerManagerInternal.java b/core/java/android/os/PowerManagerInternal.java
index a01b8ed..77ac2651 100644
--- a/core/java/android/os/PowerManagerInternal.java
+++ b/core/java/android/os/PowerManagerInternal.java
@@ -18,6 +18,8 @@
import android.view.Display;
+import java.util.function.Consumer;
+
/**
* Power manager local system service interface.
*
@@ -125,6 +127,23 @@
public abstract void registerLowPowerModeObserver(LowPowerModeListener listener);
+ /**
+ * Same as {@link #registerLowPowerModeObserver} but can take a lambda.
+ */
+ public void registerLowPowerModeObserver(int serviceType, Consumer<PowerSaveState> listener) {
+ registerLowPowerModeObserver(new LowPowerModeListener() {
+ @Override
+ public int getServiceType() {
+ return serviceType;
+ }
+
+ @Override
+ public void onLowPowerModeChanged(PowerSaveState state) {
+ listener.accept(state);
+ }
+ });
+ }
+
public interface LowPowerModeListener {
int getServiceType();
void onLowPowerModeChanged(PowerSaveState state);
diff --git a/core/java/android/os/PowerSaveState.java b/core/java/android/os/PowerSaveState.java
index 7058a1d..de1128df 100644
--- a/core/java/android/os/PowerSaveState.java
+++ b/core/java/android/os/PowerSaveState.java
@@ -27,7 +27,7 @@
/**
* Whether we should enable battery saver for this service.
*
- * @see com.android.server.power.BatterySaverPolicy.ServiceType
+ * @see com.android.server.power.BatterySaverPolicy
*/
public final boolean batterySaverEnabled;
/**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 6ce12c1..d5820b6 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -20,13 +20,34 @@
import android.annotation.TestApi;
import android.app.ActivityManager;
import android.app.ActivityThread;
+import android.app.ApplicationErrorReport;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
import android.net.TrafficStats;
import android.net.Uri;
+import android.os.StrictMode.ThreadPolicy;
+import android.os.StrictMode.VmPolicy;
+import android.os.strictmode.CleartextNetworkViolation;
+import android.os.strictmode.ContentUriWithoutPermissionViolation;
+import android.os.strictmode.CustomViolation;
+import android.os.strictmode.DiskReadViolation;
+import android.os.strictmode.DiskWriteViolation;
+import android.os.strictmode.FileUriExposedViolation;
+import android.os.strictmode.InstanceCountViolation;
+import android.os.strictmode.IntentReceiverLeakedViolation;
+import android.os.strictmode.LeakedClosableViolation;
+import android.os.strictmode.NetworkViolation;
+import android.os.strictmode.ResourceMismatchViolation;
+import android.os.strictmode.ServiceConnectionLeakedViolation;
+import android.os.strictmode.SqliteObjectLeakedViolation;
+import android.os.strictmode.UnbufferedIOViolation;
+import android.os.strictmode.UntaggedSocketViolation;
+import android.os.strictmode.Violation;
+import android.os.strictmode.WebViewMethodCalledOnWrongThreadViolation;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Printer;
@@ -35,6 +56,7 @@
import android.view.IWindowManager;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.BackgroundThread;
import com.android.internal.os.RuntimeInit;
import com.android.internal.util.FastPrintWriter;
import com.android.internal.util.HexDump;
@@ -140,6 +162,13 @@
*/
private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.clear";
+ /**
+ * Quick feature-flag that can be used to disable the defaults provided by
+ * {@link #initThreadDefaults(ApplicationInfo)} and
+ * {@link #initVmDefaults(ApplicationInfo)}.
+ */
+ private static final boolean DISABLE = false;
+
// Only log a duplicate stack trace to the logs every second.
private static final long MIN_LOG_INTERVAL_MS = 1000;
@@ -156,36 +185,30 @@
// Byte 1: Thread-policy
/** @hide */
- @TestApi
- public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
+ @TestApi public static final int DETECT_DISK_WRITE = 0x01; // for ThreadPolicy
/** @hide */
- @TestApi
- public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
+ @TestApi public static final int DETECT_DISK_READ = 0x02; // for ThreadPolicy
/** @hide */
- @TestApi
- public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
+ @TestApi public static final int DETECT_NETWORK = 0x04; // for ThreadPolicy
/**
* For StrictMode.noteSlowCall()
*
* @hide
*/
- @TestApi
- public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
+ @TestApi public static final int DETECT_CUSTOM = 0x08; // for ThreadPolicy
/**
* For StrictMode.noteResourceMismatch()
*
* @hide
*/
- @TestApi
- public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
+ @TestApi public static final int DETECT_RESOURCE_MISMATCH = 0x10; // for ThreadPolicy
/** @hide */
- @TestApi
- public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
+ @TestApi public static final int DETECT_UNBUFFERED_IO = 0x20; // for ThreadPolicy
private static final int ALL_THREAD_DETECT_BITS =
DETECT_DISK_WRITE
@@ -202,48 +225,40 @@
*
* @hide
*/
- @TestApi
- public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
*
* @hide
*/
- @TestApi
- public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy
/**
* Note, a "VM_" bit, not thread.
*
* @hide
*/
- @TestApi
- public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
+ @TestApi public static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy
/** @hide */
@TestApi
public static final int DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION = 0x80 << 8; // for VmPolicy
/** @hide */
- @TestApi
- public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
+ @TestApi public static final int DETECT_VM_UNTAGGED_SOCKET = 0x80 << 24; // for VmPolicy
private static final int ALL_VM_DETECT_BITS =
DETECT_VM_CURSOR_LEAKS
@@ -354,11 +369,7 @@
} else {
msg = "StrictMode policy violation:";
}
- if (info.hasStackTrace()) {
- Log.d(TAG, msg + " " + info.getStackTrace());
- } else {
- Log.d(TAG, msg + " missing stack trace!");
- }
+ Log.d(TAG, msg + " " + info.getStackTrace());
};
private static volatile ViolationLogger sLogger = LOGCAT_LOGGER;
@@ -714,6 +725,11 @@
return enable(DETECT_VM_ACTIVITY_LEAKS);
}
+ /** @hide */
+ public Builder permitActivityLeaks() {
+ return disable(DETECT_VM_ACTIVITY_LEAKS);
+ }
+
/**
* Detect everything that's potentially suspect.
*
@@ -847,6 +863,11 @@
return enable(DETECT_VM_UNTAGGED_SOCKET);
}
+ /** @hide */
+ public Builder permitUntaggedSockets() {
+ return disable(DETECT_VM_UNTAGGED_SOCKET);
+ }
+
/**
* Crashes the whole process on violation. This penalty runs at the end of all enabled
* penalties so you'll still get your logging or other violations before the process
@@ -954,7 +975,8 @@
setThreadPolicyMask(policy.mask);
}
- private static void setThreadPolicyMask(final int policyMask) {
+ /** @hide */
+ public static void setThreadPolicyMask(final int policyMask) {
// In addition to the Java-level thread-local in Dalvik's
// BlockGuard, we also need to keep a native thread-local in
// Binder in order to propagate the value across Binder calls,
@@ -991,55 +1013,6 @@
CloseGuard.setEnabled(enabled);
}
- /** @hide */
- public static class StrictModeViolation extends BlockGuard.BlockGuardPolicyException {
- public StrictModeViolation(int policyState, int policyViolated, String message) {
- super(policyState, policyViolated, message);
- }
- }
-
- /** @hide */
- public static class StrictModeNetworkViolation extends StrictModeViolation {
- public StrictModeNetworkViolation(int policyMask) {
- super(policyMask, DETECT_NETWORK, null);
- }
- }
-
- /** @hide */
- private static class StrictModeDiskReadViolation extends StrictModeViolation {
- public StrictModeDiskReadViolation(int policyMask) {
- super(policyMask, DETECT_DISK_READ, null);
- }
- }
-
- /** @hide */
- private static class StrictModeDiskWriteViolation extends StrictModeViolation {
- public StrictModeDiskWriteViolation(int policyMask) {
- super(policyMask, DETECT_DISK_WRITE, null);
- }
- }
-
- /** @hide */
- private static class StrictModeCustomViolation extends StrictModeViolation {
- public StrictModeCustomViolation(int policyMask, String name) {
- super(policyMask, DETECT_CUSTOM, name);
- }
- }
-
- /** @hide */
- private static class StrictModeResourceMismatchViolation extends StrictModeViolation {
- public StrictModeResourceMismatchViolation(int policyMask, Object tag) {
- super(policyMask, DETECT_RESOURCE_MISMATCH, tag != null ? tag.toString() : null);
- }
- }
-
- /** @hide */
- private static class StrictModeUnbufferedIOViolation extends StrictModeViolation {
- public StrictModeUnbufferedIOViolation(int policyMask) {
- super(policyMask, DETECT_UNBUFFERED_IO, null);
- }
- }
-
/**
* Returns the bitmask of the current thread's policy.
*
@@ -1069,12 +1042,17 @@
* end of a block
*/
public static ThreadPolicy allowThreadDiskWrites() {
+ return new ThreadPolicy(allowThreadDiskWritesMask());
+ }
+
+ /** @hide */
+ public static int allowThreadDiskWritesMask() {
int oldPolicyMask = getThreadPolicyMask();
int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_WRITE | DETECT_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
- return new ThreadPolicy(oldPolicyMask);
+ return oldPolicyMask;
}
/**
@@ -1085,31 +1063,52 @@
* @return the old policy, to be passed to setThreadPolicy to restore the policy.
*/
public static ThreadPolicy allowThreadDiskReads() {
+ return new ThreadPolicy(allowThreadDiskReadsMask());
+ }
+
+ /** @hide */
+ public static int allowThreadDiskReadsMask() {
int oldPolicyMask = getThreadPolicyMask();
int newPolicyMask = oldPolicyMask & ~(DETECT_DISK_READ);
if (newPolicyMask != oldPolicyMask) {
setThreadPolicyMask(newPolicyMask);
}
- return new ThreadPolicy(oldPolicyMask);
+ return oldPolicyMask;
}
- // We don't want to flash the screen red in the system server
- // process, nor do we want to modify all the call sites of
- // conditionallyEnableDebugLogging() in the system server,
- // so instead we use this to determine if we are the system server.
- private static boolean amTheSystemServerProcess() {
- // Fast path. Most apps don't have the system server's UID.
- if (Process.myUid() != Process.SYSTEM_UID) {
- return false;
- }
+ /**
+ * Determine if the given app is "bundled" as part of the system image.
+ * These bundled apps are developed in lock-step with the OS, and they
+ * aren't updated outside of an OTA, so we want to chase any
+ * {@link StrictMode} regressions by enabling detection when running on
+ * {@link Build#IS_USERDEBUG} or {@link Build#IS_ENG} builds.
+ * <p>
+ * Unbundled apps included in the system image are expected to detect and
+ * triage their own {@link StrictMode} issues separate from the OS release
+ * process, which is why we don't enable them here.
+ *
+ * @hide
+ */
+ public static boolean isBundledSystemApp(ApplicationInfo ai) {
+ if (ai == null || ai.packageName == null) {
+ // Probably system server
+ return true;
+ } else if (ai.isSystemApp()) {
+ // Ignore unbundled apps living in the wrong namespace
+ if (ai.packageName.equals("com.android.vending")
+ || ai.packageName.equals("com.android.chrome")) {
+ return false;
+ }
- // The settings app, though, has the system server's UID so
- // look up our stack to see if we came from the system server.
- Throwable stack = new Throwable();
- stack.fillInStackTrace();
- for (StackTraceElement ste : stack.getStackTrace()) {
- String clsName = ste.getClassName();
- if (clsName != null && clsName.startsWith("com.android.server.")) {
+ // Ignore bundled apps that are way too spammy
+ // STOPSHIP: burn this list down to zero
+ if (ai.packageName.equals("com.android.phone")) {
+ return false;
+ }
+
+ if (ai.packageName.equals("android")
+ || ai.packageName.startsWith("android.")
+ || ai.packageName.startsWith("com.android.")) {
return true;
}
}
@@ -1117,81 +1116,81 @@
}
/**
- * Enable DropBox logging for debug phone builds.
+ * Initialize default {@link ThreadPolicy} for the current thread.
*
* @hide
*/
- public static boolean conditionallyEnableDebugLogging() {
- boolean doFlashes =
- SystemProperties.getBoolean(VISUAL_PROPERTY, false) && !amTheSystemServerProcess();
- final boolean suppress = SystemProperties.getBoolean(DISABLE_PROPERTY, false);
+ public static void initThreadDefaults(ApplicationInfo ai) {
+ final ThreadPolicy.Builder builder = new ThreadPolicy.Builder();
+ final int targetSdkVersion = (ai != null) ? ai.targetSdkVersion
+ : Build.VERSION_CODES.CUR_DEVELOPMENT;
- // For debug builds, log event loop stalls to dropbox for analysis.
- // Similar logic also appears in ActivityThread.java for system apps.
- if (!doFlashes && (Build.IS_USER || suppress)) {
- setCloseGuardEnabled(false);
- return false;
+ // Starting in HC, we don't allow network usage on the main thread
+ if (targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
+ builder.detectNetwork();
+ builder.penaltyDeathOnNetwork();
}
- // Eng builds have flashes on all the time. The suppression property
- // overrides this, so we force the behavior only after the short-circuit
- // check above.
- if (Build.IS_ENG) {
- doFlashes = true;
- }
-
- // Thread policy controls BlockGuard.
- int threadPolicyMask =
- StrictMode.DETECT_DISK_WRITE
- | StrictMode.DETECT_DISK_READ
- | StrictMode.DETECT_NETWORK;
-
- if (!Build.IS_USER) {
- threadPolicyMask |= StrictMode.PENALTY_DROPBOX;
- }
- if (doFlashes) {
- threadPolicyMask |= StrictMode.PENALTY_FLASH;
- }
-
- StrictMode.setThreadPolicyMask(threadPolicyMask);
-
- // VM Policy controls CloseGuard, detection of Activity leaks,
- // and instance counting.
- if (Build.IS_USER) {
- setCloseGuardEnabled(false);
- } else {
- VmPolicy.Builder policyBuilder = new VmPolicy.Builder().detectAll();
- if (!Build.IS_ENG) {
- // Activity leak detection causes too much slowdown for userdebug because of the
- // GCs.
- policyBuilder = policyBuilder.disable(DETECT_VM_ACTIVITY_LEAKS);
+ if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) {
+ // Detect nothing extra
+ } else if (Build.IS_USERDEBUG) {
+ // Detect everything in bundled apps
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.penaltyDropBox();
+ if (SystemProperties.getBoolean(VISUAL_PROPERTY, false)) {
+ builder.penaltyFlashScreen();
+ }
}
- policyBuilder = policyBuilder.penaltyDropBox();
- if (Build.IS_ENG) {
- policyBuilder.penaltyLog();
+ } else if (Build.IS_ENG) {
+ // Detect everything in bundled apps
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.penaltyDropBox();
+ builder.penaltyLog();
+ builder.penaltyFlashScreen();
}
- // All core system components need to tag their sockets to aid
- // system health investigations
- if (android.os.Process.myUid() < android.os.Process.FIRST_APPLICATION_UID) {
- policyBuilder.enable(DETECT_VM_UNTAGGED_SOCKET);
- } else {
- policyBuilder.disable(DETECT_VM_UNTAGGED_SOCKET);
- }
- setVmPolicy(policyBuilder.build());
- setCloseGuardEnabled(vmClosableObjectLeaksEnabled());
}
- return true;
+
+ setThreadPolicy(builder.build());
}
/**
- * Used by the framework to make network usage on the main thread a fatal error.
+ * Initialize default {@link VmPolicy} for the current VM.
*
* @hide
*/
- public static void enableDeathOnNetwork() {
- int oldPolicy = getThreadPolicyMask();
- int newPolicy = oldPolicy | DETECT_NETWORK | PENALTY_DEATH_ON_NETWORK;
- setThreadPolicyMask(newPolicy);
+ public static void initVmDefaults(ApplicationInfo ai) {
+ final VmPolicy.Builder builder = new VmPolicy.Builder();
+ final int targetSdkVersion = (ai != null) ? ai.targetSdkVersion
+ : Build.VERSION_CODES.CUR_DEVELOPMENT;
+
+ // Starting in N, we don't allow file:// Uri exposure
+ if (targetSdkVersion >= Build.VERSION_CODES.N) {
+ builder.detectFileUriExposure();
+ builder.penaltyDeathOnFileUriExposure();
+ }
+
+ if (Build.IS_USER || DISABLE || SystemProperties.getBoolean(DISABLE_PROPERTY, false)) {
+ // Detect nothing extra
+ } else if (Build.IS_USERDEBUG) {
+ // Detect everything in bundled apps (except activity leaks, which
+ // are expensive to track)
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.permitActivityLeaks();
+ builder.penaltyDropBox();
+ }
+ } else if (Build.IS_ENG) {
+ // Detect everything in bundled apps
+ if (isBundledSystemApp(ai)) {
+ builder.detectAll();
+ builder.penaltyDropBox();
+ builder.penaltyLog();
+ }
+ }
+
+ setVmPolicy(builder.build());
}
/**
@@ -1308,9 +1307,7 @@
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeDiskWriteViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new DiskWriteViolation());
}
// Not part of BlockGuard.Policy; just part of StrictMode:
@@ -1321,10 +1318,7 @@
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e =
- new StrictModeCustomViolation(mPolicyMask, name);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new CustomViolation(name));
}
// Not part of BlockGuard.Policy; just part of StrictMode:
@@ -1335,13 +1329,10 @@
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e =
- new StrictModeResourceMismatchViolation(mPolicyMask, tag);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new ResourceMismatchViolation(tag));
}
- // Part of BlockGuard.Policy; just part of StrictMode:
+ // Not part of BlockGuard.Policy; just part of StrictMode:
public void onUnbufferedIO() {
if ((mPolicyMask & DETECT_UNBUFFERED_IO) == 0) {
return;
@@ -1349,10 +1340,7 @@
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e =
- new StrictModeUnbufferedIOViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new UnbufferedIOViolation());
}
// Part of BlockGuard.Policy interface:
@@ -1363,9 +1351,7 @@
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeDiskReadViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new DiskReadViolation());
}
// Part of BlockGuard.Policy interface:
@@ -1379,9 +1365,7 @@
if (tooManyViolationsThisLoop()) {
return;
}
- BlockGuard.BlockGuardPolicyException e = new StrictModeNetworkViolation(mPolicyMask);
- e.fillInStackTrace();
- startHandlingViolationException(e);
+ startHandlingViolationException(new NetworkViolation());
}
public void setPolicyMask(int policyMask) {
@@ -1393,8 +1377,8 @@
// has yet occurred). This sees if we're in an event loop
// thread and, if so, uses it to roughly measure how long the
// violation took.
- void startHandlingViolationException(BlockGuard.BlockGuardPolicyException e) {
- final ViolationInfo info = new ViolationInfo(e, e.getPolicy());
+ void startHandlingViolationException(Violation e) {
+ final ViolationInfo info = new ViolationInfo(e, mPolicyMask);
info.violationUptimeMillis = SystemClock.uptimeMillis();
handleViolationWithTimingAttempt(info);
}
@@ -1423,7 +1407,7 @@
//
// TODO: if in gather mode, ignore Looper.myLooper() and always
// go into this immediate mode?
- if (looper == null || (info.policy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
+ if (looper == null || (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DEATH) {
info.durationMillis = -1; // unknown (redundant, already set)
handleViolation(info);
return;
@@ -1443,7 +1427,7 @@
}
final IWindowManager windowManager =
- (info.policy & PENALTY_FLASH) != 0 ? sWindowManager.get() : null;
+ info.penaltyEnabled(PENALTY_FLASH) ? sWindowManager.get() : null;
if (windowManager != null) {
try {
windowManager.showStrictModeViolation(true);
@@ -1496,14 +1480,9 @@
// to people who push/pop temporary policy in regions of code,
// hence the policy being passed around.
void handleViolation(final ViolationInfo info) {
- if (info == null || !info.hasStackTrace()) {
- Log.wtf(TAG, "unexpected null stacktrace");
- return;
- }
+ if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.mPolicy);
- if (LOG_V) Log.d(TAG, "handleViolation; policy=" + info.policy);
-
- if ((info.policy & PENALTY_GATHER) != 0) {
+ if (info.penaltyEnabled(PENALTY_GATHER)) {
ArrayList<ViolationInfo> violations = gatheredViolations.get();
if (violations == null) {
violations = new ArrayList<ViolationInfo>(1);
@@ -1535,7 +1514,7 @@
long timeSinceLastViolationMillis =
lastViolationTime == 0 ? Long.MAX_VALUE : (now - lastViolationTime);
- if ((info.policy & PENALTY_LOG) != 0
+ if (info.penaltyEnabled(PENALTY_LOG)
&& timeSinceLastViolationMillis > MIN_LOG_INTERVAL_MS) {
sLogger.log(info);
}
@@ -1546,20 +1525,19 @@
// by the ActivityManagerService remaining set.
int violationMaskSubset = 0;
- if ((info.policy & PENALTY_DIALOG) != 0
+ if (info.penaltyEnabled(PENALTY_DIALOG)
&& timeSinceLastViolationMillis > MIN_DIALOG_INTERVAL_MS) {
violationMaskSubset |= PENALTY_DIALOG;
}
- if ((info.policy & PENALTY_DROPBOX) != 0 && lastViolationTime == 0) {
+ if (info.penaltyEnabled(PENALTY_DROPBOX) && lastViolationTime == 0) {
violationMaskSubset |= PENALTY_DROPBOX;
}
if (violationMaskSubset != 0) {
violationMaskSubset |= info.getViolationBit();
- final int savedPolicyMask = getThreadPolicyMask();
- final boolean justDropBox = (info.policy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
+ final boolean justDropBox = (info.mPolicy & THREAD_PENALTY_MASK) == PENALTY_DROPBOX;
if (justDropBox) {
// If all we're going to ask the activity manager
// to do is dropbox it (the common case during
@@ -1568,40 +1546,19 @@
// isn't always super fast, despite the implementation
// in the ActivityManager trying to be mostly async.
dropboxViolationAsync(violationMaskSubset, info);
- return;
- }
-
- // Normal synchronous call to the ActivityManager.
- try {
- // First, remove any policy before we call into the Activity Manager,
- // otherwise we'll infinite recurse as we try to log policy violations
- // to disk, thus violating policy, thus requiring logging, etc...
- // We restore the current policy below, in the finally block.
- setThreadPolicyMask(0);
-
- ActivityManager.getService()
- .handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
- } catch (RemoteException e) {
- if (e instanceof DeadObjectException) {
- // System process is dead; ignore
- } else {
- Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
- }
- } finally {
- // Restore the policy.
- setThreadPolicyMask(savedPolicyMask);
+ } else {
+ handleApplicationStrictModeViolation(violationMaskSubset, info);
}
}
- if ((info.policy & PENALTY_DEATH) != 0) {
+ if ((info.getPolicyMask() & PENALTY_DEATH) != 0) {
executeDeathPenalty(info);
}
}
}
private static void executeDeathPenalty(ViolationInfo info) {
- throw new StrictModeViolation(info.policy, info.getViolationBit(), null);
+ throw new RuntimeException("StrictMode death penalty", info.mViolation);
}
/**
@@ -1622,33 +1579,44 @@
if (LOG_V) Log.d(TAG, "Dropboxing async; in-flight=" + outstanding);
- new Thread("callActivityManagerForStrictModeDropbox") {
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- try {
- IActivityManager am = ActivityManager.getService();
- if (am == null) {
- Log.d(TAG, "No activity manager; failed to Dropbox violation.");
- } else {
- am.handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
- }
- } catch (RemoteException e) {
- if (e instanceof DeadObjectException) {
- // System process is dead; ignore
- } else {
- Log.e(TAG, "RemoteException handling StrictMode violation", e);
- }
- }
- int outstanding = sDropboxCallsInFlight.decrementAndGet();
- if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstanding);
+ BackgroundThread.getHandler().post(() -> {
+ handleApplicationStrictModeViolation(violationMaskSubset, info);
+ int outstandingInner = sDropboxCallsInFlight.decrementAndGet();
+ if (LOG_V) Log.d(TAG, "Dropbox complete; in-flight=" + outstandingInner);
+ });
+ }
+
+ private static void handleApplicationStrictModeViolation(int violationMaskSubset,
+ ViolationInfo info) {
+ final int oldMask = getThreadPolicyMask();
+ try {
+ // First, remove any policy before we call into the Activity Manager,
+ // otherwise we'll infinite recurse as we try to log policy violations
+ // to disk, thus violating policy, thus requiring logging, etc...
+ // We restore the current policy below, in the finally block.
+ setThreadPolicyMask(0);
+
+ IActivityManager am = ActivityManager.getService();
+ if (am == null) {
+ Log.w(TAG, "No activity manager; failed to Dropbox violation.");
+ } else {
+ am.handleApplicationStrictModeViolation(
+ RuntimeInit.getApplicationObject(), violationMaskSubset, info);
}
- }.start();
+ } catch (RemoteException e) {
+ if (e instanceof DeadObjectException) {
+ // System process is dead; ignore
+ } else {
+ Log.e(TAG, "RemoteException handling StrictMode violation", e);
+ }
+ } finally {
+ setThreadPolicyMask(oldMask);
+ }
}
private static class AndroidCloseGuardReporter implements CloseGuard.Reporter {
public void report(String message, Throwable allocationSite) {
- onVmPolicyViolation(allocationSite);
+ onVmPolicyViolation(new LeakedClosableViolation(message, allocationSite));
}
}
@@ -1686,8 +1654,7 @@
int limit = policy.classInstanceLimit.get(klass);
long instances = instanceCounts[i];
if (instances > limit) {
- Throwable tr = new InstanceCountViolation(klass, instances, limit);
- onVmPolicyViolation(tr);
+ onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}
}
@@ -1811,24 +1778,22 @@
/** @hide */
public static void onSqliteObjectLeaked(String message, Throwable originStack) {
- Throwable t = new Throwable(message);
- t.setStackTrace(originStack.getStackTrace());
- onVmPolicyViolation(t);
+ onVmPolicyViolation(new SqliteObjectLeakedViolation(message, originStack));
}
/** @hide */
public static void onWebViewMethodCalledOnWrongThread(Throwable originStack) {
- onVmPolicyViolation(originStack);
+ onVmPolicyViolation(new WebViewMethodCalledOnWrongThreadViolation(originStack));
}
/** @hide */
public static void onIntentReceiverLeaked(Throwable originStack) {
- onVmPolicyViolation(originStack);
+ onVmPolicyViolation(new IntentReceiverLeakedViolation(originStack));
}
/** @hide */
public static void onServiceConnectionLeaked(Throwable originStack) {
- onVmPolicyViolation(originStack);
+ onVmPolicyViolation(new ServiceConnectionLeakedViolation(originStack));
}
/** @hide */
@@ -1837,19 +1802,13 @@
if ((sVmPolicy.mask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
throw new FileUriExposedException(message);
} else {
- onVmPolicyViolation(new Throwable(message));
+ onVmPolicyViolation(new FileUriExposedViolation(message));
}
}
/** @hide */
public static void onContentUriWithoutPermission(Uri uri, String location) {
- final String message =
- uri
- + " exposed beyond app through "
- + location
- + " without permission grant flags; did you forget"
- + " FLAG_GRANT_READ_URI_PERMISSION?";
- onVmPolicyViolation(new Throwable(message));
+ onVmPolicyViolation(new ContentUriWithoutPermissionViolation(uri, location));
}
/** @hide */
@@ -1881,29 +1840,24 @@
}
msg += HexDump.dumpHexString(firstPacket).trim() + " ";
final boolean forceDeath = (sVmPolicy.mask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0;
- onVmPolicyViolation(new Throwable(msg), forceDeath);
+ onVmPolicyViolation(new CleartextNetworkViolation(msg), forceDeath);
}
/** @hide */
- public static final String UNTAGGED_SOCKET_VIOLATION_MESSAGE =
- "Untagged socket detected; use"
- + " TrafficStats.setThreadSocketTag() to track all network usage";
-
- /** @hide */
public static void onUntaggedSocket() {
- onVmPolicyViolation(new Throwable(UNTAGGED_SOCKET_VIOLATION_MESSAGE));
+ onVmPolicyViolation(new UntaggedSocketViolation());
}
// Map from VM violation fingerprint to uptime millis.
- private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<Integer, Long>();
+ private static final HashMap<Integer, Long> sLastVmViolationTime = new HashMap<>();
/** @hide */
- public static void onVmPolicyViolation(Throwable originStack) {
+ public static void onVmPolicyViolation(Violation originStack) {
onVmPolicyViolation(originStack, false);
}
/** @hide */
- public static void onVmPolicyViolation(Throwable originStack, boolean forceDeath) {
+ public static void onVmPolicyViolation(Violation originStack, boolean forceDeath) {
final boolean penaltyDropbox = (sVmPolicy.mask & PENALTY_DROPBOX) != 0;
final boolean penaltyDeath = ((sVmPolicy.mask & PENALTY_DEATH) != 0) || forceDeath;
final boolean penaltyLog = (sVmPolicy.mask & PENALTY_LOG) != 0;
@@ -1946,31 +1900,7 @@
}
if (penaltyDropbox && lastViolationTime == 0) {
- // The violationMask, passed to ActivityManager, is a
- // subset of the original StrictMode policy bitmask, with
- // only the bit violated and penalty bits to be executed
- // by the ActivityManagerService remaining set.
- final int savedPolicyMask = getThreadPolicyMask();
- try {
- // First, remove any policy before we call into the Activity Manager,
- // otherwise we'll infinite recurse as we try to log policy violations
- // to disk, thus violating policy, thus requiring logging, etc...
- // We restore the current policy below, in the finally block.
- setThreadPolicyMask(0);
-
- ActivityManager.getService()
- .handleApplicationStrictModeViolation(
- RuntimeInit.getApplicationObject(), violationMaskSubset, info);
- } catch (RemoteException e) {
- if (e instanceof DeadObjectException) {
- // System process is dead; ignore
- } else {
- Log.e(TAG, "RemoteException trying to handle StrictMode violation", e);
- }
- } finally {
- // Restore the policy.
- setThreadPolicyMask(savedPolicyMask);
- }
+ handleApplicationStrictModeViolation(violationMaskSubset, info);
}
if (penaltyDeath) {
@@ -1998,14 +1928,12 @@
gatheredViolations.set(null);
}
- private static class LogStackTrace extends Exception {}
-
/**
* Called from Parcel.readException() when the exception is EX_STRICT_MODE_VIOLATIONS, we here
* read back all the encoded violations.
*/
/* package */ static void readAndHandleBinderCallViolations(Parcel p) {
- LogStackTrace localCallSite = new LogStackTrace();
+ Throwable localCallSite = new Throwable();
final int policyMask = getThreadPolicyMask();
final boolean currentlyGathering = (policyMask & PENALTY_GATHER) != 0;
@@ -2323,8 +2251,7 @@
long instances = VMDebug.countInstancesOfClass(klass, false);
if (instances > limit) {
- Throwable tr = new InstanceCountViolation(klass, instances, limit);
- onVmPolicyViolation(tr);
+ onVmPolicyViolation(new InstanceCountViolation(klass, instances, limit));
}
}
@@ -2337,18 +2264,16 @@
@TestApi
public static final class ViolationInfo implements Parcelable {
/** Stack and violation details. */
- @Nullable private final Throwable mThrowable;
+ private final Violation mViolation;
/** Path leading to a violation that occurred across binder. */
private final Deque<StackTraceElement[]> mBinderStack = new ArrayDeque<>();
/** Memoized stack trace of full violation. */
@Nullable private String mStackTrace;
- /** Memoized violation bit. */
- private int mViolationBit;
/** The strict mode policy mask at the time of violation. */
- public final int policy;
+ private final int mPolicy;
/** The wall time duration of the violation, when known. -1 when not known. */
public int durationMillis = -1;
@@ -2378,17 +2303,11 @@
/** If this is a instance count violation, the number of instances in memory, else -1. */
public long numInstances = -1;
- /** Create an uninitialized instance of ViolationInfo */
- public ViolationInfo() {
- mThrowable = null;
- policy = 0;
- }
-
/** Create an instance of ViolationInfo initialized from an exception. */
- public ViolationInfo(Throwable tr, int policy) {
- this.mThrowable = tr;
+ ViolationInfo(Violation tr, int policy) {
+ this.mViolation = tr;
+ this.mPolicy = policy;
violationUptimeMillis = SystemClock.uptimeMillis();
- this.policy = policy;
this.numAnimationsRunning = ValueAnimator.getCurrentAnimationsCount();
Intent broadcastIntent = ActivityThread.getIntentBeingBroadcast();
if (broadcastIntent != null) {
@@ -2396,7 +2315,7 @@
}
ThreadSpanState state = sThisThreadSpanState.get();
if (tr instanceof InstanceCountViolation) {
- this.numInstances = ((InstanceCountViolation) tr).mInstances;
+ this.numInstances = ((InstanceCountViolation) tr).getNumberOfInstances();
}
synchronized (state) {
int spanActiveCount = state.mActiveSize;
@@ -2418,10 +2337,10 @@
/** Equivalent output to {@link ApplicationErrorReport.CrashInfo#stackTrace}. */
public String getStackTrace() {
- if (mThrowable != null && mStackTrace == null) {
+ if (mStackTrace == null) {
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 256);
- mThrowable.printStackTrace(pw);
+ mViolation.printStackTrace(pw);
for (StackTraceElement[] traces : mBinderStack) {
pw.append("# via Binder call with stack:\n");
for (StackTraceElement traceElement : traces) {
@@ -2444,20 +2363,21 @@
*/
@TestApi
public String getViolationDetails() {
- if (mThrowable != null) {
- return mThrowable.getMessage();
- } else {
- return "";
- }
+ return mViolation.getMessage();
}
/**
- * If this violation has a useful stack trace.
+ * Policy mask at time of violation.
*
* @hide
*/
- public boolean hasStackTrace() {
- return mThrowable != null;
+ @TestApi
+ public int getPolicyMask() {
+ return mPolicy;
+ }
+
+ boolean penaltyEnabled(int p) {
+ return (mPolicy & p) != 0;
}
/**
@@ -2475,37 +2395,47 @@
*
* @hide
*/
- int getViolationBit() {
- if (mThrowable == null || mThrowable.getMessage() == null) {
- return 0;
+ @TestApi
+ public int getViolationBit() {
+ if (mViolation instanceof DiskWriteViolation) {
+ return DETECT_DISK_WRITE;
+ } else if (mViolation instanceof DiskReadViolation) {
+ return DETECT_DISK_READ;
+ } else if (mViolation instanceof NetworkViolation) {
+ return DETECT_NETWORK;
+ } else if (mViolation instanceof CustomViolation) {
+ return DETECT_CUSTOM;
+ } else if (mViolation instanceof ResourceMismatchViolation) {
+ return DETECT_RESOURCE_MISMATCH;
+ } else if (mViolation instanceof UnbufferedIOViolation) {
+ return DETECT_UNBUFFERED_IO;
+ } else if (mViolation instanceof SqliteObjectLeakedViolation) {
+ return DETECT_VM_CURSOR_LEAKS;
+ } else if (mViolation instanceof LeakedClosableViolation) {
+ return DETECT_VM_CLOSABLE_LEAKS;
+ } else if (mViolation instanceof InstanceCountViolation) {
+ return DETECT_VM_INSTANCE_LEAKS;
+ } else if (mViolation instanceof IntentReceiverLeakedViolation) {
+ return DETECT_VM_REGISTRATION_LEAKS;
+ } else if (mViolation instanceof ServiceConnectionLeakedViolation) {
+ return DETECT_VM_REGISTRATION_LEAKS;
+ } else if (mViolation instanceof FileUriExposedViolation) {
+ return DETECT_VM_FILE_URI_EXPOSURE;
+ } else if (mViolation instanceof CleartextNetworkViolation) {
+ return DETECT_VM_CLEARTEXT_NETWORK;
+ } else if (mViolation instanceof ContentUriWithoutPermissionViolation) {
+ return DETECT_VM_CONTENT_URI_WITHOUT_PERMISSION;
+ } else if (mViolation instanceof UntaggedSocketViolation) {
+ return DETECT_VM_UNTAGGED_SOCKET;
}
- if (mViolationBit != 0) {
- return mViolationBit;
- }
- String message = mThrowable.getMessage();
- int violationIndex = message.indexOf("violation=");
- if (violationIndex == -1) {
- return 0;
- }
- int numberStartIndex = violationIndex + "violation=".length();
- int numberEndIndex = message.indexOf(' ', numberStartIndex);
- if (numberEndIndex == -1) {
- numberEndIndex = message.length();
- }
- String violationString = message.substring(numberStartIndex, numberEndIndex);
- try {
- mViolationBit = Integer.parseInt(violationString);
- return mViolationBit;
- } catch (NumberFormatException e) {
- return 0;
- }
+ throw new IllegalStateException("missing violation bit");
}
@Override
public int hashCode() {
int result = 17;
- if (mThrowable != null) {
- result = 37 * result + mThrowable.hashCode();
+ if (mViolation != null) {
+ result = 37 * result + mViolation.hashCode();
}
if (numAnimationsRunning != 0) {
result *= 37;
@@ -2533,7 +2463,7 @@
* should be removed.
*/
public ViolationInfo(Parcel in, boolean unsetGatheringBit) {
- mThrowable = (Throwable) in.readSerializable();
+ mViolation = (Violation) in.readSerializable();
int binderStackSize = in.readInt();
for (int i = 0; i < binderStackSize; i++) {
StackTraceElement[] traceElements = new StackTraceElement[in.readInt()];
@@ -2550,9 +2480,9 @@
}
int rawPolicy = in.readInt();
if (unsetGatheringBit) {
- policy = rawPolicy & ~PENALTY_GATHER;
+ mPolicy = rawPolicy & ~PENALTY_GATHER;
} else {
- policy = rawPolicy;
+ mPolicy = rawPolicy;
}
durationMillis = in.readInt();
violationNumThisLoop = in.readInt();
@@ -2566,7 +2496,7 @@
/** Save a ViolationInfo instance to a parcel. */
@Override
public void writeToParcel(Parcel dest, int flags) {
- dest.writeSerializable(mThrowable);
+ dest.writeSerializable(mViolation);
dest.writeInt(mBinderStack.size());
for (StackTraceElement[] traceElements : mBinderStack) {
dest.writeInt(traceElements.length);
@@ -2578,7 +2508,7 @@
}
}
int start = dest.dataPosition();
- dest.writeInt(policy);
+ dest.writeInt(mPolicy);
dest.writeInt(durationMillis);
dest.writeInt(violationNumThisLoop);
dest.writeInt(numAnimationsRunning);
@@ -2591,7 +2521,7 @@
Slog.d(
TAG,
"VIO: policy="
- + policy
+ + mPolicy
+ " dur="
+ durationMillis
+ " numLoop="
@@ -2610,10 +2540,8 @@
/** Dump a ViolationInfo instance to a Printer. */
public void dump(Printer pw, String prefix) {
- if (mThrowable != null) {
- pw.println(prefix + "stackTrace: " + getStackTrace());
- }
- pw.println(prefix + "policy: " + policy);
+ pw.println(prefix + "stackTrace: " + getStackTrace());
+ pw.println(prefix + "policy: " + mPolicy);
if (durationMillis != -1) {
pw.println(prefix + "durationMillis: " + durationMillis);
}
@@ -2657,27 +2585,6 @@
};
}
- // Dummy throwable, for now, since we don't know when or where the
- // leaked instances came from. We might in the future, but for
- // now we suppress the stack trace because it's useless and/or
- // misleading.
- private static class InstanceCountViolation extends Throwable {
- private final long mInstances;
- private final int mLimit;
-
- private static final StackTraceElement[] FAKE_STACK = {
- new StackTraceElement(
- "android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
- };
-
- public InstanceCountViolation(Class klass, long instances, int limit) {
- super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
- setStackTrace(FAKE_STACK);
- mInstances = instances;
- mLimit = limit;
- }
- }
-
private static final class InstanceTracker {
private static final HashMap<Class<?>, Integer> sInstanceCounts =
new HashMap<Class<?>, Integer>();
diff --git a/core/java/android/os/TokenWatcher.java b/core/java/android/os/TokenWatcher.java
index 9b3a2d6..00333dad 100644
--- a/core/java/android/os/TokenWatcher.java
+++ b/core/java/android/os/TokenWatcher.java
@@ -16,17 +16,23 @@
package android.os;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.WeakHashMap;
-import java.util.Set;
import android.util.Log;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Set;
+import java.util.WeakHashMap;
+
/**
- * Helper class that helps you use IBinder objects as reference counted
- * tokens. IBinders make good tokens because we find out when they are
- * removed
+ * A TokenWatcher watches a collection of {@link IBinder}s. IBinders are added
+ * to the collection by calling {@link #acquire}, and removed by calling {@link
+ * #release}. IBinders are also implicitly removed when they become weakly
+ * reachable. Each IBinder may be added at most once.
*
+ * The {@link #acquired} method is invoked by posting to the specified handler
+ * whenever the size of the watched collection becomes nonzero. The {@link
+ * #released} method is invoked on the specified handler whenever the size of
+ * the watched collection becomes zero.
*/
public abstract class TokenWatcher
{
@@ -59,15 +65,23 @@
* Record that this token has been acquired. When acquire is called, and
* the current count is 0, the acquired method is called on the given
* handler.
- *
- * @param token An IBinder object. If this token has already been acquired,
- * no action is taken.
+ *
+ * Note that the same {@code token} can only be acquired once. If this
+ * {@code token} has already been acquired, no action is taken. The first
+ * subsequent call to {@link #release} will release this {@code token}
+ * immediately.
+ *
+ * @param token An IBinder object.
* @param tag A string used by the {@link #dump} method for debugging,
* to see who has references.
*/
public void acquire(IBinder token, String tag)
{
synchronized (mTokens) {
+ if (mTokens.containsKey(token)) {
+ return;
+ }
+
// explicitly checked to avoid bogus sendNotification calls because
// of the WeakHashMap and the GC
int oldSize = mTokens.size();
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 706c2f7..de52736 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -804,6 +804,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.
*
@@ -929,7 +942,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() {
@@ -939,7 +952,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;
}
/**
@@ -2310,6 +2325,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/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index e865ed1..0b76eec 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -17,6 +17,7 @@
package android.os.storage;
import android.content.pm.IPackageMoveObserver;
+import android.os.IVoldTaskListener;
import android.os.ParcelFileDescriptor;
import android.os.storage.DiskInfo;
import android.os.storage.IStorageEventListener;
@@ -165,7 +166,7 @@
void forgetAllVolumes() = 56;
String getPrimaryStorageUuid() = 57;
void setPrimaryStorageUuid(in String volumeUuid, IPackageMoveObserver callback) = 58;
- long benchmark(in String volId) = 59;
+ void benchmark(in String volId, IVoldTaskListener listener) = 59;
void setDebugFlags(int flags, int mask) = 60;
void createUserKey(int userId, int serialNumber, boolean ephemeral) = 61;
void destroyUserKey(int userId) = 62;
@@ -177,7 +178,7 @@
boolean isConvertibleToFBE() = 68;
void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
void fixateNewestUserKeyAuth(int userId) = 71;
- void fstrim(int flags) = 72;
+ void fstrim(int flags, IVoldTaskListener listener) = 72;
AppFuseMount mountProxyFileDescriptorBridge() = 73;
ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 6594cd0..0b007dd 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -42,10 +42,12 @@
import android.os.FileUtils;
import android.os.Handler;
import android.os.IVold;
+import android.os.IVoldTaskListener;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.ParcelableException;
+import android.os.PersistableBundle;
import android.os.ProxyFileDescriptorCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
@@ -87,7 +89,9 @@
import java.util.List;
import java.util.Objects;
import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -884,9 +888,32 @@
}
/** {@hide} */
+ @Deprecated
public long benchmark(String volId) {
+ final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
+ benchmark(volId, new IVoldTaskListener.Stub() {
+ @Override
+ public void onStatus(int status, PersistableBundle extras) {
+ // Ignored
+ }
+
+ @Override
+ public void onFinished(int status, PersistableBundle extras) {
+ result.complete(extras);
+ }
+ });
try {
- return mStorageManager.benchmark(volId);
+ // Convert ms to ns
+ return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE) * 1000000;
+ } catch (Exception e) {
+ return Long.MAX_VALUE;
+ }
+ }
+
+ /** {@hide} */
+ public void benchmark(String volId, IVoldTaskListener listener) {
+ try {
+ mStorageManager.benchmark(volId, listener);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/CleartextNetworkViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/CleartextNetworkViolation.java
index e28e1b3..893780d 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/CleartextNetworkViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class CleartextNetworkViolation extends Violation {
+ public CleartextNetworkViolation(String msg) {
+ super(msg);
+ }
}
diff --git a/core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java b/core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java
new file mode 100644
index 0000000..017c4f9
--- /dev/null
+++ b/core/java/android/os/strictmode/ContentUriWithoutPermissionViolation.java
@@ -0,0 +1,30 @@
+/*
+ * 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.os.strictmode;
+
+import android.net.Uri;
+
+/** @hide */
+public final class ContentUriWithoutPermissionViolation extends Violation {
+ public ContentUriWithoutPermissionViolation(Uri uri, String location) {
+ super(
+ uri
+ + " exposed beyond app through "
+ + location
+ + " without permission grant flags; did you forget"
+ + " FLAG_GRANT_READ_URI_PERMISSION?");
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/CustomViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/CustomViolation.java
index e28e1b3..bc1656d 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/CustomViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class CustomViolation extends Violation {
+ public CustomViolation(String name) {
+ super(name);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/DiskReadViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/DiskReadViolation.java
index e28e1b3..2edd33e 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/DiskReadViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class DiskReadViolation extends Violation {
+ public DiskReadViolation() {
+ super(null);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/DiskWriteViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/DiskWriteViolation.java
index e28e1b3..6465718 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/DiskWriteViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class DiskWriteViolation extends Violation {
+ public DiskWriteViolation() {
+ super(null);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/FileUriExposedViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/FileUriExposedViolation.java
index e28e1b3..5f71ee5 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/FileUriExposedViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class FileUriExposedViolation extends Violation {
+ public FileUriExposedViolation(String msg) {
+ super(msg);
+ }
}
diff --git a/core/java/android/os/strictmode/InstanceCountViolation.java b/core/java/android/os/strictmode/InstanceCountViolation.java
new file mode 100644
index 0000000..d3da800
--- /dev/null
+++ b/core/java/android/os/strictmode/InstanceCountViolation.java
@@ -0,0 +1,36 @@
+/*
+ * 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.os.strictmode;
+
+/** @hide */
+public class InstanceCountViolation extends Violation {
+ private final long mInstances;
+
+ private static final StackTraceElement[] FAKE_STACK = {
+ new StackTraceElement(
+ "android.os.StrictMode", "setClassInstanceLimit", "StrictMode.java", 1)
+ };
+
+ public InstanceCountViolation(Class klass, long instances, int limit) {
+ super(klass.toString() + "; instances=" + instances + "; limit=" + limit);
+ setStackTrace(FAKE_STACK);
+ mInstances = instances;
+ }
+
+ public long getNumberOfInstances() {
+ return mInstances;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/IntentReceiverLeakedViolation.java
similarity index 66%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/IntentReceiverLeakedViolation.java
index e28e1b3..1d1dfc0 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/IntentReceiverLeakedViolation.java
@@ -11,16 +11,14 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class IntentReceiverLeakedViolation extends Violation {
+ public IntentReceiverLeakedViolation(Throwable originStack) {
+ super(null);
+ setStackTrace(originStack.getStackTrace());
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/LeakedClosableViolation.java
similarity index 66%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/LeakedClosableViolation.java
index e28e1b3..de12533 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/LeakedClosableViolation.java
@@ -11,16 +11,14 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class LeakedClosableViolation extends Violation {
+ public LeakedClosableViolation(String message, Throwable allocationSite) {
+ super(message);
+ initCause(allocationSite);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/NetworkViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/NetworkViolation.java
index e28e1b3..637d0b6 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/NetworkViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class NetworkViolation extends Violation {
+ public NetworkViolation() {
+ super(null);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/ResourceMismatchViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/ResourceMismatchViolation.java
index e28e1b3..01ae7f8 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/ResourceMismatchViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class ResourceMismatchViolation extends Violation {
+ public ResourceMismatchViolation(Object tag) {
+ super(tag.toString());
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java
similarity index 65%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java
index e28e1b3..5bab3bd 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/ServiceConnectionLeakedViolation.java
@@ -11,16 +11,14 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class ServiceConnectionLeakedViolation extends Violation {
+ public ServiceConnectionLeakedViolation(Throwable originStack) {
+ super(null);
+ setStackTrace(originStack.getStackTrace());
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/SqliteObjectLeakedViolation.java
similarity index 66%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/SqliteObjectLeakedViolation.java
index e28e1b3..8360088 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/SqliteObjectLeakedViolation.java
@@ -11,16 +11,15 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-package android.telephony.ims.feature;
+/** @hide */
+public final class SqliteObjectLeakedViolation extends Violation {
-/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
- * @hide
- */
-
-public interface IRcsFeature {
+ public SqliteObjectLeakedViolation(String message, Throwable originStack) {
+ super(message);
+ initCause(originStack);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/UnbufferedIOViolation.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/UnbufferedIOViolation.java
index e28e1b3..571ba50 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/UnbufferedIOViolation.java
@@ -11,16 +11,13 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class UnbufferedIOViolation extends Violation {
+ public UnbufferedIOViolation() {
+ super(null);
+ }
}
diff --git a/core/java/android/os/strictmode/UntaggedSocketViolation.java b/core/java/android/os/strictmode/UntaggedSocketViolation.java
new file mode 100644
index 0000000..9752753
--- /dev/null
+++ b/core/java/android/os/strictmode/UntaggedSocketViolation.java
@@ -0,0 +1,28 @@
+/*
+ * 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.os.strictmode;
+
+/** @hide */
+public final class UntaggedSocketViolation extends Violation {
+ /** @hide */
+ public static final String MESSAGE =
+ "Untagged socket detected; use"
+ + " TrafficStats.setThreadSocketTag() to track all network usage";
+
+ public UntaggedSocketViolation() {
+ super(MESSAGE);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/Violation.java
similarity index 71%
rename from telephony/java/android/telephony/ims/feature/IRcsFeature.java
rename to core/java/android/os/strictmode/Violation.java
index e28e1b3..ebae7fc 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/Violation.java
@@ -11,16 +11,18 @@
* 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
+ * limitations under the License.
*/
-package android.telephony.ims.feature;
+package android.os.strictmode;
/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
+ * Root class for all StrictMode violations.
+ *
* @hide
*/
-
-public interface IRcsFeature {
+public abstract class Violation extends Throwable {
+ protected Violation(String message) {
+ super(message);
+ }
}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java
similarity index 64%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java
index e28e1b3..d4c557a 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/os/strictmode/WebViewMethodCalledOnWrongThreadViolation.java
@@ -11,16 +11,14 @@
* 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
+ * limitations under the License.
*/
+package android.os.strictmode;
-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 {
+/** @hide */
+public final class WebViewMethodCalledOnWrongThreadViolation extends Violation {
+ public WebViewMethodCalledOnWrongThreadViolation(Throwable originStack) {
+ super(null);
+ setStackTrace(originStack.getStackTrace());
+ }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 62f4bf5..1bef2b3 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -72,6 +72,7 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.MemoryIntArray;
+import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
@@ -210,8 +211,13 @@
/** @hide */
public static final String EXTRA_NETWORK_TEMPLATE = "network_template";
- /** @hide */
- public static final String EXTRA_SUB_ID = "sub_id";
+
+ /**
+ * An int extra specifying a subscription ID.
+ *
+ * @see android.telephony.SubscriptionInfo#getSubscriptionId
+ */
+ public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
/**
* Activity Action: Modify Airplane mode settings using a voice command.
@@ -915,6 +921,9 @@
* In some cases, a matching Activity may not exist, so ensure you
* safeguard against this.
* <p>
+ * The subscription ID of the subscription for which available network operators should be
+ * displayed may be optionally specified with {@link #EXTRA_SUB_ID}.
+ * <p>
* Input: Nothing.
* <p>
* Output: Nothing.
@@ -1886,7 +1895,11 @@
arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
}
IContentProvider cp = mProviderHolder.getProvider(cr);
+ String prevValue = getStringForUser(cr, name, userHandle);
cp.call(cr.getPackageName(), mCallSetCommand, name, arg);
+ String newValue = getStringForUser(cr, name, userHandle);
+ StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newValue, prevValue, tag,
+ makeDefault ? 1 : 0, userHandle);
} catch (RemoteException e) {
Log.w(TAG, "Can't set key " + name + " in " + mUri, e);
return false;
@@ -5304,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
@@ -8007,28 +8029,40 @@
public static final String HDMI_SYSTEM_AUDIO_CONTROL_ENABLED =
"hdmi_system_audio_control_enabled";
- /**
- * Whether TV will automatically turn on upon reception of the CEC command
- * <Text View On> or <Image View On>. (0 = false, 1 = true)
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
- "hdmi_control_auto_wakeup_enabled";
+ /**
+ * Whether TV will automatically turn on upon reception of the CEC command
+ * <Text View On> or <Image View On>. (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_WAKEUP_ENABLED =
+ "hdmi_control_auto_wakeup_enabled";
- /**
- * Whether TV will also turn off other CEC devices when it goes to standby mode.
- * (0 = false, 1 = true)
- * @hide
- */
- public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
- "hdmi_control_auto_device_off_enabled";
+ /**
+ * Whether TV will also turn off other CEC devices when it goes to standby mode.
+ * (0 = false, 1 = true)
+ *
+ * @hide
+ */
+ public static final String HDMI_CONTROL_AUTO_DEVICE_OFF_ENABLED =
+ "hdmi_control_auto_device_off_enabled";
- /**
- * The interval in milliseconds at which location requests will be throttled when they are
- * coming from the background.
- * @hide
- */
- public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
+ /**
+ * If <b>true</b>, enables out-of-the-box execution for priv apps.
+ * Default: false
+ * Values: 0 = false, 1 = true
+ *
+ * @hide
+ */
+ public static final String PRIV_APP_OOB_ENABLED = "priv_app_oob_enabled";
+
+ /**
+ * The interval in milliseconds at which location requests will be throttled when they are
+ * coming from the background.
+ *
+ * @hide
+ */
+ public static final String LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS =
"location_background_throttle_interval_ms";
/**
@@ -8488,6 +8522,13 @@
public static final String NETWORK_METERED_MULTIPATH_PREFERENCE =
"network_metered_multipath_preference";
+ /**
+ * Network watchlist last report time.
+ * @hide
+ */
+ public static final String NETWORK_WATCHLIST_LAST_REPORT_TIME =
+ "network_watchlist_last_report_time";
+
/**
* The thresholds of the wifi throughput badging (SD, HD etc.) as a comma-delimited list of
* colon-delimited key-value pairs. The key is the badging enum value defined in
@@ -9280,11 +9321,20 @@
public static final String DEFAULT_DNS_SERVER = "default_dns_server";
/**
- * Whether to disable DNS over TLS (boolean)
+ * The requested Private DNS mode (string), and an accompanying specifier (string).
+ *
+ * Currently, the specifier holds the chosen provider name when the mode requests
+ * a specific provider. It may be used to store the provider name even when the
+ * mode changes so that temporarily disabling and re-enabling the specific
+ * provider mode does not necessitate retyping the provider hostname.
*
* @hide
*/
- public static final String DNS_TLS_DISABLED = "dns_tls_disabled";
+ public static final String PRIVATE_DNS_MODE = "private_dns_mode";
+ /**
+ * @hide
+ */
+ public static final String PRIVATE_DNS_SPECIFIER = "private_dns_specifier";
/** {@hide} */
public static final String
@@ -10370,7 +10420,9 @@
DOCK_AUDIO_MEDIA_ENABLED,
ENCODED_SURROUND_OUTPUT,
LOW_POWER_MODE_TRIGGER_LEVEL,
- BLUETOOTH_ON
+ BLUETOOTH_ON,
+ PRIVATE_DNS_MODE,
+ PRIVATE_DNS_SPECIFIER
};
/** @hide */
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/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 6a15ade..2a245d0 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -680,8 +680,8 @@
*
* @return The screen state to use while dozing, such as {@link Display#STATE_ON},
* {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
- * or {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN} for the default
- * behavior.
+ * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
+ * for the default behavior.
*
* @see #setDozeScreenState
* @hide For use by system UI components only.
@@ -700,12 +700,18 @@
* perform transitions between states while dozing to conserve power and
* achieve various effects.
* </p><p>
- * It is recommended that the state be set to {@link Display#STATE_DOZE_SUSPEND}
- * once the dream has completely finished drawing and before it releases its wakelock
- * to allow the display hardware to be fully suspended. While suspended, the
- * display will preserve its on-screen contents or hand off control to dedicated
- * doze hardware if the devices supports it. If the doze suspend state is
- * used, the dream must make sure to set the mode back
+ * Some devices will have dedicated hardware ("Sidekick") to animate
+ * the display content while the CPU sleeps. If the dream and the hardware support
+ * this, {@link Display#STATE_ON_SUSPEND} or {@link Display#STATE_DOZE_SUSPEND}
+ * will switch control to the Sidekick.
+ * </p><p>
+ * If not using Sidekick, it is recommended that the state be set to
+ * {@link Display#STATE_DOZE_SUSPEND} once the dream has completely
+ * finished drawing and before it releases its wakelock
+ * to allow the display hardware to be fully suspended. While suspended,
+ * the display will preserve its on-screen contents.
+ * </p><p>
+ * If the doze suspend state is used, the dream must make sure to set the mode back
* to {@link Display#STATE_DOZE} or {@link Display#STATE_ON} before drawing again
* since the display updates may be ignored and not seen by the user otherwise.
* </p><p>
@@ -716,8 +722,8 @@
*
* @param state The screen state to use while dozing, such as {@link Display#STATE_ON},
* {@link Display#STATE_DOZE}, {@link Display#STATE_DOZE_SUSPEND},
- * or {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN} for the default
- * behavior.
+ * {@link Display#STATE_ON_SUSPEND}, {@link Display#STATE_OFF}, or {@link Display#STATE_UNKNOWN}
+ * for the default behavior.
*
* @hide For use by system UI components only.
*/
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index fef9223..7285fb4 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -101,5 +101,13 @@
* application's compositor process to bind to, or null to clear the current binding.
*/
void setAndBindCompositor(in String componentName);
+
+ /**
+ * Sets the current standby status of the VR device. Standby mode is only used on standalone vr
+ * devices. Standby mode is a deep sleep state where it's appropriate to turn off vr mode.
+ *
+ * @param standy True if the device is entering standby, false if it's exiting standby.
+ */
+ void setStandbyEnabled(boolean standby);
}
diff --git a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
index a9ccae1..1808123 100644
--- a/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
+++ b/core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
@@ -16,9 +16,6 @@
package android.util.apk;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Pair;
@@ -30,7 +27,6 @@
import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
-import java.nio.DirectByteBuffer;
import java.security.DigestException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
@@ -122,40 +118,6 @@
}
/**
- * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
- * contained in the block against the file.
- */
- private static class SignatureInfo {
- /** Contents of APK Signature Scheme v2 block. */
- private final ByteBuffer signatureBlock;
-
- /** Position of the APK Signing Block in the file. */
- private final long apkSigningBlockOffset;
-
- /** Position of the ZIP Central Directory in the file. */
- private final long centralDirOffset;
-
- /** Position of the ZIP End of Central Directory (EoCD) in the file. */
- private final long eocdOffset;
-
- /** Contents of ZIP End of Central Directory (EoCD) of the file. */
- private final ByteBuffer eocd;
-
- private SignatureInfo(
- ByteBuffer signatureBlock,
- long apkSigningBlockOffset,
- long centralDirOffset,
- long eocdOffset,
- ByteBuffer eocd) {
- this.signatureBlock = signatureBlock;
- this.apkSigningBlockOffset = apkSigningBlockOffset;
- this.centralDirOffset = centralDirOffset;
- this.eocdOffset = eocdOffset;
- this.eocd = eocd;
- }
- }
-
- /**
* Returns the APK Signature Scheme v2 block contained in the provided APK file and the
* additional information relevant for verifying the block against the file.
*
@@ -497,6 +459,7 @@
// TODO: Compute digests of chunks in parallel when beneficial. This requires some research
// into how to parallelize (if at all) based on the capabilities of the hardware on which
// this code is running and based on the size of input.
+ DataDigester digester = new MultipleDigestDataDigester(mds);
int dataSourceIndex = 0;
for (DataSource input : contents) {
long inputOffset = 0;
@@ -508,7 +471,7 @@
mds[i].update(chunkContentPrefix);
}
try {
- input.feedIntoMessageDigests(mds, inputOffset, chunkSize);
+ input.feedIntoDataDigester(digester, inputOffset, chunkSize);
} catch (IOException e) {
throw new DigestException(
"Failed to digest chunk #" + chunkIndex + " of section #"
@@ -967,155 +930,26 @@
}
/**
- * Source of data to be digested.
+ * {@link DataDigester} that updates multiple {@link MessageDigest}s whenever data is feeded.
*/
- private static interface DataSource {
+ private static class MultipleDigestDataDigester implements DataDigester {
+ private final MessageDigest[] mMds;
- /**
- * Returns the size (in bytes) of the data offered by this source.
- */
- long size();
-
- /**
- * Feeds the specified region of this source's data into the provided digests. Each digest
- * instance gets the same data.
- *
- * @param offset offset of the region inside this data source.
- * @param size size (in bytes) of the region.
- */
- void feedIntoMessageDigests(MessageDigest[] mds, long offset, int size) throws IOException;
- }
-
- /**
- * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
- * of the file requested by
- * {@link DataSource#feedIntoMessageDigests(MessageDigest[], long, int) feedIntoMessageDigests}.
- */
- private static final class MemoryMappedFileDataSource implements DataSource {
- private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
-
- private final FileDescriptor mFd;
- private final long mFilePosition;
- private final long mSize;
-
- /**
- * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
- *
- * @param position start position of the region in the file.
- * @param size size (in bytes) of the region.
- */
- public MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
- mFd = fd;
- mFilePosition = position;
- mSize = size;
+ MultipleDigestDataDigester(MessageDigest[] mds) {
+ mMds = mds;
}
@Override
- public long size() {
- return mSize;
- }
-
- @Override
- public void feedIntoMessageDigests(
- MessageDigest[] mds, long offset, int size) throws IOException {
- // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
- // method was settled on a straightforward mmap with prefaulting.
- //
- // This method is not using FileChannel.map API because that API does not offset a way
- // to "prefault" the resulting memory pages. Without prefaulting, performance is about
- // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
- // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
- // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
- // time, which is not compensated for by faster reads.
-
- // We mmap the smallest region of the file containing the requested data. mmap requires
- // that the start offset in the file must be a multiple of memory page size. We thus may
- // need to mmap from an offset less than the requested offset.
- long filePosition = mFilePosition + offset;
- long mmapFilePosition =
- (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
- int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
- long mmapRegionSize = size + dataStartOffsetInMmapRegion;
- long mmapPtr = 0;
- try {
- mmapPtr = Os.mmap(
- 0, // let the OS choose the start address of the region in memory
- mmapRegionSize,
- OsConstants.PROT_READ,
- OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
- mFd,
- mmapFilePosition);
- // Feeding a memory region into MessageDigest requires the region to be represented
- // as a direct ByteBuffer.
- ByteBuffer buf = new DirectByteBuffer(
- size,
- mmapPtr + dataStartOffsetInMmapRegion,
- mFd, // not really needed, but just in case
- null, // no need to clean up -- it's taken care of by the finally block
- true // read only buffer
- );
- for (MessageDigest md : mds) {
- buf.position(0);
- md.update(buf);
- }
- } catch (ErrnoException e) {
- throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
- } finally {
- if (mmapPtr != 0) {
- try {
- Os.munmap(mmapPtr, mmapRegionSize);
- } catch (ErrnoException ignored) {}
- }
+ public void consume(ByteBuffer buffer) {
+ buffer = buffer.slice();
+ for (MessageDigest md : mMds) {
+ buffer.position(0);
+ md.update(buffer);
}
}
- }
-
- /**
- * {@link DataSource} which provides data from a {@link ByteBuffer}.
- */
- private static final class ByteBufferDataSource implements DataSource {
- /**
- * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
- * The buffer's position is 0 and limit is equal to capacity.
- */
- private final ByteBuffer mBuf;
-
- public ByteBufferDataSource(ByteBuffer buf) {
- // Defensive copy, to avoid changes to mBuf being visible in buf.
- mBuf = buf.slice();
- }
@Override
- public long size() {
- return mBuf.capacity();
- }
-
- @Override
- public void feedIntoMessageDigests(
- MessageDigest[] mds, long offset, int size) throws IOException {
- // There's no way to tell MessageDigest to read data from ByteBuffer from a position
- // other than the buffer's current position. We thus need to change the buffer's
- // position to match the requested offset.
- //
- // In the future, it may be necessary to compute digests of multiple regions in
- // parallel. Given that digest computation is a slow operation, we enable multiple
- // such requests to be fulfilled by this instance. This is achieved by serially
- // creating a new ByteBuffer corresponding to the requested data range and then,
- // potentially concurrently, feeding these buffers into MessageDigest instances.
- ByteBuffer region;
- synchronized (mBuf) {
- mBuf.position((int) offset);
- mBuf.limit((int) offset + size);
- region = mBuf.slice();
- }
-
- for (MessageDigest md : mds) {
- // Need to reset position to 0 at the start of each iteration because
- // MessageDigest.update below sets it to the buffer's limit.
- region.position(0);
- md.update(region);
- }
- }
+ public void finish() {}
}
/**
diff --git a/core/java/android/util/apk/ApkVerityBuilder.java b/core/java/android/util/apk/ApkVerityBuilder.java
new file mode 100644
index 0000000..7412ef4
--- /dev/null
+++ b/core/java/android/util/apk/ApkVerityBuilder.java
@@ -0,0 +1,351 @@
+/*
+ * 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.util.apk;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+
+/**
+ * ApkVerityBuilder builds the APK verity tree and the verity header, which will be used by the
+ * kernel to verity the APK content on access.
+ *
+ * <p>Unlike a regular Merkle tree, APK verity tree does not cover the content fully. Due to
+ * the existing APK format, it has to skip APK Signing Block and also has some special treatment for
+ * the "Central Directory offset" field of ZIP End of Central Directory.
+ *
+ * @hide
+ */
+abstract class ApkVerityBuilder {
+ private ApkVerityBuilder() {}
+
+ private static final int CHUNK_SIZE_BYTES = 4096; // Typical Linux block size
+ private static final int DIGEST_SIZE_BYTES = 32; // SHA-256 size
+ private static final int FSVERITY_HEADER_SIZE_BYTES = 64;
+ private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE = 4;
+ private static final int ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET = 16;
+ private static final String JCA_DIGEST_ALGORITHM = "SHA-256";
+ private static final byte[] DEFAULT_SALT = new byte[8];
+
+ static class ApkVerityResult {
+ public final ByteBuffer fsverityData;
+ public final byte[] rootHash;
+
+ ApkVerityResult(ByteBuffer fsverityData, byte[] rootHash) {
+ this.fsverityData = fsverityData;
+ this.rootHash = rootHash;
+ }
+ }
+
+ /**
+ * Generates fsverity metadata and the Merkle tree into the {@link ByteBuffer} created by the
+ * {@link ByteBufferFactory}. The bytes layout in the buffer will be used by the kernel and is
+ * ready to be appended to the target file to set up fsverity. For fsverity to work, this data
+ * must be placed at the next page boundary, and the caller must add additional padding in that
+ * case.
+ *
+ * @return ApkVerityResult containing the fsverity data and the root hash of the Merkle tree.
+ */
+ static ApkVerityResult generateApkVerity(RandomAccessFile apk,
+ SignatureInfo signatureInfo, ByteBufferFactory bufferFactory)
+ throws IOException, SecurityException, NoSuchAlgorithmException, DigestException {
+ assertSigningBlockAlignedAndHasFullPages(signatureInfo);
+
+ long signingBlockSize =
+ signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
+ long dataSize = apk.length() - signingBlockSize - ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ int[] levelOffset = calculateVerityLevelOffset(dataSize);
+ ByteBuffer output = bufferFactory.create(
+ CHUNK_SIZE_BYTES + // fsverity header + extensions + padding
+ levelOffset[levelOffset.length - 1] + // Merkle tree size
+ FSVERITY_HEADER_SIZE_BYTES); // second fsverity header (verbatim copy)
+
+ // Start generating the tree from the block boundary as the kernel will expect.
+ ByteBuffer treeOutput = slice(output, CHUNK_SIZE_BYTES,
+ output.limit() - FSVERITY_HEADER_SIZE_BYTES);
+ byte[] rootHash = generateApkVerityTree(apk, signatureInfo, DEFAULT_SALT, levelOffset,
+ treeOutput);
+
+ ByteBuffer integrityHeader = generateFsverityHeader(apk.length(), DEFAULT_SALT);
+ output.put(integrityHeader);
+ output.put(generateFsverityExtensions());
+
+ integrityHeader.rewind();
+ output.put(integrityHeader);
+ output.rewind();
+ return new ApkVerityResult(output, rootHash);
+ }
+
+ /**
+ * A helper class to consume and digest data by block continuously, and write into a buffer.
+ */
+ private static class BufferedDigester implements DataDigester {
+ /** Amount of the data to digest in each cycle before writting out the digest. */
+ private static final int BUFFER_SIZE = CHUNK_SIZE_BYTES;
+
+ /**
+ * Amount of data the {@link MessageDigest} has consumed since the last reset. This must be
+ * always less than BUFFER_SIZE since {@link MessageDigest} is reset whenever it has
+ * consumed BUFFER_SIZE of data.
+ */
+ private int mBytesDigestedSinceReset;
+
+ /** The final output {@link ByteBuffer} to write the digest to sequentially. */
+ private final ByteBuffer mOutput;
+
+ private final MessageDigest mMd;
+ private final byte[] mDigestBuffer = new byte[DIGEST_SIZE_BYTES];
+ private final byte[] mSalt;
+
+ private BufferedDigester(byte[] salt, ByteBuffer output) throws NoSuchAlgorithmException {
+ mSalt = salt;
+ mOutput = output.slice();
+ mMd = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
+ mMd.update(mSalt);
+ mBytesDigestedSinceReset = 0;
+ }
+
+ /**
+ * Consumes and digests data up to BUFFER_SIZE (may continue from the previous remaining),
+ * then writes the final digest to the output buffer. Repeat until all data are consumed.
+ * If the last consumption is not enough for BUFFER_SIZE, the state will stay and future
+ * consumption will continuous from there.
+ */
+ @Override
+ public void consume(ByteBuffer buffer) throws DigestException {
+ int offset = buffer.position();
+ int remaining = buffer.remaining();
+ while (remaining > 0) {
+ int allowance = (int) Math.min(remaining, BUFFER_SIZE - mBytesDigestedSinceReset);
+ // Optimization: set the buffer limit to avoid allocating a new ByteBuffer object.
+ buffer.limit(buffer.position() + allowance);
+ mMd.update(buffer);
+ offset += allowance;
+ remaining -= allowance;
+ mBytesDigestedSinceReset += allowance;
+
+ if (mBytesDigestedSinceReset == BUFFER_SIZE) {
+ mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
+ mOutput.put(mDigestBuffer);
+ // After digest, MessageDigest resets automatically, so no need to reset again.
+ mMd.update(mSalt);
+ mBytesDigestedSinceReset = 0;
+ }
+ }
+ }
+
+ /** Finish the current digestion if any. */
+ @Override
+ public void finish() throws DigestException {
+ if (mBytesDigestedSinceReset == 0) {
+ return;
+ }
+ mMd.digest(mDigestBuffer, 0, mDigestBuffer.length);
+ mOutput.put(mDigestBuffer);
+ }
+
+ private void fillUpLastOutputChunk() {
+ int extra = (int) (BUFFER_SIZE - mOutput.position() % BUFFER_SIZE);
+ if (extra == 0) {
+ return;
+ }
+ mOutput.put(ByteBuffer.allocate(extra));
+ }
+ }
+
+ /**
+ * Digest the source by chunk in the given range. If the last chunk is not a full chunk,
+ * digest the remaining.
+ */
+ private static void consumeByChunk(DataDigester digester, DataSource source, int chunkSize)
+ throws IOException, DigestException {
+ long inputRemaining = source.size();
+ long inputOffset = 0;
+ while (inputRemaining > 0) {
+ int size = (int) Math.min(inputRemaining, chunkSize);
+ source.feedIntoDataDigester(digester, inputOffset, size);
+ inputOffset += size;
+ inputRemaining -= size;
+ }
+ }
+
+ // Rationale: 1) 1 MB should fit in memory space on all devices. 2) It is not too granular
+ // thus the syscall overhead is not too big.
+ private static final int MMAP_REGION_SIZE_BYTES = 1024 * 1024;
+
+ private static void generateApkVerityDigestAtLeafLevel(RandomAccessFile apk,
+ SignatureInfo signatureInfo, byte[] salt, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ BufferedDigester digester = new BufferedDigester(salt, output);
+
+ // 1. Digest from the beginning of the file, until APK Signing Block is reached.
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), 0, signatureInfo.apkSigningBlockOffset),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 2. Skip APK Signing Block and continue digesting, until the Central Directory offset
+ // field in EoCD is reached.
+ long eocdCdOffsetFieldPosition =
+ signatureInfo.eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET;
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), signatureInfo.centralDirOffset,
+ eocdCdOffsetFieldPosition - signatureInfo.centralDirOffset),
+ MMAP_REGION_SIZE_BYTES);
+
+ // 3. Fill up the rest of buffer with 0s.
+ ByteBuffer alternativeCentralDirOffset = ByteBuffer.allocate(
+ ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE).order(ByteOrder.LITTLE_ENDIAN);
+ alternativeCentralDirOffset.putInt(Math.toIntExact(signatureInfo.apkSigningBlockOffset));
+ alternativeCentralDirOffset.flip();
+ digester.consume(alternativeCentralDirOffset);
+
+ // 4. Read from end of the Central Directory offset field in EoCD to the end of the file.
+ long offsetAfterEocdCdOffsetField =
+ eocdCdOffsetFieldPosition + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
+ consumeByChunk(digester,
+ new MemoryMappedFileDataSource(apk.getFD(), offsetAfterEocdCdOffsetField,
+ apk.length() - offsetAfterEocdCdOffsetField),
+ MMAP_REGION_SIZE_BYTES);
+ digester.finish();
+
+ // 5. Fill up the rest of buffer with 0s.
+ digester.fillUpLastOutputChunk();
+ }
+
+ private static byte[] generateApkVerityTree(RandomAccessFile apk, SignatureInfo signatureInfo,
+ byte[] salt, int[] levelOffset, ByteBuffer output)
+ throws IOException, NoSuchAlgorithmException, DigestException {
+ // 1. Digest the apk to generate the leaf level hashes.
+ generateApkVerityDigestAtLeafLevel(apk, signatureInfo, salt, slice(output,
+ levelOffset[levelOffset.length - 2], levelOffset[levelOffset.length - 1]));
+
+ // 2. Digest the lower level hashes bottom up.
+ for (int level = levelOffset.length - 3; level >= 0; level--) {
+ ByteBuffer inputBuffer = slice(output, levelOffset[level + 1], levelOffset[level + 2]);
+ ByteBuffer outputBuffer = slice(output, levelOffset[level], levelOffset[level + 1]);
+
+ DataSource source = new ByteBufferDataSource(inputBuffer);
+ BufferedDigester digester = new BufferedDigester(salt, outputBuffer);
+ consumeByChunk(digester, source, CHUNK_SIZE_BYTES);
+ digester.finish();
+
+ digester.fillUpLastOutputChunk();
+ }
+
+ // 3. Digest the first block (i.e. first level) to generate the root hash.
+ 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;
+ }
+
+ private static ByteBuffer generateFsverityHeader(long fileSize, byte[] salt) {
+ if (salt.length != 8) {
+ throw new IllegalArgumentException("salt is not 8 bytes long");
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(FSVERITY_HEADER_SIZE_BYTES);
+ buffer.order(ByteOrder.LITTLE_ENDIAN);
+
+ // TODO(b/30972906): insert a reference when there is a public one.
+ buffer.put("TrueBrew".getBytes()); // magic
+ buffer.put((byte) 1); // major version
+ buffer.put((byte) 0); // minor version
+ buffer.put((byte) 12); // log2(block-size) == log2(4096)
+ buffer.put((byte) 7); // log2(leaves-per-node) == log2(block-size / digest-size)
+ // == log2(4096 / 32)
+ buffer.putShort((short) 1); // meta algorithm, 1: SHA-256 FIXME finalize constant
+ buffer.putShort((short) 1); // data algorithm, 1: SHA-256 FIXME finalize constant
+ buffer.putInt(0x1); // flags, 0x1: has extension, FIXME also hide it
+ buffer.putInt(0); // reserved
+ buffer.putLong(fileSize); // original i_size
+ buffer.put(salt); // salt (8 bytes)
+
+ // TODO(b/30972906): Add extension.
+
+ buffer.rewind();
+ return buffer;
+ }
+
+ private static ByteBuffer generateFsverityExtensions() {
+ return ByteBuffer.allocate(64); // TODO(b/30972906): implement this.
+ }
+
+ /**
+ * Returns an array of summed area table of level size in the verity tree. In other words, the
+ * returned array is offset of each level in the verity tree file format, plus an additional
+ * offset of the next non-existing level (i.e. end of the last level + 1). Thus the array size
+ * is level + 1. Thus, the returned array is guarantee to have at least 2 elements.
+ */
+ private static int[] calculateVerityLevelOffset(long fileSize) {
+ ArrayList<Long> levelSize = new ArrayList<>();
+ while (true) {
+ long levelDigestSize = divideRoundup(fileSize, CHUNK_SIZE_BYTES) * DIGEST_SIZE_BYTES;
+ long chunksSize = CHUNK_SIZE_BYTES * divideRoundup(levelDigestSize, CHUNK_SIZE_BYTES);
+ levelSize.add(chunksSize);
+ if (levelDigestSize <= CHUNK_SIZE_BYTES) {
+ break;
+ }
+ fileSize = levelDigestSize;
+ }
+
+ // Reverse and convert to summed area table.
+ int[] levelOffset = new int[levelSize.size() + 1];
+ levelOffset[0] = 0;
+ for (int i = 0; i < levelSize.size(); i++) {
+ // We don't support verity tree if it is larger then Integer.MAX_VALUE.
+ levelOffset[i + 1] = levelOffset[i]
+ + Math.toIntExact(levelSize.get(levelSize.size() - i - 1));
+ }
+ return levelOffset;
+ }
+
+ private static void assertSigningBlockAlignedAndHasFullPages(SignatureInfo signatureInfo) {
+ if (signatureInfo.apkSigningBlockOffset % CHUNK_SIZE_BYTES != 0) {
+ throw new IllegalArgumentException(
+ "APK Signing Block does not start at the page boundary: "
+ + signatureInfo.apkSigningBlockOffset);
+ }
+
+ if ((signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset)
+ % CHUNK_SIZE_BYTES != 0) {
+ throw new IllegalArgumentException(
+ "Size of APK Signing Block is not a multiple of 4096: "
+ + (signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset));
+ }
+ }
+
+ /** Returns a slice of the buffer which shares content with the provided buffer. */
+ private static ByteBuffer slice(ByteBuffer buffer, int begin, int end) {
+ ByteBuffer b = buffer.duplicate();
+ b.position(0); // to ensure position <= limit invariant.
+ b.limit(end);
+ b.position(begin);
+ return b.slice();
+ }
+
+ /** Divides a number and round up to the closest integer. */
+ private static long divideRoundup(long dividend, long divisor) {
+ return (dividend + divisor - 1) / divisor;
+ }
+}
diff --git a/core/java/android/util/apk/ByteBufferDataSource.java b/core/java/android/util/apk/ByteBufferDataSource.java
new file mode 100644
index 0000000..3976568
--- /dev/null
+++ b/core/java/android/util/apk/ByteBufferDataSource.java
@@ -0,0 +1,66 @@
+/*
+ * 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.util.apk;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a {@link ByteBuffer}.
+ */
+class ByteBufferDataSource implements DataSource {
+ /**
+ * Underlying buffer. The data is stored between position 0 and the buffer's capacity.
+ * The buffer's position is 0 and limit is equal to capacity.
+ */
+ private final ByteBuffer mBuf;
+
+ ByteBufferDataSource(ByteBuffer buf) {
+ // Defensive copy, to avoid changes to mBuf being visible in buf, and to ensure position is
+ // 0 and limit == capacity.
+ mBuf = buf.slice();
+ }
+
+ @Override
+ public long size() {
+ return mBuf.capacity();
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException {
+ // There's no way to tell MessageDigest to read data from ByteBuffer from a position
+ // other than the buffer's current position. We thus need to change the buffer's
+ // position to match the requested offset.
+ //
+ // In the future, it may be necessary to compute digests of multiple regions in
+ // parallel. Given that digest computation is a slow operation, we enable multiple
+ // such requests to be fulfilled by this instance. This is achieved by serially
+ // creating a new ByteBuffer corresponding to the requested data range and then,
+ // potentially concurrently, feeding these buffers into MessageDigest instances.
+ ByteBuffer region;
+ synchronized (mBuf) {
+ mBuf.position(0);
+ mBuf.limit((int) offset + size);
+ mBuf.position((int) offset);
+ region = mBuf.slice();
+ }
+
+ md.consume(region);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/android/util/apk/ByteBufferFactory.java
similarity index 68%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/android/util/apk/ByteBufferFactory.java
index e28e1b3..7a99882 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/android/util/apk/ByteBufferFactory.java
@@ -11,16 +11,18 @@
* 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
+ * limitations under the License.
*/
-package android.telephony.ims.feature;
+package android.util.apk;
+
+import java.nio.ByteBuffer;
/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
+ * Provider of {@link ByteBuffer} instances.
* @hide
*/
-
-public interface IRcsFeature {
+public interface ByteBufferFactory {
+ /** Initiates a {@link ByteBuffer} with the given size. */
+ ByteBuffer create(int capacity);
}
diff --git a/core/java/android/util/apk/DataDigester.java b/core/java/android/util/apk/DataDigester.java
new file mode 100644
index 0000000..278be80
--- /dev/null
+++ b/core/java/android/util/apk/DataDigester.java
@@ -0,0 +1,28 @@
+/*
+ * 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.util.apk;
+
+import java.nio.ByteBuffer;
+import java.security.DigestException;
+
+interface DataDigester {
+ /** Consumes the {@link ByteBuffer}. */
+ void consume(ByteBuffer buffer) throws DigestException;
+
+ /** Finishes the digestion. Must be called after the last {@link #consume(ByteBuffer)}. */
+ void finish() throws DigestException;
+}
diff --git a/core/java/android/util/apk/DataSource.java b/core/java/android/util/apk/DataSource.java
new file mode 100644
index 0000000..82f3800
--- /dev/null
+++ b/core/java/android/util/apk/DataSource.java
@@ -0,0 +1,38 @@
+/*
+ * 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.util.apk;
+
+import java.io.IOException;
+import java.security.DigestException;
+
+/** Source of data to be digested. */
+interface DataSource {
+
+ /**
+ * Returns the size (in bytes) of the data offered by this source.
+ */
+ long size();
+
+ /**
+ * Feeds the specified region of this source's data into the provided digester.
+ *
+ * @param offset offset of the region inside this data source.
+ * @param size size (in bytes) of the region.
+ */
+ void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException;
+}
diff --git a/core/java/android/util/apk/MemoryMappedFileDataSource.java b/core/java/android/util/apk/MemoryMappedFileDataSource.java
new file mode 100644
index 0000000..8d2b1e32
--- /dev/null
+++ b/core/java/android/util/apk/MemoryMappedFileDataSource.java
@@ -0,0 +1,105 @@
+/*
+ * 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.util.apk;
+
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.DirectByteBuffer;
+import java.security.DigestException;
+
+/**
+ * {@link DataSource} which provides data from a file descriptor by memory-mapping the sections
+ * of the file.
+ */
+class MemoryMappedFileDataSource implements DataSource {
+ private static final long MEMORY_PAGE_SIZE_BYTES = Os.sysconf(OsConstants._SC_PAGESIZE);
+
+ private final FileDescriptor mFd;
+ private final long mFilePosition;
+ private final long mSize;
+
+ /**
+ * Constructs a new {@code MemoryMappedFileDataSource} for the specified region of the file.
+ *
+ * @param position start position of the region in the file.
+ * @param size size (in bytes) of the region.
+ */
+ MemoryMappedFileDataSource(FileDescriptor fd, long position, long size) {
+ mFd = fd;
+ mFilePosition = position;
+ mSize = size;
+ }
+
+ @Override
+ public long size() {
+ return mSize;
+ }
+
+ @Override
+ public void feedIntoDataDigester(DataDigester md, long offset, int size)
+ throws IOException, DigestException {
+ // IMPLEMENTATION NOTE: After a lot of experimentation, the implementation of this
+ // method was settled on a straightforward mmap with prefaulting.
+ //
+ // This method is not using FileChannel.map API because that API does not offset a way
+ // to "prefault" the resulting memory pages. Without prefaulting, performance is about
+ // 10% slower on small to medium APKs, but is significantly worse for APKs in 500+ MB
+ // range. FileChannel.load (which currently uses madvise) doesn't help. Finally,
+ // invoking madvise (MADV_SEQUENTIAL) after mmap with prefaulting wastes quite a bit of
+ // time, which is not compensated for by faster reads.
+
+ // We mmap the smallest region of the file containing the requested data. mmap requires
+ // that the start offset in the file must be a multiple of memory page size. We thus may
+ // need to mmap from an offset less than the requested offset.
+ long filePosition = mFilePosition + offset;
+ long mmapFilePosition =
+ (filePosition / MEMORY_PAGE_SIZE_BYTES) * MEMORY_PAGE_SIZE_BYTES;
+ int dataStartOffsetInMmapRegion = (int) (filePosition - mmapFilePosition);
+ long mmapRegionSize = size + dataStartOffsetInMmapRegion;
+ long mmapPtr = 0;
+ try {
+ mmapPtr = Os.mmap(
+ 0, // let the OS choose the start address of the region in memory
+ mmapRegionSize,
+ OsConstants.PROT_READ,
+ OsConstants.MAP_SHARED | OsConstants.MAP_POPULATE, // "prefault" all pages
+ mFd,
+ mmapFilePosition);
+ ByteBuffer buf = new DirectByteBuffer(
+ size,
+ mmapPtr + dataStartOffsetInMmapRegion,
+ mFd, // not really needed, but just in case
+ null, // no need to clean up -- it's taken care of by the finally block
+ true // read only buffer
+ );
+ md.consume(buf);
+ } catch (ErrnoException e) {
+ throw new IOException("Failed to mmap " + mmapRegionSize + " bytes", e);
+ } finally {
+ if (mmapPtr != 0) {
+ try {
+ Os.munmap(mmapPtr, mmapRegionSize);
+ } catch (ErrnoException ignored) { }
+ }
+ }
+ }
+}
diff --git a/core/java/android/util/apk/SignatureInfo.java b/core/java/android/util/apk/SignatureInfo.java
new file mode 100644
index 0000000..8e1233a
--- /dev/null
+++ b/core/java/android/util/apk/SignatureInfo.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util.apk;
+
+import java.nio.ByteBuffer;
+
+/**
+ * APK Signature Scheme v2 block and additional information relevant to verifying the signatures
+ * contained in the block against the file.
+ */
+class SignatureInfo {
+ /** Contents of APK Signature Scheme v2 block. */
+ public final ByteBuffer signatureBlock;
+
+ /** Position of the APK Signing Block in the file. */
+ public final long apkSigningBlockOffset;
+
+ /** Position of the ZIP Central Directory in the file. */
+ public final long centralDirOffset;
+
+ /** Position of the ZIP End of Central Directory (EoCD) in the file. */
+ public final long eocdOffset;
+
+ /** Contents of ZIP End of Central Directory (EoCD) of the file. */
+ public final ByteBuffer eocd;
+
+ SignatureInfo(ByteBuffer signatureBlock, long apkSigningBlockOffset, long centralDirOffset,
+ long eocdOffset, ByteBuffer eocd) {
+ this.signatureBlock = signatureBlock;
+ this.apkSigningBlockOffset = apkSigningBlockOffset;
+ this.centralDirOffset = centralDirOffset;
+ this.eocdOffset = eocdOffset;
+ this.eocd = eocd;
+ }
+}
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 43a9789..a94806a 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -127,42 +127,48 @@
public static final long FIELD_TYPE_UNKNOWN = 0;
+ /**
+ * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+ * so no extra mapping needs to be maintained in this case.
+ */
public static final long FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
public static final long FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
- public static final long FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_INT64 = 3L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_UINT64 = 4L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_INT32 = 5L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_FIXED64 = 6L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_FIXED32 = 7L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_BOOL = 8L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_STRING = 9L << FIELD_TYPE_SHIFT;
+// public static final long FIELD_TYPE_GROUP = 10L << FIELD_TYPE_SHIFT; // Deprecated.
+ public static final long FIELD_TYPE_MESSAGE = 11L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_BYTES = 12L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_UINT32 = 13L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_ENUM = 14L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SFIXED32 = 15L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SFIXED64 = 16L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SINT32 = 17L << FIELD_TYPE_SHIFT;
+ public static final long FIELD_TYPE_SINT64 = 18L << FIELD_TYPE_SHIFT;
private static final String[] FIELD_TYPE_NAMES = new String[] {
"Double",
"Float",
- "Int32",
"Int64",
- "UInt32",
"UInt64",
- "SInt32",
- "SInt64",
- "Fixed32",
+ "Int32",
"Fixed64",
- "SFixed32",
- "SFixed64",
+ "Fixed32",
"Bool",
"String",
+ "Group", // This field is deprecated but reserved here for indexing.
+ "Message",
"Bytes",
+ "UInt32",
"Enum",
- "Object",
+ "SFixed32",
+ "SFixed64",
+ "SInt32",
+ "SInt64",
};
//
@@ -867,21 +873,21 @@
assertNotCompacted();
final int id = (int)fieldId;
- switch ((int)((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
+ switch ((int) ((fieldId & (FIELD_TYPE_MASK | FIELD_COUNT_MASK)) >> FIELD_TYPE_SHIFT)) {
// bytes
- case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
+ case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
writeBytesImpl(id, val);
break;
- case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
- case (int)((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
+ case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
+ case (int) ((FIELD_TYPE_BYTES | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
writeRepeatedBytesImpl(id, val);
break;
// Object
- case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
+ case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_SINGLE) >> FIELD_TYPE_SHIFT):
writeObjectImpl(id, val);
break;
- case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
- case (int)((FIELD_TYPE_OBJECT | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
+ case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED) >> FIELD_TYPE_SHIFT):
+ case (int) ((FIELD_TYPE_MESSAGE | FIELD_COUNT_PACKED) >> FIELD_TYPE_SHIFT):
writeRepeatedObjectImpl(id, val);
break;
// nothing else allowed
@@ -899,7 +905,7 @@
assertNotCompacted();
final int id = (int)fieldId;
- if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_OBJECT) {
+ if ((fieldId & FIELD_TYPE_MASK) == FIELD_TYPE_MESSAGE) {
final long count = fieldId & FIELD_COUNT_MASK;
if (count == FIELD_COUNT_SINGLE) {
return startObjectImpl(id, false);
@@ -2091,7 +2097,7 @@
@Deprecated
public long startObject(long fieldId) {
assertNotCompacted();
- final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
return startObjectImpl(id, false);
}
@@ -2119,7 +2125,7 @@
@Deprecated
public long startRepeatedObject(long fieldId) {
assertNotCompacted();
- final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
return startObjectImpl(id, true);
}
@@ -2217,7 +2223,7 @@
@Deprecated
public void writeObject(long fieldId, byte[] value) {
assertNotCompacted();
- final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
+ final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_MESSAGE);
writeObjectImpl(id, value);
}
@@ -2237,7 +2243,7 @@
@Deprecated
public void writeRepeatedObject(long fieldId, byte[] value) {
assertNotCompacted();
- final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
+ final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_MESSAGE);
writeRepeatedObjectImpl(id, value);
}
@@ -2296,7 +2302,7 @@
final String typeString = getFieldTypeString(fieldType);
if (typeString != null && countString != null) {
final StringBuilder sb = new StringBuilder();
- if (expectedType == FIELD_TYPE_OBJECT) {
+ if (expectedType == FIELD_TYPE_MESSAGE) {
sb.append("start");
} else {
sb.append("write");
@@ -2306,7 +2312,7 @@
sb.append(" called for field ");
sb.append((int)fieldId);
sb.append(" which should be used with ");
- if (fieldType == FIELD_TYPE_OBJECT) {
+ if (fieldType == FIELD_TYPE_MESSAGE) {
sb.append("start");
} else {
sb.append("write");
@@ -2321,7 +2327,7 @@
throw new IllegalArgumentException(sb.toString());
} else {
final StringBuilder sb = new StringBuilder();
- if (expectedType == FIELD_TYPE_OBJECT) {
+ if (expectedType == FIELD_TYPE_MESSAGE) {
sb.append("start");
} else {
sb.append("write");
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e7c3f92..6a44cdb 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -294,11 +294,10 @@
/**
* Display state: The display is dozing in a suspended low power state; it is still
- * on but is optimized for showing static system-provided content while the device
- * is non-interactive. This mode may be used to conserve even more power by allowing
- * the hardware to stop applying frame buffer updates from the graphics subsystem or
- * to take over the display and manage it autonomously to implement low power always-on
- * display functionality.
+ * on but the CPU is not updating it. This may be used in one of two ways: to show
+ * static system-provided content while the device is non-interactive, or to allow
+ * a "Sidekick" compute resource to update the display. For this reason, the
+ * CPU must not control the display in this mode.
*
* @see #getState
* @see android.os.PowerManager#isInteractive
@@ -313,6 +312,18 @@
*/
public static final int STATE_VR = 5;
+ /**
+ * Display state: The display is in a suspended full power state; it is still
+ * on but the CPU is not updating it. This may be used in one of two ways: to show
+ * static system-provided content while the device is non-interactive, or to allow
+ * a "Sidekick" compute resource to update the display. For this reason, the
+ * CPU must not control the display in this mode.
+ *
+ * @see #getState
+ * @see android.os.PowerManager#isInteractive
+ */
+ public static final int STATE_ON_SUSPEND = 6;
+
/* The color mode constants defined below must be kept in sync with the ones in
* system/core/include/system/graphics-base.h */
@@ -994,7 +1005,7 @@
* Gets the state of the display, such as whether it is on or off.
*
* @return The state of the display: one of {@link #STATE_OFF}, {@link #STATE_ON},
- * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, or
+ * {@link #STATE_DOZE}, {@link #STATE_DOZE_SUSPEND}, {@link #STATE_ON_SUSPEND}, or
* {@link #STATE_UNKNOWN}.
*/
public int getState() {
@@ -1113,6 +1124,8 @@
return "DOZE_SUSPEND";
case STATE_VR:
return "VR";
+ case STATE_ON_SUSPEND:
+ return "ON_SUSPEND";
default:
return Integer.toString(state);
}
@@ -1120,11 +1133,11 @@
/**
* Returns true if display updates may be suspended while in the specified
- * display power state.
+ * display power state. In SUSPEND states, updates are absolutely forbidden.
* @hide
*/
public static boolean isSuspendedState(int state) {
- return state == STATE_OFF || state == STATE_DOZE_SUSPEND;
+ return state == STATE_OFF || state == STATE_DOZE_SUSPEND || state == STATE_ON_SUSPEND;
}
/**
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 5804560..ab0b3ee 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -20,6 +20,7 @@
import android.app.Notification;
import android.content.Context;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
@@ -43,6 +44,7 @@
public static final int NO_COLOR = Notification.COLOR_INVALID;
private final int mChildMinWidth;
private final int mContentEndMargin;
+ private final int mGravity;
private View mAppName;
private View mHeaderText;
private OnClickListener mExpandClickListener;
@@ -50,7 +52,6 @@
private ImageView mExpandButton;
private CachingIconView mIcon;
private View mProfileBadge;
- private View mInfo;
private int mIconColor;
private int mOriginalNotificationColor;
private boolean mExpanded;
@@ -61,6 +62,7 @@
private boolean mEntireHeaderClickable;
private boolean mExpandOnlyOnButton;
private boolean mAcceptAllTouches;
+ private int mTotalWidth;
ViewOutlineProvider mProvider = new ViewOutlineProvider() {
@Override
@@ -92,6 +94,11 @@
mHeaderBackgroundHeight = res.getDimensionPixelSize(
R.dimen.notification_header_background_height);
mEntireHeaderClickable = res.getBoolean(R.bool.config_notificationHeaderClickableForExpand);
+
+ int[] attrIds = { android.R.attr.gravity };
+ TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+ mGravity = ta.getInt(0, 0);
+ ta.recycle();
}
@Override
@@ -146,6 +153,7 @@
mHeaderText.measure(childWidthSpec, wrapContentHeightSpec);
}
}
+ mTotalWidth = Math.min(totalWidth, givenWidth);
setMeasuredDimension(givenWidth, givenHeight);
}
@@ -153,6 +161,10 @@
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int left = getPaddingStart();
int end = getMeasuredWidth();
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
+ if (centerAligned) {
+ left += getMeasuredWidth() / 2 - mTotalWidth / 2;
+ }
int childCount = getChildCount();
int ownHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom();
for (int i = 0; i < childCount; i++) {
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 6f8315a..5641009 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -295,6 +295,12 @@
public static final int POWER_MODE_DOZE_SUSPEND = 3;
/**
+ * Display power mode on: used while putting the screen into a suspended
+ * full power mode. Use only with {@link SurfaceControl#setDisplayPowerMode}.
+ */
+ public static final int POWER_MODE_ON_SUSPEND = 4;
+
+ /**
* A value for windowType used to indicate that the window should be omitted from screenshots
* and display mirroring. A temporary workaround until we express such things with
* the hierarchy.
@@ -1206,56 +1212,65 @@
}
public Transaction show(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, 0, SURFACE_HIDDEN);
return this;
}
public Transaction hide(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
return this;
}
public Transaction setPosition(SurfaceControl sc, float x, float y) {
+ sc.checkNotReleased();
nativeSetPosition(mNativeObject, sc.mNativeObject, x, y);
return this;
}
public Transaction setSize(SurfaceControl sc, int w, int h) {
- nativeSetSize(mNativeObject, sc.mNativeObject,
- w, h);
+ sc.checkNotReleased();
+ nativeSetSize(mNativeObject, sc.mNativeObject, w, h);
return this;
}
public Transaction setLayer(SurfaceControl sc, int z) {
+ sc.checkNotReleased();
nativeSetLayer(mNativeObject, sc.mNativeObject, z);
return this;
}
public Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo, int z) {
+ sc.checkNotReleased();
nativeSetRelativeLayer(mNativeObject, sc.mNativeObject,
relativeTo.getHandle(), z);
return this;
}
public Transaction setTransparentRegionHint(SurfaceControl sc, Region transparentRegion) {
+ sc.checkNotReleased();
nativeSetTransparentRegionHint(mNativeObject,
sc.mNativeObject, transparentRegion);
return this;
}
public Transaction setAlpha(SurfaceControl sc, float alpha) {
+ sc.checkNotReleased();
nativeSetAlpha(mNativeObject, sc.mNativeObject, alpha);
return this;
}
public Transaction setMatrix(SurfaceControl sc,
float dsdx, float dtdx, float dtdy, float dsdy) {
+ sc.checkNotReleased();
nativeSetMatrix(mNativeObject, sc.mNativeObject,
dsdx, dtdx, dtdy, dsdy);
return this;
}
public Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetWindowCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1267,6 +1282,7 @@
}
public Transaction setFinalCrop(SurfaceControl sc, Rect crop) {
+ sc.checkNotReleased();
if (crop != null) {
nativeSetFinalCrop(mNativeObject, sc.mNativeObject,
crop.left, crop.top, crop.right, crop.bottom);
@@ -1278,40 +1294,48 @@
}
public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+ sc.checkNotReleased();
nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
return this;
}
- public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) {
+ public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
+ long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber);
return this;
}
public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface,
long frameNumber) {
+ sc.checkNotReleased();
nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject,
barrierSurface.mNativeObject, frameNumber);
return this;
}
public Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparentChildren(mNativeObject, sc.mNativeObject, newParentHandle);
return this;
}
/** Re-parents a specific child layer to a new parent */
public Transaction reparent(SurfaceControl sc, IBinder newParentHandle) {
+ sc.checkNotReleased();
nativeReparent(mNativeObject, sc.mNativeObject,
newParentHandle);
return this;
}
public Transaction detachChildren(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSeverChildren(mNativeObject, sc.mNativeObject);
return this;
}
public Transaction setOverrideScalingMode(SurfaceControl sc, int overrideScalingMode) {
+ sc.checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, sc.mNativeObject,
overrideScalingMode);
return this;
@@ -1322,6 +1346,7 @@
* @param color A float array with three values to represent r, g, b in range [0..1]
*/
public Transaction setColor(SurfaceControl sc, @Size(3) float[] color) {
+ sc.checkNotReleased();
nativeSetColor(mNativeObject, sc.mNativeObject, color);
return this;
}
@@ -1334,6 +1359,7 @@
* (at which point the geometry influencing aspects of this transaction will then occur)
*/
public Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
+ sc.checkNotReleased();
nativeSetGeometryAppliesWithResize(mNativeObject, sc.mNativeObject);
return this;
}
@@ -1343,6 +1369,7 @@
* Surface with the {@link #SECURE} flag.
*/
Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+ sc.checkNotReleased();
if (isSecure) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SECURE, SECURE);
} else {
@@ -1356,6 +1383,7 @@
* Surface with the {@link #OPAQUE} flag.
*/
public Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+ sc.checkNotReleased();
if (isOpaque) {
nativeSetFlags(mNativeObject, sc.mNativeObject, SURFACE_OPAQUE, SURFACE_OPAQUE);
} else {
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/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 4500862..c44c8dd 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -92,7 +92,7 @@
* Defines the duration in milliseconds a user needs to hold down the
* appropriate button to enable the accessibility shortcut once it's configured.
*/
- private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1500;
+ private static final int A11Y_SHORTCUT_KEY_TIMEOUT_AFTER_CONFIRMATION = 1000;
/**
* Defines the duration in milliseconds we will wait to see if a touch event
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c29a1da..eb5fc92 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1422,7 +1422,7 @@
* this window is visible.
* @hide
*/
- @RequiresPermission(android.Manifest.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
+ @RequiresPermission(permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS)
public static final int PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS = 0x00080000;
/**
@@ -1443,6 +1443,15 @@
public static final int PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN = 0x00200000;
/**
+ * Flag to indicate that this window should be considered a screen decoration similar to the
+ * nav bar and status bar. This will cause this window to affect the window insets reported
+ * to other windows when it is visible.
+ * @hide
+ */
+ @RequiresPermission(permission.STATUS_BAR_SERVICE)
+ public static final int PRIVATE_FLAG_IS_SCREEN_DECOR = 0x00400000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1526,7 +1535,11 @@
@ViewDebug.FlagToString(
mask = PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN,
equals = PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN,
- name = "ACQUIRES_SLEEP_TOKEN")
+ name = "ACQUIRES_SLEEP_TOKEN"),
+ @ViewDebug.FlagToString(
+ mask = PRIVATE_FLAG_IS_SCREEN_DECOR,
+ equals = PRIVATE_FLAG_IS_SCREEN_DECOR,
+ name = "IS_SCREEN_DECOR")
})
@TestApi
public int privateFlags;
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 69cc100..cd1b190 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.ClipData;
import android.graphics.Rect;
import android.graphics.Region;
import android.hardware.display.DisplayManagerInternal;
@@ -140,6 +141,30 @@
}
/**
+ * An interface to customize drag and drop behaviors.
+ */
+ public interface IDragDropCallback {
+ /**
+ * Called when drag operation is started.
+ */
+ default boolean performDrag(IWindow window, IBinder dragToken,
+ int touchSource, float touchX, float touchY, float thumbCenterX, float thumbCenterY,
+ ClipData data) {
+ return true;
+ }
+
+ /**
+ * Called when drop result is reported.
+ */
+ default void reportDropResult(IWindow window, boolean consumed) {}
+
+ /**
+ * Called when drag operation is cancelled.
+ */
+ default void cancelDragAndDrop(IBinder dragToken) {}
+ }
+
+ /**
* Request that the window manager call
* {@link DisplayManagerInternal#performTraversalInTransactionFromWindowManager}
* within a surface transaction at a later time.
@@ -225,9 +250,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.
*/
@@ -354,4 +376,9 @@
* {@param vr2dDisplayId}.
*/
public abstract void setVr2dDisplayId(int vr2dDisplayId);
+
+ /**
+ * Sets callback to DragDropController.
+ */
+ public abstract void registerDragDropControllerCallback(IDragDropCallback callback);
}
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 137e551..ebe3633 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -758,7 +758,8 @@
* @param attrs The window layout parameters to be modified. These values
* are modified in-place.
*/
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs);
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission);
/**
* After the window manager has computed the current configuration based
@@ -1172,13 +1173,13 @@
/**
* Called when layout of the windows is about to start.
*
- * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}.
+ * @param displayId Id of the display we are doing layout on.
* @param displayWidth The current full width of the screen.
* @param displayHeight The current full height of the screen.
* @param displayRotation The current rotation being applied to the base window.
* @param uiMode The current uiMode in configuration.
*/
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
+ public void beginLayoutLw(int displayId, int displayWidth, int displayHeight,
int displayRotation, int uiMode);
/**
diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
index 19213ca..c3d6c69 100644
--- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java
+++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java
@@ -187,8 +187,11 @@
Log.i(LOG_TAG, "Window cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
- window = connection.getWindow(accessibilityWindowId);
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ window = connection.getWindow(accessibilityWindowId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (window != null) {
sAccessibilityCache.addWindow(window);
return window;
@@ -225,8 +228,11 @@
Log.i(LOG_TAG, "Windows cache miss");
}
final long identityToken = Binder.clearCallingIdentity();
- windows = connection.getWindows();
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ windows = connection.getWindows();
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (windows != null) {
sAccessibilityCache.setWindows(windows);
return windows;
@@ -283,10 +289,14 @@
}
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId(
- accessibilityWindowId, accessibilityNodeId, interactionId, this,
- prefetchFlags, Thread.currentThread().getId(), arguments);
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfoByAccessibilityId(
+ accessibilityWindowId, accessibilityNodeId, interactionId, this,
+ prefetchFlags, Thread.currentThread().getId(), arguments);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -333,10 +343,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByViewId(
- accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfosByViewId(
+ accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -381,10 +396,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findAccessibilityNodeInfosByText(
- accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findAccessibilityNodeInfosByText(
+ accessibilityWindowId, accessibilityNodeId, text, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear(
interactionId);
@@ -428,10 +448,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.findFocus(accessibilityWindowId,
- accessibilityNodeId, focusType, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.findFocus(accessibilityWindowId,
+ accessibilityNodeId, focusType, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
@@ -472,10 +497,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.focusSearch(accessibilityWindowId,
- accessibilityNodeId, direction, interactionId, this,
- Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.focusSearch(accessibilityWindowId,
+ accessibilityNodeId, direction, interactionId, this,
+ Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear(
interactionId);
@@ -515,10 +545,15 @@
if (connection != null) {
final int interactionId = mInteractionIdCounter.getAndIncrement();
final long identityToken = Binder.clearCallingIdentity();
- final boolean success = connection.performAccessibilityAction(
- accessibilityWindowId, accessibilityNodeId, action, arguments,
- interactionId, this, Thread.currentThread().getId());
- Binder.restoreCallingIdentity(identityToken);
+ final boolean success;
+ try {
+ success = connection.performAccessibilityAction(
+ accessibilityWindowId, accessibilityNodeId, action, arguments,
+ interactionId, this, Thread.currentThread().getId());
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
+
if (success) {
return getPerformAccessibilityActionResultAndClear(interactionId);
}
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 0b9bc57..35f6acb 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -436,8 +436,11 @@
// client using it is called through Binder from another process. Example: MMS
// app adds a SMS notification and the NotificationManagerService calls this method
long identityToken = Binder.clearCallingIdentity();
- service.sendAccessibilityEvent(event, userId);
- Binder.restoreCallingIdentity(identityToken);
+ try {
+ service.sendAccessibilityEvent(event, userId);
+ } finally {
+ Binder.restoreCallingIdentity(identityToken);
+ }
if (DEBUG) {
Log.i(LOG_TAG, event + " sent");
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 6a0669b..a56f86d 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1897,7 +1897,7 @@
public abstract static class AutofillCallback {
/** @hide */
- @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN})
+ @IntDef({EVENT_INPUT_SHOWN, EVENT_INPUT_HIDDEN, EVENT_INPUT_UNAVAILABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface AutofillEventType {}
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 26d2141..2779aa2 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
+import android.os.LocaleList;
import android.view.View.OnClickListener;
import android.view.textclassifier.TextClassifier.EntityType;
@@ -438,4 +439,31 @@
mLogType, mVersionInfo);
}
}
+
+ /**
+ * TextClassification optional input parameters.
+ */
+ public static final class Options {
+
+ private LocaleList mDefaultLocales;
+
+ /**
+ * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+ * the provided text. If no locale preferences exist, set this to null or an empty
+ * locale list.
+ */
+ public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+ mDefaultLocales = defaultLocales;
+ return this;
+ }
+
+ /**
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
+ */
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
+ }
+ }
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 46dbd0e..aeb8489 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -56,23 +56,7 @@
* No-op TextClassifier.
* This may be used to turn off TextClassifier features.
*/
- TextClassifier NO_OP = new TextClassifier() {
-
- @Override
- public TextSelection suggestSelection(
- CharSequence text,
- int selectionStartIndex,
- int selectionEndIndex,
- LocaleList defaultLocales) {
- return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
- }
-
- @Override
- public TextClassification classifyText(
- CharSequence text, int startIndex, int endIndex, LocaleList defaultLocales) {
- return TextClassification.EMPTY;
- }
- };
+ TextClassifier NO_OP = new TextClassifier() {};
/**
* Returns suggested text selection start and end indices, recognized entity types, and their
@@ -82,21 +66,34 @@
* by the sub sequence starting at selectionStartIndex and ending at selectionEndIndex)
* @param selectionStartIndex start index of the selected part of text
* @param selectionEndIndex end index of the selected part of text
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; selectionStartIndex is negative;
* selectionEndIndex is greater than text.length() or not greater than selectionStartIndex
*/
@WorkerThread
@NonNull
- TextSelection suggestSelection(
+ default TextSelection suggestSelection(
@NonNull CharSequence text,
@IntRange(from = 0) int selectionStartIndex,
@IntRange(from = 0) int selectionEndIndex,
- @Nullable LocaleList defaultLocales);
+ @Nullable TextSelection.Options options) {
+ return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ }
+
+ /**
+ * @see #suggestSelection(CharSequence, int, int, TextSelection.Options)
+ */
+ // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextSelection suggestSelection(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int selectionStartIndex,
+ @IntRange(from = 0) int selectionEndIndex,
+ @Nullable LocaleList defaultLocales) {
+ return new TextSelection.Builder(selectionStartIndex, selectionEndIndex).build();
+ }
/**
* Classifies the specified text and returns a {@link TextClassification} object that can be
@@ -106,41 +103,48 @@
* by the sub sequence starting at startIndex and ending at endIndex)
* @param startIndex start index of the text to classify
* @param endIndex end index of the text to classify
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options optional input parameters
*
* @throws IllegalArgumentException if text is null; startIndex is negative;
* endIndex is greater than text.length() or not greater than startIndex
*/
@WorkerThread
@NonNull
- TextClassification classifyText(
+ default TextClassification classifyText(
@NonNull CharSequence text,
@IntRange(from = 0) int startIndex,
@IntRange(from = 0) int endIndex,
- @Nullable LocaleList defaultLocales);
+ @Nullable TextClassification.Options options) {
+ return TextClassification.EMPTY;
+ }
/**
- * Returns a {@link LinksInfo} that may be applied to the text to annotate it with links
+ * @see #classifyText(CharSequence, int, int, TextClassification.Options)
+ */
+ // TODO: Consider deprecating (b/68846316)
+ @WorkerThread
+ @NonNull
+ default TextClassification classifyText(
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int startIndex,
+ @IntRange(from = 0) int endIndex,
+ @Nullable LocaleList defaultLocales) {
+ return TextClassification.EMPTY;
+ }
+
+ /**
+ * 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 linkMask See {@link android.text.util.Linkify} for a list of linkMasks that may be
- * specified. Subclasses of this interface may specify additional linkMasks
- * @param defaultLocales ordered list of locale preferences that can be used to disambiguate
- * the provided text. If no locale preferences exist, set this to null or an empty locale
- * list in which case the classifier will decide whether to use no locale information, use
- * a default locale, or use the system default.
+ * @param options configuration for link generation. If null, defaults will be used.
*
* @throws IllegalArgumentException if text is null
- * @hide
*/
@WorkerThread
- default LinksInfo getLinks(
- @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
- return LinksInfo.NO_OP;
+ default TextLinks generateLinks(
+ @NonNull CharSequence text, @Nullable TextLinks.Options options) {
+ return new TextLinks.Builder(text.toString()).build();
}
/**
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 1c07be4..107013a 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -30,13 +30,8 @@
import android.provider.Browser;
import android.provider.ContactsContract;
import android.provider.Settings;
-import android.text.Spannable;
-import android.text.TextUtils;
-import android.text.method.WordIterator;
-import android.text.style.ClickableSpan;
import android.text.util.Linkify;
import android.util.Patterns;
-import android.view.View;
import android.widget.TextViewMetrics;
import com.android.internal.annotations.GuardedBy;
@@ -46,13 +41,8 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.text.BreakIterator;
import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -100,16 +90,24 @@
@Override
public TextSelection suggestSelection(
@NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
- @Nullable LocaleList defaultLocales) {
+ @Nullable TextSelection.Options options) {
validateInput(text, selectionStartIndex, selectionEndIndex);
try {
if (text.length() > 0) {
- final SmartSelection smartSelection = getSmartSelection(defaultLocales);
+ final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
+ final SmartSelection smartSelection = getSmartSelection(locales);
final String string = text.toString();
- final int[] startEnd = smartSelection.suggest(
- string, selectionStartIndex, selectionEndIndex);
- final int start = startEnd[0];
- final int end = startEnd[1];
+ final int start;
+ final int end;
+ if (getSettings().isDarkLaunch() && !options.isDarkLaunchAllowed()) {
+ start = selectionStartIndex;
+ end = selectionEndIndex;
+ } else {
+ final int[] startEnd = smartSelection.suggest(
+ string, selectionStartIndex, selectionEndIndex);
+ start = startEnd[0];
+ end = startEnd[1];
+ }
if (start <= end
&& start >= 0 && end <= string.length()
&& start <= selectionStartIndex && end >= selectionEndIndex) {
@@ -139,18 +137,27 @@
}
// Getting here means something went wrong, return a NO_OP result.
return TextClassifier.NO_OP.suggestSelection(
- text, selectionStartIndex, selectionEndIndex, defaultLocales);
+ text, selectionStartIndex, selectionEndIndex, options);
+ }
+
+ @Override
+ public TextSelection suggestSelection(
+ @NonNull CharSequence text, int selectionStartIndex, int selectionEndIndex,
+ @Nullable LocaleList defaultLocales) {
+ return suggestSelection(text, selectionStartIndex, selectionEndIndex,
+ new TextSelection.Options().setDefaultLocales(defaultLocales));
}
@Override
public TextClassification classifyText(
@NonNull CharSequence text, int startIndex, int endIndex,
- @Nullable LocaleList defaultLocales) {
+ @Nullable TextClassification.Options options) {
validateInput(text, startIndex, endIndex);
try {
if (text.length() > 0) {
final String string = text.toString();
- SmartSelection.ClassificationResult[] results = getSmartSelection(defaultLocales)
+ final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
+ final SmartSelection.ClassificationResult[] results = getSmartSelection(locales)
.classifyText(string, startIndex, endIndex,
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
@@ -165,23 +172,41 @@
Log.e(LOG_TAG, "Error getting text classification info.", t);
}
// Getting here means something went wrong, return a NO_OP result.
- return TextClassifier.NO_OP.classifyText(
- text, startIndex, endIndex, defaultLocales);
+ return TextClassifier.NO_OP.classifyText(text, startIndex, endIndex, options);
}
@Override
- public LinksInfo getLinks(
- @NonNull CharSequence text, int linkMask, @Nullable LocaleList defaultLocales) {
- Preconditions.checkArgument(text != null);
+ public TextClassification classifyText(
+ @NonNull CharSequence text, int startIndex, int endIndex,
+ @Nullable LocaleList defaultLocales) {
+ return classifyText(text, startIndex, endIndex,
+ new TextClassification.Options().setDefaultLocales(defaultLocales));
+ }
+
+ @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 {
- return LinksInfoFactory.create(
- mContext, getSmartSelection(defaultLocales), text.toString(), linkMask);
+ 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);
}
- // Getting here means something went wrong, return a NO_OP result.
- return TextClassifier.NO_OP.getLinks(text, linkMask, defaultLocales);
+ return builder.build();
}
@Override
@@ -466,180 +491,6 @@
}
/**
- * Detects and creates links for specified text.
- */
- private static final class LinksInfoFactory {
-
- private LinksInfoFactory() {}
-
- public static LinksInfo create(
- Context context, SmartSelection smartSelection, String text, int linkMask) {
- final WordIterator wordIterator = new WordIterator();
- wordIterator.setCharSequence(text, 0, text.length());
- final List<SpanSpec> spans = new ArrayList<>();
- int start = 0;
- int end;
- while ((end = wordIterator.nextBoundary(start)) != BreakIterator.DONE) {
- final String token = text.substring(start, end);
- if (TextUtils.isEmpty(token)) {
- continue;
- }
-
- final int[] selection = smartSelection.suggest(text, start, end);
- final int selectionStart = selection[0];
- final int selectionEnd = selection[1];
- if (selectionStart >= 0 && selectionEnd <= text.length()
- && selectionStart <= selectionEnd) {
- final SmartSelection.ClassificationResult[] results =
- smartSelection.classifyText(
- text, selectionStart, selectionEnd,
- getHintFlags(text, selectionStart, selectionEnd));
- if (results.length > 0) {
- final String type = getHighestScoringType(results);
- if (matches(type, linkMask)) {
- // For links without disambiguation, we simply use the default intent.
- final List<Intent> intents = IntentFactory.create(
- context, type, text.substring(selectionStart, selectionEnd));
- if (!intents.isEmpty() && hasActivityHandler(context, intents.get(0))) {
- final ClickableSpan span = createSpan(context, intents.get(0));
- spans.add(new SpanSpec(selectionStart, selectionEnd, span));
- }
- }
- }
- }
- start = end;
- }
- return new LinksInfoImpl(text, avoidOverlaps(spans, text));
- }
-
- /**
- * Returns true if the classification type matches the specified linkMask.
- */
- private static boolean matches(String type, int linkMask) {
- type = type.trim().toLowerCase(Locale.ENGLISH);
- if ((linkMask & Linkify.PHONE_NUMBERS) != 0
- && TextClassifier.TYPE_PHONE.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.EMAIL_ADDRESSES) != 0
- && TextClassifier.TYPE_EMAIL.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.MAP_ADDRESSES) != 0
- && TextClassifier.TYPE_ADDRESS.equals(type)) {
- return true;
- }
- if ((linkMask & Linkify.WEB_URLS) != 0
- && TextClassifier.TYPE_URL.equals(type)) {
- return true;
- }
- return false;
- }
-
- /**
- * Trim the number of spans so that no two spans overlap.
- *
- * This algorithm first ensures that there is only one span per start index, then it
- * makes sure that no two spans overlap.
- */
- private static List<SpanSpec> avoidOverlaps(List<SpanSpec> spans, String text) {
- Collections.sort(spans, Comparator.comparingInt(span -> span.mStart));
- // Group spans by start index. Take the longest span.
- final Map<Integer, SpanSpec> reps = new LinkedHashMap<>(); // order matters.
- final int size = spans.size();
- for (int i = 0; i < size; i++) {
- final SpanSpec span = spans.get(i);
- final LinksInfoFactory.SpanSpec rep = reps.get(span.mStart);
- if (rep == null || rep.mEnd < span.mEnd) {
- reps.put(span.mStart, span);
- }
- }
- // Avoid span intersections. Take the longer span.
- final LinkedList<SpanSpec> result = new LinkedList<>();
- for (SpanSpec rep : reps.values()) {
- if (result.isEmpty()) {
- result.add(rep);
- continue;
- }
-
- final SpanSpec last = result.getLast();
- if (rep.mStart < last.mEnd) {
- // Spans intersect. Use the one with characters.
- if ((rep.mEnd - rep.mStart) > (last.mEnd - last.mStart)) {
- result.set(result.size() - 1, rep);
- }
- } else {
- result.add(rep);
- }
- }
- return result;
- }
-
- private static ClickableSpan createSpan(final Context context, final Intent intent) {
- return new ClickableSpan() {
- // TODO: Style this span.
- @Override
- public void onClick(View widget) {
- context.startActivity(intent);
- }
- };
- }
-
- private static boolean hasActivityHandler(Context context, Intent intent) {
- if (intent == null) {
- return false;
- }
- final ResolveInfo resolveInfo = context.getPackageManager().resolveActivity(intent, 0);
- return resolveInfo != null && resolveInfo.activityInfo != null;
- }
-
- /**
- * Implementation of LinksInfo that adds ClickableSpans to the specified text.
- */
- private static final class LinksInfoImpl implements LinksInfo {
-
- private final CharSequence mOriginalText;
- private final List<SpanSpec> mSpans;
-
- LinksInfoImpl(CharSequence originalText, List<SpanSpec> spans) {
- mOriginalText = originalText;
- mSpans = spans;
- }
-
- @Override
- public boolean apply(@NonNull CharSequence text) {
- Preconditions.checkArgument(text != null);
- if (text instanceof Spannable && mOriginalText.toString().equals(text.toString())) {
- Spannable spannable = (Spannable) text;
- final int size = mSpans.size();
- for (int i = 0; i < size; i++) {
- final SpanSpec span = mSpans.get(i);
- spannable.setSpan(span.mSpan, span.mStart, span.mEnd, 0);
- }
- return true;
- }
- return false;
- }
- }
-
- /**
- * Span plus its start and end index.
- */
- private static final class SpanSpec {
-
- private final int mStart;
- private final int mEnd;
- private final ClickableSpan mSpan;
-
- SpanSpec(int start, int end, ClickableSpan span) {
- mStart = start;
- mEnd = end;
- mSpan = span;
- }
- }
- }
-
- /**
* Creates intents based on the classification type.
*/
private static final class IntentFactory {
@@ -656,8 +507,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/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 11ebe83..0a67954 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -19,6 +19,8 @@
import android.annotation.FloatRange;
import android.annotation.IntRange;
import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.LocaleList;
import android.view.textclassifier.TextClassifier.EntityType;
import com.android.internal.util.Preconditions;
@@ -181,4 +183,55 @@
mStartIndex, mEndIndex, mEntityConfidence, mLogSource, mVersionInfo);
}
}
+
+ /**
+ * TextSelection optional input parameters.
+ */
+ public static final class Options {
+
+ private LocaleList mDefaultLocales;
+ private boolean mDarkLaunchAllowed;
+
+ /**
+ * @param defaultLocales ordered list of locale preferences that may be used to disambiguate
+ * the provided text. If no locale preferences exist, set this to null or an empty
+ * locale list.
+ */
+ public Options setDefaultLocales(@Nullable LocaleList defaultLocales) {
+ mDefaultLocales = defaultLocales;
+ return this;
+ }
+
+ /**
+ * @return ordered list of locale preferences that can be used to disambiguate
+ * the provided text.
+ */
+ @Nullable
+ public LocaleList getDefaultLocales() {
+ return mDefaultLocales;
+ }
+
+ /**
+ * @param allowed whether or not the TextClassifier should return selection suggestions
+ * when "dark launched". When a TextClassifier is dark launched, it can suggest
+ * selection changes that should not be used to actually change the user's selection.
+ * Instead, the suggested selection is logged, compared with the user's selection
+ * interaction, and used to generate quality metrics for the TextClassifier.
+ *
+ * @hide
+ */
+ public void setDarkLaunchAllowed(boolean allowed) {
+ mDarkLaunchAllowed = allowed;
+ }
+
+ /**
+ * Returns true if the TextClassifier should return selection suggestions when
+ * "dark launched". Otherwise, returns false.
+ *
+ * @hide
+ */
+ public boolean isDarkLaunchAllowed() {
+ return mDarkLaunchAllowed;
+ }
+ }
}
diff --git a/core/java/android/webkit/ServiceWorkerClient.java b/core/java/android/webkit/ServiceWorkerClient.java
index d6e8f36..9124c85 100644
--- a/core/java/android/webkit/ServiceWorkerClient.java
+++ b/core/java/android/webkit/ServiceWorkerClient.java
@@ -29,9 +29,9 @@
* application to return the data. If the return value is {@code null}, the
* Service Worker will continue to load the resource as usual.
* Otherwise, the return response and data will be used.
- * NOTE: This method is called on a thread other than the UI thread
- * so clients should exercise caution when accessing private data
- * or the view system.
+ *
+ * <p class="note"><b>Note:</b> This method is called on a thread other than the UI thread so
+ * clients should exercise caution when accessing private data or the view system.
*
* @param request Object containing the details of the request.
* @return A {@link android.webkit.WebResourceResponse} containing the
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 259bf60..665d694 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -191,7 +191,7 @@
* {@link #getSettings() WebSettings}.{@link WebSettings#setBuiltInZoomControls(boolean)}
* (introduced in API level {@link android.os.Build.VERSION_CODES#CUPCAKE}).
*
- * <p>NOTE: Using zoom if either the height or width is set to
+ * <p class="note"><b>Note:</b> Using zoom if either the height or width is set to
* {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} may lead to undefined behavior
* and should be avoided.
*
@@ -308,10 +308,15 @@
* WebView may upload anonymous diagnostic data to Google when the user has consented. This data
* helps Google improve WebView. Data is collected on a per-app basis for each app which has
* instantiated a WebView. An individual app can opt out of this feature by putting the following
- * tag in its manifest:
+ * tag in its manifest's {@code <application>} element:
* <pre>
- * <meta-data android:name="android.webkit.WebView.MetricsOptOut"
- * android:value="true" />
+ * <manifest>
+ * <application>
+ * ...
+ * <meta-data android:name="android.webkit.WebView.MetricsOptOut"
+ * android:value="true" />
+ * </application>
+ * </manifest>
* </pre>
* <p>
* Data will only be uploaded for a given app if the user has consented AND the app has not opted
@@ -323,11 +328,17 @@
* If Safe Browsing is enabled, WebView will block malicious URLs and present a warning UI to the
* user to allow them to navigate back safely or proceed to the malicious page.
* <p>
- * The recommended way for apps to enable the feature is putting the following tag in the manifest:
+ * The recommended way for apps to enable the feature is putting the following tag in the manifest's
+ * {@code <application>} element:
* <p>
* <pre>
- * <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
- * android:value="true" />
+ * <manifest>
+ * <application>
+ * ...
+ * <meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
+ * android:value="true" />
+ * </application>
+ * </manifest>
* </pre>
*
*/
@@ -536,9 +547,13 @@
}
/**
- * Constructs a new WebView with a Context object.
+ * Constructs a new WebView with an Activity Context object.
*
- * @param context a Context object used to access application assets
+ * <p class="note"><b>Note:</b> WebView should always be instantiated with an Activity Context.
+ * If instantiated with an Application Context, WebView will be unable to provide several
+ * features, such as JavaScript dialogs and autofill.
+ *
+ * @param context an Activity Context to access application assets
*/
public WebView(Context context) {
this(context, null);
@@ -547,7 +562,7 @@
/**
* Constructs a new WebView with layout parameters.
*
- * @param context a Context object used to access application assets
+ * @param context an Activity Context to access application assets
* @param attrs an AttributeSet passed to our parent
*/
public WebView(Context context, AttributeSet attrs) {
@@ -557,7 +572,7 @@
/**
* Constructs a new WebView with layout parameters and a default style.
*
- * @param context a Context object used to access application assets
+ * @param context an Activity Context to access application assets
* @param attrs an AttributeSet passed to our parent
* @param defStyleAttr an attribute in the current theme that contains a
* reference to a style resource that supplies default values for
@@ -570,7 +585,7 @@
/**
* Constructs a new WebView with layout parameters and a default style.
*
- * @param context a Context object used to access application assets
+ * @param context an Activity Context to access application assets
* @param attrs an AttributeSet passed to our parent
* @param defStyleAttr an attribute in the current theme that contains a
* reference to a style resource that supplies default values for
@@ -587,7 +602,7 @@
/**
* Constructs a new WebView with layout parameters and a default style.
*
- * @param context a Context object used to access application assets
+ * @param context an Activity Context to access application assets
* @param attrs an AttributeSet passed to our parent
* @param defStyleAttr an attribute in the current theme that contains a
* reference to a style resource that supplies default values for
@@ -612,7 +627,7 @@
* time. This guarantees that these interfaces will be available when the JS
* context is initialized.
*
- * @param context a Context object used to access application assets
+ * @param context an Activity Context to access application assets
* @param attrs an AttributeSet passed to our parent
* @param defStyleAttr an attribute in the current theme that contains a
* reference to a style resource that supplies default values for
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index c5b64eb..517ad07 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -130,7 +130,7 @@
* <p>This method is called when the body of the HTTP response has started loading, is reflected
* in the DOM, and will be visible in subsequent draws. This callback occurs early in the
* document loading process, and as such you should expect that linked resources (for example,
- * css and images) may not be available.
+ * CSS and images) may not be available.
*
* <p>For more fine-grained notification of visual state updates, see {@link
* WebView#postVisualStateCallback}.
@@ -150,13 +150,15 @@
* Notify the host application of a resource request and allow the
* application to return the data. If the return value is {@code null}, the WebView
* will continue to load the resource as usual. Otherwise, the return
- * response and data will be used. NOTE: This method is called on a thread
+ * response and data will be used.
+ *
+ * <p class="note"><b>Note:</b> This method is called on a thread
* other than the UI thread so clients should exercise caution
* when accessing private data or the view system.
*
- * <p>Note: when Safe Browsing is enabled, these URLs still undergo Safe Browsing checks. If
- * this is undesired, whitelist the URL with {@link WebView#setSafeBrowsingWhitelist} or ignore
- * the warning with {@link #onSafeBrowsingHit}.
+ * <p class="note"><b>Note:</b> When Safe Browsing is enabled, these URLs still undergo Safe
+ * Browsing checks. If this is undesired, whitelist the URL with {@link
+ * WebView#setSafeBrowsingWhitelist} or ignore the warning with {@link #onSafeBrowsingHit}.
*
* @param view The {@link android.webkit.WebView} that is requesting the
* resource.
@@ -178,13 +180,15 @@
* Notify the host application of a resource request and allow the
* application to return the data. If the return value is {@code null}, the WebView
* will continue to load the resource as usual. Otherwise, the return
- * response and data will be used. NOTE: This method is called on a thread
+ * response and data will be used.
+ *
+ * <p class="note"><b>Note:</b> This method is called on a thread
* other than the UI thread so clients should exercise caution
* when accessing private data or the view system.
*
- * <p>Note: when Safe Browsing is enabled, these URLs still undergo Safe Browsing checks. If
- * this is undesired, whitelist the URL with {@link WebView#setSafeBrowsingWhitelist} or ignore
- * the warning with {@link #onSafeBrowsingHit}.
+ * <p class="note"><b>Note:</b> When Safe Browsing is enabled, these URLs still undergo Safe
+ * Browsing checks. If this is undesired, whitelist the URL with {@link
+ * WebView#setSafeBrowsingWhitelist} or ignore the warning with {@link #onSafeBrowsingHit}.
*
* @param view The {@link android.webkit.WebView} that is requesting the
* resource.
@@ -248,7 +252,7 @@
public static final int ERROR_FILE_NOT_FOUND = -14;
/** Too many requests during this load */
public static final int ERROR_TOO_MANY_REQUESTS = -15;
- /** Resource load was cancelled by Safe Browsing */
+ /** Resource load was canceled by Safe Browsing */
public static final int ERROR_UNSAFE_RESOURCE = -16;
/** @hide */
@@ -272,8 +276,8 @@
/**
* Report an error to the host application. These errors are unrecoverable
- * (i.e. the main resource is unavailable). The errorCode parameter
- * corresponds to one of the ERROR_* constants.
+ * (i.e. the main resource is unavailable). The {@code errorCode} parameter
+ * corresponds to one of the {@code ERROR_*} constants.
* @param view The WebView that is initiating the callback.
* @param errorCode The error code corresponding to an ERROR_* value.
* @param description A String describing the error.
@@ -289,11 +293,11 @@
/**
* Report web resource loading error to the host application. These errors usually indicate
* inability to connect to the server. Note that unlike the deprecated version of the callback,
- * the new version will be called for any resource (iframe, image, etc), not just for the main
+ * the new version will be called for any resource (iframe, image, etc.), not just for the main
* page. Thus, it is recommended to perform minimum required work in this callback.
* @param view The WebView that is initiating the callback.
* @param request The originating request.
- * @param error Information about the error occured.
+ * @param error Information about the error occurred.
*/
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
if (request.isForMainFrame()) {
@@ -306,12 +310,12 @@
/**
* Notify the host application that an HTTP error has been received from the server while
* loading a resource. HTTP errors have status codes >= 400. This callback will be called
- * for any resource (iframe, image, etc), not just for the main page. Thus, it is recommended to
- * perform minimum required work in this callback. Note that the content of the server
- * response may not be provided within the <b>errorResponse</b> parameter.
+ * for any resource (iframe, image, etc.), not just for the main page. Thus, it is recommended
+ * to perform minimum required work in this callback. Note that the content of the server
+ * response may not be provided within the {@code errorResponse} parameter.
* @param view The WebView that is initiating the callback.
* @param request The originating request.
- * @param errorResponse Information about the error occured.
+ * @param errorResponse Information about the error occurred.
*/
public void onReceivedHttpError(
WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
@@ -365,7 +369,7 @@
* if desired and providing the keys. There are three ways to
* respond: proceed(), cancel() or ignore(). Webview stores the response
* in memory (for the life of the application) if proceed() or cancel() is
- * called and does not call onReceivedClientCertRequest() again for the
+ * called and does not call {@code onReceivedClientCertRequest()} again for the
* same host and port pair. Webview does not store the response if ignore()
* is called. Note that, multiple layers in chromium network stack might be
* caching the responses, so the behavior for ignore is only a best case
@@ -432,7 +436,7 @@
/**
* Notify the host application that a key was not handled by the WebView.
* Except system keys, WebView always consumes the keys in the normal flow
- * or if shouldOverrideKeyEvent returns {@code true}. This is called asynchronously
+ * or if {@link #shouldOverrideKeyEvent} returns {@code true}. This is called asynchronously
* from where the key is dispatched. It gives the host application a chance
* to handle the unhandled key events.
*
@@ -446,7 +450,7 @@
/**
* Notify the host application that a input event was not handled by the WebView.
* Except system keys, WebView always consumes input events in the normal flow
- * or if shouldOverrideKeyEvent returns {@code true}. This is called asynchronously
+ * or if {@link #shouldOverrideKeyEvent} returns {@code true}. This is called asynchronously
* from where the event is dispatched. It gives the host application a chance
* to handle the unhandled input events.
*
@@ -503,7 +507,7 @@
}
/**
- * Notify host application that the given webview's render process has exited.
+ * Notify host application that the given WebView's render process has exited.
*
* Multiple WebView instances may be associated with a single render process;
* onRenderProcessGone will be called for each WebView that was affected.
@@ -513,10 +517,10 @@
*
* The given WebView can't be used, and should be removed from the view hierarchy,
* all references to it should be cleaned up, e.g any references in the Activity
- * or other classes saved using findViewById and similar calls, etc
+ * or other classes saved using {@link android.view.View#findViewById} and similar calls, etc.
*
* To cause an render process crash for test purpose, the application can
- * call loadUrl("chrome://crash") on the WebView. Note that multiple WebView
+ * call {@code loadUrl("chrome://crash")} on the WebView. Note that multiple WebView
* instances may be affected if they share a render process, not just the
* specific WebView which loaded chrome://crash.
*
@@ -537,12 +541,13 @@
* behavior is to show an interstitial to the user, with the reporting checkbox visible.
*
* If the application needs to show its own custom interstitial UI, the callback can be invoked
- * asynchronously with backToSafety() or proceed(), depending on user response.
+ * asynchronously with {@link SafeBrowsingResponse#backToSafety} or {@link
+ * SafeBrowsingResponse#proceed}, depending on user response.
*
* @param view The WebView that hit the malicious resource.
* @param request Object containing the details of the request.
* @param threatType The reason the resource was caught by Safe Browsing, corresponding to a
- * SAFE_BROWSING_THREAT_* value.
+ * {@code SAFE_BROWSING_THREAT_*} value.
* @param callback Applications must invoke one of the callback methods.
*/
public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
index 341c69f..de0b97d 100644
--- a/core/java/android/webkit/WebViewLibraryLoader.java
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -229,7 +229,9 @@
/**
* Load WebView's native library into the current process.
- * Note: assumes that we have waited for relro creation.
+ *
+ * <p class="note"><b>Note:</b> Assumes that we have waited for relro creation.
+ *
* @param clazzLoader class loader used to find the linker namespace to load the library into.
* @param packageInfo the package from which WebView is loaded.
*/
diff --git a/core/java/android/webkit/WebViewProvider.java b/core/java/android/webkit/WebViewProvider.java
index c46c681..a896925 100644
--- a/core/java/android/webkit/WebViewProvider.java
+++ b/core/java/android/webkit/WebViewProvider.java
@@ -316,7 +316,7 @@
/**
* Provides mechanism for the name-sake methods declared in View and ViewGroup to be delegated
* into the WebViewProvider instance.
- * NOTE For many of these methods, the WebView will provide a super.Foo() call before or after
+ * NOTE: For many of these methods, the WebView will provide a super.Foo() call before or after
* making the call into the provider instance. This is done for convenience in the common case
* of maintaining backward compatibility. For remaining super class calls (e.g. where the
* provider may need to only conditionally make the call based on some internal state) see the
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/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 5e22650..71854ae 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -20,10 +20,12 @@
import android.annotation.Nullable;
import android.annotation.UiThread;
import android.annotation.WorkerThread;
+import android.content.Context;
import android.graphics.Canvas;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.AsyncTask;
+import android.os.Build;
import android.os.LocaleList;
import android.text.Layout;
import android.text.Selection;
@@ -81,6 +83,7 @@
mEditor = Preconditions.checkNotNull(editor);
mTextView = mEditor.getTextView();
mTextClassificationHelper = new TextClassificationHelper(
+ mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
0, 1, mTextView.getTextLocales());
@@ -385,6 +388,7 @@
private void resetTextClassificationHelper() {
mTextClassificationHelper.init(
+ mTextView.getContext(),
mTextView.getTextClassifier(),
getText(mTextView),
mTextView.getSelectionStart(), mTextView.getSelectionEnd(),
@@ -787,6 +791,7 @@
private static final int TRIM_DELTA = 120; // characters
+ private Context mContext;
private TextClassifier mTextClassifier;
/** The original TextView text. **/
@@ -795,7 +800,10 @@
private int mSelectionStart;
/** End index relative to mText. */
private int mSelectionEnd;
- private LocaleList mLocales;
+
+ private final TextSelection.Options mSelectionOptions = new TextSelection.Options();
+ private final TextClassification.Options mClassificationOptions =
+ new TextClassification.Options();
/** Trimmed text starting from mTrimStart in mText. */
private CharSequence mTrimmedText;
@@ -816,21 +824,24 @@
/** Whether the TextClassifier has been initialized. */
private boolean mHot;
- TextClassificationHelper(TextClassifier textClassifier,
+ TextClassificationHelper(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
- init(textClassifier, text, selectionStart, selectionEnd, locales);
+ init(context, textClassifier, text, selectionStart, selectionEnd, locales);
}
@UiThread
- public void init(TextClassifier textClassifier,
+ public void init(Context context, TextClassifier textClassifier,
CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
+ mContext = Preconditions.checkNotNull(context);
mTextClassifier = Preconditions.checkNotNull(textClassifier);
mText = Preconditions.checkNotNull(text).toString();
mLastClassificationText = null; // invalidate.
Preconditions.checkArgument(selectionEnd > selectionStart);
mSelectionStart = selectionStart;
mSelectionEnd = selectionEnd;
- mLocales = locales;
+ mClassificationOptions.setDefaultLocales(locales);
+ mSelectionOptions.setDefaultLocales(locales)
+ .setDarkLaunchAllowed(true);
}
@WorkerThread
@@ -843,8 +854,16 @@
public SelectionResult suggestSelection() {
mHot = true;
trimText();
- final TextSelection selection = mTextClassifier.suggestSelection(
- mTrimmedText, mRelativeStart, mRelativeEnd, mLocales);
+ final TextSelection selection;
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
+ selection = mTextClassifier.suggestSelection(
+ mTrimmedText, mRelativeStart, mRelativeEnd, mSelectionOptions);
+ } else {
+ // Use old APIs.
+ selection = mTextClassifier.suggestSelection(
+ mTrimmedText, mRelativeStart, mRelativeEnd,
+ mSelectionOptions.getDefaultLocales());
+ }
// Do not classify new selection boundaries if TextClassifier should be dark launched.
if (!mTextClassifier.getSettings().isDarkLaunch()) {
mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
@@ -874,20 +893,28 @@
if (!Objects.equals(mText, mLastClassificationText)
|| mSelectionStart != mLastClassificationSelectionStart
|| mSelectionEnd != mLastClassificationSelectionEnd
- || !Objects.equals(mLocales, mLastClassificationLocales)) {
+ || !Objects.equals(
+ mClassificationOptions.getDefaultLocales(),
+ mLastClassificationLocales)) {
mLastClassificationText = mText;
mLastClassificationSelectionStart = mSelectionStart;
mLastClassificationSelectionEnd = mSelectionEnd;
- mLastClassificationLocales = mLocales;
+ mLastClassificationLocales = mClassificationOptions.getDefaultLocales();
trimText();
+ final TextClassification classification;
+ if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.O_MR1) {
+ classification = mTextClassifier.classifyText(
+ mTrimmedText, mRelativeStart, mRelativeEnd, mClassificationOptions);
+ } else {
+ // Use old APIs.
+ classification = mTextClassifier.classifyText(
+ mTrimmedText, mRelativeStart, mRelativeEnd,
+ mClassificationOptions.getDefaultLocales());
+ }
mLastClassificationResult = new SelectionResult(
- mSelectionStart,
- mSelectionEnd,
- mTextClassifier.classifyText(
- mTrimmedText, mRelativeStart, mRelativeEnd, mLocales),
- selection);
+ mSelectionStart, mSelectionEnd, classification, selection);
}
return mLastClassificationResult;
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index e6ef10b..71baaf1 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -51,9 +51,11 @@
private static final boolean DEBUG = true;
+ public static final int THRESHOLD_COLOR_LIGHT = 0xffe0e0e0;
public static final int MAIN_COLOR_LIGHT = 0xffe0e0e0;
public static final int SECONDARY_COLOR_LIGHT = 0xff9e9e9e;
- public static final int MAIN_COLOR_DARK = 0xff212121;
+ public static final int THRESHOLD_COLOR_DARK = 0xff212121;
+ public static final int MAIN_COLOR_DARK = 0xff000000;
public static final int SECONDARY_COLOR_DARK = 0xff000000;
private final TonalPalette mGreyPalette;
@@ -197,12 +199,12 @@
// light fallback or darker than our dark fallback.
ColorUtils.colorToHSL(mainColor, mTmpHSL);
final float mainLuminosity = mTmpHSL[2];
- ColorUtils.colorToHSL(MAIN_COLOR_LIGHT, mTmpHSL);
+ ColorUtils.colorToHSL(THRESHOLD_COLOR_LIGHT, mTmpHSL);
final float lightLuminosity = mTmpHSL[2];
if (mainLuminosity > lightLuminosity) {
return false;
}
- ColorUtils.colorToHSL(MAIN_COLOR_DARK, mTmpHSL);
+ ColorUtils.colorToHSL(THRESHOLD_COLOR_DARK, mTmpHSL);
final float darkLuminosity = mTmpHSL[2];
if (mainLuminosity < darkLuminosity) {
return false;
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
similarity index 68%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to core/java/com/android/internal/net/INetworkWatchlistManager.aidl
index e28e1b3..7e88369 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/core/java/com/android/internal/net/INetworkWatchlistManager.aidl
@@ -11,16 +11,16 @@
* 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
+ * limitations under the License.
*/
-package android.telephony.ims.feature;
+package com.android.internal.net;
-/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
- * @hide
- */
+import android.os.SharedMemory;
-public interface IRcsFeature {
+/** {@hide} */
+interface INetworkWatchlistManager {
+ boolean startWatchlistLogging();
+ boolean stopWatchlistLogging();
+ void reportWatchlistIfNecessary();
}
diff --git a/core/java/com/android/internal/os/BaseCommand.java b/core/java/com/android/internal/os/BaseCommand.java
index 3baccee..05ec9e9 100644
--- a/core/java/com/android/internal/os/BaseCommand.java
+++ b/core/java/com/android/internal/os/BaseCommand.java
@@ -106,6 +106,14 @@
}
/**
+ * Peek the next argument on the command line, whatever it is; if there are
+ * no arguments left, return null.
+ */
+ public String peekNextArg() {
+ return mArgs.peekNextArg();
+ }
+
+ /**
* Return the next argument on the command line, whatever it is; if there are
* no arguments left, throws an IllegalArgumentException to report this to the user.
*/
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index f0d05da..2ec64a5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -5412,6 +5412,18 @@
}
}
+ public String[] getWifiIfaces() {
+ synchronized (mWifiNetworkLock) {
+ return mWifiIfaces;
+ }
+ }
+
+ public String[] getMobileIfaces() {
+ synchronized (mModemNetworkLock) {
+ return mModemIfaces;
+ }
+ }
+
@Override public long getScreenOnTime(long elapsedRealtimeUs, int which) {
return mScreenOnTimer.getTotalTimeLocked(elapsedRealtimeUs, which);
}
@@ -9614,7 +9626,8 @@
}
public boolean isScreenOn(int state) {
- return state == Display.STATE_ON || state == Display.STATE_VR;
+ return state == Display.STATE_ON || state == Display.STATE_VR
+ || state == Display.STATE_ON_SUSPEND;
}
public boolean isScreenOff(int state) {
diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
index 8884d24..a39997d 100644
--- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.util.IntArray;
import android.util.Slog;
@@ -82,6 +83,7 @@
if (!mProcFileAvailable && mReadErrorCounter >= TOTAL_READ_ERROR_COUNT) {
return null;
}
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
mProcFileAvailable = true;
return readFreqs(reader, powerProfile);
@@ -89,6 +91,8 @@
mReadErrorCounter++;
Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
return null;
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
}
@@ -106,12 +110,15 @@
if (!mProcFileAvailable) {
return;
}
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) {
mNowTimeMs = SystemClock.elapsedRealtime();
readDelta(reader, callback);
mLastTimeReadMs = mNowTimeMs;
} catch (IOException e) {
Slog.e(TAG, "Failed to read " + UID_TIMES_PROC_FILE + ": " + e);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
}
diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
index 37d9d1d..65615c0 100644
--- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
+++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java
@@ -16,6 +16,7 @@
package com.android.internal.os;
import android.annotation.Nullable;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Slog;
@@ -65,6 +66,7 @@
* a fresh delta.
*/
public void readDelta(@Nullable Callback callback) {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
long nowUs = SystemClock.elapsedRealtime() * 1000;
try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) {
TextUtils.SimpleStringSplitter splitter = new TextUtils.SimpleStringSplitter(' ');
@@ -121,6 +123,8 @@
}
} catch (IOException e) {
Slog.e(TAG, "Failed to read uid_cputime: " + e.getMessage());
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
mLastTimeReadUs = nowUs;
}
@@ -160,12 +164,15 @@
private void removeUidsFromKernelModule(int startUid, int endUid) {
Slog.d(TAG, "Removing uids " + startUid + "-" + endUid);
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
try (FileWriter writer = new FileWriter(sRemoveUidProcFile)) {
writer.write(startUid + "-" + endUid);
writer.flush();
} catch (IOException e) {
Slog.e(TAG, "failed to remove uids " + startUid + " - " + endUid
+ " from uid_cputime module", e);
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
}
}
}
diff --git a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
index fb6b8b0..3af3e2a 100644
--- a/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
+++ b/core/java/com/android/internal/policy/DividerSnapAlgorithm.java
@@ -16,6 +16,10 @@
package com.android.internal.policy;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_LEFT;
+import static android.view.WindowManager.DOCKED_RIGHT;
+
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -99,11 +103,12 @@
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
boolean isHorizontalDivision, Rect insets) {
- this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets, false);
+ this(res, displayWidth, displayHeight, dividerSize, isHorizontalDivision, insets,
+ DOCKED_INVALID, false);
}
public DividerSnapAlgorithm(Resources res, int displayWidth, int displayHeight, int dividerSize,
- boolean isHorizontalDivision, Rect insets, boolean isMinimizedMode) {
+ boolean isHorizontalDivision, Rect insets, int dockSide, boolean isMinimizedMode) {
mMinFlingVelocityPxPerSecond =
MIN_FLING_VELOCITY_DP_PER_SECOND * res.getDisplayMetrics().density;
mMinDismissVelocityPxPerSecond =
@@ -121,7 +126,7 @@
com.android.internal.R.dimen.default_minimal_size_resizable_task);
mTaskHeightInMinimizedMode = res.getDimensionPixelSize(
com.android.internal.R.dimen.task_height_of_minimized_mode);
- calculateTargets(isHorizontalDivision);
+ calculateTargets(isHorizontalDivision, dockSide);
mFirstSplitTarget = mTargets.get(1);
mLastSplitTarget = mTargets.get(mTargets.size() - 2);
mDismissStartTarget = mTargets.get(0);
@@ -254,7 +259,7 @@
return mTargets.get(minIndex);
}
- private void calculateTargets(boolean isHorizontalDivision) {
+ private void calculateTargets(boolean isHorizontalDivision, int dockedSide) {
mTargets.clear();
int dividerMax = isHorizontalDivision
? mDisplayHeight
@@ -273,7 +278,7 @@
addMiddleTarget(isHorizontalDivision);
break;
case SNAP_MODE_MINIMIZED:
- addMinimizedTarget(isHorizontalDivision);
+ addMinimizedTarget(isHorizontalDivision, dockedSide);
break;
}
mTargets.add(new SnapTarget(dividerMax - navBarSize, dividerMax,
@@ -331,12 +336,16 @@
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
- private void addMinimizedTarget(boolean isHorizontalDivision) {
+ private void addMinimizedTarget(boolean isHorizontalDivision, int dockedSide) {
// In portrait offset the position by the statusbar height, in landscape add the statusbar
// height as well to match portrait offset
int position = mTaskHeightInMinimizedMode + mInsets.top;
if (!isHorizontalDivision) {
- position += mInsets.left;
+ if (dockedSide == DOCKED_LEFT) {
+ position += mInsets.left;
+ } else if (dockedSide == DOCKED_RIGHT) {
+ position = mDisplayWidth - position - mInsets.right;
+ }
}
mTargets.add(new SnapTarget(position, position, SnapTarget.FLAG_NONE));
}
diff --git a/core/java/com/android/internal/widget/ImageFloatingTextView.java b/core/java/com/android/internal/widget/ImageFloatingTextView.java
index 7870333..09f7282 100644
--- a/core/java/com/android/internal/widget/ImageFloatingTextView.java
+++ b/core/java/com/android/internal/widget/ImageFloatingTextView.java
@@ -176,8 +176,4 @@
}
return false;
}
-
- public int getLayoutHeight() {
- return getLayout().getHeight();
- }
}
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
new file mode 100644
index 0000000..792f921
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -0,0 +1,393 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.content.Context;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.util.Pools;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewTreeObserver;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+import com.android.internal.util.NotificationColorUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A message of a {@link MessagingLayout}.
+ */
+@RemoteViews.RemoteView
+public class MessagingGroup extends LinearLayout implements MessagingLinearLayout.MessagingChild {
+ private static Pools.SimplePool<MessagingGroup> sInstancePool
+ = new Pools.SynchronizedPool<>(10);
+ private MessagingLinearLayout mMessageContainer;
+ private ImageFloatingTextView mSenderName;
+ private ImageView mAvatarView;
+ private String mAvatarSymbol = "";
+ private int mLayoutColor;
+ private CharSequence mAvatarName = "";
+ private Icon mAvatarIcon;
+ private ColorFilter mMessageBackgroundFilter;
+ private int mTextColor;
+ private List<MessagingMessage> mMessages;
+ private ArrayList<MessagingMessage> mAddedMessages = new ArrayList<>();
+ private boolean mFirstLayout;
+ private boolean mIsHidingAnimated;
+
+ public MessagingGroup(@NonNull Context context) {
+ super(context);
+ }
+
+ public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MessagingGroup(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mMessageContainer = findViewById(R.id.group_message_container);
+ mSenderName = findViewById(R.id.message_name);
+ mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
+ mAvatarView = findViewById(R.id.message_icon);
+ }
+
+ public void setSender(CharSequence sender) {
+ if (sender == null) {
+ mAvatarView.setVisibility(GONE);
+ mSenderName.setVisibility(GONE);
+ setGravity(Gravity.END);
+ mMessageBackgroundFilter = new PorterDuffColorFilter(mLayoutColor,
+ PorterDuff.Mode.SRC_ATOP);
+ mTextColor = NotificationColorUtil.isColorLight(mLayoutColor) ? getNormalTextColor()
+ : Color.WHITE;
+ } else {
+ mSenderName.setText(sender);
+ mAvatarView.setVisibility(VISIBLE);
+ mSenderName.setVisibility(VISIBLE);
+ setGravity(Gravity.START);
+ mMessageBackgroundFilter = null;
+ mTextColor = getNormalTextColor();
+ }
+ }
+
+ private int getNormalTextColor() {
+ return mContext.getColor(R.color.notification_primary_text_color_light);
+ }
+
+ public void setAvatar(Icon icon) {
+ mAvatarIcon = icon;
+ mAvatarView.setImageIcon(icon);
+ mAvatarSymbol = "";
+ mLayoutColor = 0;
+ mAvatarName = "";
+ }
+
+ static MessagingGroup createGroup(MessagingLinearLayout layout) {;
+ MessagingGroup createdGroup = sInstancePool.acquire();
+ if (createdGroup == null) {
+ createdGroup = (MessagingGroup) LayoutInflater.from(layout.getContext()).inflate(
+ R.layout.notification_template_messaging_group, layout,
+ false);
+ createdGroup.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
+ }
+ layout.addView(createdGroup);
+ return createdGroup;
+ }
+
+ public void removeMessage(MessagingMessage messagingMessage) {
+ mMessageContainer.removeView(messagingMessage);
+ Runnable recycleRunnable = () -> {
+ mMessageContainer.removeTransientView(messagingMessage);
+ messagingMessage.recycle();
+ if (mMessageContainer.getChildCount() == 0
+ && mMessageContainer.getTransientViewCount() == 0) {
+ ViewParent parent = getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(MessagingGroup.this);
+ }
+ setAvatar(null);
+ mAvatarView.setAlpha(1.0f);
+ mAvatarView.setTranslationY(0.0f);
+ mSenderName.setAlpha(1.0f);
+ mSenderName.setTranslationY(0.0f);
+ sInstancePool.release(MessagingGroup.this);
+ }
+ };
+ if (isShown()) {
+ mMessageContainer.addTransientView(messagingMessage, 0);
+ performRemoveAnimation(messagingMessage, recycleRunnable);
+ if (mMessageContainer.getChildCount() == 0) {
+ removeGroupAnimated(null);
+ }
+ } else {
+ recycleRunnable.run();
+ }
+
+ }
+
+ private void removeGroupAnimated(Runnable endAction) {
+ MessagingPropertyAnimator.fadeOut(mAvatarView, null);
+ MessagingPropertyAnimator.startLocalTranslationTo(mAvatarView,
+ (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ MessagingPropertyAnimator.fadeOut(mSenderName, null);
+ MessagingPropertyAnimator.startLocalTranslationTo(mSenderName,
+ (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ boolean endActionTriggered = false;
+ for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
+ View child = mMessageContainer.getChildAt(i);
+ if (child.getVisibility() == View.GONE) {
+ continue;
+ }
+ final ViewGroup.LayoutParams lp = child.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide
+ && !((MessagingLinearLayout.LayoutParams) lp).visibleBefore) {
+ continue;
+ }
+ Runnable childEndAction = endActionTriggered ? null : endAction;
+ performRemoveAnimation(child, childEndAction);
+ endActionTriggered = true;
+ }
+ if (!endActionTriggered && endAction != null) {
+ endAction.run();
+ }
+ }
+
+ public void performRemoveAnimation(View message,
+ Runnable recycleRunnable) {
+ MessagingPropertyAnimator.fadeOut(message, recycleRunnable);
+ MessagingPropertyAnimator.startLocalTranslationTo(message,
+ (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+ }
+
+ public CharSequence getSenderName() {
+ return mSenderName.getText();
+ }
+
+ public void setSenderVisible(boolean visible) {
+ mSenderName.setVisibility(visible ? VISIBLE : GONE);
+ }
+
+ public static void dropCache() {
+ sInstancePool = new Pools.SynchronizedPool<>(10);
+ }
+
+ @Override
+ public int getMeasuredType() {
+ boolean hasNormal = false;
+ for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
+ View child = mMessageContainer.getChildAt(i);
+ if (child instanceof MessagingLinearLayout.MessagingChild) {
+ int type = ((MessagingLinearLayout.MessagingChild) child).getMeasuredType();
+ if (type == MEASURED_TOO_SMALL) {
+ if (hasNormal) {
+ return MEASURED_SHORTENED;
+ } else {
+ return MEASURED_TOO_SMALL;
+ }
+ } else if (type == MEASURED_SHORTENED) {
+ return MEASURED_SHORTENED;
+ } else {
+ hasNormal = true;
+ }
+ }
+ }
+ return MEASURED_NORMAL;
+ }
+
+ @Override
+ public int getConsumedLines() {
+ int result = 0;
+ for (int i = 0; i < mMessageContainer.getChildCount(); i++) {
+ View child = mMessageContainer.getChildAt(i);
+ if (child instanceof MessagingLinearLayout.MessagingChild) {
+ result += ((MessagingLinearLayout.MessagingChild) child).getConsumedLines();
+ }
+ }
+ // A group is usually taking up quite some space with the padding and the name, let's add 1
+ return result + 1;
+ }
+
+ @Override
+ public void setMaxDisplayedLines(int lines) {
+ mMessageContainer.setMaxDisplayedLines(lines);
+ }
+
+ @Override
+ public void hideAnimated() {
+ setIsHidingAnimated(true);
+ removeGroupAnimated(() -> setIsHidingAnimated(false));
+ }
+
+ @Override
+ public boolean isHidingAnimated() {
+ return mIsHidingAnimated;
+ }
+
+ private void setIsHidingAnimated(boolean isHiding) {
+ ViewParent parent = getParent();
+ mIsHidingAnimated = isHiding;
+ invalidate();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).invalidate();
+ }
+ }
+
+ public Icon getAvatarSymbolIfMatching(CharSequence avatarName, String avatarSymbol,
+ int layoutColor) {
+ if (mAvatarName.equals(avatarName) && mAvatarSymbol.equals(avatarSymbol)
+ && layoutColor == mLayoutColor) {
+ return mAvatarIcon;
+ }
+ return null;
+ }
+
+ public void setCreatedAvatar(Icon cachedIcon, CharSequence avatarName, String avatarSymbol,
+ int layoutColor) {
+ if (!mAvatarName.equals(avatarName) || !mAvatarSymbol.equals(avatarSymbol)
+ || layoutColor != mLayoutColor) {
+ setAvatar(cachedIcon);
+ mAvatarSymbol = avatarSymbol;
+ mLayoutColor = layoutColor;
+ mAvatarName = avatarName;
+ }
+ }
+
+ public void setLayoutColor(int layoutColor) {
+ mLayoutColor = layoutColor;
+ }
+
+ public void setMessages(List<MessagingMessage> group) {
+ // Let's now make sure all children are added and in the correct order
+ for (int messageIndex = 0; messageIndex < group.size(); messageIndex++) {
+ MessagingMessage message = group.get(messageIndex);
+ if (message.getGroup() != this) {
+ message.setMessagingGroup(this);
+ ViewParent parent = mMessageContainer.getParent();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).removeView(message);
+ }
+ mMessageContainer.addView(message, messageIndex);
+ mAddedMessages.add(message);
+ }
+ if (messageIndex != mMessageContainer.indexOfChild(message)) {
+ mMessageContainer.removeView(message);
+ mMessageContainer.addView(message, messageIndex);
+ }
+ // Let's make sure the message color is correct
+ Drawable targetDrawable = message.getBackground();
+
+ if (targetDrawable != null) {
+ targetDrawable.mutate().setColorFilter(mMessageBackgroundFilter);
+ }
+ message.setTextColor(mTextColor);
+ }
+ mMessages = group;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!mAddedMessages.isEmpty()) {
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ for (MessagingMessage message : mAddedMessages) {
+ if (!message.isShown()) {
+ continue;
+ }
+ MessagingPropertyAnimator.fadeIn(message);
+ if (!mFirstLayout) {
+ MessagingPropertyAnimator.startLocalTranslationFrom(message,
+ message.getHeight(), MessagingLayout.LINEAR_OUT_SLOW_IN);
+ }
+ }
+ mAddedMessages.clear();
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+ mFirstLayout = false;
+ }
+
+ /**
+ * Calculates the group compatibility between this and another group.
+ *
+ * @param otherGroup the other group to compare it with
+ *
+ * @return 0 if the groups are totally incompatible or 1 + the number of matching messages if
+ * they match.
+ */
+ public int calculateGroupCompatibility(MessagingGroup otherGroup) {
+ if (TextUtils.equals(getSenderName(),otherGroup.getSenderName())) {
+ int result = 1;
+ for (int i = 0; i < mMessages.size() && i < otherGroup.mMessages.size(); i++) {
+ MessagingMessage ownMessage = mMessages.get(mMessages.size() - 1 - i);
+ MessagingMessage otherMessage = otherGroup.mMessages.get(
+ otherGroup.mMessages.size() - 1 - i);
+ if (!ownMessage.sameAs(otherMessage)) {
+ return result;
+ }
+ result++;
+ }
+ return result;
+ }
+ return 0;
+ }
+
+ public View getSender() {
+ return mSenderName;
+ }
+
+ public View getAvatar() {
+ return mAvatarView;
+ }
+
+ public MessagingLinearLayout getMessageContainer() {
+ return mMessageContainer;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
new file mode 100644
index 0000000..2acdc01
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -0,0 +1,444 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.view.RemotableViewMethod;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+import android.widget.FrameLayout;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.graphics.ColorUtils;
+import com.android.internal.util.NotificationColorUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
+/**
+ * A custom-built layout for the Notification.MessagingStyle allows dynamic addition and removal
+ * messages and adapts the layout accordingly.
+ */
+@RemoteViews.RemoteView
+public class MessagingLayout extends FrameLayout {
+
+ private static final float COLOR_SHIFT_AMOUNT = 60;
+ private static final Consumer<MessagingMessage> REMOVE_MESSAGE
+ = MessagingMessage::removeMessage;
+ public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f);
+ public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR
+ = new MessagingPropertyAnimator();
+ private List<MessagingMessage> mMessages = new ArrayList<>();
+ private List<MessagingMessage> mHistoricMessages = new ArrayList<>();
+ private MessagingLinearLayout mMessagingLinearLayout;
+ private View mContractedMessage;
+ private boolean mShowHistoricMessages;
+ private ArrayList<MessagingGroup> mGroups = new ArrayList<>();
+ private TextView mTitleView;
+ private int mLayoutColor;
+ private int mAvatarSize;
+ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private Paint mTextPaint = new Paint();
+ private CharSequence mConversationTitle;
+ private Icon mLargeIcon;
+ private boolean mIsOneToOne;
+ private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
+
+ public MessagingLayout(@NonNull Context context) {
+ super(context);
+ }
+
+ public MessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MessagingLayout(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mMessagingLinearLayout = findViewById(R.id.notification_messaging);
+ mMessagingLinearLayout.setMessagingLayout(this);
+ // We still want to clip, but only on the top, since views can temporarily out of bounds
+ // during transitions.
+ DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
+ Rect rect = new Rect(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
+ mMessagingLinearLayout.setClipBounds(rect);
+ mTitleView = findViewById(R.id.title);
+ mAvatarSize = getResources().getDimensionPixelSize(R.dimen.messaging_avatar_size);
+ mTextPaint.setTextAlign(Paint.Align.CENTER);
+ mTextPaint.setAntiAlias(true);
+ }
+
+ @RemotableViewMethod
+ public void setLargeIcon(Icon icon) {
+ mLargeIcon = icon;
+ }
+
+ @RemotableViewMethod
+ public void setData(Bundle extras) {
+ Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+ List<Notification.MessagingStyle.Message> newMessages
+ = Notification.MessagingStyle.Message.getMessagesFromBundleArray(messages);
+ Parcelable[] histMessages = extras.getParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES);
+ List<Notification.MessagingStyle.Message> newHistoricMessages
+ = Notification.MessagingStyle.Message.getMessagesFromBundleArray(histMessages);
+ mConversationTitle = null;
+ TextView headerText = findViewById(R.id.header_text);
+ if (headerText != null) {
+ mConversationTitle = headerText.getText();
+ }
+ bind(newMessages, newHistoricMessages);
+ }
+
+ private void bind(List<Notification.MessagingStyle.Message> newMessages,
+ List<Notification.MessagingStyle.Message> newHistoricMessages) {
+
+ List<MessagingMessage> historicMessages = createMessages(newHistoricMessages,
+ true /* isHistoric */);
+ List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */);
+ addMessagesToGroups(historicMessages, messages);
+
+ // Let's remove the remaining messages
+ mMessages.forEach(REMOVE_MESSAGE);
+ mHistoricMessages.forEach(REMOVE_MESSAGE);
+
+ mMessages = messages;
+ mHistoricMessages = historicMessages;
+
+ updateContractedMessage();
+ updateHistoricMessageVisibility();
+ updateTitleAndNamesDisplay();
+ }
+
+ private void updateTitleAndNamesDisplay() {
+ ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
+ ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
+ for (int i = 0; i < mGroups.size(); i++) {
+ MessagingGroup group = mGroups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (TextUtils.isEmpty(senderName)) {
+ continue;
+ }
+ boolean visible = !mIsOneToOne;
+ group.setSenderVisible(visible);
+ if ((visible || mLargeIcon == null) && !uniqueNames.containsKey(senderName)) {
+ char c = senderName.charAt(0);
+ if (uniqueCharacters.containsKey(c)) {
+ // this character was already used, lets make it more unique. We first need to
+ // resolve the existing character if it exists
+ CharSequence existingName = uniqueCharacters.get(c);
+ if (existingName != null) {
+ uniqueNames.put(existingName, findNameSplit((String) existingName));
+ uniqueCharacters.put(c, null);
+ }
+ uniqueNames.put(senderName, findNameSplit((String) senderName));
+ } else {
+ uniqueNames.put(senderName, Character.toString(c));
+ uniqueCharacters.put(c, senderName);
+ }
+ }
+ }
+
+ // Now that we have the correct symbols, let's look what we have cached
+ ArrayMap<CharSequence, Icon> cachedAvatars = new ArrayMap<>();
+ for (int i = 0; i < mGroups.size(); i++) {
+ // Let's now set the avatars
+ MessagingGroup group = mGroups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (TextUtils.isEmpty(senderName) || (mIsOneToOne && mLargeIcon != null)) {
+ continue;
+ }
+ String symbol = uniqueNames.get(senderName);
+ Icon cachedIcon = group.getAvatarSymbolIfMatching(senderName,
+ symbol, mLayoutColor);
+ if (cachedIcon != null) {
+ cachedAvatars.put(senderName, cachedIcon);
+ }
+ }
+
+ for (int i = 0; i < mGroups.size(); i++) {
+ // Let's now set the avatars
+ MessagingGroup group = mGroups.get(i);
+ CharSequence senderName = group.getSenderName();
+ if (TextUtils.isEmpty(senderName)) {
+ continue;
+ }
+ if (mIsOneToOne && mLargeIcon != null) {
+ group.setAvatar(mLargeIcon);
+ } else {
+ Icon cachedIcon = cachedAvatars.get(senderName);
+ if (cachedIcon == null) {
+ cachedIcon = createAvatarSymbol(senderName, uniqueNames.get(senderName),
+ mLayoutColor);
+ cachedAvatars.put(senderName, cachedIcon);
+ }
+ group.setCreatedAvatar(cachedIcon, senderName, uniqueNames.get(senderName),
+ mLayoutColor);
+ }
+ }
+ }
+
+ public Icon createAvatarSymbol(CharSequence senderName, String symbol, int layoutColor) {
+ Bitmap bitmap = Bitmap.createBitmap(mAvatarSize, mAvatarSize, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ float radius = mAvatarSize / 2.0f;
+ int color = findColor(senderName, layoutColor);
+ mPaint.setColor(color);
+ canvas.drawCircle(radius, radius, radius, mPaint);
+ boolean needDarkText = ColorUtils.calculateLuminance(color) > 0.5f;
+ mTextPaint.setColor(needDarkText ? Color.BLACK : Color.WHITE);
+ mTextPaint.setTextSize(symbol.length() == 1 ? mAvatarSize * 0.75f : mAvatarSize * 0.4f);
+ int yPos = (int) (radius - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)) ;
+ canvas.drawText(symbol, radius, yPos, mTextPaint);
+ return Icon.createWithBitmap(bitmap);
+ }
+
+ private int findColor(CharSequence senderName, int layoutColor) {
+ double luminance = NotificationColorUtil.calculateLuminance(layoutColor);
+ float shift = Math.abs(senderName.hashCode()) % 5 / 4.0f - 0.5f;
+
+ // we need to offset the range if the luminance is too close to the borders
+ shift += Math.max(COLOR_SHIFT_AMOUNT / 2.0f / 100 - luminance, 0);
+ shift -= Math.max(COLOR_SHIFT_AMOUNT / 2.0f / 100 - (1.0f - luminance), 0);
+ return NotificationColorUtil.getShiftedColor(layoutColor,
+ (int) (shift * COLOR_SHIFT_AMOUNT));
+ }
+
+ private String findNameSplit(String existingName) {
+ String[] split = existingName.split(" ");
+ if (split.length > 1) {
+ return Character.toString(split[0].charAt(0))
+ + Character.toString(split[1].charAt(0));
+ }
+ return existingName.substring(0, 1);
+ }
+
+ @RemotableViewMethod
+ public void setLayoutColor(int color) {
+ mLayoutColor = color;
+ }
+
+ @RemotableViewMethod
+ public void setIsOneToOne(boolean oneToOne) {
+ mIsOneToOne = oneToOne;
+ }
+
+ private void addMessagesToGroups(List<MessagingMessage> historicMessages,
+ List<MessagingMessage> messages) {
+ // Let's first find our groups!
+ List<List<MessagingMessage>> groups = new ArrayList<>();
+ List<CharSequence> senders = new ArrayList<>();
+
+ // Lets first find the groups
+ findGroups(historicMessages, messages, groups, senders);
+
+ // Let's now create the views and reorder them accordingly
+ createGroupViews(groups, senders);
+ }
+
+ private void createGroupViews(List<List<MessagingMessage>> groups, List<CharSequence> senders) {
+ mGroups.clear();
+ for (int groupIndex = 0; groupIndex < groups.size(); groupIndex++) {
+ List<MessagingMessage> group = groups.get(groupIndex);
+ MessagingGroup newGroup = null;
+ // we'll just take the first group that exists or create one there is none
+ for (int messageIndex = group.size() - 1; messageIndex >= 0; messageIndex--) {
+ MessagingMessage message = group.get(messageIndex);
+ newGroup = message.getGroup();
+ if (newGroup != null) {
+ break;
+ }
+ }
+ if (newGroup == null) {
+ newGroup = MessagingGroup.createGroup(mMessagingLinearLayout);
+ mAddedGroups.add(newGroup);
+ }
+ newGroup.setLayoutColor(mLayoutColor);
+ newGroup.setSender(senders.get(groupIndex));
+ mGroups.add(newGroup);
+
+ if (mMessagingLinearLayout.indexOfChild(newGroup) != groupIndex) {
+ mMessagingLinearLayout.removeView(newGroup);
+ mMessagingLinearLayout.addView(newGroup, groupIndex);
+ }
+ newGroup.setMessages(group);
+ }
+ }
+
+ private void findGroups(List<MessagingMessage> historicMessages,
+ List<MessagingMessage> messages, List<List<MessagingMessage>> groups,
+ List<CharSequence> senders) {
+ CharSequence currentSender = null;
+ List<MessagingMessage> currentGroup = null;
+ int histSize = historicMessages.size();
+ for (int i = 0; i < histSize + messages.size(); i++) {
+ MessagingMessage message;
+ if (i < histSize) {
+ message = historicMessages.get(i);
+ } else {
+ message = messages.get(i - histSize);
+ }
+ boolean isNewGroup = currentGroup == null;
+ CharSequence sender = message.getMessage().getSender();
+ isNewGroup |= !TextUtils.equals(sender, currentSender);
+ if (isNewGroup) {
+ currentGroup = new ArrayList<>();
+ groups.add(currentGroup);
+ senders.add(sender);
+ currentSender = sender;
+ }
+ currentGroup.add(message);
+ }
+ }
+
+ private void updateContractedMessage() {
+ for (int i = mMessages.size() - 1; i >= 0; i--) {
+ MessagingMessage m = mMessages.get(i);
+ // Incoming messages have a non-empty sender.
+ if (!TextUtils.isEmpty(m.getMessage().getSender())) {
+ mContractedMessage = m;
+ return;
+ }
+ }
+ if (!mMessages.isEmpty()) {
+ // No incoming messages, fall back to outgoing message
+ mContractedMessage = mMessages.get(mMessages.size() - 1);
+ return;
+ }
+ mContractedMessage = null;
+ }
+
+ /**
+ * Creates new messages, reusing existing ones if they are available.
+ *
+ * @param newMessages the messages to parse.
+ */
+ private List<MessagingMessage> createMessages(
+ List<Notification.MessagingStyle.Message> newMessages, boolean historic) {
+ List<MessagingMessage> result = new ArrayList<>();;
+ for (int i = 0; i < newMessages.size(); i++) {
+ Notification.MessagingStyle.Message m = newMessages.get(i);
+ MessagingMessage message = findAndRemoveMatchingMessage(m);
+ if (message == null) {
+ message = MessagingMessage.createMessage(this, m);
+ message.addOnLayoutChangeListener(MESSAGING_PROPERTY_ANIMATOR);
+ }
+ message.setIsHistoric(historic);
+ result.add(message);
+ }
+ return result;
+ }
+
+ private MessagingMessage findAndRemoveMatchingMessage(Notification.MessagingStyle.Message m) {
+ for (int i = 0; i < mMessages.size(); i++) {
+ MessagingMessage existing = mMessages.get(i);
+ if (existing.sameAs(m)) {
+ mMessages.remove(i);
+ return existing;
+ }
+ }
+ for (int i = 0; i < mHistoricMessages.size(); i++) {
+ MessagingMessage existing = mHistoricMessages.get(i);
+ if (existing.sameAs(m)) {
+ mHistoricMessages.remove(i);
+ return existing;
+ }
+ }
+ return null;
+ }
+
+ public void showHistoricMessages(boolean show) {
+ mShowHistoricMessages = show;
+ updateHistoricMessageVisibility();
+ }
+
+ private void updateHistoricMessageVisibility() {
+ for (int i = 0; i < mHistoricMessages.size(); i++) {
+ MessagingMessage existing = mHistoricMessages.get(i);
+ existing.setVisibility(mShowHistoricMessages ? VISIBLE : GONE);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!mAddedGroups.isEmpty()) {
+ getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ for (MessagingGroup group : mAddedGroups) {
+ if (!group.isShown()) {
+ continue;
+ }
+ MessagingPropertyAnimator.fadeIn(group.getAvatar());
+ MessagingPropertyAnimator.fadeIn(group.getSender());
+ MessagingPropertyAnimator.startLocalTranslationFrom(group,
+ group.getHeight(), LINEAR_OUT_SLOW_IN);
+ }
+ mAddedGroups.clear();
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+ }
+
+ public View getContractedMessage() {
+ return mContractedMessage;
+ }
+
+ public MessagingLinearLayout getMessagingLinearLayout() {
+ return mMessagingLinearLayout;
+ }
+
+ public ArrayList<MessagingGroup> getMessagingGroups() {
+ return mGroups;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 70473a0..f0ef370 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -36,28 +36,14 @@
@RemoteViews.RemoteView
public class MessagingLinearLayout extends ViewGroup {
- private static final int NOT_MEASURED_BEFORE = -1;
/**
* Spacing to be applied between views.
*/
private int mSpacing;
- /**
- * The maximum height allowed.
- */
- private int mMaxHeight;
+ private int mMaxDisplayedLines = Integer.MAX_VALUE;
- private int mIndentLines;
-
- /**
- * Id of the child that's also visible in the contracted layout.
- */
- private int mContractedChildId;
- /**
- * The last measured with in a layout pass if it was measured before or
- * {@link #NOT_MEASURED_BEFORE} if this is the first layout pass.
- */
- private int mLastMeasuredWidth = NOT_MEASURED_BEFORE;
+ private MessagingLayout mMessagingLayout;
public MessagingLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
@@ -79,7 +65,6 @@
a.recycle();
}
-
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// This is essentially a bottom-up linear layout that only adds children that fit entirely
@@ -91,118 +76,67 @@
break;
}
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
- boolean recalculateVisibility = mLastMeasuredWidth == NOT_MEASURED_BEFORE
- || getMeasuredHeight() != targetHeight
- || mLastMeasuredWidth != widthSize;
-
- final int count = getChildCount();
- if (recalculateVisibility) {
- // We only need to recalculate the view visibilities if the view wasn't measured already
- // in this pass, otherwise we may drop messages here already since we are measured
- // exactly with what we returned before, which was optimized already with the
- // line-indents.
- for (int i = 0; i < count; ++i) {
- final View child = getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
- lp.hide = true;
- }
-
- int totalHeight = mPaddingTop + mPaddingBottom;
- boolean first = true;
-
- // Starting from the bottom: we measure every view as if it were the only one. If it still
-
- // fits, we take it, otherwise we stop there.
- for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
- if (getChildAt(i).getVisibility() == GONE) {
- continue;
- }
- final View child = getChildAt(i);
- LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
- ImageFloatingTextView textChild = null;
- if (child instanceof ImageFloatingTextView) {
- // Pretend we need the image padding for all views, we don't know which
- // one will end up needing to do this (might end up not using all the space,
- // but calculating this exactly would be more expensive).
- textChild = (ImageFloatingTextView) child;
- textChild.setNumIndentLines(mIndentLines == 2 ? 3 : mIndentLines);
- }
-
- int spacing = first ? 0 : mSpacing;
- measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
- - mPaddingTop - mPaddingBottom + spacing);
-
- final int childHeight = child.getMeasuredHeight();
- int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
- lp.bottomMargin + spacing);
- first = false;
- boolean measuredTooSmall = false;
- if (textChild != null) {
- measuredTooSmall = childHeight < textChild.getLayoutHeight()
- + textChild.getPaddingTop() + textChild.getPaddingBottom();
- }
-
- if (newHeight <= targetHeight && !measuredTooSmall) {
- totalHeight = newHeight;
- lp.hide = false;
- } else {
- break;
- }
- }
- }
// Now that we know which views to take, fix up the indents and see what width we get.
int measuredWidth = mPaddingLeft + mPaddingRight;
- int imageLines = mIndentLines;
- // Need to redo the height because it may change due to changing indents.
- int totalHeight = mPaddingTop + mPaddingBottom;
- boolean first = true;
- for (int i = 0; i < count; i++) {
+ final int count = getChildCount();
+ int totalHeight;
+ for (int i = 0; i < count; ++i) {
final View child = getChildAt(i);
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (child.getVisibility() == GONE || lp.hide) {
- continue;
- }
-
- if (child instanceof ImageFloatingTextView) {
- ImageFloatingTextView textChild = (ImageFloatingTextView) child;
- if (imageLines == 2 && textChild.getLineCount() > 2) {
- // HACK: If we need indent for two lines, and they're coming from the same
- // view, we need extra spacing to compensate for the lack of margins,
- // so add an extra line of indent.
- imageLines = 3;
- }
- boolean changed = textChild.setNumIndentLines(Math.max(0, imageLines));
- if (changed || !recalculateVisibility) {
- final int childWidthMeasureSpec = getChildMeasureSpec(widthMeasureSpec,
- mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin,
- lp.width);
- // we want to measure it at most as high as it is currently, otherwise we'll
- // drop later lines
- final int childHeightMeasureSpec = getChildMeasureSpec(heightMeasureSpec,
- targetHeight - child.getMeasuredHeight(), lp.height);
-
- child.measure(childWidthMeasureSpec, childHeightMeasureSpec);;
- }
- imageLines -= textChild.getLineCount();
- }
-
- measuredWidth = Math.max(measuredWidth,
- child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
- + mPaddingLeft + mPaddingRight);
- totalHeight = Math.max(totalHeight, totalHeight + child.getMeasuredHeight() +
- lp.topMargin + lp.bottomMargin + (first ? 0 : mSpacing));
- first = false;
+ lp.hide = true;
}
+ totalHeight = mPaddingTop + mPaddingBottom;
+ boolean first = true;
+ int linesRemaining = mMaxDisplayedLines;
+
+ // Starting from the bottom: we measure every view as if it were the only one. If it still
+ // fits, we take it, otherwise we stop there.
+ for (int i = count - 1; i >= 0 && totalHeight < targetHeight; i--) {
+ if (getChildAt(i).getVisibility() == GONE) {
+ continue;
+ }
+ final View child = getChildAt(i);
+ LayoutParams lp = (LayoutParams) getChildAt(i).getLayoutParams();
+ MessagingChild messagingChild = null;
+ if (child instanceof MessagingChild) {
+ messagingChild = (MessagingChild) child;
+ messagingChild.setMaxDisplayedLines(linesRemaining);
+ }
+ int spacing = first ? 0 : mSpacing;
+ measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, totalHeight
+ - mPaddingTop - mPaddingBottom + spacing);
+
+ final int childHeight = child.getMeasuredHeight();
+ int newHeight = Math.max(totalHeight, totalHeight + childHeight + lp.topMargin +
+ lp.bottomMargin + spacing);
+ first = false;
+ int measureType = MessagingChild.MEASURED_NORMAL;
+ if (messagingChild != null) {
+ measureType = messagingChild.getMeasuredType();
+ linesRemaining -= messagingChild.getConsumedLines();
+ }
+ boolean isShortened = measureType == MessagingChild.MEASURED_SHORTENED;
+ boolean isTooSmall = measureType == MessagingChild.MEASURED_TOO_SMALL;
+ if (newHeight <= targetHeight && !isTooSmall) {
+ totalHeight = newHeight;
+ measuredWidth = Math.max(measuredWidth,
+ child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin
+ + mPaddingLeft + mPaddingRight);
+ lp.hide = false;
+ if (isShortened || linesRemaining <= 0) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
setMeasuredDimension(
resolveSize(Math.max(getSuggestedMinimumWidth(), measuredWidth),
widthMeasureSpec),
- resolveSize(Math.max(getSuggestedMinimumHeight(), totalHeight),
- heightMeasureSpec));
- mLastMeasuredWidth = widthSize;
+ Math.max(getSuggestedMinimumHeight(), totalHeight));
}
@Override
@@ -221,14 +155,23 @@
childTop = mPaddingTop;
boolean first = true;
-
+ final boolean shown = isShown();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
- final LayoutParams lp = (LayoutParams) child.getLayoutParams();
-
- if (child.getVisibility() == GONE || lp.hide) {
+ if (child.getVisibility() == GONE) {
continue;
}
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ MessagingChild messagingChild = (MessagingChild) child;
+ if (lp.hide) {
+ if (shown && lp.visibleBefore) {
+ messagingChild.hideAnimated();
+ }
+ lp.visibleBefore = false;
+ continue;
+ } else {
+ lp.visibleBefore = true;
+ }
final int childWidth = child.getMeasuredWidth();
final int childHeight = child.getMeasuredHeight();
@@ -251,14 +194,16 @@
first = false;
}
- mLastMeasuredWidth = NOT_MEASURED_BEFORE;
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.hide) {
- return true;
+ MessagingChild messagingChild = (MessagingChild) child;
+ if (!messagingChild.isHidingAnimated()) {
+ return true;
+ }
}
return super.drawChild(canvas, child, drawingTime);
}
@@ -284,31 +229,37 @@
}
/**
- * Sets how many lines should be indented to avoid a floating image.
+ * Sets how many lines should be displayed at most
*/
@RemotableViewMethod
- public void setNumIndentLines(int numberLines) {
- mIndentLines = numberLines;
+ public void setMaxDisplayedLines(int numberLines) {
+ mMaxDisplayedLines = numberLines;
}
- /**
- * Set id of the child that's also visible in the contracted layout.
- */
- @RemotableViewMethod
- public void setContractedChildId(int contractedChildId) {
- mContractedChildId = contractedChildId;
+ public void setMessagingLayout(MessagingLayout layout) {
+ mMessagingLayout = layout;
}
- /**
- * Get id of the child that's also visible in the contracted layout.
- */
- public int getContractedChildId() {
- return mContractedChildId;
+ public MessagingLayout getMessagingLayout() {
+ return mMessagingLayout;
+ }
+
+ public interface MessagingChild {
+ int MEASURED_NORMAL = 0;
+ int MEASURED_SHORTENED = 1;
+ int MEASURED_TOO_SMALL = 2;
+
+ int getMeasuredType();
+ int getConsumedLines();
+ void setMaxDisplayedLines(int lines);
+ void hideAnimated();
+ boolean isHidingAnimated();
}
public static class LayoutParams extends MarginLayoutParams {
- boolean hide = false;
+ public boolean hide = false;
+ public boolean visibleBefore = false;
public LayoutParams(Context c, AttributeSet attrs) {
super(c, attrs);
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
new file mode 100644
index 0000000..f09621f
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -0,0 +1,197 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.StyleRes;
+import android.app.Notification;
+import android.content.Context;
+import android.text.Layout;
+import android.util.AttributeSet;
+import android.util.Pools;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.widget.RemoteViews;
+
+import com.android.internal.R;
+
+import java.util.Objects;
+
+/**
+ * A message of a {@link MessagingLayout}.
+ */
+@RemoteViews.RemoteView
+public class MessagingMessage extends ImageFloatingTextView implements
+ MessagingLinearLayout.MessagingChild {
+
+ private static Pools.SimplePool<MessagingMessage> sInstancePool
+ = new Pools.SynchronizedPool<>(10);
+ private Notification.MessagingStyle.Message mMessage;
+ private MessagingGroup mGroup;
+ private boolean mIsHistoric;
+ private boolean mIsHidingAnimated;
+
+ public MessagingMessage(@NonNull Context context) {
+ super(context);
+ }
+
+ public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public MessagingMessage(@NonNull Context context, @Nullable AttributeSet attrs,
+ @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ private void setMessage(Notification.MessagingStyle.Message message) {
+ mMessage = message;
+ setText(message.getText());
+ }
+
+ public Notification.MessagingStyle.Message getMessage() {
+ return mMessage;
+ }
+
+ boolean sameAs(Notification.MessagingStyle.Message message) {
+ if (!Objects.equals(message.getText(), mMessage.getText())) {
+ return false;
+ }
+ if (!Objects.equals(message.getSender(), mMessage.getSender())) {
+ return false;
+ }
+ if (!Objects.equals(message.getTimestamp(), mMessage.getTimestamp())) {
+ return false;
+ }
+ return true;
+ }
+
+ boolean sameAs(MessagingMessage message) {
+ return sameAs(message.getMessage());
+ }
+
+ static MessagingMessage createMessage(MessagingLayout layout,
+ Notification.MessagingStyle.Message m) {
+ MessagingLinearLayout messagingLinearLayout = layout.getMessagingLinearLayout();
+ MessagingMessage createdMessage = sInstancePool.acquire();
+ if (createdMessage == null) {
+ createdMessage = (MessagingMessage) LayoutInflater.from(layout.getContext()).inflate(
+ R.layout.notification_template_messaging_message, messagingLinearLayout,
+ false);
+ }
+ createdMessage.setMessage(m);
+ return createdMessage;
+ }
+
+ public void removeMessage() {
+ mGroup.removeMessage(this);
+ }
+
+ public void recycle() {
+ mGroup = null;
+ mMessage = null;
+ setAlpha(1.0f);
+ setTranslationY(0);
+ sInstancePool.release(this);
+ }
+
+ public void setMessagingGroup(MessagingGroup group) {
+ mGroup = group;
+ }
+
+ public static void dropCache() {
+ sInstancePool = new Pools.SynchronizedPool<>(10);
+ }
+
+ public void setIsHistoric(boolean isHistoric) {
+ mIsHistoric = isHistoric;
+ }
+
+ public MessagingGroup getGroup() {
+ return mGroup;
+ }
+
+ @Override
+ public int getMeasuredType() {
+ boolean measuredTooSmall = getMeasuredHeight()
+ < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
+ if (measuredTooSmall) {
+ return MEASURED_TOO_SMALL;
+ } else {
+ Layout layout = getLayout();
+ if (layout == null) {
+ return MEASURED_TOO_SMALL;
+ }
+ if (layout.getEllipsisCount(layout.getLineCount() - 1) > 0) {
+ return MEASURED_SHORTENED;
+ } else {
+ return MEASURED_NORMAL;
+ }
+ }
+ }
+
+ @Override
+ public void hideAnimated() {
+ setIsHidingAnimated(true);
+ mGroup.performRemoveAnimation(this, () -> setIsHidingAnimated(false));
+ }
+
+ private void setIsHidingAnimated(boolean isHiding) {
+ ViewParent parent = getParent();
+ mIsHidingAnimated = isHiding;
+ invalidate();
+ if (parent instanceof ViewGroup) {
+ ((ViewGroup) parent).invalidate();
+ }
+ }
+
+ @Override
+ public boolean isHidingAnimated() {
+ return mIsHidingAnimated;
+ }
+
+ @Override
+ public void setMaxDisplayedLines(int lines) {
+ setMaxLines(lines);
+ }
+
+ @Override
+ public int getConsumedLines() {
+ return getLineCount();
+ }
+
+ public int getLayoutHeight() {
+ Layout layout = getLayout();
+ if (layout == null) {
+ return 0;
+ }
+ return layout.getHeight();
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+ return false;
+ }
+}
diff --git a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
new file mode 100644
index 0000000..7c3ab7f
--- /dev/null
+++ b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
@@ -0,0 +1,233 @@
+/*
+ * 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.internal.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.util.IntProperty;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
+
+import com.android.internal.R;
+
+/**
+ * A listener that automatically starts animations when the layout bounds change.
+ */
+public class MessagingPropertyAnimator implements View.OnLayoutChangeListener {
+ static final long APPEAR_ANIMATION_LENGTH = 210;
+ private static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
+ public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
+ private static final int TAG_LOCAL_TRANSLATION_ANIMATOR = R.id.tag_local_translation_y_animator;
+ private static final int TAG_LOCAL_TRANSLATION_Y = R.id.tag_local_translation_y;
+ private static final int TAG_LAYOUT_TOP = R.id.tag_layout_top;
+ private static final int TAG_ALPHA_ANIMATOR = R.id.tag_alpha_animator;
+ private static final ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS =
+ view -> view.getId() == com.android.internal.R.id.notification_messaging;
+ private static final IntProperty<View> LOCAL_TRANSLATION_Y =
+ new IntProperty<View>("localTranslationY") {
+ @Override
+ public void setValue(View object, int value) {
+ setLocalTranslationY(object, value);
+ }
+
+ @Override
+ public Integer get(View object) {
+ return getLocalTranslationY(object);
+ }
+ };
+
+ @Override
+ public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+ int oldTop, int oldRight, int oldBottom) {
+ int oldHeight = oldBottom - oldTop;
+ Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
+ if (layoutTop != null) {
+ oldTop = layoutTop;
+ }
+ int topChange = oldTop - top;
+ if (oldHeight == 0 || topChange == 0 || !v.isShown() || isGone(v)) {
+ // First layout
+ return;
+ }
+ if (layoutTop != null) {
+ v.setTagInternal(TAG_LAYOUT_TOP, top);
+ }
+ int newHeight = bottom - top;
+ int heightDifference = oldHeight - newHeight;
+ // Only add the difference if the height changes and it's getting smaller
+ heightDifference = Math.max(heightDifference, 0);
+ startLocalTranslationFrom(v, topChange + heightDifference + getLocalTranslationY(v));
+ }
+
+ private boolean isGone(View view) {
+ if (view.getVisibility() == View.GONE) {
+ return true;
+ }
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide) {
+ return true;
+ }
+ return false;
+ }
+
+ public static void startLocalTranslationFrom(View v, int startTranslation) {
+ startLocalTranslationFrom(v, startTranslation, MessagingLayout.FAST_OUT_SLOW_IN);
+ }
+
+ public static void startLocalTranslationFrom(View v, int startTranslation,
+ Interpolator interpolator) {
+ startLocalTranslation(v, startTranslation, 0, interpolator);
+ }
+
+ public static void startLocalTranslationTo(View v, int endTranslation,
+ Interpolator interpolator) {
+ startLocalTranslation(v, getLocalTranslationY(v), endTranslation, interpolator);
+ }
+
+ public static int getLocalTranslationY(View v) {
+ Integer tag = (Integer) v.getTag(TAG_LOCAL_TRANSLATION_Y);
+ if (tag == null) {
+ return 0;
+ }
+ return tag;
+ }
+
+ private static void setLocalTranslationY(View v, int value) {
+ v.setTagInternal(TAG_LOCAL_TRANSLATION_Y, value);
+ updateTopAndBottom(v);
+ }
+
+ private static void updateTopAndBottom(View v) {
+ int layoutTop = (int) v.getTag(TAG_LAYOUT_TOP);
+ int localTranslation = getLocalTranslationY(v);
+ int height = v.getHeight();
+ v.setTop(layoutTop + localTranslation);
+ v.setBottom(layoutTop + height + localTranslation);
+ }
+
+ private static void startLocalTranslation(final View v, int start, int end,
+ Interpolator interpolator) {
+ ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR);
+ if (existing != null) {
+ existing.cancel();
+ }
+ ObjectAnimator animator = ObjectAnimator.ofInt(v, LOCAL_TRANSLATION_Y, start, end);
+ Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
+ if (layoutTop == null) {
+ layoutTop = v.getTop();
+ v.setTagInternal(TAG_LAYOUT_TOP, layoutTop);
+ }
+ setLocalTranslationY(v, start);
+ animator.setInterpolator(interpolator);
+ animator.setDuration(APPEAR_ANIMATION_LENGTH);
+ animator.addListener(new AnimatorListenerAdapter() {
+ public boolean mCancelled;
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, null);
+ setClippingDeactivated(v, false);
+ if (!mCancelled) {
+ setLocalTranslationY(v, 0);
+ v.setTagInternal(TAG_LAYOUT_TOP, null);
+ }
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
+ });
+ setClippingDeactivated(v, true);
+ v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, animator);
+ animator.start();
+ }
+
+ public static void fadeIn(final View v) {
+ ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_ALPHA_ANIMATOR);
+ if (existing != null) {
+ existing.cancel();
+ }
+ if (v.getVisibility() == View.INVISIBLE) {
+ v.setVisibility(View.VISIBLE);
+ }
+ ObjectAnimator animator = ObjectAnimator.ofFloat(v, View.ALPHA,
+ 0.0f, 1.0f);
+ v.setAlpha(0.0f);
+ animator.setInterpolator(ALPHA_IN);
+ animator.setDuration(APPEAR_ANIMATION_LENGTH);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ v.setTagInternal(TAG_ALPHA_ANIMATOR, null);
+ updateLayerType(v, false /* animating */);
+ }
+ });
+ updateLayerType(v, true /* animating */);
+ v.setTagInternal(TAG_ALPHA_ANIMATOR, animator);
+ animator.start();
+ }
+
+ private static void updateLayerType(View view, boolean animating) {
+ if (view.hasOverlappingRendering() && animating) {
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ } else if (view.getLayerType() == View.LAYER_TYPE_HARDWARE) {
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ }
+
+ public static void fadeOut(final View view, Runnable endAction) {
+ ObjectAnimator existing = (ObjectAnimator) view.getTag(TAG_ALPHA_ANIMATOR);
+ if (existing != null) {
+ existing.cancel();
+ }
+ ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA,
+ view.getAlpha(), 0.0f);
+ animator.setInterpolator(ALPHA_OUT);
+ animator.setDuration(APPEAR_ANIMATION_LENGTH);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setTagInternal(TAG_ALPHA_ANIMATOR, null);
+ updateLayerType(view, false /* animating */);
+ if (endAction != null) {
+ endAction.run();
+ }
+ }
+ });
+ updateLayerType(view, true /* animating */);
+ view.setTagInternal(TAG_ALPHA_ANIMATOR, animator);
+ animator.start();
+ }
+
+ public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
+ ViewClippingUtil.setClippingDeactivated(transformedView, deactivated,
+ CLIPPING_PARAMETERS);
+ }
+
+ public static boolean isAnimatingTranslation(View v) {
+ return v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR) != null;
+ }
+
+ public static boolean isAnimatingAlpha(View v) {
+ return v.getTag(TAG_ALPHA_ANIMATOR) != null;
+ }
+}
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 073aac5..26023b4 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -16,7 +16,10 @@
package com.android.internal.widget;
+import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Pair;
@@ -37,6 +40,7 @@
@RemoteViews.RemoteView
public class NotificationActionListLayout extends LinearLayout {
+ private final int mGravity;
private int mTotalWidth = 0;
private ArrayList<Pair<Integer, TextView>> mMeasureOrderTextViews = new ArrayList<>();
private ArrayList<View> mMeasureOrderOther = new ArrayList<>();
@@ -45,7 +49,20 @@
private Drawable mDefaultBackground;
public NotificationActionListLayout(Context context, AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0);
+ }
+
+ public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
+ }
+
+ public NotificationActionListLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+
+ int[] attrIds = { android.R.attr.gravity };
+ TypedArray ta = context.obtainStyledAttributes(attrs, attrIds, defStyleAttr, defStyleRes);
+ mGravity = ta.getInt(0, 0);
+ ta.recycle();
}
@Override
@@ -95,6 +112,7 @@
final boolean constrained =
MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED;
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
final int innerWidth = MeasureSpec.getSize(widthMeasureSpec) - mPaddingLeft - mPaddingRight;
final int otherSize = mMeasureOrderOther.size();
@@ -137,7 +155,7 @@
// Make sure to measure the last child full-width if we didn't use up the entire width,
// or we didn't measure yet because there's just one child.
- if (lastNotGoneChild != null && (constrained && usedWidth < innerWidth
+ if (lastNotGoneChild != null && !centerAligned && (constrained && usedWidth < innerWidth
|| notGoneChildren == 1)) {
MarginLayoutParams lp = (MarginLayoutParams) lastNotGoneChild.getLayoutParams();
if (notGoneChildren > 1) {
@@ -201,9 +219,10 @@
}
final boolean isLayoutRtl = isLayoutRtl();
final int paddingTop = mPaddingTop;
+ final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
int childTop;
- int childLeft;
+ int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0;
// Where bottom of child should go
final int height = bottom - top;
@@ -216,13 +235,12 @@
final int layoutDirection = getLayoutDirection();
switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
case Gravity.RIGHT:
- // mTotalWidth contains the padding already
- childLeft = mPaddingLeft + right - left - mTotalWidth;
+ childLeft += mPaddingLeft + right - left - mTotalWidth;
break;
case Gravity.LEFT:
default:
- childLeft = mPaddingLeft;
+ childLeft += mPaddingLeft;
break;
}
diff --git a/core/java/com/android/internal/widget/RemeasuringLinearLayout.java b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
new file mode 100644
index 0000000..e352b45
--- /dev/null
+++ b/core/java/com/android/internal/widget/RemeasuringLinearLayout.java
@@ -0,0 +1,68 @@
+/*
+ * 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.internal.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.RemoteViews;
+
+/**
+ * A LinearLayout that sets it's height again after the last measure pass. This is needed for
+ * MessagingLayouts where groups need to be able to snap it's height to.
+ */
+@RemoteViews.RemoteView
+public class RemeasuringLinearLayout extends LinearLayout {
+
+ public RemeasuringLinearLayout(Context context) {
+ super(context);
+ }
+
+ public RemeasuringLinearLayout(Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public RemeasuringLinearLayout(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public RemeasuringLinearLayout(Context context, AttributeSet attrs, int defStyleAttr,
+ int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ int count = getChildCount();
+ int height = 0;
+ for (int i = 0; i < count; ++i) {
+ final View child = getChildAt(i);
+ if (child == null || child.getVisibility() == View.GONE) {
+ continue;
+ }
+
+ final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+ height = Math.max(height, height + child.getMeasuredHeight() + lp.topMargin +
+ lp.bottomMargin);
+ }
+ setMeasuredDimension(getMeasuredWidth(), height);
+ }
+}
diff --git a/core/java/com/android/internal/widget/ViewClippingUtil.java b/core/java/com/android/internal/widget/ViewClippingUtil.java
new file mode 100644
index 0000000..59bbed4
--- /dev/null
+++ b/core/java/com/android/internal/widget/ViewClippingUtil.java
@@ -0,0 +1,108 @@
+/*
+ * 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.internal.widget;
+
+import android.util.ArraySet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import com.android.internal.R;
+
+/**
+ * A utility class that allows to clip views and their parents to allow for better transitions
+ */
+public class ViewClippingUtil {
+ private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
+ private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
+ private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
+
+ public static void setClippingDeactivated(final View transformedView, boolean deactivated,
+ ClippingParameters clippingParameters) {
+ if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
+ return;
+ }
+ if (!(transformedView.getParent() instanceof ViewGroup)) {
+ return;
+ }
+ ViewGroup parent = (ViewGroup) transformedView.getParent();
+ while (true) {
+ if (!deactivated && !clippingParameters.isClippingEnablingAllowed(transformedView)) {
+ return;
+ }
+ ArraySet<View> clipSet = (ArraySet<View>) parent.getTag(CLIP_CLIPPING_SET);
+ if (clipSet == null) {
+ clipSet = new ArraySet<>();
+ parent.setTagInternal(CLIP_CLIPPING_SET, clipSet);
+ }
+ Boolean clipChildren = (Boolean) parent.getTag(CLIP_CHILDREN_TAG);
+ if (clipChildren == null) {
+ clipChildren = parent.getClipChildren();
+ parent.setTagInternal(CLIP_CHILDREN_TAG, clipChildren);
+ }
+ Boolean clipToPadding = (Boolean) parent.getTag(CLIP_TO_PADDING);
+ if (clipToPadding == null) {
+ clipToPadding = parent.getClipToPadding();
+ parent.setTagInternal(CLIP_TO_PADDING, clipToPadding);
+ }
+ if (!deactivated) {
+ clipSet.remove(transformedView);
+ if (clipSet.isEmpty()) {
+ parent.setClipChildren(clipChildren);
+ parent.setClipToPadding(clipToPadding);
+ parent.setTagInternal(CLIP_CLIPPING_SET, null);
+ clippingParameters.onClippingStateChanged(parent, true);
+ }
+ } else {
+ clipSet.add(transformedView);
+ parent.setClipChildren(false);
+ parent.setClipToPadding(false);
+ clippingParameters.onClippingStateChanged(parent, false);
+ }
+ if (clippingParameters.shouldFinish(parent)) {
+ return;
+ }
+ final ViewParent viewParent = parent.getParent();
+ if (viewParent instanceof ViewGroup) {
+ parent = (ViewGroup) viewParent;
+ } else {
+ return;
+ }
+ }
+ }
+
+ public interface ClippingParameters {
+ /**
+ * Should we stop clipping at this view? If true is returned, {@param view} is the last view
+ * where clipping is activated / deactivated.
+ */
+ boolean shouldFinish(View view);
+
+ /**
+ * Is it allowed to enable clipping on this view.
+ */
+ default boolean isClippingEnablingAllowed(View view) {
+ return !MessagingPropertyAnimator.isAnimatingTranslation(view);
+ }
+
+ /**
+ * A method that is called whenever the view starts clipping again / stops clipping to the
+ * children and padding.
+ */
+ default void onClippingStateChanged(View view, boolean isClipping) {};
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index f88db25..fb8b9f7 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -185,7 +185,6 @@
"android/opengl/poly_clip.cpp", // TODO: .arm
"android/opengl/util.cpp",
"android_server_NetworkManagementSocketTagger.cpp",
- "android_server_Watchdog.cpp",
"android_ddm_DdmHandleNativeHeap.cpp",
"android_backup_BackupDataInput.cpp",
"android_backup_BackupDataOutput.cpp",
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_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index c4f22ee..08d9527 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -296,7 +296,8 @@
JNIEnv *env,
jclass /* clazzObj */,
jstring ifaceNameObj,
- jstring serviceNameObj) {
+ jstring serviceNameObj,
+ jboolean retry) {
using ::android::hidl::base::V1_0::IBase;
using ::android::hardware::details::getRawServiceInternal;
@@ -319,8 +320,7 @@
serviceName = str.c_str();
}
- // TODO(b/67981006): true /* retry */
- sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, false /* retry */, false /* getStub */);
+ sp<IBase> ret = getRawServiceInternal(ifaceName, serviceName, retry /* retry */, false /* getStub */);
sp<hardware::IBinder> service = hardware::toBinder<hidl::base::V1_0::IBase>(ret);
if (service == NULL) {
@@ -360,7 +360,7 @@
{ "registerService", "(Ljava/lang/String;)V",
(void *)JHwBinder_native_registerService },
- { "getService", "(Ljava/lang/String;Ljava/lang/String;)L" PACKAGE_PATH "/IHwBinder;",
+ { "getService", "(Ljava/lang/String;Ljava/lang/String;Z)L" PACKAGE_PATH "/IHwBinder;",
(void *)JHwBinder_native_getService },
{ "configureRpcThreadpool", "(JZ)V",
diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp
index 40d49b7..bb916d2 100644
--- a/core/jni/android_os_HwBlob.cpp
+++ b/core/jni/android_os_HwBlob.cpp
@@ -26,6 +26,7 @@
#include <android_runtime/AndroidRuntime.h>
#include <hidl/Status.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
#include "core_jni_helpers.h"
@@ -60,12 +61,12 @@
JNIEnv *env, jobject thiz, const sp<JHwBlob> &context) {
sp<JHwBlob> old = (JHwBlob *)env->GetLongField(thiz, gFields.contextID);
- if (context != NULL) {
- context->incStrong(NULL /* id */);
+ if (context != nullptr) {
+ context->incStrong(nullptr /* id */);
}
- if (old != NULL) {
- old->decStrong(NULL /* id */);
+ if (old != nullptr) {
+ old->decStrong(nullptr /* id */);
}
env->SetLongField(thiz, gFields.contextID, (long)context.get());
@@ -150,6 +151,10 @@
return mBuffer;
}
+void *JHwBlob::data() {
+ return mBuffer;
+}
+
size_t JHwBlob::size() const {
return mSize;
}
@@ -242,8 +247,8 @@
static void releaseNativeContext(void *nativeContext) {
sp<JHwBlob> parcel = (JHwBlob *)nativeContext;
- if (parcel != NULL) {
- parcel->decStrong(NULL /* id */);
+ if (parcel != nullptr) {
+ parcel->decStrong(nullptr /* id */);
}
}
@@ -313,6 +318,82 @@
return env->NewStringUTF(s->c_str());
}
+#define DEFINE_BLOB_ARRAY_COPIER(Suffix,Type,NewType) \
+static void JHwBlob_native_copyTo ## Suffix ## Array( \
+ JNIEnv *env, \
+ jobject thiz, \
+ jlong offset, \
+ Type ## Array array, \
+ jint size) { \
+ if (array == nullptr) { \
+ jniThrowException(env, "java/lang/NullPointerException", nullptr); \
+ return; \
+ } \
+ \
+ if (env->GetArrayLength(array) < size) { \
+ signalExceptionForError(env, BAD_VALUE); \
+ return; \
+ } \
+ \
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
+ \
+ if ((offset + size * sizeof(Type)) > blob->size()) { \
+ signalExceptionForError(env, -ERANGE); \
+ return; \
+ } \
+ \
+ env->Set ## NewType ## ArrayRegion( \
+ array, \
+ 0 /* start */, \
+ size, \
+ reinterpret_cast<const Type *>( \
+ static_cast<const uint8_t *>(blob->data()) + offset)); \
+}
+
+DEFINE_BLOB_ARRAY_COPIER(Int8,jbyte,Byte)
+DEFINE_BLOB_ARRAY_COPIER(Int16,jshort,Short)
+DEFINE_BLOB_ARRAY_COPIER(Int32,jint,Int)
+DEFINE_BLOB_ARRAY_COPIER(Int64,jlong,Long)
+DEFINE_BLOB_ARRAY_COPIER(Float,jfloat,Float)
+DEFINE_BLOB_ARRAY_COPIER(Double,jdouble,Double)
+
+static void JHwBlob_native_copyToBoolArray(
+ JNIEnv *env,
+ jobject thiz,
+ jlong offset,
+ jbooleanArray array,
+ jint size) {
+ if (array == nullptr) {
+ jniThrowException(env, "java/lang/NullPointerException", nullptr);
+ return;
+ }
+
+ if (env->GetArrayLength(array) < size) {
+ signalExceptionForError(env, BAD_VALUE);
+ return;
+ }
+
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+ if ((offset + size * sizeof(bool)) > blob->size()) {
+ signalExceptionForError(env, -ERANGE);
+ return;
+ }
+
+ const bool *src =
+ reinterpret_cast<const bool *>(
+ static_cast<const uint8_t *>(blob->data()) + offset);
+
+ jboolean *dst = env->GetBooleanArrayElements(array, nullptr /* isCopy */);
+
+ for (jint i = 0; i < size; ++i) {
+ dst[i] = src[i];
+ }
+
+ env->ReleaseBooleanArrayElements(array, dst, 0 /* mode */);
+ dst = nullptr;
+}
+
#define DEFINE_BLOB_PUTTER(Suffix,Type) \
static void JHwBlob_native_put ## Suffix( \
JNIEnv *env, jobject thiz, jlong offset, Type x) { \
@@ -375,6 +456,59 @@
blob->putBlob(offset + hidl_string::kOffsetOfBuffer, subBlob);
}
+#define DEFINE_BLOB_ARRAY_PUTTER(Suffix,Type,NewType) \
+static void JHwBlob_native_put ## Suffix ## Array( \
+ JNIEnv *env, jobject thiz, jlong offset, Type ## Array array) { \
+ Scoped ## NewType ## ArrayRO autoArray(env, array); \
+ \
+ if (array == nullptr) { \
+ /* NullpointerException already pending */ \
+ return; \
+ } \
+ \
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz); \
+ \
+ status_t err = blob->write( \
+ offset, autoArray.get(), autoArray.size() * sizeof(Type)); \
+ \
+ if (err != OK) { \
+ signalExceptionForError(env, err); \
+ } \
+}
+
+DEFINE_BLOB_ARRAY_PUTTER(Int8,jbyte,Byte)
+DEFINE_BLOB_ARRAY_PUTTER(Int16,jshort,Short)
+DEFINE_BLOB_ARRAY_PUTTER(Int32,jint,Int)
+DEFINE_BLOB_ARRAY_PUTTER(Int64,jlong,Long)
+DEFINE_BLOB_ARRAY_PUTTER(Float,jfloat,Float)
+DEFINE_BLOB_ARRAY_PUTTER(Double,jdouble,Double)
+
+static void JHwBlob_native_putBoolArray(
+ JNIEnv *env, jobject thiz, jlong offset, jbooleanArray array) {
+ ScopedBooleanArrayRO autoArray(env, array);
+
+ if (array == nullptr) {
+ /* NullpointerException already pending */
+ return;
+ }
+
+ sp<JHwBlob> blob = JHwBlob::GetNativeContext(env, thiz);
+
+ if ((offset + autoArray.size() * sizeof(bool)) > blob->size()) {
+ signalExceptionForError(env, -ERANGE);
+ return;
+ }
+
+ const jboolean *src = autoArray.get();
+
+ bool *dst = reinterpret_cast<bool *>(
+ static_cast<uint8_t *>(blob->data()) + offset);
+
+ for (size_t i = 0; i < autoArray.size(); ++i) {
+ dst[i] = src[i];
+ }
+}
+
static void JHwBlob_native_putBlob(
JNIEnv *env, jobject thiz, jlong offset, jobject blobObj) {
if (blobObj == nullptr) {
@@ -413,6 +547,14 @@
{ "getDouble", "(J)D", (void *)JHwBlob_native_getDouble },
{ "getString", "(J)Ljava/lang/String;", (void *)JHwBlob_native_getString },
+ { "copyToBoolArray", "(J[ZI)V", (void *)JHwBlob_native_copyToBoolArray },
+ { "copyToInt8Array", "(J[BI)V", (void *)JHwBlob_native_copyToInt8Array },
+ { "copyToInt16Array", "(J[SI)V", (void *)JHwBlob_native_copyToInt16Array },
+ { "copyToInt32Array", "(J[II)V", (void *)JHwBlob_native_copyToInt32Array },
+ { "copyToInt64Array", "(J[JI)V", (void *)JHwBlob_native_copyToInt64Array },
+ { "copyToFloatArray", "(J[FI)V", (void *)JHwBlob_native_copyToFloatArray },
+ { "copyToDoubleArray", "(J[DI)V", (void *)JHwBlob_native_copyToDoubleArray },
+
{ "putBool", "(JZ)V", (void *)JHwBlob_native_putBool },
{ "putInt8", "(JB)V", (void *)JHwBlob_native_putInt8 },
{ "putInt16", "(JS)V", (void *)JHwBlob_native_putInt16 },
@@ -422,6 +564,14 @@
{ "putDouble", "(JD)V", (void *)JHwBlob_native_putDouble },
{ "putString", "(JLjava/lang/String;)V", (void *)JHwBlob_native_putString },
+ { "putBoolArray", "(J[Z)V", (void *)JHwBlob_native_putBoolArray },
+ { "putInt8Array", "(J[B)V", (void *)JHwBlob_native_putInt8Array },
+ { "putInt16Array", "(J[S)V", (void *)JHwBlob_native_putInt16Array },
+ { "putInt32Array", "(J[I)V", (void *)JHwBlob_native_putInt32Array },
+ { "putInt64Array", "(J[J)V", (void *)JHwBlob_native_putInt64Array },
+ { "putFloatArray", "(J[F)V", (void *)JHwBlob_native_putFloatArray },
+ { "putDoubleArray", "(J[D)V", (void *)JHwBlob_native_putDoubleArray },
+
{ "putBlob", "(JL" PACKAGE_PATH "/HwBlob;)V",
(void *)JHwBlob_native_putBlob },
diff --git a/core/jni/android_os_HwBlob.h b/core/jni/android_os_HwBlob.h
index 39393cb..6b1db63 100644
--- a/core/jni/android_os_HwBlob.h
+++ b/core/jni/android_os_HwBlob.h
@@ -50,6 +50,8 @@
size_t offset, const android::hardware::hidl_string **s) const;
const void *data() const;
+ void *data();
+
size_t size() const;
status_t putBlob(size_t offset, const sp<JHwBlob> &blob);
diff --git a/core/jni/android_os_HwRemoteBinder.cpp b/core/jni/android_os_HwRemoteBinder.cpp
index cf59a56a..ca5e1e4 100644
--- a/core/jni/android_os_HwRemoteBinder.cpp
+++ b/core/jni/android_os_HwRemoteBinder.cpp
@@ -22,9 +22,13 @@
#include "android_os_HwParcel.h"
-#include <nativehelper/JNIHelp.h>
+#include <android/hidl/base/1.0/IBase.h>
+#include <android/hidl/base/1.0/BpHwBase.h>
+#include <android/hidl/base/1.0/BnHwBase.h>
#include <android_runtime/AndroidRuntime.h>
#include <hidl/Status.h>
+#include <hidl/HidlTransportSupport.h>
+#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <nativehelper/ScopedLocalRef.h>
@@ -413,6 +417,44 @@
return res;
}
+static sp<hidl::base::V1_0::IBase> toIBase(JNIEnv* env, jclass hwRemoteBinderClazz, jobject jbinder)
+{
+ if (jbinder == nullptr) {
+ return nullptr;
+ }
+ if (!env->IsInstanceOf(jbinder, hwRemoteBinderClazz)) {
+ return nullptr;
+ }
+ sp<JHwRemoteBinder> context = JHwRemoteBinder::GetNativeContext(env, jbinder);
+ sp<hardware::IBinder> cbinder = context->getBinder();
+ return hardware::fromBinder<hidl::base::V1_0::IBase, hidl::base::V1_0::BpHwBase,
+ hidl::base::V1_0::BnHwBase>(cbinder);
+}
+
+// equals iff other is also a non-null android.os.HwRemoteBinder object
+// and getBinder() returns the same object.
+// In particular, if other is an android.os.HwBinder object (for stubs) then
+// it returns false.
+static jboolean JHwRemoteBinder_equals(JNIEnv* env, jobject thiz, jobject other)
+{
+ if (env->IsSameObject(thiz, other)) {
+ return true;
+ }
+ if (other == NULL) {
+ return false;
+ }
+
+ ScopedLocalRef<jclass> clazz(env, FindClassOrDie(env, CLASS_PATH));
+
+ return hardware::interfacesEqual(toIBase(env, clazz.get(), thiz), toIBase(env, clazz.get(), other));
+}
+
+static jint JHwRemoteBinder_hashCode(JNIEnv* env, jobject thiz) {
+ jlong longHash = reinterpret_cast<jlong>(
+ JHwRemoteBinder::GetNativeContext(env, thiz)->getBinder().get());
+ return static_cast<jint>(longHash ^ (longHash >> 32)); // See Long.hashCode()
+}
+
static JNINativeMethod gMethods[] = {
{ "native_init", "()J", (void *)JHwRemoteBinder_native_init },
@@ -430,6 +472,11 @@
{"unlinkToDeath",
"(Landroid/os/IHwBinder$DeathRecipient;)Z",
(void*)JHwRemoteBinder_unlinkToDeath},
+
+ {"equals", "(Ljava/lang/Object;)Z",
+ (void*)JHwRemoteBinder_equals},
+
+ {"hashCode", "()I", (void*)JHwRemoteBinder_hashCode},
};
namespace android {
diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp
index f0ac79a..d18c172 100644
--- a/core/jni/android_os_Parcel.cpp
+++ b/core/jni/android_os_Parcel.cpp
@@ -554,18 +554,6 @@
}
}
-static void android_os_Parcel_clearFileDescriptor(JNIEnv* env, jclass clazz, jobject object)
-{
- if (object == NULL) {
- jniThrowNullPointerException(env, NULL);
- return;
- }
- int fd = jniGetFDFromFileDescriptor(env, object);
- if (fd >= 0) {
- jniSetFileDescriptorOfFD(env, object, -1);
- }
-}
-
static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
Parcel* parcel = new Parcel();
@@ -811,7 +799,6 @@
{"openFileDescriptor", "(Ljava/lang/String;I)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_openFileDescriptor},
{"dupFileDescriptor", "(Ljava/io/FileDescriptor;)Ljava/io/FileDescriptor;", (void*)android_os_Parcel_dupFileDescriptor},
{"closeFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_closeFileDescriptor},
- {"clearFileDescriptor", "(Ljava/io/FileDescriptor;)V", (void*)android_os_Parcel_clearFileDescriptor},
{"nativeCreate", "()J", (void*)android_os_Parcel_create},
{"nativeFreeBuffer", "(J)J", (void*)android_os_Parcel_freeBuffer},
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 5ef2a9e..6243fad 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -102,8 +102,11 @@
cPackageInfo[i] = cString;
env->ReleaseStringUTFChars(element, cString);
}
+ // If we can run this code, the device should already pass AVB.
+ // So, we don't need to check AVB here.
std::string error;
- int32_t status = VintfObject::CheckCompatibility(cPackageInfo, &error);
+ int32_t status = VintfObject::CheckCompatibility(
+ cPackageInfo, &error, ::android::vintf::DISABLE_AVB_CHECK);
if (status)
LOG(WARNING) << "VintfObject.verify() returns " << status << ": " << error;
return status;
diff --git a/core/jni/android_server_Watchdog.cpp b/core/jni/android_server_Watchdog.cpp
deleted file mode 100644
index 01d565b..0000000
--- a/core/jni/android_server_Watchdog.cpp
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- ** Copyright 2010, 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.
- */
-
-#define LOG_TAG "Watchdog_N"
-#include <utils/Log.h>
-
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <string.h>
-#include <errno.h>
-
-#include "jni.h"
-#include <nativehelper/JNIHelp.h>
-#include "core_jni_helpers.h"
-
-static void dumpOneStack(int tid, int outFd) {
- char buf[64];
-
- snprintf(buf, sizeof(buf), "/proc/%d/stack", tid);
- int stackFd = open(buf, O_RDONLY);
- if (stackFd >= 0) {
- // header for readability
- strncat(buf, ":\n", sizeof(buf) - strlen(buf) - 1);
- write(outFd, buf, strlen(buf));
-
- // copy the stack dump text
- int nBytes;
- while ((nBytes = read(stackFd, buf, sizeof(buf))) > 0) {
- write(outFd, buf, nBytes);
- }
-
- // footer and done
- write(outFd, "\n", 1);
- close(stackFd);
- } else {
- ALOGE("Unable to open stack of tid %d : %d (%s)", tid, errno, strerror(errno));
- }
-}
-
-static void dumpKernelStacks(JNIEnv* env, jobject clazz, jstring pathStr) {
- char buf[128];
- DIR* taskdir;
-
- ALOGI("dumpKernelStacks");
- if (!pathStr) {
- jniThrowException(env, "java/lang/IllegalArgumentException", "Null path");
- return;
- }
-
- const char *path = env->GetStringUTFChars(pathStr, NULL);
-
- int outFd = open(path, O_WRONLY | O_APPEND | O_CREAT,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
- if (outFd < 0) {
- ALOGE("Unable to open stack dump file: %d (%s)", errno, strerror(errno));
- goto done;
- }
-
- snprintf(buf, sizeof(buf), "\n----- begin pid %d kernel stacks -----\n", getpid());
- write(outFd, buf, strlen(buf));
-
- // look up the list of all threads in this process
- snprintf(buf, sizeof(buf), "/proc/%d/task", getpid());
- taskdir = opendir(buf);
- if (taskdir != NULL) {
- struct dirent * ent;
- while ((ent = readdir(taskdir)) != NULL) {
- int tid = atoi(ent->d_name);
- if (tid > 0 && tid <= 65535) {
- // dump each stack trace
- dumpOneStack(tid, outFd);
- }
- }
- closedir(taskdir);
- }
-
- snprintf(buf, sizeof(buf), "----- end pid %d kernel stacks -----\n", getpid());
- write(outFd, buf, strlen(buf));
-
- close(outFd);
-done:
- env->ReleaseStringUTFChars(pathStr, path);
-}
-
-// ----------------------------------------
-
-namespace android {
-
-static const JNINativeMethod g_methods[] = {
- { "native_dumpKernelStacks", "(Ljava/lang/String;)V", (void*)dumpKernelStacks },
-};
-
-int register_android_server_Watchdog(JNIEnv* env) {
- return RegisterMethodsOrDie(env, "com/android/server/Watchdog", g_methods, NELEM(g_methods));
-}
-
-}
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_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index dea38e8..1350f3f 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -171,6 +171,7 @@
// Garbage collect if we've allocated at least GC_INTERVAL refs since the last time.
// TODO: Consider removing this completely. We should no longer be generating GlobalRefs
// that are reclaimed as a result of GC action.
+__attribute__((no_sanitize("unsigned-integer-overflow")))
static void gcIfManyNewRefs(JNIEnv* env)
{
uint32_t totalRefs = gNumLocalRefsCreated.load(std::memory_order_relaxed)
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/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index 50e811d..e998b09 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -27,6 +27,7 @@
import "frameworks/base/core/proto/android/os/procrank.proto";
import "frameworks/base/core/proto/android/server/activitymanagerservice.proto";
import "frameworks/base/core/proto/android/server/alarmmanagerservice.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
import "frameworks/base/core/proto/android/server/fingerprint.proto";
import "frameworks/base/core/proto/android/server/powermanagerservice.proto";
import "frameworks/base/core/proto/android/service/appwidget.proto";
@@ -135,4 +136,9 @@
(section).type = SECTION_DUMPSYS,
(section).args = "alarm --proto"
];
+
+ optional com.android.server.wm.proto.WindowManagerServiceProto window = 3017 [
+ (section).type = SECTION_DUMPSYS,
+ (section).args = "window --proto"
+ ];
}
diff --git a/core/proto/android/os/kernelwake.proto b/core/proto/android/os/kernelwake.proto
index 12649e1..d032a45 100644
--- a/core/proto/android/os/kernelwake.proto
+++ b/core/proto/android/os/kernelwake.proto
@@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
syntax = "proto2";
+
option java_multiple_files = true;
option java_outer_classname = "WakeupSourcesProto";
+import "frameworks/base/tools/streaming_proto/stream.proto";
+
package android.os;
message KernelWakeSources {
@@ -27,6 +29,8 @@
// Next Tag: 11
message WakeupSourceProto {
+ option (stream_proto.stream).enable_fields_mapping = true;
+
// Name of the event which triggers application processor
optional string name = 1;
diff --git a/core/proto/android/os/pagetypeinfo.proto b/core/proto/android/os/pagetypeinfo.proto
index f82ea76..22b3d73 100644
--- a/core/proto/android/os/pagetypeinfo.proto
+++ b/core/proto/android/os/pagetypeinfo.proto
@@ -18,6 +18,8 @@
option java_multiple_files = true;
option java_outer_classname = "PageTypeInfoProto";
+import "frameworks/base/tools/streaming_proto/stream.proto";
+
package android.os;
/*
@@ -61,6 +63,7 @@
// Next tag: 9
message BlockProto {
+ option (stream_proto.stream).enable_fields_mapping = true;
optional int32 node = 1;
diff --git a/core/proto/android/os/procrank.proto b/core/proto/android/os/procrank.proto
index ab6a6a3..4d62a60 100644
--- a/core/proto/android/os/procrank.proto
+++ b/core/proto/android/os/procrank.proto
@@ -18,6 +18,8 @@
option java_multiple_files = true;
option java_outer_classname = "ProcrankProto";
+import "frameworks/base/tools/streaming_proto/stream.proto";
+
package android.os;
//Memory usage of running processes
@@ -31,6 +33,8 @@
// Next Tag: 11
message ProcessProto {
+ option (stream_proto.stream).enable_fields_mapping = true;
+
// ID of the process
optional int32 pid = 1;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index 064523a..4d48a42 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -15,6 +15,7 @@
*/
syntax = "proto2";
+
import "frameworks/base/core/proto/android/content/configuration.proto";
import "frameworks/base/core/proto/android/graphics/rect.proto";
import "frameworks/base/core/proto/android/view/displayinfo.proto";
diff --git a/core/proto/android/server/windowmanagertrace.proto b/core/proto/android/server/windowmanagertrace.proto
new file mode 100644
index 0000000..0c65bb2
--- /dev/null
+++ b/core/proto/android/server/windowmanagertrace.proto
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+import "frameworks/base/core/proto/android/content/configuration.proto";
+import "frameworks/base/core/proto/android/graphics/rect.proto";
+import "frameworks/base/core/proto/android/server/windowmanagerservice.proto";
+import "frameworks/base/core/proto/android/view/displayinfo.proto";
+import "frameworks/base/core/proto/android/view/windowlayoutparams.proto";
+
+package com.android.server.wm.proto;
+
+option java_multiple_files = true;
+
+/* represents a file full of window manager trace entries.
+ Encoded, it should start with 0x9 0x57 0x49 0x4e 0x54 0x52 0x41 0x43 0x45 (.WINTRACE), such
+ that they can be easily identified. */
+message WindowManagerTraceFileProto {
+
+ /* constant; MAGIC_NUMBER = (long) MAGIC_NUMBER_H << 32 | MagicNumber.MAGIC_NUMBER_L
+ (this is needed because enums have to be 32 bits and there's no nice way to put 64bit
+ constants into .proto files. */
+ enum MagicNumber {
+ INVALID = 0;
+ MAGIC_NUMBER_L = 0x544e4957; /* WINT (little-endian ASCII) */
+ MAGIC_NUMBER_H = 0x45434152; /* RACE (little-endian ASCII) */
+ }
+
+ optional fixed64 magic_number = 1; /* Must be the first field, set to value in MagicNumber */
+ repeated WindowManagerTraceProto entry = 2;
+}
+
+/* one window manager trace entry. */
+message WindowManagerTraceProto {
+ /* required: elapsed realtime in nanos since boot of when this entry was logged */
+ optional fixed64 elapsed_realtime_nanos = 1;
+
+ /* where the trace originated */
+ optional string where = 2;
+
+ optional WindowManagerServiceProto window_manager_service = 3;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 77bfec3..b8d3a57 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3062,10 +3062,10 @@
android:protectionLevel="signature|privileged|development|appop" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
- <!-- @hide Allows an application to change the app idle state of an app.
+ <!-- @hide @SystemApi Allows an application to change the app idle state of an app.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.CHANGE_APP_IDLE_STATE"
- android:protectionLevel="signature" />
+ android:protectionLevel="signature|privileged" />
<!-- @hide @SystemApi Allows an application to temporarily whitelist an inactive app to
access the network and acquire wakelocks.
@@ -3840,14 +3840,6 @@
</intent-filter>
</receiver>
- <receiver android:name="com.android.server.updates.TzDataInstallReceiver"
- android:permission="android.permission.UPDATE_CONFIG">
- <intent-filter>
- <action android:name="android.intent.action.UPDATE_TZDATA" />
- <data android:scheme="content" android:host="*" android:mimeType="*/*" />
- </intent-filter>
- </receiver>
-
<receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver"
android:permission="android.permission.UPDATE_CONFIG">
<intent-filter>
@@ -3952,6 +3944,10 @@
<service android:name="com.android.server.timezone.TimeZoneUpdateIdler"
android:permission="android.permission.BIND_JOB_SERVICE" >
</service>
+
+ <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService"
+ android:permission="android.permission.BIND_JOB_SERVICE" >
+ </service>
</application>
</manifest>
diff --git a/core/res/res/drawable/dialog_background_material.xml b/core/res/res/drawable/dialog_background_material.xml
index 2f8d1fa..e017d3c 100644
--- a/core/res/res/drawable/dialog_background_material.xml
+++ b/core/res/res/drawable/dialog_background_material.xml
@@ -17,7 +17,7 @@
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:inset="16dp">
<shape android:shape="rectangle">
- <corners android:radius="2dp" />
+ <corners android:radius="?attr/dialogCornerRadius" />
<solid android:color="?attr/colorBackground" />
</shape>
</inset>
diff --git a/core/res/res/drawable/ic_reply_notification_large.xml b/core/res/res/drawable/ic_reply_notification_large.xml
new file mode 100644
index 0000000..e75afddf
--- /dev/null
+++ b/core/res/res/drawable/ic_reply_notification_large.xml
@@ -0,0 +1,29 @@
+<!--
+ ~ 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
+ -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="8dp">
+ <vector android:width="24dp"
+ android:height="24dp"
+ android:viewportHeight="24.0"
+ android:viewportWidth="24.0">
+ <path
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M10.0,9.0L10.0,5.0l-7.0,7.0 7.0,7.0l0.0,-4.1c5.0,0.0 8.5,1.6 11.0,5.1 -1.0,-5.0 -4.0,-10.0 -11.0,-11.0z"/>
+ <path
+ android:fillColor="#00000000"
+ android:pathData="M0 0h24v24H0z"/>
+ </vector>
+</inset>
diff --git a/core/res/res/drawable/messaging_message_background.xml b/core/res/res/drawable/messaging_message_background.xml
new file mode 100644
index 0000000..8a2096a
--- /dev/null
+++ b/core/res/res/drawable/messaging_message_background.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle"
+ android:tint="#14000000">
+ <corners android:radius="4dp" />
+ <padding android:bottom="6dp"
+ android:left="8dp"
+ android:right="8dp"
+ android:top="6dp" />
+</shape>
diff --git a/core/res/res/layout/chooser_row.xml b/core/res/res/layout/chooser_row.xml
index 6c1271d..cf81260 100644
--- a/core/res/res/layout/chooser_row.xml
+++ b/core/res/res/layout/chooser_row.xml
@@ -22,8 +22,7 @@
android:layout_height="100dp"
android:gravity="start|top"
android:paddingStart="@dimen/chooser_grid_padding"
- android:paddingEnd="@dimen/chooser_grid_padding"
- android:weightSum="4">
+ android:paddingEnd="@dimen/chooser_grid_padding">
</LinearLayout>
diff --git a/core/res/res/layout/notification_material_action.xml b/core/res/res/layout/notification_material_action.xml
index 548ee05..3c9f6ee 100644
--- a/core/res/res/layout/notification_material_action.xml
+++ b/core/res/res/layout/notification_material_action.xml
@@ -25,6 +25,7 @@
android:layout_marginStart="4dp"
android:textColor="@color/notification_default_color"
android:singleLine="true"
+ android:textAlignment="viewStart"
android:ellipsize="end"
android:background="@drawable/notification_material_action_background"
/>
diff --git a/core/res/res/layout/notification_material_action_tombstone.xml b/core/res/res/layout/notification_material_action_tombstone.xml
index 1f59ea0..817f298 100644
--- a/core/res/res/layout/notification_material_action_tombstone.xml
+++ b/core/res/res/layout/notification_material_action_tombstone.xml
@@ -26,6 +26,7 @@
android:textColor="#555555"
android:singleLine="true"
android:ellipsize="end"
+ android:textAlignment="viewStart"
android:alpha="0.5"
android:enabled="false"
android:background="@drawable/notification_material_action_background"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index f0c980c..3a28f4d 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -37,6 +37,7 @@
android:textAppearance="?attr/notificationHeaderTextAppearance"
android:layout_marginStart="@dimen/notification_header_app_name_margin_start"
android:layout_marginEnd="@dimen/notification_header_separating_margin"
+ android:visibility="?attr/notificationHeaderAppNameVisibility"
android:singleLine="true"
/>
<TextView
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
index ee5c758..865685f 100644
--- a/core/res/res/layout/notification_template_material_ambient.xml
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -23,8 +23,8 @@
android:paddingStart="@dimen/notification_extra_margin_ambient"
android:paddingEnd="@dimen/notification_extra_margin_ambient"
>
- <include layout="@layout/notification_template_header"
- android:theme="@style/Theme.Material.Notification.Ambient" />
+ <include layout="@layout/notification_template_ambient_header"
+ android:theme="@style/Theme.Material.Notification.Ambient" />
<LinearLayout
android:id="@+id/notification_action_list_margin_target"
@@ -53,6 +53,7 @@
android:textAppearance="@style/TextAppearance.Material.Notification.Title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:gravity="top|center_horizontal"
android:singleLine="true"
android:ellipsize="marquee"
android:fadingEdge="horizontal"
@@ -65,7 +66,7 @@
android:textAppearance="@style/TextAppearance.Material.Notification"
android:singleLine="false"
android:layout_weight="1"
- android:gravity="top"
+ android:gravity="top|center_horizontal"
android:visibility="gone"
android:textSize="16sp"
android:textColor="#eeffffff"
@@ -75,5 +76,19 @@
/>
</LinearLayout>
</LinearLayout>
- <include layout="@layout/notification_material_action_list" />
+ <FrameLayout android:id="@+id/actions_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom">
+ <com.android.internal.widget.NotificationActionListLayout
+ android:id="@+id/actions"
+ android:layout_width="match_parent"
+ android:layout_height="@dimen/notification_action_list_height"
+ android:paddingEnd="4dp"
+ android:orientation="horizontal"
+ android:gravity="center"
+ android:visibility="gone"
+ android:background="@color/notification_action_list"
+ />
+ </FrameLayout>
</FrameLayout>
diff --git a/core/res/res/layout/notification_template_material_messaging.xml b/core/res/res/layout/notification_template_material_messaging.xml
index fd5154a..f72230b 100644
--- a/core/res/res/layout/notification_template_material_messaging.xml
+++ b/core/res/res/layout/notification_template_material_messaging.xml
@@ -14,13 +14,17 @@
~ See the License for the specific language governing permissions and
~ limitations under the License
-->
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.MessagingLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/status_bar_latest_event_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:tag="messaging"
>
- <include layout="@layout/notification_template_header" />
+ <include layout="@layout/notification_template_header"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/notification_header_height"
+ android:layout_marginEnd="56dp"/>
<LinearLayout
android:id="@+id/notification_action_list_margin_target"
android:layout_width="match_parent"
@@ -39,7 +43,6 @@
android:paddingEnd="@dimen/notification_content_margin_end"
android:minHeight="@dimen/notification_min_content_height"
android:layout_marginBottom="@dimen/notification_content_margin_bottom"
- android:clipToPadding="false"
android:orientation="vertical"
>
<include layout="@layout/notification_template_part_line1"
@@ -50,31 +53,14 @@
android:id="@+id/notification_messaging"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:spacing="@dimen/notification_messaging_spacing" >
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text0"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text1"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text2"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text3"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text4"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text5"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- <com.android.internal.widget.ImageFloatingTextView android:id="@+id/inbox_text6"
- style="@style/Widget.Material.Notification.MessagingText"
- />
- </com.android.internal.widget.MessagingLinearLayout>
+ android:layout_marginTop="8dp"
+ android:spacing="@dimen/notification_messaging_spacing" />
</LinearLayout>
</LinearLayout>
<include layout="@layout/notification_material_action_list" />
- <include layout="@layout/notification_template_right_icon" />
-</FrameLayout>
+ <include layout="@layout/notification_template_right_icon"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="18dp"
+ android:layout_gravity="top|end"/>
+</com.android.internal.widget.MessagingLayout>
diff --git a/core/res/res/layout/notification_template_messaging_group.xml b/core/res/res/layout/notification_template_messaging_group.xml
new file mode 100644
index 0000000..8973ceb
--- /dev/null
+++ b/core/res/res/layout/notification_template_messaging_group.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2016 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.internal.widget.MessagingGroup
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/status_bar_latest_event_content"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal" >
+ <ImageView
+ android:id="@+id/message_icon"
+ android:layout_width="@dimen/messaging_avatar_size"
+ android:layout_height="@dimen/messaging_avatar_size"
+ android:layout_marginEnd="8dp"
+ android:scaleType="centerCrop"
+ android:importantForAccessibility="no" />
+ <com.android.internal.widget.RemeasuringLinearLayout
+ android:id="@+id/message_group_and_sender_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+ <com.android.internal.widget.MessagingLinearLayout
+ android:id="@+id/group_message_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:spacing="2dp"
+ android:layout_weight="1"/>
+ <com.android.internal.widget.ImageFloatingTextView
+ android:id="@+id/message_name"
+ style="@style/Widget.Material.Notification.MessagingName"
+ android:layout_width="wrap_content"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
+ android:paddingTop="2dp"
+ />
+ </com.android.internal.widget.RemeasuringLinearLayout>
+</com.android.internal.widget.MessagingGroup>
diff --git a/core/res/res/layout/notification_template_messaging_message.xml b/core/res/res/layout/notification_template_messaging_message.xml
new file mode 100644
index 0000000..ab6466c
--- /dev/null
+++ b/core/res/res/layout/notification_template_messaging_message.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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
+ -->
+<com.android.internal.widget.MessagingMessage
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/message_text"
+ style="@style/Widget.Material.Notification.MessagingText"
+/>
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index d379256..8fb2887 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -19,12 +19,12 @@
android:id="@+id/right_icon_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:layout_marginTop="36dp"
android:layout_gravity="top|end">
<ImageView android:id="@+id/right_icon"
android:layout_width="@dimen/notification_right_icon_size"
android:layout_height="@dimen/notification_right_icon_size"
android:layout_gravity="top|end"
- android:layout_marginTop="36dp"
android:layout_marginEnd="@dimen/notification_content_margin_end"
android:scaleType="centerCrop"
android:importantForAccessibility="no" />
@@ -32,7 +32,7 @@
android:layout_width="16dp"
android:layout_height="16dp"
android:layout_gravity="top|end"
- android:layout_marginTop="64dp"
+ android:layout_marginTop="28dp"
android:layout_marginEnd="12dp"
android:background="@drawable/notification_reply_background"
android:src="@drawable/ic_reply_notification"
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/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index db4dcd2..0eefec9 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -984,6 +984,8 @@
<attr name="dialogTitleDecorLayout" format="reference" />
<!-- Preferred padding for dialog content. -->
<attr name="dialogPreferredPadding" format="dimension" />
+ <!-- Corner radius of dialogs. -->
+ <attr name="dialogCornerRadius" format="dimension" />
<!-- Theme to use for alert dialogs spawned from this theme. -->
<attr name="alertDialogTheme" format="reference" />
@@ -8713,6 +8715,14 @@
<attr name="notificationHeaderStyle" format="reference" />
<attr name="notificationHeaderTextAppearance" format="reference" />
<attr name="notificationHeaderIconSize" format="dimension" />
+ <attr name="notificationHeaderAppNameVisibility" format="enum">
+ <!-- Visible on screen; the default value. -->
+ <enum name="visible" value="0" />
+ <!-- Not displayed, but taken into account during layout (space is left for it). -->
+ <enum name="invisible" value="1" />
+ <!-- Completely hidden, as if the view had not been added. -->
+ <enum name="gone" value="2" />
+ </attr>
</declare-styleable>
<attr name="lockPatternStyle" format="reference" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4a8bc13..1c2e5a4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1698,6 +1698,11 @@
a transaction, so it interacts poorly with SECURE_DELETE. -->
<string name="db_default_journal_mode" translatable="false">TRUNCATE</string>
+ <!-- Enables compatibility WAL mode.
+ In this mode, only database journal mode will be changed, connection pool
+ size will still be limited to a single connection. -->
+ <bool name="db_compatibility_wal_supported">true</bool>
+
<!-- Maximum size of the persistent journal file in bytes.
If the journal file grows to be larger than this amount then SQLite will
truncate it after committing the transaction. -->
@@ -2519,7 +2524,13 @@
<bool name="config_networkSamplingWakesDevice">true</bool>
- <string-array translatable="false" name="config_cdma_home_system" />
+ <!-- Home (non-roaming) values for CDMA roaming indicator.
+ Carriers can override this table by resource overlay. If not,
+ the default values come from 3GPP2 C.R1001 table
+ 8.1-1. Enhanced Roaming Indicator Number Assignments -->
+ <string-array translatable="false" name="config_cdma_home_system">
+ <item>1</item>
+ </string-array>
<!--From SmsMessage-->
<!--Support decoding the user data payload as pack GSM 8-bit (a GSM alphabet
@@ -3147,4 +3158,7 @@
<!-- Component name of media projection permission dialog -->
<string name="config_mediaProjectionPermissionDialogComponent" translateable="false">com.android.systemui/com.android.systemui.media.MediaProjectionPermissionActivity</string>
+
+ <!-- Corner radius of system dialogs -->
+ <dimen name="config_dialogCornerRadius">2dp</dimen>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index dc75ba6..946216c 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -605,6 +605,8 @@
<!-- The size of the right icon image when on low ram -->
<dimen name="notification_right_icon_size_low_ram">40dp</dimen>
+ <dimen name="messaging_avatar_size">24dp</dimen>
+
<!-- Max width/height of the autofill data set picker as a fraction of the screen width/height -->
<dimen name="autofill_dataset_picker_max_size">90%</dimen>
@@ -624,4 +626,7 @@
<dimen name="slice_icon_size">24dp</dimen>
<!-- Standard padding used in a slice view -->
<dimen name="slice_padding">16dp</dimen>
+
+ <!-- Default dialog corner radius -->
+ <dimen name="dialog_corner_radius">2dp</dimen>
</resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index cd3624d..b40117e 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -139,6 +139,27 @@
<!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. -->
<item type="id" name="accessibilityActionMoveWindow" />
+ <!-- A tag used to save an animator in local y translation -->
+ <item type="id" name="tag_local_translation_y_animator" />
+
+ <!-- A tag used to save the local translation y -->
+ <item type="id" name="tag_local_translation_y" />
+
+ <!-- A tag used to save the original top of a view -->
+ <item type="id" name="tag_layout_top" />
+
+ <!-- A tag used to save an animator in alpha -->
+ <item type="id" name="tag_alpha_animator" />
+
+ <!-- A tag used to save the clip children in a tag -->
+ <item type="id" name="clip_children_tag" />
+
+ <!-- A tag used to save the set of deactivated children that clip -->
+ <item type="id" name="clip_children_set_tag" />
+
+ <!-- A tag used to save the clip to padding in a tag -->
+ <item type="id" name="clip_to_padding_tag" />
+
<!-- Action used to manually trigger an autofill request -->
<item type="id" name="autofill" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 083bf90..fdd56c4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2847,6 +2847,7 @@
<public name="cantSaveState" />
<public name="ttcIndex" />
<public name="fontVariationSettings" />
+ <public name="dialogCornerRadius" />
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 78a8e2a..9e0722b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4744,4 +4744,7 @@
A toast message shown when an app shortcut that wasn't restored due to an unknown issue is clicked,
-->
<string name="shortcut_restore_unknown_issue">Couldn\u2019t restore shortcut</string>
+
+ <!--Battery saver warning. STOPSHIP: Remove it eventually. -->
+ <string name="battery_saver_warning" translatable="false">Battery saver activated.\n\nSee go/extreme-battery-saver.\n\nThis contains aggressive experimental changes for P and may affect background app behavior.\n</string>
</resources>
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 470ac52..2cd4dcb 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -505,8 +505,17 @@
<item name="layout_width">match_parent</item>
<item name="layout_height">wrap_content</item>
<item name="ellipsize">end</item>
- <item name="visibility">gone</item>
<item name="textAppearance">@style/TextAppearance.Material.Notification</item>
+ <item name="background">@drawable/messaging_message_background</item>
+ </style>
+
+ <style name="Widget.Material.Notification.MessagingName" parent="Widget.Material.Light.TextView">
+ <item name="layout_width">wrap_content</item>
+ <item name="layout_height">wrap_content</item>
+ <item name="ellipsize">end</item>
+ <item name="textAppearance">@style/TextAppearance.Material.Notification</item>
+ <item name="textColor">@color/notification_primary_text_color_light</item>
+ <item name="textSize">12sp</item>
</style>
<!-- Widget Styles -->
@@ -1296,6 +1305,11 @@
<item name="layout_marginBottom">@dimen/notification_header_margin_bottom</item>
<item name="paddingStart">@dimen/notification_content_margin_start</item>
<item name="paddingEnd">16dp</item>
+ <item name="gravity">top</item>
+ </style>
+
+ <style name="Notification.Header.Ambient">
+ <item name="gravity">top|center_horizontal</item>
</style>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e513816..d630839 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -667,6 +667,7 @@
<java-symbol type="string" name="date_time" />
<java-symbol type="string" name="date_time_set" />
<java-symbol type="string" name="date_time_done" />
+ <java-symbol type="bool" name="db_compatibility_wal_supported" />
<java-symbol type="string" name="db_default_journal_mode" />
<java-symbol type="string" name="db_default_sync_mode" />
<java-symbol type="string" name="db_wal_sync_mode" />
@@ -1323,6 +1324,7 @@
<java-symbol type="drawable" name="cling_button" />
<java-symbol type="drawable" name="cling_arrow_up" />
<java-symbol type="drawable" name="cling_bg" />
+ <java-symbol type="drawable" name="ic_corp_badge" />
<java-symbol type="drawable" name="ic_corp_badge_color" />
<java-symbol type="drawable" name="ic_corp_badge_case" />
<java-symbol type="drawable" name="ic_corp_icon" />
@@ -3104,6 +3106,22 @@
<java-symbol type="dimen" name="chooser_service_spacing" />
<java-symbol type="bool" name="config_showSysuiShutdown" />
+ <java-symbol type="layout" name="notification_template_messaging_message" />
+ <java-symbol type="layout" name="notification_template_messaging_group" />
+ <java-symbol type="id" name="message_text" />
+ <java-symbol type="id" name="message_name" />
+ <java-symbol type="id" name="message_icon" />
+ <java-symbol type="id" name="group_message_container" />
+ <java-symbol type="id" name="tag_local_translation_y_animator" />
+ <java-symbol type="id" name="tag_local_translation_y" />
+ <java-symbol type="id" name="tag_layout_top" />
+ <java-symbol type="id" name="tag_alpha_animator" />
+ <java-symbol type="id" name="clip_children_set_tag" />
+ <java-symbol type="id" name="clip_to_padding_tag" />
+ <java-symbol type="id" name="clip_children_tag" />
+ <java-symbol type="drawable" name="ic_reply_notification_large" />
+ <java-symbol type="dimen" name="messaging_avatar_size" />
+
<java-symbol type="integer" name="config_stableDeviceDisplayWidth" />
<java-symbol type="integer" name="config_stableDeviceDisplayHeight" />
<java-symbol type="bool" name="config_display_no_service_when_sim_unready" />
@@ -3127,6 +3145,7 @@
<java-symbol type="string" name="shortcut_restore_not_supported" />
<java-symbol type="string" name="shortcut_restore_signature_mismatch" />
<java-symbol type="string" name="shortcut_restore_unknown_issue" />
+ <java-symbol type="string" name="battery_saver_warning" />
<!-- From media projection -->
<java-symbol type="string" name="config_mediaProjectionPermissionDialogComponent" />
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index bf0c906..68d5523 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -88,6 +88,7 @@
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.DeviceDefault.Dialog</item>
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
@@ -214,6 +215,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar. This theme
@@ -223,6 +228,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
@@ -234,6 +243,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
@@ -244,6 +257,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -263,6 +280,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
@@ -272,6 +293,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
@@ -280,6 +305,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
@@ -289,6 +318,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -314,6 +347,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for a window without an action bar that will be displayed either
@@ -324,6 +361,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for a presentation window on a secondary display. -->
@@ -332,6 +373,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for panel windows. This removes all extraneous window
@@ -342,6 +387,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -351,6 +400,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
@@ -360,6 +413,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -369,6 +426,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault style for input methods, which is used by the
@@ -378,11 +439,19 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
@@ -394,6 +463,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
@@ -401,6 +474,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault} with a light-colored style -->
@@ -441,6 +518,7 @@
<!-- Dialog attributes -->
<item name="dialogTheme">@style/Theme.DeviceDefault.Light.Dialog</item>
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
@@ -562,6 +640,10 @@
<item name="colorPrimary">@color/primary_device_default_dark</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
@@ -570,6 +652,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
@@ -579,6 +665,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
@@ -590,6 +680,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
@@ -600,6 +694,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -609,6 +707,10 @@
<item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
<item name="windowAnimationStyle">@style/Animation.DeviceDefault.Dialog</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
<item name="buttonBarStyle">@style/DeviceDefault.Light.ButtonBar.AlertDialog</item>
<item name="borderlessButtonStyle">@style/Widget.DeviceDefault.Light.Button.Borderless.Small</item>
@@ -628,6 +730,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
@@ -636,6 +742,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
@@ -645,6 +755,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -680,6 +794,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for a window without an action bar that will be displayed either
@@ -690,6 +808,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for a presentation window on a secondary display. -->
@@ -698,6 +820,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault light theme for panel windows. This removes all extraneous window
@@ -708,6 +834,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
@@ -717,6 +847,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
@@ -724,6 +858,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
@@ -731,6 +869,10 @@
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- DeviceDefault theme for a window that should look like the Settings app. -->
@@ -750,6 +892,10 @@
<item name="navigationBarDividerColor">#1f000000</item>
<item name="navigationBarColor">@android:color/white</item>
<item name="windowLightNavigationBar">true</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- @hide DeviceDefault theme for a window that should use Settings theme colors
@@ -761,6 +907,7 @@
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
<item name="colorControlNormal">?attr/textColorPrimary</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.QuickSettings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
@@ -769,6 +916,7 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings_light</item>
<item name="colorSecondary">@color/secondary_device_default_settings_light</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
@@ -778,6 +926,10 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_dark</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
@@ -786,6 +938,10 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
@@ -794,6 +950,10 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
<style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
@@ -802,9 +962,13 @@
<item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
<item name="colorSecondary">@color/secondary_device_default_settings</item>
<item name="colorAccent">@color/accent_device_default_light</item>
+
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
</style>
- <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar"/>
+ <style name="Theme.DeviceDefault.Settings.Dialog.NoActionBar" parent="Theme.DeviceDefault.Light.Dialog.NoActionBar" />
<!-- Theme used for the intent picker activity. -->
<style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
@@ -820,6 +984,10 @@
<item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
<item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+ <!-- Dialog attributes -->
+ <item name="dialogCornerRadius">@dimen/config_dialogCornerRadius</item>
+ <item name="alertDialogTheme">@style/Theme.DeviceDefault.Light.Dialog.Alert</item>
+
<!-- Color palette -->
<item name="colorPrimary">@color/primary_device_default_light</item>
<item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
@@ -831,7 +999,7 @@
<style name="ThemeOverlay.DeviceDefault" />
- <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for
+ <!-- @hide Theme overlay that inherits from material actionbar, and use accent color for
primary text -->
<style name="ThemeOverlay.DeviceDefault.ActionBar.Accent" parent="ThemeOverlay.Material.ActionBar">
<item name="textColorPrimary">@color/btn_colored_borderless_text_material</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 9bea3ee..c317121 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -186,6 +186,7 @@
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+ <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -554,6 +555,7 @@
<item name="dialogCustomTitleDecorLayout">@layout/dialog_custom_title_material</item>
<item name="dialogTitleDecorLayout">@layout/dialog_title_material</item>
<item name="dialogPreferredPadding">@dimen/dialog_padding_material</item>
+ <item name="dialogCornerRadius">@dimen/dialog_corner_radius</item>
<!-- AlertDialog attributes -->
<item name="alertDialogTheme">@style/ThemeOverlay.Material.Dialog.Alert</item>
@@ -1325,12 +1327,15 @@
<style name="Theme.Material.Notification" parent="">
<item name="notificationHeaderStyle">@style/Notification.Header</item>
<item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info</item>
+ <item name="notificationHeaderAppNameVisibility">visible</item>
<item name="notificationHeaderIconSize">@dimen/notification_header_icon_size</item>
</style>
<!-- Theme for inflating ambient notification -->
<style name="Theme.Material.Notification.Ambient">
+ <item name="notificationHeaderStyle">@style/Notification.Header.Ambient</item>
<item name="notificationHeaderTextAppearance">@style/TextAppearance.Material.Notification.Info.Ambient</item>
+ <item name="notificationHeaderAppNameVisibility">gone</item>
<item name="notificationHeaderIconSize">@dimen/notification_header_icon_size_ambient</item>
</style>
diff --git a/core/tests/coretests/res/font/samplexmlfont.xml b/core/tests/coretests/res/font/samplexmlfont.xml
index f1d14ff..dc2319e 100644
--- a/core/tests/coretests/res/font/samplexmlfont.xml
+++ b/core/tests/coretests/res/font/samplexmlfont.xml
@@ -1,10 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<font-family xmlns:android="http://schemas.android.com/apk/res/android">
- <font android:fontStyle="normal" android:fontWeight="400" android:fontVariationSettings="'wdth' 0.8"
- android:font="@font/samplefont" android:ttcIndex="0"/>
- <font android:fontStyle="italic" android:fontWeight="400" android:fontVariationSettings="'contrast' 0.5"
- android:font="@font/samplefont2" android:ttcIndex="1" />
- <font android:fontStyle="normal" android:fontWeight="800" android:fontVariationSettings="'wdth' 500.0, 'wght' 300.0"
- android:font="@font/samplefont3" android:ttcIndex="2" />
+ <font android:fontStyle="normal" android:fontWeight="400" android:font="@font/samplefont" />
+ <font android:fontStyle="italic" android:fontWeight="400" android:font="@font/samplefont2" />
+ <font android:fontStyle="normal" android:fontWeight="800" android:font="@font/samplefont3" />
<font android:fontStyle="italic" android:fontWeight="800" android:font="@font/samplefont4" />
</font-family>
diff --git a/core/tests/coretests/res/font/samplexmlfontforparsing.xml b/core/tests/coretests/res/font/samplexmlfontforparsing.xml
new file mode 100644
index 0000000..98e3213
--- /dev/null
+++ b/core/tests/coretests/res/font/samplexmlfontforparsing.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<font-family xmlns:android="http://schemas.android.com/apk/res/android">
+ <font android:fontStyle="normal" android:fontWeight="400" android:fontVariationSettings="'wdth' 0.8"
+ android:font="@font/samplefont" android:ttcIndex="0" />
+ <font android:fontStyle="italic" android:fontWeight="400" android:fontVariationSettings="'cntr' 0.5"
+ android:font="@font/samplefont2" android:ttcIndex="1" />
+ <font android:fontStyle="normal" android:fontWeight="800" android:fontVariationSettings="'wdth' 500.0, 'wght' 300.0"
+ android:font="@font/samplefont3" android:ttcIndex="2" />
+ <font android:fontStyle="italic" android:fontWeight="800" android:font="@font/samplefont4" />
+</font-family>
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index a12a0b8..42ff2e9 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -58,7 +58,7 @@
@Test
public void testParse() throws XmlPullParserException, IOException {
- XmlResourceParser parser = mResources.getXml(R.font.samplexmlfont);
+ XmlResourceParser parser = mResources.getXml(R.font.samplexmlfontforparsing);
FamilyResourceEntry result = FontResourcesParser.parse(parser, mResources);
@@ -76,7 +76,7 @@
assertEquals(400, font2.getWeight());
assertEquals(1, font2.getItalic());
assertEquals(1, font2.getTtcIndex());
- assertEquals("'contrast' 0.5", font2.getVariationSettings());
+ assertEquals("'cntr' 0.5", font2.getVariationSettings());
assertEquals("res/font/samplefont2.ttf", font2.getFileName());
FontFileResourceEntry font3 = fileEntries[2];
assertEquals(800, font3.getWeight());
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/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index ebe0527..d36ed63 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -26,7 +26,6 @@
import static java.lang.reflect.Modifier.isPublic;
import static java.lang.reflect.Modifier.isStatic;
-import android.platform.test.annotations.Presubmit;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
@@ -180,7 +179,6 @@
Settings.Global.DNS_RESOLVER_MIN_SAMPLES,
Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
- Settings.Global.DNS_TLS_DISABLED,
Settings.Global.DOCK_SOUNDS_ENABLED_WHEN_ACCESSIBILITY,
Settings.Global.DOWNLOAD_MAX_BYTES_OVER_MOBILE,
Settings.Global.DOWNLOAD_RECOMMENDED_MAX_BYTES_OVER_MOBILE,
@@ -265,6 +263,7 @@
Settings.Global.NETSTATS_UID_TAG_ROTATE_AGE,
Settings.Global.NETWORK_AVOID_BAD_WIFI,
Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE,
+ Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
Settings.Global.NETWORK_PREFERENCE,
Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE,
Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS,
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/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index bbdbdb1..0245570 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -49,6 +49,11 @@
import static org.hamcrest.Matchers.anyOf;
import static org.hamcrest.Matchers.is;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.app.Activity;
import android.app.Instrumentation;
@@ -633,15 +638,21 @@
@Test
public void testSetSelectionAndActionMode() throws Throwable {
+ final TextView textView = mActivity.findViewById(R.id.textview);
+ final ActionMode.Callback amCallback = mock(ActionMode.Callback.class);
+ when(amCallback.onCreateActionMode(any(ActionMode.class), any(Menu.class)))
+ .thenReturn(true);
+ when(amCallback.onPrepareActionMode(any(ActionMode.class), any(Menu.class)))
+ .thenReturn(true);
+ textView.setCustomSelectionActionModeCallback(amCallback);
+
final String text = "abc def";
onView(withId(R.id.textview)).perform(replaceText(text));
-
- final TextView textView = mActivity.findViewById(R.id.textview);
mActivityRule.runOnUiThread(
() -> Selection.setSelection((Spannable) textView.getText(), 0, 3));
mInstrumentation.waitForIdleSync();
// Don't automatically start action mode.
- // TODO: Implement assertActionModeNotStarted()
+ verify(amCallback, never()).onCreateActionMode(any(ActionMode.class), any(Menu.class));
// Make sure that "Select All" is included in the selection action mode when the entire text
// is not selected.
onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(text.indexOf('e')));
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/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
index dfe8511..3919fdd 100644
--- a/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
+++ b/core/tests/coretests/src/com/android/internal/widget/MessagingLinearLayoutTest.java
@@ -23,11 +23,11 @@
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
+import android.text.Layout;
import android.view.LayoutInflater;
import android.view.View.MeasureSpec;
import com.android.frameworks.coretests.R;
-import com.google.common.base.Function;
import org.junit.Before;
import org.junit.Test;
@@ -52,33 +52,28 @@
@Test
public void testSingleChild() {
- FakeImageFloatingTextView child = fakeChild((i) -> 3);
+ FakeImageFloatingTextView child = fakeChild(3);
- mView.setNumIndentLines(2);
mView.addView(child);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(3, child.getNumIndentLines());
assertFalse(child.isHidden());
assertEquals(150, mView.getMeasuredHeight());
}
@Test
public void testLargeSmall() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> 3);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
+ FakeImageFloatingTextView child1 = fakeChild(3);
+ FakeImageFloatingTextView child2 = fakeChild(1);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(3, child1.getNumIndentLines());
- assertEquals(0, child2.getNumIndentLines());
assertFalse("child1 should not be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(205, mView.getMeasuredHeight());
@@ -86,18 +81,15 @@
@Test
public void testSmallSmall() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> 1);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
+ FakeImageFloatingTextView child1 = fakeChild(1);
+ FakeImageFloatingTextView child2 = fakeChild(1);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(2, child1.getNumIndentLines());
- assertEquals(1, child2.getNumIndentLines());
assertFalse("child1 should not be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(105, mView.getMeasuredHeight());
@@ -105,17 +97,15 @@
@Test
public void testLargeLarge() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> 7);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 7);
+ FakeImageFloatingTextView child1 = fakeChild(7);
+ FakeImageFloatingTextView child2 = fakeChild(7);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
- assertEquals(3, child2.getNumIndentLines());
assertTrue("child1 should be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
assertEquals(350, mView.getMeasuredHeight());
@@ -123,10 +113,9 @@
@Test
public void testLargeSmall_largeWrapsWith3indentbutNotFullHeight_andHitsMax() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> i > 2 ? 7 : 6);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
+ FakeImageFloatingTextView child1 = fakeChild(7);
+ FakeImageFloatingTextView child2 = fakeChild(1);
- mView.setNumIndentLines(2);
mView.addView(child1);
mView.addView(child2);
@@ -135,51 +124,18 @@
assertFalse("child1 should not be hidden", child1.isHidden());
assertFalse("child2 should not be hidden", child2.isHidden());
- assertEquals(355, mView.getMeasuredHeight());
- assertEquals(3, child1.getNumIndentLines());
- assertEquals(0, child2.getNumIndentLines());
+ assertEquals(355, mView.getMeasuredHeight());;
}
- @Test
- public void testLargeSmall_largeWrapsWith3indentbutnot3() {
- FakeImageFloatingTextView child1 = fakeChild((i) -> i > 2 ? 4 : 3);
- FakeImageFloatingTextView child2 = fakeChild((i) -> 1);
-
- mView.setNumIndentLines(2);
- mView.addView(child1);
- mView.addView(child2);
-
- mView.measure(WIDTH_SPEC, HEIGHT_SPEC);
- mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
-
- assertFalse("child1 should not be hidden", child1.isHidden());
- assertFalse("child2 should not be hidden", child2.isHidden());
- assertEquals(255, mView.getMeasuredHeight());
- assertEquals(3, child1.getNumIndentLines());
- assertEquals(0, child2.getNumIndentLines());
- }
-
- private class FakeImageFloatingTextView extends ImageFloatingTextView {
+ private class FakeImageFloatingTextView extends MessagingMessage {
public static final int LINE_HEIGHT = 50;
- private final Function<Integer, Integer> mLinesForIndent;
- private int mNumIndentLines;
+ private final int mNumLines;
public FakeImageFloatingTextView(Context context,
- Function<Integer, Integer> linesForIndent) {
+ int linesForIndent) {
super(context, null, 0, 0);
- mLinesForIndent = linesForIndent;
- }
-
- @Override
- public boolean setNumIndentLines(int lines) {
- boolean changed = (mNumIndentLines != lines);
- mNumIndentLines = lines;
- return changed;
- }
-
- public int getNumIndentLines() {
- return mNumIndentLines;
+ mNumLines = linesForIndent;
}
@Override
@@ -195,6 +151,20 @@
heightMeasureSpec)));
}
+ public int getMeasuredType() {
+ boolean measuredTooSmall = getMeasuredHeight()
+ < getLayoutHeight() + getPaddingTop() + getPaddingBottom();
+ if (measuredTooSmall) {
+ return MEASURED_TOO_SMALL;
+ } else {
+ if (getMeasuredHeight() == getDesiredHeight()) {
+ return MEASURED_NORMAL;
+ } else {
+ return MEASURED_SHORTENED;
+ }
+ }
+ }
+
private int clampToMultiplesOfLineHeight(int size) {
if (size <= LINE_HEIGHT) {
return size;
@@ -204,7 +174,7 @@
@Override
public int getLineCount() {
- return mLinesForIndent.apply(mNumIndentLines);
+ return mNumLines;
}
public int getDesiredHeight() {
@@ -229,7 +199,7 @@
}
}
- private FakeImageFloatingTextView fakeChild(Function<Integer,Integer> linesForIndent) {
- return new FakeImageFloatingTextView(mContext, linesForIndent);
+ private FakeImageFloatingTextView fakeChild(int numLines) {
+ return new FakeImageFloatingTextView(mContext, numLines);
}
}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 2f9ae57..f7e0b46 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -232,6 +232,7 @@
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
+ <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
<permission name="android.permission.DELETE_PACKAGES"/>
<permission name="android.permission.FORCE_STOP_PACKAGES"/>
@@ -266,6 +267,7 @@
<permission name="android.permission.BACKUP"/>
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.CHANGE_APP_IDLE_STATE"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_CONFIGURATION"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
@@ -326,6 +328,7 @@
<privapp-permissions package="com.android.systemui">
<permission name="android.permission.BATTERY_STATS"/>
<permission name="android.permission.BIND_APPWIDGET"/>
+ <permission name="android.permission.BIND_SLICE" />
<permission name="android.permission.BLUETOOTH_PRIVILEGED"/>
<permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST"/>
diff --git a/data/keyboards/Vendor_045e_Product_02e0.kl b/data/keyboards/Vendor_045e_Product_02e0.kl
new file mode 100644
index 0000000..1012fb1
--- /dev/null
+++ b/data/keyboards/Vendor_045e_Product_02e0.kl
@@ -0,0 +1,59 @@
+# 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.
+
+#
+# Xbox Wireless Controller
+#
+
+
+# Mapping according to https://developer.android.com/training/game-controllers/controller-input.html
+
+key 0x132 BUTTON_X
+key 0x130 BUTTON_A
+key 0x131 BUTTON_B
+key 0x133 BUTTON_Y
+
+key 0x134 BUTTON_L1
+key 0x135 BUTTON_R1
+
+# LT axis
+axis 0x02 LTRIGGER
+# RT axis
+axis 0x05 RTRIGGER
+
+
+# Left Analog Stick
+axis 0x00 X
+axis 0x01 Y
+# Right Analog Stick
+axis 0x03 Z
+axis 0x04 RZ
+
+# Left stick click
+key 0x138 BUTTON_THUMBL
+# Right stick click
+key 0x139 BUTTON_THUMBR
+
+# Hat
+axis 0x10 HAT_X
+axis 0x11 HAT_Y
+
+# Mapping according to https://www.kernel.org/doc/Documentation/input/gamepad.txt
+# Two overlapping rectangles
+key 0x136 BUTTON_SELECT
+# Hamburger - 3 parallel lines
+key 0x137 BUTTON_START
+
+# Xbox key
+key 0x8b HOME
\ No newline at end of file
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/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 7e959a8..a7469cd 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -20,6 +20,7 @@
import android.app.Application;
import android.app.KeyguardManager;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Binder;
import android.os.IBinder;
@@ -762,6 +763,10 @@
}
private long getFingerprintOnlySid() {
+ final PackageManager packageManager = mContext.getPackageManager();
+ if (!packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ return 0;
+ }
FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
if (fingerprintManager == null) {
return 0;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 17de8fa..5d248c2 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1868,10 +1868,7 @@
/* static */ inline int compareLocales(const ResTable_config &l, const ResTable_config &r) {
if (l.locale != r.locale) {
- // NOTE: This is the old behaviour with respect to comparison orders.
- // The diff value here doesn't make much sense (given our bit packing scheme)
- // but it's stable, and that's all we need.
- return l.locale - r.locale;
+ return (l.locale > r.locale) ? 1 : -1;
}
// The language & region are equal, so compare the scripts and variants.
@@ -1890,30 +1887,49 @@
}
int ResTable_config::compare(const ResTable_config& o) const {
- int32_t diff = (int32_t)(imsi - o.imsi);
- if (diff != 0) return diff;
- diff = compareLocales(*this, o);
- if (diff != 0) return diff;
- diff = (int32_t)(screenType - o.screenType);
- if (diff != 0) return diff;
- diff = (int32_t)(input - o.input);
- if (diff != 0) return diff;
- diff = (int32_t)(screenSize - o.screenSize);
- if (diff != 0) return diff;
- diff = (int32_t)(version - o.version);
- if (diff != 0) return diff;
- diff = (int32_t)(screenLayout - o.screenLayout);
- if (diff != 0) return diff;
- diff = (int32_t)(screenLayout2 - o.screenLayout2);
- if (diff != 0) return diff;
- diff = (int32_t)(colorMode - o.colorMode);
- if (diff != 0) return diff;
- diff = (int32_t)(uiMode - o.uiMode);
- if (diff != 0) return diff;
- diff = (int32_t)(smallestScreenWidthDp - o.smallestScreenWidthDp);
- if (diff != 0) return diff;
- diff = (int32_t)(screenSizeDp - o.screenSizeDp);
- return (int)diff;
+ if (imsi != o.imsi) {
+ return (imsi > o.imsi) ? 1 : -1;
+ }
+
+ int32_t diff = compareLocales(*this, o);
+ if (diff < 0) {
+ return -1;
+ }
+ if (diff > 0) {
+ return 1;
+ }
+
+ if (screenType != o.screenType) {
+ return (screenType > o.screenType) ? 1 : -1;
+ }
+ if (input != o.input) {
+ return (input > o.input) ? 1 : -1;
+ }
+ if (screenSize != o.screenSize) {
+ return (screenSize > o.screenSize) ? 1 : -1;
+ }
+ if (version != o.version) {
+ return (version > o.version) ? 1 : -1;
+ }
+ if (screenLayout != o.screenLayout) {
+ return (screenLayout > o.screenLayout) ? 1 : -1;
+ }
+ if (screenLayout2 != o.screenLayout2) {
+ return (screenLayout2 > o.screenLayout2) ? 1 : -1;
+ }
+ if (colorMode != o.colorMode) {
+ return (colorMode > o.colorMode) ? 1 : -1;
+ }
+ if (uiMode != o.uiMode) {
+ return (uiMode > o.uiMode) ? 1 : -1;
+ }
+ if (smallestScreenWidthDp != o.smallestScreenWidthDp) {
+ return (smallestScreenWidthDp > o.smallestScreenWidthDp) ? 1 : -1;
+ }
+ if (screenSizeDp != o.screenSizeDp) {
+ return (screenSizeDp > o.screenSizeDp) ? 1 : -1;
+ }
+ return 0;
}
int ResTable_config::compareLogical(const ResTable_config& o) const {
diff --git a/libs/androidfw/ZipUtils.cpp b/libs/androidfw/ZipUtils.cpp
index 5abfc8e..5d243da 100644
--- a/libs/androidfw/ZipUtils.cpp
+++ b/libs/androidfw/ZipUtils.cpp
@@ -20,10 +20,11 @@
#define LOG_TAG "ziputil"
+#include "android-base/file.h"
#include <androidfw/ZipUtils.h>
-#include <androidfw/ZipFileRO.h>
#include <utils/Log.h>
#include <utils/Compat.h>
+#include <ziparchive/zip_archive.h>
#include <stdlib.h>
#include <string.h>
@@ -33,211 +34,121 @@
using namespace android;
-static inline unsigned long get4LE(const unsigned char* buf) {
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-
-static const unsigned long kReadBufSize = 32768;
-
-/*
- * Utility function that expands zip/gzip "deflate" compressed data
- * into a buffer.
- *
- * (This is a clone of the previous function, but it takes a FILE* instead
- * of an fd. We could pass fileno(fd) to the above, but we can run into
- * trouble when "fp" has a different notion of what fd's file position is.)
- *
- * "fp" is an open file positioned at the start of the "deflate" data
- * "buf" must hold at least "uncompressedLen" bytes.
- */
-/*static*/ template<typename T> bool inflateToBuffer(T& reader, void* buf,
- long uncompressedLen, long compressedLen)
-{
- bool result = false;
-
- z_stream zstream;
- int zerr;
- unsigned long compRemaining;
-
- assert(uncompressedLen >= 0);
- assert(compressedLen >= 0);
-
- compRemaining = compressedLen;
-
- /*
- * Initialize the zlib stream.
- */
- memset(&zstream, 0, sizeof(zstream));
- zstream.zalloc = Z_NULL;
- zstream.zfree = Z_NULL;
- zstream.opaque = Z_NULL;
- zstream.next_in = NULL;
- zstream.avail_in = 0;
- zstream.next_out = (Bytef*) buf;
- zstream.avail_out = uncompressedLen;
- zstream.data_type = Z_UNKNOWN;
-
- /*
- * Use the undocumented "negative window bits" feature to tell zlib
- * that there's no zlib header waiting for it.
- */
- zerr = inflateInit2(&zstream, -MAX_WBITS);
- if (zerr != Z_OK) {
- if (zerr == Z_VERSION_ERROR) {
- ALOGE("Installed zlib is not compatible with linked version (%s)\n",
- ZLIB_VERSION);
- } else {
- ALOGE("Call to inflateInit2 failed (zerr=%d)\n", zerr);
- }
- goto bail;
+// TODO: This can go away once the only remaining usage in aapt goes away.
+class FileReader : public zip_archive::Reader {
+ public:
+ FileReader(FILE* fp) : Reader(), mFp(fp), mCurrentOffset(0) {
}
- /*
- * Loop while we have data.
- */
- do {
- unsigned long getSize;
-
- /* read as much as we can */
- if (zstream.avail_in == 0) {
- getSize = (compRemaining > kReadBufSize) ?
- kReadBufSize : compRemaining;
- ALOGV("+++ reading %ld bytes (%ld left)\n",
- getSize, compRemaining);
-
- unsigned char* nextBuffer = NULL;
- const unsigned long nextSize = reader.read(&nextBuffer, getSize);
-
- if (nextSize < getSize || nextBuffer == NULL) {
- ALOGD("inflate read failed (%ld vs %ld)\n", nextSize, getSize);
- goto z_bail;
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ // Data is usually requested sequentially, so this helps avoid pointless
+ // fseeks every time we perform a read. There's an impedence mismatch
+ // here because the original API was designed around pread and pwrite.
+ if (offset != mCurrentOffset) {
+ if (fseek(mFp, offset, SEEK_SET) != 0) {
+ return false;
}
- compRemaining -= nextSize;
-
- zstream.next_in = nextBuffer;
- zstream.avail_in = nextSize;
+ mCurrentOffset = offset;
}
- /* uncompress the data */
- zerr = inflate(&zstream, Z_NO_FLUSH);
- if (zerr != Z_OK && zerr != Z_STREAM_END) {
- ALOGD("zlib inflate call failed (zerr=%d)\n", zerr);
- goto z_bail;
+ size_t read = fread(buf, 1, len, mFp);
+ if (read != len) {
+ return false;
}
- /* output buffer holds all, so no need to write the output */
- } while (zerr == Z_OK);
-
- assert(zerr == Z_STREAM_END); /* other errors should've been caught */
-
- if ((long) zstream.total_out != uncompressedLen) {
- ALOGW("Size mismatch on inflated file (%ld vs %ld)\n",
- zstream.total_out, uncompressedLen);
- goto z_bail;
+ mCurrentOffset += read;
+ return true;
}
- // success!
- result = true;
-
-z_bail:
- inflateEnd(&zstream); /* free up any allocated structures */
-
-bail:
- return result;
-}
-
-class FileReader {
-public:
- explicit FileReader(FILE* fp) :
- mFp(fp), mReadBuf(new unsigned char[kReadBufSize])
- {
- }
-
- ~FileReader() {
- delete[] mReadBuf;
- }
-
- long read(unsigned char** nextBuffer, long readSize) const {
- *nextBuffer = mReadBuf;
- return fread(mReadBuf, 1, readSize, mFp);
- }
-
- FILE* mFp;
- unsigned char* mReadBuf;
+ private:
+ FILE* mFp;
+ mutable uint32_t mCurrentOffset;
};
-class FdReader {
-public:
- explicit FdReader(int fd) :
- mFd(fd), mReadBuf(new unsigned char[kReadBufSize])
- {
- }
+class FdReader : public zip_archive::Reader {
+ public:
+ explicit FdReader(int fd) : mFd(fd) {
+ }
- ~FdReader() {
- delete[] mReadBuf;
- }
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ return android::base::ReadFullyAtOffset(mFd, buf, len, static_cast<off_t>(offset));
+ }
- long read(unsigned char** nextBuffer, long readSize) const {
- *nextBuffer = mReadBuf;
- return TEMP_FAILURE_RETRY(::read(mFd, mReadBuf, readSize));
- }
-
- int mFd;
- unsigned char* mReadBuf;
+ private:
+ const int mFd;
};
-class BufferReader {
-public:
- BufferReader(void* input, size_t inputSize) :
- mInput(reinterpret_cast<unsigned char*>(input)),
- mInputSize(inputSize),
- mBufferReturned(false)
- {
+class BufferReader : public zip_archive::Reader {
+ public:
+ BufferReader(const void* input, size_t inputSize) : Reader(),
+ mInput(reinterpret_cast<const uint8_t*>(input)),
+ mInputSize(inputSize) {
}
- long read(unsigned char** nextBuffer, long /*readSize*/) {
- if (!mBufferReturned) {
- mBufferReturned = true;
- *nextBuffer = mInput;
- return mInputSize;
+ bool ReadAtOffset(uint8_t* buf, size_t len, uint32_t offset) const {
+ if (offset + len > mInputSize) {
+ return false;
}
- *nextBuffer = NULL;
- return 0;
+ memcpy(buf, mInput + offset, len);
+ return true;
}
- unsigned char* mInput;
+ private:
+ const uint8_t* mInput;
const size_t mInputSize;
- bool mBufferReturned;
+};
+
+class BufferWriter : public zip_archive::Writer {
+ public:
+ BufferWriter(void* output, size_t outputSize) : Writer(),
+ mOutput(reinterpret_cast<uint8_t*>(output)), mOutputSize(outputSize), mBytesWritten(0) {
+ }
+
+ bool Append(uint8_t* buf, size_t bufSize) override {
+ if (mBytesWritten + bufSize > mOutputSize) {
+ return false;
+ }
+
+ memcpy(mOutput + mBytesWritten, buf, bufSize);
+ mBytesWritten += bufSize;
+ return true;
+ }
+
+ private:
+ uint8_t* const mOutput;
+ const size_t mOutputSize;
+ size_t mBytesWritten;
};
/*static*/ bool ZipUtils::inflateToBuffer(FILE* fp, void* buf,
long uncompressedLen, long compressedLen)
{
FileReader reader(fp);
- return ::inflateToBuffer<FileReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
/*static*/ bool ZipUtils::inflateToBuffer(int fd, void* buf,
long uncompressedLen, long compressedLen)
{
FdReader reader(fd);
- return ::inflateToBuffer<FdReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-/*static*/ bool ZipUtils::inflateToBuffer(void* in, void* buf,
+/*static*/ bool ZipUtils::inflateToBuffer(const void* in, void* buf,
long uncompressedLen, long compressedLen)
{
BufferReader reader(in, compressedLen);
- return ::inflateToBuffer<BufferReader>(reader, buf,
- uncompressedLen, compressedLen);
+ BufferWriter writer(buf, uncompressedLen);
+ return (zip_archive::Inflate(reader, compressedLen, uncompressedLen, &writer, nullptr) == 0);
}
-
+static inline unsigned long get4LE(const unsigned char* buf) {
+ return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
+}
/*
* Look at the contents of a gzip archive. We want to know where the
@@ -275,7 +186,7 @@
/* quick sanity checks */
if (method == EOF || flags == EOF)
return false;
- if (method != ZipFileRO::kCompressDeflated)
+ if (method != kCompressDeflated)
return false;
/* skip over 4 bytes of mod time, 1 byte XFL, 1 byte OS */
diff --git a/libs/androidfw/include/androidfw/ZipUtils.h b/libs/androidfw/include/androidfw/ZipUtils.h
index 55575d7..4d35e99 100644
--- a/libs/androidfw/include/androidfw/ZipUtils.h
+++ b/libs/androidfw/include/androidfw/ZipUtils.h
@@ -40,7 +40,7 @@
long compressedLen);
static bool inflateToBuffer(int fd, void* buf, long uncompressedLen,
long compressedLen);
- static bool inflateToBuffer(void *in, void* buf, long uncompressedLen,
+ static bool inflateToBuffer(const void *in, void* buf, long uncompressedLen,
long compressedLen);
/*
diff --git a/libs/hwui/.clang-format b/libs/hwui/.clang-format
new file mode 100644
index 0000000..5e9bba8
--- /dev/null
+++ b/libs/hwui/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: Google
+DerivePointerAlignment: false
+IndentWidth: 4
+ConstructorInitializerIndentWidth: 8
+ContinuationIndentWidth: 8
+ColumnLimit: 100
+AllowShortFunctionsOnASingleLine: Inline
+AccessModifierOffset: -4
+#BreakConstructorInitializers: BeforeComma
+BreakConstructorInitializersBeforeComma: true
diff --git a/libs/hwui/AmbientShadow.cpp b/libs/hwui/AmbientShadow.cpp
index 3982fa0..aa96698 100644
--- a/libs/hwui/AmbientShadow.cpp
+++ b/libs/hwui/AmbientShadow.cpp
@@ -25,7 +25,7 @@
// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
// therefore, the maximum number of extra vertices will be twice bigger.
-#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
+#define MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * EXTRA_CORNER_VERTEX_PER_PI)
// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
#define CORNER_RADIANS_DIVISOR (M_PI / EXTRA_CORNER_VERTEX_PER_PI)
@@ -36,9 +36,9 @@
*/
#define EXTRA_EDGE_VERTEX_PER_PI 50
-#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
+#define MAX_EXTRA_EDGE_VERTEX_NUMBER (2 * EXTRA_EDGE_VERTEX_PER_PI)
-#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
+#define EDGE_RADIANS_DIVISOR (M_PI / EXTRA_EDGE_VERTEX_PER_PI)
/**
* Other constants:
@@ -56,8 +56,8 @@
#include "Vertex.h"
#include "VertexBuffer.h"
-#include <algorithm>
#include <utils/Log.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -67,8 +67,8 @@
*/
inline Vector2 getNormalFromVertices(const Vector3* vertices, int current, int next) {
// Convert from Vector3 to Vector2 first.
- Vector2 currentVertex = { vertices[current].x, vertices[current].y };
- Vector2 nextVertex = { vertices[next].x, vertices[next].y };
+ Vector2 currentVertex = {vertices[current].x, vertices[current].y};
+ Vector2 nextVertex = {vertices[next].x, vertices[next].y};
return ShadowTessellator::calculateNormal(currentVertex, nextVertex);
}
@@ -79,24 +79,24 @@
return 1.0 / (1 + std::max(factoredZ, 0.0f));
}
-inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike,
- const Vector3& secondVertex, const Vector3& centroid) {
- Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
+inline int getEdgeExtraAndUpdateSpike(Vector2* currentSpike, const Vector3& secondVertex,
+ const Vector3& centroid) {
+ Vector2 secondSpike = {secondVertex.x - centroid.x, secondVertex.y - centroid.y};
secondSpike.normalize();
int result = ShadowTessellator::getExtraVertexNumber(secondSpike, *currentSpike,
- EDGE_RADIANS_DIVISOR);
+ EDGE_RADIANS_DIVISOR);
*currentSpike = secondSpike;
return result;
}
// Given the caster's vertex count, compute all the buffers size depending on
// whether or not the caster is opaque.
-inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount,
- int* totalUmbraCount, int casterVertexCount, bool isCasterOpaque) {
+inline void computeBufferSize(int* totalVertexCount, int* totalIndexCount, int* totalUmbraCount,
+ int casterVertexCount, bool isCasterOpaque) {
// Compute the size of the vertex buffer.
- int outerVertexCount = casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER +
- MAX_EXTRA_EDGE_VERTEX_NUMBER;
+ int outerVertexCount =
+ casterVertexCount * 2 + MAX_EXTRA_CORNER_VERTEX_NUMBER + MAX_EXTRA_EDGE_VERTEX_NUMBER;
int innerVertexCount = casterVertexCount + MAX_EXTRA_EDGE_VERTEX_NUMBER;
*totalVertexCount = outerVertexCount + innerVertexCount;
@@ -163,44 +163,42 @@
* | |
* (V3)-----------------------------------(V2)
*/
-void AmbientShadow::createAmbientShadow(bool isCasterOpaque,
- const Vector3* casterVertices, int casterVertexCount, const Vector3& centroid3d,
- float heightFactor, float geomFactor, VertexBuffer& shadowVertexBuffer) {
+void AmbientShadow::createAmbientShadow(bool isCasterOpaque, const Vector3* casterVertices,
+ int casterVertexCount, const Vector3& centroid3d,
+ float heightFactor, float geomFactor,
+ VertexBuffer& shadowVertexBuffer) {
shadowVertexBuffer.setMeshFeatureFlags(VertexBuffer::kAlpha | VertexBuffer::kIndices);
// In order to computer the outer vertices in one loop, we need pre-compute
// the normal by the vertex (n - 1) to vertex 0, and the spike and alpha value
// for vertex 0.
- Vector2 previousNormal = getNormalFromVertices(casterVertices,
- casterVertexCount - 1 , 0);
- Vector2 currentSpike = {casterVertices[0].x - centroid3d.x,
- casterVertices[0].y - centroid3d.y};
+ Vector2 previousNormal = getNormalFromVertices(casterVertices, casterVertexCount - 1, 0);
+ Vector2 currentSpike = {casterVertices[0].x - centroid3d.x, casterVertices[0].y - centroid3d.y};
currentSpike.normalize();
float currentAlpha = getAlphaFromFactoredZ(casterVertices[0].z * heightFactor);
// Preparing all the output data.
int totalVertexCount, totalIndexCount, totalUmbraCount;
- computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount,
- casterVertexCount, isCasterOpaque);
- AlphaVertex* shadowVertices =
- shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
+ computeBufferSize(&totalVertexCount, &totalIndexCount, &totalUmbraCount, casterVertexCount,
+ isCasterOpaque);
+ AlphaVertex* shadowVertices = shadowVertexBuffer.alloc<AlphaVertex>(totalVertexCount);
int vertexBufferIndex = 0;
uint16_t* indexBuffer = shadowVertexBuffer.allocIndices<uint16_t>(totalIndexCount);
int indexBufferIndex = 0;
uint16_t umbraVertices[totalUmbraCount];
int umbraIndex = 0;
- for (int i = 0; i < casterVertexCount; i++) {
+ for (int i = 0; i < casterVertexCount; i++) {
// Corner: first figure out the extra vertices we need for the corner.
const Vector3& innerVertex = casterVertices[i];
- Vector2 currentNormal = getNormalFromVertices(casterVertices, i,
- (i + 1) % casterVertexCount);
+ Vector2 currentNormal =
+ getNormalFromVertices(casterVertices, i, (i + 1) % casterVertexCount);
- int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(currentNormal,
- previousNormal, CORNER_RADIANS_DIVISOR);
+ int extraVerticesNumber = ShadowTessellator::getExtraVertexNumber(
+ currentNormal, previousNormal, CORNER_RADIANS_DIVISOR);
float expansionDist = innerVertex.z * heightFactor * geomFactor;
- const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
+ const int cornerSlicesNumber = extraVerticesNumber + 1; // Minimal as 1.
#if DEBUG_SHADOW
ALOGD("cornerSlicesNumber is %d", cornerSlicesNumber);
#endif
@@ -212,9 +210,8 @@
if (!isCasterOpaque) {
umbraVertices[umbraIndex++] = vertexBufferIndex;
}
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
- casterVertices[i].x, casterVertices[i].y,
- currentAlpha);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], casterVertices[i].x,
+ casterVertices[i].y, currentAlpha);
const Vector3& innerStart = casterVertices[i];
@@ -225,8 +222,7 @@
// This will create vertices from [0, cornerSlicesNumber] inclusively,
// which means minimally 2 vertices even without the extra ones.
for (int j = 0; j <= cornerSlicesNumber; j++) {
- Vector2 averageNormal =
- previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
+ Vector2 averageNormal = previousNormal * (cornerSlicesNumber - j) + currentNormal * j;
averageNormal /= cornerSlicesNumber;
averageNormal.normalize();
Vector2 outerVertex;
@@ -235,8 +231,8 @@
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
indexBuffer[indexBufferIndex++] = currentInnerVertexIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x,
- outerVertex.y, OUTER_ALPHA);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], outerVertex.x, outerVertex.y,
+ OUTER_ALPHA);
if (j == 0) {
outerStart = outerVertex;
@@ -257,8 +253,8 @@
outerNext.y = innerNext.y + currentNormal.y * expansionDist;
// Compute the angle and see how many extra points we need.
- int extraVerticesNumber = getEdgeExtraAndUpdateSpike(¤tSpike,
- innerNext, centroid3d);
+ int extraVerticesNumber =
+ getEdgeExtraAndUpdateSpike(¤tSpike, innerNext, centroid3d);
#if DEBUG_SHADOW
ALOGD("extraVerticesNumber %d for edge %d", extraVerticesNumber, i);
#endif
@@ -269,20 +265,20 @@
for (int k = 1; k < extraVerticesNumber; k++) {
int startWeight = extraVerticesNumber - k;
Vector2 currentOuter =
- (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
+ (outerLast * startWeight + outerNext * k) / extraVerticesNumber;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentOuter.x,
- currentOuter.y, OUTER_ALPHA);
+ currentOuter.y, OUTER_ALPHA);
if (!isCasterOpaque) {
umbraVertices[umbraIndex++] = vertexBufferIndex;
}
Vector3 currentInner =
- (innerStart * startWeight + innerNext * k) / extraVerticesNumber;
+ (innerStart * startWeight + innerNext * k) / extraVerticesNumber;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], currentInner.x,
- currentInner.y,
- getAlphaFromFactoredZ(currentInner.z * heightFactor));
+ currentInner.y,
+ getAlphaFromFactoredZ(currentInner.z * heightFactor));
}
}
currentAlpha = nextAlpha;
@@ -293,11 +289,10 @@
if (!isCasterOpaque) {
// Add the centroid as the last one in the vertex buffer.
- float centroidOpacity =
- getAlphaFromFactoredZ(centroid3d.z * heightFactor);
+ float centroidOpacity = getAlphaFromFactoredZ(centroid3d.z * heightFactor);
int centroidIndex = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x,
- centroid3d.y, centroidOpacity);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid3d.x, centroid3d.y,
+ centroidOpacity);
for (int i = 0; i < umbraIndex; i++) {
// Note that umbraVertices[0] is always 0.
@@ -322,7 +317,7 @@
#if DEBUG_SHADOW
for (int i = 0; i < vertexBufferIndex; i++) {
ALOGD("vertexBuffer i %d, (%f, %f %f)", i, shadowVertices[i].x, shadowVertices[i].y,
- shadowVertices[i].alpha);
+ shadowVertices[i].alpha);
}
for (int i = 0; i < indexBufferIndex; i++) {
ALOGD("indexBuffer i %d, indexBuffer[i] %d", i, indexBuffer[i]);
@@ -330,5 +325,5 @@
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/AmbientShadow.h b/libs/hwui/AmbientShadow.h
index 8eb1048f..cb1d915 100644
--- a/libs/hwui/AmbientShadow.h
+++ b/libs/hwui/AmbientShadow.h
@@ -31,12 +31,12 @@
*/
class AmbientShadow {
public:
- static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly,
- int polyLength, const Vector3& centroid3d, float heightFactor,
- float geomFactor, VertexBuffer& shadowVertexBuffer);
-}; // AmbientShadow
+ static void createAmbientShadow(bool isCasterOpaque, const Vector3* poly, int polyLength,
+ const Vector3& centroid3d, float heightFactor, float geomFactor,
+ VertexBuffer& shadowVertexBuffer);
+}; // AmbientShadow
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
+#endif // ANDROID_HWUI_AMBIENT_SHADOW_H
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/AnimationContext.cpp b/libs/hwui/AnimationContext.cpp
index 5759ccd..46c9da2 100644
--- a/libs/hwui/AnimationContext.cpp
+++ b/libs/hwui/AnimationContext.cpp
@@ -26,11 +26,9 @@
: mClock(clock)
, mCurrentFrameAnimations(*this)
, mNextFrameAnimations(*this)
- , mFrameTimeMs(0) {
-}
+ , mFrameTimeMs(0) {}
-AnimationContext::~AnimationContext() {
-}
+AnimationContext::~AnimationContext() {}
void AnimationContext::destroy() {
startFrame(TreeInfo::MODE_RT_ONLY);
@@ -39,7 +37,7 @@
AnimatorManager& animators = current->mRenderNode->animators();
animators.endAllActiveAnimators();
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
- "endAllAnimators failed to remove from current frame list!");
+ "endAllAnimators failed to remove from current frame list!");
}
}
@@ -56,7 +54,7 @@
void AnimationContext::startFrame(TreeInfo::TraversalMode mode) {
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle,
- "Missed running animations last frame!");
+ "Missed running animations last frame!");
AnimationHandle* head = mNextFrameAnimations.mNextHandle;
if (head) {
mNextFrameAnimations.mNextHandle = nullptr;
@@ -73,20 +71,17 @@
animators.pushStaging();
animators.animateNoDamage(info);
LOG_ALWAYS_FATAL_IF(mCurrentFrameAnimations.mNextHandle == current,
- "Animate failed to remove from current frame list!");
+ "Animate failed to remove from current frame list!");
}
}
void AnimationContext::callOnFinished(BaseRenderNodeAnimator* animator,
- AnimationListener* listener) {
+ AnimationListener* listener) {
listener->onAnimationFinished(animator);
}
AnimationHandle::AnimationHandle(AnimationContext& context)
- : mContext(context)
- , mPreviousHandle(nullptr)
- , mNextHandle(nullptr) {
-}
+ : mContext(context), mPreviousHandle(nullptr), mNextHandle(nullptr) {}
AnimationHandle::AnimationHandle(RenderNode& animatingNode, AnimationContext& context)
: mRenderNode(&animatingNode)
@@ -98,7 +93,7 @@
AnimationHandle::~AnimationHandle() {
LOG_ALWAYS_FATAL_IF(mPreviousHandle || mNextHandle,
- "AnimationHandle destroyed while still animating!");
+ "AnimationHandle destroyed while still animating!");
}
void AnimationHandle::notifyAnimationsRan() {
@@ -112,7 +107,7 @@
void AnimationHandle::release() {
LOG_ALWAYS_FATAL_IF(mRenderNode->animators().hasAnimators(),
- "Releasing the handle for an RenderNode with outstanding animators!");
+ "Releasing the handle for an RenderNode with outstanding animators!");
removeFromList();
mRenderNode->animators().setAnimationHandle(nullptr);
delete this;
diff --git a/libs/hwui/AnimationContext.h b/libs/hwui/AnimationContext.h
index 71ee860..74d5e79 100644
--- a/libs/hwui/AnimationContext.h
+++ b/libs/hwui/AnimationContext.h
@@ -43,6 +43,7 @@
*/
class AnimationHandle {
PREVENT_COPY_AND_ASSIGN(AnimationHandle);
+
public:
AnimationContext& context() { return mContext; }
@@ -74,14 +75,14 @@
class AnimationContext {
PREVENT_COPY_AND_ASSIGN(AnimationContext);
+
public:
ANDROID_API explicit AnimationContext(renderthread::TimeLord& clock);
ANDROID_API virtual ~AnimationContext();
nsecs_t frameTimeMs() { return mFrameTimeMs; }
bool hasAnimations() {
- return mCurrentFrameAnimations.mNextHandle
- || mNextFrameAnimations.mNextHandle;
+ return mCurrentFrameAnimations.mNextHandle || mNextFrameAnimations.mNextHandle;
}
// Will always add to the next frame list, which is swapped when
@@ -96,7 +97,8 @@
// as part of the standard RenderNode:prepareTree pass.
ANDROID_API virtual void runRemainingAnimations(TreeInfo& info);
- ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator, AnimationListener* listener);
+ ANDROID_API virtual void callOnFinished(BaseRenderNodeAnimator* animator,
+ AnimationListener* listener);
ANDROID_API virtual void destroy();
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index b6fbf89..74cf1fd 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -44,16 +44,14 @@
, mDuration(300)
, mStartDelay(0)
, mMayRunAsync(true)
- , mPlayTime(0) {
-}
+ , mPlayTime(0) {}
-BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
-}
+BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {}
void BaseRenderNodeAnimator::checkMutable() {
// Should be impossible to hit as the Java-side also has guards for this
LOG_ALWAYS_FATAL_IF(mStagingPlayState != PlayState::NotStarted,
- "Animator has already been started!");
+ "Animator has already been started!");
}
void BaseRenderNodeAnimator::setInterpolator(Interpolator* interpolator) {
@@ -119,34 +117,36 @@
void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
switch (request) {
- case Request::Start:
- mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
- mPlayTime : 0;
- mPlayState = PlayState::Running;
- mPendingActionUponFinish = Action::None;
- break;
- case Request::Reverse:
- mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
- mPlayTime : mDuration;
- mPlayState = PlayState::Reversing;
- mPendingActionUponFinish = Action::None;
- break;
- case Request::Reset:
- mPlayTime = 0;
- mPlayState = PlayState::Finished;
- mPendingActionUponFinish = Action::Reset;
- break;
- case Request::Cancel:
- mPlayState = PlayState::Finished;
- mPendingActionUponFinish = Action::None;
- break;
- case Request::End:
- mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
- mPlayState = PlayState::Finished;
- mPendingActionUponFinish = Action::End;
- break;
- default:
- LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
+ case Request::Start:
+ mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
+ ? mPlayTime
+ : 0;
+ mPlayState = PlayState::Running;
+ mPendingActionUponFinish = Action::None;
+ break;
+ case Request::Reverse:
+ mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing)
+ ? mPlayTime
+ : mDuration;
+ mPlayState = PlayState::Reversing;
+ mPendingActionUponFinish = Action::None;
+ break;
+ case Request::Reset:
+ mPlayTime = 0;
+ mPlayState = PlayState::Finished;
+ mPendingActionUponFinish = Action::Reset;
+ break;
+ case Request::Cancel:
+ mPlayState = PlayState::Finished;
+ mPendingActionUponFinish = Action::None;
+ break;
+ case Request::End:
+ mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
+ mPlayState = PlayState::Finished;
+ mPendingActionUponFinish = Action::End;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
};
}
@@ -182,8 +182,8 @@
if (mStagingPlayState == PlayState::Finished) {
callOnFinishedListener(context);
- } else if (mStagingPlayState == PlayState::Running
- || mStagingPlayState == PlayState::Reversing) {
+ } else if (mStagingPlayState == PlayState::Running ||
+ mStagingPlayState == PlayState::Reversing) {
bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
if (prevFramePlayState != mStagingPlayState) {
transitionToRunning(context);
@@ -197,7 +197,7 @@
if (mPlayState == PlayState::Reversing) {
// Reverse is not supported for animations with a start delay, so here we
// assume no start delay.
- mStartTime = currentFrameTime - (mDuration - mPlayTime);
+ mStartTime = currentFrameTime - (mDuration - mPlayTime);
} else {
// Animation should play forward
if (mPlayTime == 0) {
@@ -223,9 +223,9 @@
}
mStartTime = frameTimeMs + mStartDelay;
if (mStartTime < 0) {
- ALOGW("Ended up with a really weird start time of %" PRId64
- " with frame time %" PRId64 " and start delay %" PRId64,
- mStartTime, frameTimeMs, mStartDelay);
+ ALOGW("Ended up with a really weird start time of %" PRId64 " with frame time %" PRId64
+ " and start delay %" PRId64,
+ mStartTime, frameTimeMs, mStartDelay);
// Set to 0 so that the animate() basically instantly finishes
mStartTime = 0;
}
@@ -247,7 +247,7 @@
updatePlayTime(mDuration);
}
// Reset pending action.
- mPendingActionUponFinish = Action ::None;
+ mPendingActionUponFinish = Action::None;
return true;
}
@@ -276,7 +276,7 @@
float fraction = 1.0f;
if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
- fraction = mPlayTime / (float) mDuration;
+ fraction = mPlayTime / (float)mDuration;
}
fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);
@@ -308,35 +308,35 @@
************************************************************/
struct RenderPropertyAnimator::PropertyAccessors {
- RenderNode::DirtyPropertyMask dirtyMask;
- GetFloatProperty getter;
- SetFloatProperty setter;
+ RenderNode::DirtyPropertyMask dirtyMask;
+ GetFloatProperty getter;
+ SetFloatProperty setter;
};
// Maps RenderProperty enum to accessors
const RenderPropertyAnimator::PropertyAccessors RenderPropertyAnimator::PROPERTY_ACCESSOR_LUT[] = {
- {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX, &RenderProperties::setTranslationX },
- {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY, &RenderProperties::setTranslationY },
- {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ, &RenderProperties::setTranslationZ },
- {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX },
- {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY },
- {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation },
- {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX },
- {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY },
- {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX },
- {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY },
- {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ },
- {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha },
+ {RenderNode::TRANSLATION_X, &RenderProperties::getTranslationX,
+ &RenderProperties::setTranslationX},
+ {RenderNode::TRANSLATION_Y, &RenderProperties::getTranslationY,
+ &RenderProperties::setTranslationY},
+ {RenderNode::TRANSLATION_Z, &RenderProperties::getTranslationZ,
+ &RenderProperties::setTranslationZ},
+ {RenderNode::SCALE_X, &RenderProperties::getScaleX, &RenderProperties::setScaleX},
+ {RenderNode::SCALE_Y, &RenderProperties::getScaleY, &RenderProperties::setScaleY},
+ {RenderNode::ROTATION, &RenderProperties::getRotation, &RenderProperties::setRotation},
+ {RenderNode::ROTATION_X, &RenderProperties::getRotationX, &RenderProperties::setRotationX},
+ {RenderNode::ROTATION_Y, &RenderProperties::getRotationY, &RenderProperties::setRotationY},
+ {RenderNode::X, &RenderProperties::getX, &RenderProperties::setX},
+ {RenderNode::Y, &RenderProperties::getY, &RenderProperties::setY},
+ {RenderNode::Z, &RenderProperties::getZ, &RenderProperties::setZ},
+ {RenderNode::ALPHA, &RenderProperties::getAlpha, &RenderProperties::setAlpha},
};
RenderPropertyAnimator::RenderPropertyAnimator(RenderProperty property, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {
-}
+ : BaseRenderNodeAnimator(finalValue), mPropertyAccess(&(PROPERTY_ACCESSOR_LUT[property])) {}
void RenderPropertyAnimator::onAttached() {
- if (!mHasStartValue
- && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
+ if (!mHasStartValue && mStagingTarget->isPropertyFieldDirty(mPropertyAccess->dirtyMask)) {
setStartValue((mStagingTarget->stagingProperties().*mPropertyAccess->getter)());
}
}
@@ -385,11 +385,9 @@
* CanvasPropertyPrimitiveAnimator
************************************************************/
-CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(
- CanvasPropertyPrimitive* property, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mProperty(property) {
-}
+CanvasPropertyPrimitiveAnimator::CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
+ float finalValue)
+ : BaseRenderNodeAnimator(finalValue), mProperty(property) {}
float CanvasPropertyPrimitiveAnimator::getValue(RenderNode* target) const {
return mProperty->value;
@@ -407,50 +405,44 @@
* CanvasPropertySkPaintAnimator
************************************************************/
-CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(
- CanvasPropertyPaint* property, PaintField field, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mProperty(property)
- , mField(field) {
-}
+CanvasPropertyPaintAnimator::CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
+ PaintField field, float finalValue)
+ : BaseRenderNodeAnimator(finalValue), mProperty(property), mField(field) {}
float CanvasPropertyPaintAnimator::getValue(RenderNode* target) const {
switch (mField) {
- case STROKE_WIDTH:
- return mProperty->value.getStrokeWidth();
- case ALPHA:
- return mProperty->value.getAlpha();
+ case STROKE_WIDTH:
+ return mProperty->value.getStrokeWidth();
+ case ALPHA:
+ return mProperty->value.getAlpha();
}
- LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
+ LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
return -1;
}
static uint8_t to_uint8(float value) {
- int c = (int) (value + .5f);
- return static_cast<uint8_t>( c < 0 ? 0 : c > 255 ? 255 : c );
+ int c = (int)(value + .5f);
+ return static_cast<uint8_t>(c < 0 ? 0 : c > 255 ? 255 : c);
}
void CanvasPropertyPaintAnimator::setValue(RenderNode* target, float value) {
switch (mField) {
- case STROKE_WIDTH:
- mProperty->value.setStrokeWidth(value);
- return;
- case ALPHA:
- mProperty->value.setAlpha(to_uint8(value));
- return;
+ case STROKE_WIDTH:
+ mProperty->value.setStrokeWidth(value);
+ return;
+ case ALPHA:
+ mProperty->value.setAlpha(to_uint8(value));
+ return;
}
- LOG_ALWAYS_FATAL("Unknown field %d", (int) mField);
+ LOG_ALWAYS_FATAL("Unknown field %d", (int)mField);
}
uint32_t CanvasPropertyPaintAnimator::dirtyMask() {
return RenderNode::DISPLAY_LIST;
}
-RevealAnimator::RevealAnimator(int centerX, int centerY,
- float startValue, float finalValue)
- : BaseRenderNodeAnimator(finalValue)
- , mCenterX(centerX)
- , mCenterY(centerY) {
+RevealAnimator::RevealAnimator(int centerX, int centerY, float startValue, float finalValue)
+ : BaseRenderNodeAnimator(finalValue), mCenterX(centerX), mCenterY(centerY) {
setStartValue(startValue);
}
@@ -459,8 +451,7 @@
}
void RevealAnimator::setValue(RenderNode* target, float value) {
- target->animatorProperties().mutableRevealClip().set(true,
- mCenterX, mCenterY, value);
+ target->animatorProperties().mutableRevealClip().set(true, mCenterX, mCenterY, value);
}
uint32_t RevealAnimator::dirtyMask() {
diff --git a/libs/hwui/Animator.h b/libs/hwui/Animator.h
index aac355c..42f4cf8 100644
--- a/libs/hwui/Animator.h
+++ b/libs/hwui/Animator.h
@@ -16,11 +16,11 @@
#ifndef ANIMATOR_H
#define ANIMATOR_H
-#include <memory>
#include <cutils/compiler.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
+#include <memory>
#include "utils/Macros.h"
@@ -40,6 +40,7 @@
class AnimationListener : public VirtualLightRefBase {
public:
ANDROID_API virtual void onAnimationFinished(BaseRenderNodeAnimator*) = 0;
+
protected:
ANDROID_API virtual ~AnimationListener() {}
};
@@ -52,6 +53,7 @@
class BaseRenderNodeAnimator : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(BaseRenderNodeAnimator);
+
public:
ANDROID_API void setStartValue(float value);
ANDROID_API void setInterpolator(Interpolator* interpolator);
@@ -59,13 +61,9 @@
ANDROID_API nsecs_t duration() { return mDuration; }
ANDROID_API void setStartDelay(nsecs_t startDelayInMs);
ANDROID_API nsecs_t startDelay() { return mStartDelay; }
- ANDROID_API void setListener(AnimationListener* listener) {
- mListener = listener;
- }
+ ANDROID_API void setListener(AnimationListener* listener) { mListener = listener; }
AnimationListener* listener() { return mListener.get(); }
- ANDROID_API void setAllowRunningAsync(bool mayRunAsync) {
- mMayRunAsync = mayRunAsync;
- }
+ ANDROID_API void setAllowRunningAsync(bool mayRunAsync) { mMayRunAsync = mayRunAsync; }
bool mayRunAsync() { return mMayRunAsync; }
ANDROID_API void start();
ANDROID_API virtual void reset();
@@ -86,8 +84,9 @@
// an animation on RenderThread.
ANDROID_API nsecs_t getRemainingPlayTime();
- bool isRunning() { return mPlayState == PlayState::Running
- || mPlayState == PlayState::Reversing; }
+ bool isRunning() {
+ return mPlayState == PlayState::Running || mPlayState == PlayState::Reversing;
+ }
bool isFinished() { return mPlayState == PlayState::Finished; }
float finalValue() { return mFinalValue; }
@@ -158,13 +157,7 @@
sp<AnimationListener> mListener;
private:
- enum class Request {
- Start,
- Reverse,
- Reset,
- Cancel,
- End
- };
+ enum class Request { Start, Reverse, Reset, Cancel, End };
// Defines different actions upon finish.
enum class Action {
@@ -229,13 +222,14 @@
class CanvasPropertyPrimitiveAnimator : public BaseRenderNodeAnimator {
public:
ANDROID_API CanvasPropertyPrimitiveAnimator(CanvasPropertyPrimitive* property,
- float finalValue);
+ float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
+
private:
sp<CanvasPropertyPrimitive> mProperty;
};
@@ -247,14 +241,15 @@
ALPHA,
};
- ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property,
- PaintField field, float finalValue);
+ ANDROID_API CanvasPropertyPaintAnimator(CanvasPropertyPaint* property, PaintField field,
+ float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
protected:
virtual float getValue(RenderNode* target) const override;
virtual void setValue(RenderNode* target, float value) override;
+
private:
sp<CanvasPropertyPaint> mProperty;
PaintField mField;
@@ -262,8 +257,7 @@
class RevealAnimator : public BaseRenderNodeAnimator {
public:
- ANDROID_API RevealAnimator(int centerX, int centerY,
- float startValue, float finalValue);
+ ANDROID_API RevealAnimator(int centerX, int centerY, float startValue, float finalValue);
ANDROID_API virtual uint32_t dirtyMask();
diff --git a/libs/hwui/AnimatorManager.cpp b/libs/hwui/AnimatorManager.cpp
index 69ead58..4826d5a 100644
--- a/libs/hwui/AnimatorManager.cpp
+++ b/libs/hwui/AnimatorManager.cpp
@@ -17,8 +17,8 @@
#include <algorithm>
-#include "Animator.h"
#include "AnimationContext.h"
+#include "Animator.h"
#include "DamageAccumulator.h"
#include "RenderNode.h"
@@ -31,10 +31,7 @@
animator->detach();
}
-AnimatorManager::AnimatorManager(RenderNode& parent)
- : mParent(parent)
- , mAnimationHandle(nullptr) {
-}
+AnimatorManager::AnimatorManager(RenderNode& parent) : mParent(parent), mAnimationHandle(nullptr) {}
AnimatorManager::~AnimatorManager() {
for_each(mNewAnimators.begin(), mNewAnimators.end(), detach);
@@ -58,22 +55,22 @@
void AnimatorManager::removeAnimator(const sp<BaseRenderNodeAnimator>& animator) {
mNewAnimators.erase(std::remove(mNewAnimators.begin(), mNewAnimators.end(), animator),
- mNewAnimators.end());
+ mNewAnimators.end());
}
void AnimatorManager::setAnimationHandle(AnimationHandle* handle) {
LOG_ALWAYS_FATAL_IF(mAnimationHandle && handle, "Already have an AnimationHandle!");
mAnimationHandle = handle;
LOG_ALWAYS_FATAL_IF(!mAnimationHandle && mAnimators.size(),
- "Lost animation handle on %p (%s) with outstanding animators!",
- &mParent, mParent.getName());
+ "Lost animation handle on %p (%s) with outstanding animators!", &mParent,
+ mParent.getName());
}
void AnimatorManager::pushStaging() {
if (mNewAnimators.size()) {
if (CC_UNLIKELY(!mAnimationHandle)) {
- ALOGW("Trying to start new animators on %p (%s) without an animation handle!",
- &mParent, mParent.getName());
+ ALOGW("Trying to start new animators on %p (%s) without an animation handle!", &mParent,
+ mParent.getName());
return;
}
@@ -100,7 +97,7 @@
AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
: mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
- bool operator() (sp<BaseRenderNodeAnimator>& animator) {
+ bool operator()(sp<BaseRenderNodeAnimator>& animator) {
*mDirtyMask |= animator->dirtyMask();
bool remove = animator->animate(mContext);
if (remove) {
@@ -172,17 +169,15 @@
public:
explicit EndActiveAnimatorsFunctor(AnimationContext& context) : mContext(context) {}
- void operator() (sp<BaseRenderNodeAnimator>& animator) {
- animator->forceEndNow(mContext);
- }
+ void operator()(sp<BaseRenderNodeAnimator>& animator) { animator->forceEndNow(mContext); }
private:
AnimationContext& mContext;
};
void AnimatorManager::endAllActiveAnimators() {
- ALOGD("endAllActiveAnimators on %p (%s) with handle %p",
- &mParent, mParent.getName(), mAnimationHandle);
+ ALOGD("endAllActiveAnimators on %p (%s) with handle %p", &mParent, mParent.getName(),
+ mAnimationHandle);
EndActiveAnimatorsFunctor functor(mAnimationHandle->context());
for_each(mAnimators.begin(), mAnimators.end(), functor);
mAnimators.clear();
diff --git a/libs/hwui/AnimatorManager.h b/libs/hwui/AnimatorManager.h
index 8e6f820..9575391 100644
--- a/libs/hwui/AnimatorManager.h
+++ b/libs/hwui/AnimatorManager.h
@@ -34,6 +34,7 @@
// Responsible for managing the animators for a single RenderNode
class AnimatorManager {
PREVENT_COPY_AND_ASSIGN(AnimatorManager);
+
public:
explicit AnimatorManager(RenderNode& parent);
~AnimatorManager();
@@ -68,8 +69,8 @@
AnimationHandle* mAnimationHandle;
// To improve the efficiency of resizing & removing from the vector
- std::vector< sp<BaseRenderNodeAnimator> > mNewAnimators;
- std::vector< sp<BaseRenderNodeAnimator> > mAnimators;
+ std::vector<sp<BaseRenderNodeAnimator> > mNewAnimators;
+ std::vector<sp<BaseRenderNodeAnimator> > mAnimators;
};
} /* namespace uirenderer */
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 03a397c..f78cb41 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -23,29 +23,28 @@
#include "GlopBuilder.h"
#include "Patch.h"
#include "PathTessellator.h"
+#include "VertexBuffer.h"
#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/RenderState.h"
#include "utils/GLUtils.h"
-#include "VertexBuffer.h"
-#include <algorithm>
-#include <math.h>
#include <SkPaintDefaults.h>
#include <SkPathOps.h>
+#include <math.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
static void storeTexturedRect(TextureVertex* vertices, const Rect& bounds) {
- vertices[0] = { bounds.left, bounds.top, 0, 0 };
- vertices[1] = { bounds.right, bounds.top, 1, 0 };
- vertices[2] = { bounds.left, bounds.bottom, 0, 1 };
- vertices[3] = { bounds.right, bounds.bottom, 1, 1 };
+ vertices[0] = {bounds.left, bounds.top, 0, 0};
+ vertices[1] = {bounds.right, bounds.top, 1, 0};
+ vertices[2] = {bounds.left, bounds.bottom, 0, 1};
+ vertices[3] = {bounds.right, bounds.bottom, 1, 1};
}
void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
- const MergedBakedOpList& opList) {
-
+ const MergedBakedOpList& opList) {
const BakedOpState& firstState = *(opList.states[0]);
Bitmap* bitmap = (static_cast<const BitmapOp*>(opList.states[0]->op))->bitmap;
@@ -70,7 +69,8 @@
}
const int textureFillFlags = (bitmap->colorType() == kAlpha_8_SkColorType)
- ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+ ? TextureFillFlags::IsAlphaMaskTexture
+ : TextureFillFlags::None;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(firstState.roundRectClipState)
@@ -85,7 +85,7 @@
}
void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
- const MergedBakedOpList& opList) {
+ const MergedBakedOpList& opList) {
const PatchOp& firstOp = *(static_cast<const PatchOp*>(opList.states[0]->op));
const BakedOpState& firstState = *(opList.states[0]);
@@ -99,8 +99,8 @@
// TODO: cache mesh lookups
const Patch* opMesh = renderer.caches().patchCache.get(
- op.bitmap->width(), op.bitmap->height(),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+ op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.patch);
totalVertices += opMesh->verticesCount;
}
@@ -120,9 +120,8 @@
// TODO: cache mesh lookups
const Patch* opMesh = renderer.caches().patchCache.get(
- op.bitmap->width(), op.bitmap->height(),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
-
+ op.bitmap->width(), op.bitmap->height(), op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.patch);
uint32_t vertexCount = opMesh->verticesCount;
if (vertexCount == 0) continue;
@@ -130,17 +129,16 @@
// We use the bounds to know where to translate our vertices
// Using patchOp->state.mBounds wouldn't work because these
// bounds are clipped
- const float tx = floorf(state.computedState.transform.getTranslateX()
- + op.unmappedBounds.left + 0.5f);
- const float ty = floorf(state.computedState.transform.getTranslateY()
- + op.unmappedBounds.top + 0.5f);
+ const float tx = floorf(state.computedState.transform.getTranslateX() +
+ op.unmappedBounds.left + 0.5f);
+ const float ty = floorf(state.computedState.transform.getTranslateY() +
+ op.unmappedBounds.top + 0.5f);
// Copy & transform all the vertices for the current operation
TextureVertex* opVertices = opMesh->vertices.get();
for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
- TextureVertex::set(vertex++,
- opVertices->x + tx, opVertices->y + ty,
- opVertices->u, opVertices->v);
+ TextureVertex::set(vertex++, opVertices->x + tx, opVertices->y + ty, opVertices->u,
+ opVertices->v);
}
// Dirty the current layer if possible. When the 9-patch does not
@@ -148,16 +146,16 @@
// dirty rect to the object's bounds.
if (dirtyRenderTarget) {
if (!opMesh->hasEmptyQuads) {
- renderer.dirtyRenderTarget(Rect(tx, ty,
- tx + op.unmappedBounds.getWidth(), ty + op.unmappedBounds.getHeight()));
+ renderer.dirtyRenderTarget(Rect(tx, ty, tx + op.unmappedBounds.getWidth(),
+ ty + op.unmappedBounds.getHeight()));
} else {
const size_t count = opMesh->quads.size();
for (size_t i = 0; i < count; i++) {
const Rect& quadBounds = opMesh->quads[i];
const float x = tx + quadBounds.left;
const float y = ty + quadBounds.top;
- renderer.dirtyRenderTarget(Rect(x, y,
- x + quadBounds.getWidth(), y + quadBounds.getHeight()));
+ renderer.dirtyRenderTarget(
+ Rect(x, y, x + quadBounds.getWidth(), y + quadBounds.getHeight()));
}
}
}
@@ -165,7 +163,6 @@
indexCount += opMesh->indexCount;
}
-
Texture* texture = renderer.caches().textureCache.get(firstOp.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -188,8 +185,8 @@
renderer.renderGlop(nullptr, clip, glop);
}
-static void renderTextShadow(BakedOpRenderer& renderer,
- const TextOp& op, const BakedOpState& textOpState) {
+static void renderTextShadow(BakedOpRenderer& renderer, const TextOp& op,
+ const BakedOpState& textOpState) {
if (CC_LIKELY(!PaintUtils::hasTextShadow(op.paint))) return;
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
@@ -225,7 +222,7 @@
// Bounds should be same as text op, but with dx/dy offset and radius outset
// applied in local space.
auto& transform = textOpState.computedState.transform;
- Rect shadowBounds = op.unmappedBounds; // STROKE
+ Rect shadowBounds = op.unmappedBounds; // STROKE
const bool expandForStroke = op.paint->getStyle() != SkPaint::kFill_Style;
if (expandForStroke) {
shadowBounds.outset(op.paint->getStrokeWidth() * 0.5f);
@@ -234,13 +231,12 @@
shadowBounds.outset(textShadow.radius, textShadow.radius);
transform.mapRect(shadowBounds);
if (CC_UNLIKELY(expandForStroke &&
- (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
+ (!transform.isPureTranslate() || op.paint->getStrokeWidth() < 1.0f))) {
shadowBounds.outset(0.5f);
}
auto clipState = textOpState.computedState.clipState;
- if (clipState->mode != ClipMode::Rectangle
- || !clipState->rect.contains(shadowBounds)) {
+ if (clipState->mode != ClipMode::Rectangle || !clipState->rect.contains(shadowBounds)) {
// need clip, so pass it and clip bounds
shadowBounds.doIntersect(clipState->rect);
} else {
@@ -251,13 +247,10 @@
renderer.renderGlop(&shadowBounds, clipState, glop);
}
-enum class TextRenderType {
- Defer,
- Flush
-};
+enum class TextRenderType { Defer, Flush };
static void renderText(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
- const ClipBase* renderClip, TextRenderType renderType) {
+ const ClipBase* renderClip, TextRenderType renderType) {
FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
float x = op.x;
float y = op.y;
@@ -285,23 +278,23 @@
// font renderer which greatly simplifies the code, clipping in particular.
float sx, sy;
transform.decomposeScale(sx, sy);
- fontRenderer.setFont(op.paint, SkMatrix::MakeScale(
- roundf(std::max(1.0f, sx)),
- roundf(std::max(1.0f, sy))));
+ fontRenderer.setFont(op.paint, SkMatrix::MakeScale(roundf(std::max(1.0f, sx)),
+ roundf(std::max(1.0f, sy))));
fontRenderer.setTextureFiltering(true);
}
Rect layerBounds(FLT_MAX / 2.0f, FLT_MAX / 2.0f, FLT_MIN / 2.0f, FLT_MIN / 2.0f);
int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
SkBlendMode mode = PaintUtils::getBlendModeDirect(op.paint);
- TextDrawFunctor functor(&renderer, &state, renderClip,
- x, y, pureTranslate, alpha, mode, op.paint);
+ TextDrawFunctor functor(&renderer, &state, renderClip, x, y, pureTranslate, alpha, mode,
+ op.paint);
bool forceFinish = (renderType == TextRenderType::Flush);
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
- fontRenderer.renderPosText(op.paint, localOpClip, op.glyphs, op.glyphCount, x, y,
- op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
+ fontRenderer.renderPosText(op.paint, localOpClip, op.glyphs, op.glyphCount, x, y, op.positions,
+ mustDirtyRenderTarget ? &layerBounds : nullptr, &functor,
+ forceFinish);
if (mustDirtyRenderTarget) {
if (!pureTranslate) {
@@ -312,7 +305,7 @@
}
void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
- const MergedBakedOpList& opList) {
+ const MergedBakedOpList& opList) {
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
const TextOp& op = *(static_cast<const TextOp*>(state.op));
@@ -324,26 +317,27 @@
for (size_t i = 0; i < opList.count; i++) {
const BakedOpState& state = *(opList.states[i]);
const TextOp& op = *(static_cast<const TextOp*>(state.op));
- TextRenderType renderType = (i + 1 == opList.count)
- ? TextRenderType::Flush : TextRenderType::Defer;
+ TextRenderType renderType =
+ (i + 1 == opList.count) ? TextRenderType::Flush : TextRenderType::Defer;
renderText(renderer, op, state, clip, renderType);
}
}
namespace VertexBufferRenderFlags {
- enum {
- Offset = 0x1,
- ShadowInterp = 0x2,
- };
+enum {
+ Offset = 0x1,
+ ShadowInterp = 0x2,
+};
}
static void renderVertexBuffer(BakedOpRenderer& renderer, const BakedOpState& state,
- const VertexBuffer& vertexBuffer, float translateX, float translateY,
- const SkPaint& paint, int vertexBufferRenderFlags) {
+ const VertexBuffer& vertexBuffer, float translateX, float translateY,
+ const SkPaint& paint, int vertexBufferRenderFlags) {
if (CC_LIKELY(vertexBuffer.getVertexCount())) {
bool shadowInterp = vertexBufferRenderFlags & VertexBufferRenderFlags::ShadowInterp;
const int transformFlags = vertexBufferRenderFlags & VertexBufferRenderFlags::Offset
- ? TransformFlags::OffsetByFudgeFactor : 0;
+ ? TransformFlags::OffsetByFudgeFactor
+ : 0;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
@@ -358,24 +352,23 @@
}
static void renderConvexPath(BakedOpRenderer& renderer, const BakedOpState& state,
- const SkPath& path, const SkPaint& paint) {
+ const SkPath& path, const SkPaint& paint) {
VertexBuffer vertexBuffer;
// TODO: try clipping large paths to viewport
PathTessellator::tessellatePath(path, &paint, state.computedState.transform, vertexBuffer);
renderVertexBuffer(renderer, state, vertexBuffer, 0.0f, 0.0f, paint, 0);
}
-static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state,
- float xOffset, float yOffset, PathTexture& texture, const SkPaint& paint) {
+static void renderPathTexture(BakedOpRenderer& renderer, const BakedOpState& state, float xOffset,
+ float yOffset, PathTexture& texture, const SkPaint& paint) {
Rect dest(texture.width(), texture.height());
- dest.translate(xOffset + texture.left - texture.offset,
- yOffset + texture.top - texture.offset);
+ dest.translate(xOffset + texture.left - texture.offset, yOffset + texture.top - texture.offset);
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedUnitQuad(nullptr)
.setFillPathTexturePaint(texture, paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
+ .setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewMapUnitToRect(dest)
.build();
renderer.renderGlop(state, glop);
@@ -390,18 +383,18 @@
return bounds;
}
-void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op,
+ const BakedOpState& state) {
// TODO: support fills (accounting for concavity if useCenter && sweepAngle > 180)
- if (op.paint->getStyle() != SkPaint::kStroke_Style
- || op.paint->getPathEffect() != nullptr
- || op.useCenter) {
+ if (op.paint->getStyle() != SkPaint::kStroke_Style || op.paint->getPathEffect() != nullptr ||
+ op.useCenter) {
PathTexture* texture = renderer.caches().pathCache.getArc(
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
- op.startAngle, op.sweepAngle, op.useCenter, op.paint);
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.startAngle,
+ op.sweepAngle, op.useCenter, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
+ *texture, *(op.paint));
}
} else {
SkRect rect = getBoundsOfFill(op);
@@ -417,13 +410,15 @@
}
}
-void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBitmapOp(BakedOpRenderer& renderer, const BitmapOp& op,
+ const BakedOpState& state) {
Texture* texture = renderer.getTexture(op.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
- ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
+ ? TextureFillFlags::IsAlphaMaskTexture
+ : TextureFillFlags::None;
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
@@ -435,7 +430,8 @@
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBitmapMeshOp(BakedOpRenderer& renderer, const BitmapMeshOp& op,
+ const BakedOpState& state) {
Texture* texture = renderer.caches().textureCache.get(op.bitmap);
if (!texture) {
return;
@@ -495,13 +491,14 @@
.setRoundRectClipState(state.roundRectClipState)
.setMeshColoredTexturedMesh(mesh.get(), elementCount)
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
- .setTransform(state.computedState.transform, TransformFlags::None)
+ .setTransform(state.computedState.transform, TransformFlags::None)
.setModelViewOffsetRect(0, 0, op.unmappedBounds)
.build();
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onBitmapRectOp(BakedOpRenderer& renderer, const BitmapRectOp& op,
+ const BakedOpState& state) {
Texture* texture = renderer.getTexture(op.bitmap);
if (!texture) return;
const AutoTexture autoCleanup(texture);
@@ -512,9 +509,10 @@
std::min(1.0f, op.src.bottom / texture->height()));
const int textureFillFlags = (op.bitmap->colorType() == kAlpha_8_SkColorType)
- ? TextureFillFlags::IsAlphaMaskTexture : TextureFillFlags::None;
- const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth())
- && MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
+ ? TextureFillFlags::IsAlphaMaskTexture
+ : TextureFillFlags::None;
+ const bool tryToSnap = MathUtils::areEqual(op.src.getWidth(), op.unmappedBounds.getWidth()) &&
+ MathUtils::areEqual(op.src.getHeight(), op.unmappedBounds.getHeight());
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
@@ -526,7 +524,8 @@
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onColorOp(BakedOpRenderer& renderer, const ColorOp& op,
+ const BakedOpState& state) {
SkPaint paint;
paint.setColor(op.color);
paint.setBlendMode(op.mode);
@@ -542,26 +541,29 @@
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onFunctorOp(BakedOpRenderer& renderer, const FunctorOp& op,
+ const BakedOpState& state) {
renderer.renderFunctor(op, state);
}
-void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onLinesOp(BakedOpRenderer& renderer, const LinesOp& op,
+ const BakedOpState& state) {
VertexBuffer buffer;
PathTessellator::tessellateLines(op.points, op.floatCount, op.paint,
- state.computedState.transform, buffer);
+ state.computedState.transform, buffer);
int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
}
-void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op,
+ const BakedOpState& state) {
if (op.paint->getPathEffect() != nullptr) {
PathTexture* texture = renderer.caches().pathCache.getOval(
op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
+ *texture, *(op.paint));
}
} else {
SkPath path;
@@ -577,7 +579,8 @@
}
}
-void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onPatchOp(BakedOpRenderer& renderer, const PatchOp& op,
+ const BakedOpState& state) {
// 9 patches are built for stretching - always filter
int textureFillFlags = TextureFillFlags::ForceFilter;
if (op.bitmap->colorType() == kAlpha_8_SkColorType) {
@@ -585,9 +588,9 @@
}
// TODO: avoid redoing the below work each frame:
- const Patch* mesh = renderer.caches().patchCache.get(
- op.bitmap->width(), op.bitmap->height(),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.patch);
+ const Patch* mesh = renderer.caches().patchCache.get(op.bitmap->width(), op.bitmap->height(),
+ op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.patch);
Texture* texture = renderer.caches().textureCache.get(op.bitmap);
if (CC_LIKELY(texture)) {
@@ -598,14 +601,16 @@
.setMeshPatchQuads(*mesh)
.setFillTexturePaint(*texture, textureFillFlags, op.paint, state.alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+ .setModelViewOffsetRectSnap(
+ op.unmappedBounds.left, op.unmappedBounds.top,
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
.build();
renderer.renderGlop(state, glop);
}
}
-void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onPathOp(BakedOpRenderer& renderer, const PathOp& op,
+ const BakedOpState& state) {
PathTexture* texture = renderer.caches().pathCache.get(op.path, op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
@@ -615,10 +620,11 @@
}
}
-void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onPointsOp(BakedOpRenderer& renderer, const PointsOp& op,
+ const BakedOpState& state) {
VertexBuffer buffer;
PathTessellator::tessellatePoints(op.points, op.floatCount, op.paint,
- state.computedState.transform, buffer);
+ state.computedState.transform, buffer);
int displayFlags = op.paint->isAntiAlias() ? 0 : VertexBufferRenderFlags::Offset;
renderVertexBuffer(renderer, state, buffer, 0, 0, *(op.paint), displayFlags);
}
@@ -626,20 +632,21 @@
// See SkPaintDefaults.h
#define SkPaintDefaults_MiterLimit SkIntToScalar(4)
-void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onRectOp(BakedOpRenderer& renderer, const RectOp& op,
+ const BakedOpState& state) {
if (op.paint->getStyle() != SkPaint::kFill_Style) {
// only fill + default miter is supported by drawConvexPath, since others must handle joins
static_assert(SkPaintDefaults_MiterLimit == 4.0f, "Miter limit has changed");
- if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr
- || op.paint->getStrokeJoin() != SkPaint::kMiter_Join
- || op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
- PathTexture* texture = renderer.caches().pathCache.getRect(
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
- const AutoTexture holder(texture);
- if (CC_LIKELY(holder.texture)) {
- renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
- }
+ if (CC_UNLIKELY(op.paint->getPathEffect() != nullptr ||
+ op.paint->getStrokeJoin() != SkPaint::kMiter_Join ||
+ op.paint->getStrokeMiter() != SkPaintDefaults_MiterLimit)) {
+ PathTexture* texture = renderer.caches().pathCache.getRect(
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
+ const AutoTexture holder(texture);
+ if (CC_LIKELY(holder.texture)) {
+ renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
+ *texture, *(op.paint));
+ }
} else {
SkPath path;
path.addRect(getBoundsOfFill(op));
@@ -665,29 +672,31 @@
}
}
-void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onRoundRectOp(BakedOpRenderer& renderer, const RoundRectOp& op,
+ const BakedOpState& state) {
if (op.paint->getPathEffect() != nullptr) {
PathTexture* texture = renderer.caches().pathCache.getRoundRect(
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(),
- op.rx, op.ry, op.paint);
+ op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry,
+ op.paint);
const AutoTexture holder(texture);
if (CC_LIKELY(holder.texture)) {
renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
- *texture, *(op.paint));
+ *texture, *(op.paint));
}
} else {
const VertexBuffer* buffer = renderer.caches().tessellationCache.getRoundRect(
- state.computedState.transform, *(op.paint),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
- renderVertexBuffer(renderer, state, *buffer,
- op.unmappedBounds.left, op.unmappedBounds.top, *(op.paint), 0);
+ state.computedState.transform, *(op.paint), op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.rx, op.ry);
+ renderVertexBuffer(renderer, state, *buffer, op.unmappedBounds.left, op.unmappedBounds.top,
+ *(op.paint), 0);
}
}
static void renderShadow(BakedOpRenderer& renderer, const BakedOpState& state, float casterAlpha,
- const VertexBuffer* ambientShadowVertexBuffer, const VertexBuffer* spotShadowVertexBuffer) {
+ const VertexBuffer* ambientShadowVertexBuffer,
+ const VertexBuffer* spotShadowVertexBuffer) {
SkPaint paint;
- paint.setAntiAlias(true); // want to use AlphaVertex
+ paint.setAntiAlias(true); // want to use AlphaVertex
// The caller has made sure casterAlpha > 0.
uint8_t ambientShadowAlpha = renderer.getLightInfo().ambientShadowAlpha;
@@ -696,8 +705,8 @@
}
if (ambientShadowVertexBuffer && ambientShadowAlpha > 0) {
paint.setAlpha((uint8_t)(casterAlpha * ambientShadowAlpha));
- renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0,
- paint, VertexBufferRenderFlags::ShadowInterp);
+ renderVertexBuffer(renderer, state, *ambientShadowVertexBuffer, 0, 0, paint,
+ VertexBufferRenderFlags::ShadowInterp);
}
uint8_t spotShadowAlpha = renderer.getLightInfo().spotShadowAlpha;
@@ -706,17 +715,19 @@
}
if (spotShadowVertexBuffer && spotShadowAlpha > 0) {
paint.setAlpha((uint8_t)(casterAlpha * spotShadowAlpha));
- renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0,
- paint, VertexBufferRenderFlags::ShadowInterp);
+ renderVertexBuffer(renderer, state, *spotShadowVertexBuffer, 0, 0, paint,
+ VertexBufferRenderFlags::ShadowInterp);
}
}
-void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onShadowOp(BakedOpRenderer& renderer, const ShadowOp& op,
+ const BakedOpState& state) {
TessellationCache::vertexBuffer_pair_t buffers = op.shadowTask->getResult();
renderShadow(renderer, state, op.casterAlpha, buffers.first, buffers.second);
}
-void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onSimpleRectsOp(BakedOpRenderer& renderer, const SimpleRectsOp& op,
+ const BakedOpState& state) {
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
@@ -728,12 +739,14 @@
renderer.renderGlop(state, glop);
}
-void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op,
+ const BakedOpState& state) {
renderTextShadow(renderer, op, state);
renderText(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
}
-void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op,
+ const BakedOpState& state) {
// Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
// TODO: respect clipSideFlags, once we record with bounds
auto renderTargetClip = state.computedState.clipState;
@@ -746,14 +759,14 @@
int alpha = PaintUtils::getAlphaDirect(op.paint) * state.alpha;
SkBlendMode mode = PaintUtils::getBlendModeDirect(op.paint);
- TextDrawFunctor functor(&renderer, &state, renderTargetClip,
- 0.0f, 0.0f, false, alpha, mode, op.paint);
+ TextDrawFunctor functor(&renderer, &state, renderTargetClip, 0.0f, 0.0f, false, alpha, mode,
+ op.paint);
bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
const Rect localSpaceClip = state.computedState.computeLocalSpaceClip();
- if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, op.glyphs, op.glyphCount,
- op.path, op.hOffset, op.vOffset,
- mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
+ if (fontRenderer.renderTextOnPath(op.paint, &localSpaceClip, op.glyphs, op.glyphCount, op.path,
+ op.hOffset, op.vOffset,
+ mustDirtyRenderTarget ? &layerBounds : nullptr, &functor)) {
if (mustDirtyRenderTarget) {
// manually dirty render target, since TextDrawFunctor won't
state.computedState.transform.mapRect(layerBounds);
@@ -762,7 +775,8 @@
}
}
-void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const TextureLayerOp& op,
+ const BakedOpState& state) {
GlLayer* layer = static_cast<GlLayer*>(op.layerHandle->backingLayer());
if (!layer) {
return;
@@ -772,16 +786,17 @@
Glop glop;
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
- .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
+ .setMeshTexturedUvQuad(nullptr, Rect(0, 1, 1, 0)) // TODO: simplify with VBO
.setFillTextureLayer(*(layer), alpha)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewMapUnitToRectOptionalSnap(tryToSnap, Rect(layer->getWidth(), layer->getHeight()))
+ .setModelViewMapUnitToRectOptionalSnap(tryToSnap,
+ Rect(layer->getWidth(), layer->getHeight()))
.build();
renderer.renderGlop(state, glop);
}
void renderRectForLayer(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state,
- int color, SkBlendMode mode, SkColorFilter* colorFilter) {
+ int color, SkBlendMode mode, SkColorFilter* colorFilter) {
SkPaint paint;
paint.setColor(color);
paint.setBlendMode(mode);
@@ -790,7 +805,8 @@
BakedOpDispatcher::onRectOp(renderer, rectOp, state);
}
-void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op,
+ const BakedOpState& state) {
// Note that we don't use op->paint in this function - it's never set on a LayerOp
OffscreenBuffer* buffer = *op.layerHandle;
@@ -801,9 +817,11 @@
GlopBuilder(renderer.renderState(), renderer.caches(), &glop)
.setRoundRectClipState(state.roundRectClipState)
.setMeshTexturedIndexedVbo(buffer->vbo, buffer->elementCount)
- .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode, Blend::ModeOrderSwap::NoSwap)
+ .setFillLayer(buffer->texture, op.colorFilter, layerAlpha, op.mode,
+ Blend::ModeOrderSwap::NoSwap)
.setTransform(state.computedState.transform, TransformFlags::None)
- .setModelViewOffsetRectSnap(op.unmappedBounds.left, op.unmappedBounds.top,
+ .setModelViewOffsetRectSnap(
+ op.unmappedBounds.left, op.unmappedBounds.top,
Rect(op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight()))
.build();
renderer.renderGlop(state, glop);
@@ -812,23 +830,24 @@
buffer->hasRenderedSinceRepaint = true;
if (CC_UNLIKELY(Properties::debugLayersUpdates)) {
// render debug layer highlight
- renderRectForLayer(renderer, op, state,
- 0x7f00ff00, SkBlendMode::kSrcOver, nullptr);
+ renderRectForLayer(renderer, op, state, 0x7f00ff00, SkBlendMode::kSrcOver, nullptr);
} else if (CC_UNLIKELY(Properties::debugOverdraw)) {
// render transparent to increment overdraw for repaint area
- renderRectForLayer(renderer, op, state,
- SK_ColorTRANSPARENT, SkBlendMode::kSrcOver, nullptr);
+ renderRectForLayer(renderer, op, state, SK_ColorTRANSPARENT, SkBlendMode::kSrcOver,
+ nullptr);
}
}
}
-void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onCopyToLayerOp(BakedOpRenderer& renderer, const CopyToLayerOp& op,
+ const BakedOpState& state) {
LOG_ALWAYS_FATAL_IF(*(op.layerHandle) != nullptr, "layer already exists!");
*(op.layerHandle) = renderer.copyToLayer(state.computedState.clippedBounds);
LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "layer copy failed");
}
-void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op, const BakedOpState& state) {
+void BakedOpDispatcher::onCopyFromLayerOp(BakedOpRenderer& renderer, const CopyFromLayerOp& op,
+ const BakedOpState& state) {
LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "no layer to draw underneath!");
if (!state.computedState.clippedBounds.isEmpty()) {
if (op.paint && op.paint->getAlpha() < 255) {
@@ -836,7 +855,8 @@
layerPaint.setAlpha(op.paint->getAlpha());
layerPaint.setBlendMode(SkBlendMode::kDstIn);
layerPaint.setColorFilter(sk_ref_sp(op.paint->getColorFilter()));
- RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr, &layerPaint);
+ RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr,
+ &layerPaint);
BakedOpDispatcher::onRectOp(renderer, rectOp, state);
}
@@ -855,5 +875,5 @@
renderer.renderState().layerPool().putOrDelete(*op.layerHandle);
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h
index 4dfdd3f..e370868 100644
--- a/libs/hwui/BakedOpDispatcher.h
+++ b/libs/hwui/BakedOpDispatcher.h
@@ -33,21 +33,20 @@
*/
class BakedOpDispatcher {
public:
- // Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
+// Declares all "onMergedBitmapOps(...)" style methods for mergeable op types
#define X(Type) \
- static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
+ static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList);
MAP_MERGEABLE_OPS(X)
#undef X
- // Declares all "onBitmapOp(...)" style methods for every op type
+// Declares all "onBitmapOp(...)" style methods for every op type
#define X(Type) \
- static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
+ static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state);
MAP_RENDERABLE_OPS(X)
#undef X
-
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H
+#endif // ANDROID_HWUI_BAKED_OP_DISPATCHER_H
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index 3c3b317..6b64b94 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -19,10 +19,10 @@
#include "Caches.h"
#include "Glop.h"
#include "GlopBuilder.h"
+#include "VertexBuffer.h"
#include "renderstate/OffscreenBufferPool.h"
#include "renderstate/RenderState.h"
#include "utils/GLUtils.h"
-#include "VertexBuffer.h"
#include <algorithm>
@@ -32,8 +32,8 @@
OffscreenBuffer* BakedOpRenderer::startTemporaryLayer(uint32_t width, uint32_t height) {
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
- OffscreenBuffer* buffer = mRenderState.layerPool().get(
- mRenderState, width, height, mWideColorGamut);
+ OffscreenBuffer* buffer =
+ mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut);
startRepaintLayer(buffer, Rect(width, height));
return buffer;
}
@@ -46,13 +46,13 @@
LOG_ALWAYS_FATAL_IF(mRenderTarget.offscreenBuffer, "already has layer...");
// subtract repaintRect from region, since it will be regenerated
- if (repaintRect.contains(0, 0,
- offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight)) {
+ if (repaintRect.contains(0, 0, offscreenBuffer->viewportWidth,
+ offscreenBuffer->viewportHeight)) {
// repaint full layer, so throw away entire region
offscreenBuffer->region.clear();
} else {
offscreenBuffer->region.subtractSelf(android::Rect(repaintRect.left, repaintRect.top,
- repaintRect.right, repaintRect.bottom));
+ repaintRect.right, repaintRect.bottom));
}
mRenderTarget.offscreenBuffer = offscreenBuffer;
@@ -64,16 +64,14 @@
// attach the texture to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
- offscreenBuffer->texture.id(), 0);
+ offscreenBuffer->texture.id(), 0);
GL_CHECKPOINT(LOW);
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
LOG_ALWAYS_FATAL_IF(status != GL_FRAMEBUFFER_COMPLETE,
- "framebuffer incomplete, status %d, textureId %d, size %dx%d",
- status,
- offscreenBuffer->texture.id(),
- offscreenBuffer->texture.width(),
- offscreenBuffer->texture.height());
+ "framebuffer incomplete, status %d, textureId %d, size %dx%d", status,
+ offscreenBuffer->texture.id(), offscreenBuffer->texture.width(),
+ offscreenBuffer->texture.height());
// Change the viewport & ortho projection
setViewport(offscreenBuffer->viewportWidth, offscreenBuffer->viewportHeight);
@@ -92,7 +90,7 @@
mRenderTarget.lastStencilClip = nullptr;
mRenderTarget.offscreenBuffer->updateMeshFromRegion();
- mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
+ mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
// Detach the texture from the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
@@ -104,14 +102,14 @@
OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) {
const uint32_t width = area.getWidth();
const uint32_t height = area.getHeight();
- OffscreenBuffer* buffer = mRenderState.layerPool().get(
- mRenderState, width, height, mWideColorGamut);
+ OffscreenBuffer* buffer =
+ mRenderState.layerPool().get(mRenderState, width, height, mWideColorGamut);
if (!area.isEmpty() && width != 0 && height != 0) {
mCaches.textureState().activateTexture(0);
mCaches.textureState().bindTexture(buffer->texture.id());
- glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
- area.left, mRenderTarget.viewportHeight - area.bottom, width, height);
+ glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, area.left,
+ mRenderTarget.viewportHeight - area.bottom, width, height);
}
return buffer;
}
@@ -177,7 +175,7 @@
// Requested rect is subset of viewport - scissor to it to avoid over-clearing
mRenderState.scissor().setEnabled(true);
mRenderState.scissor().set(rect.left, mRenderTarget.viewportHeight - rect.bottom,
- rect.getWidth(), rect.getHeight());
+ rect.getWidth(), rect.getHeight());
}
glClear(GL_COLOR_BUFFER_BIT);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
@@ -222,8 +220,7 @@
// clears and re-fills stencil with provided rendertarget space quads,
// and then put stencil into test mode
-void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
- int incrementThreshold) {
+void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold) {
mRenderState.stencil().enableWrite(incrementThreshold);
mRenderState.stencil().clear();
Glop glop;
@@ -239,7 +236,8 @@
}
void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
- LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList, "can't rectlist clip without rectlist");
+ LOG_ALWAYS_FATAL_IF(clip->mode != ClipMode::RectangleList,
+ "can't rectlist clip without rectlist");
auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
int quadCount = rectList.getTransformedRectanglesCount();
std::vector<Vertex> rectangleVertices;
@@ -253,7 +251,7 @@
transform.mapRect(bounds);
bounds.doIntersect(clip->rect);
if (bounds.isEmpty()) {
- continue; // will be outside of scissor, skip
+ continue; // will be outside of scissor, skip
}
}
@@ -309,11 +307,11 @@
if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
mRenderTarget.stencil = mCaches.renderBufferCache.get(
- Stencil::getLayerStencilFormat(),
- layer->texture.width(), layer->texture.height());
+ Stencil::getLayerStencilFormat(), layer->texture.width(),
+ layer->texture.height());
// stencil is bound + allocated - associate it with current FBO
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
- GL_RENDERBUFFER, mRenderTarget.stencil->getName());
+ GL_RENDERBUFFER, mRenderTarget.stencil->getName());
}
if (clip->mode == ClipMode::RectangleList) {
@@ -344,17 +342,15 @@
}
void BakedOpRenderer::renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip,
- const Glop& glop) {
+ const Glop& glop) {
prepareRender(dirtyBounds, clip);
// Disable blending if this is the first draw to the main framebuffer, in case app has defined
// transparency where it doesn't make sense - as first draw in opaque window. Note that we only
// apply this improvement when the blend mode is SRC_OVER - other modes (e.g. CLEAR) can be
// valid draws that affect other content (e.g. draw CLEAR, then draw DST_OVER)
- bool overrideDisableBlending = !mHasDrawn
- && mOpaque
- && !mRenderTarget.frameBufferId
- && glop.blend.src == GL_ONE
- && glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
+ bool overrideDisableBlending = !mHasDrawn && mOpaque && !mRenderTarget.frameBufferId &&
+ glop.blend.src == GL_ONE &&
+ glop.blend.dst == GL_ONE_MINUS_SRC_ALPHA;
mRenderState.render(glop, mRenderTarget.orthoMatrix, overrideDisableBlending);
if (!mRenderTarget.frameBufferId) mHasDrawn = true;
}
@@ -383,5 +379,5 @@
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index 01ca367..7c0590d 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -46,23 +46,20 @@
*/
struct LightInfo {
LightInfo() : LightInfo(0, 0) {}
- LightInfo(uint8_t ambientShadowAlpha,
- uint8_t spotShadowAlpha)
- : ambientShadowAlpha(ambientShadowAlpha)
- , spotShadowAlpha(spotShadowAlpha) {}
+ LightInfo(uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha)
+ : ambientShadowAlpha(ambientShadowAlpha), spotShadowAlpha(spotShadowAlpha) {}
uint8_t ambientShadowAlpha;
uint8_t spotShadowAlpha;
};
BakedOpRenderer(Caches& caches, RenderState& renderState, bool opaque, bool wideColorGamut,
- const LightInfo& lightInfo)
+ const LightInfo& lightInfo)
: mGlopReceiver(DefaultGlopReceiver)
, mRenderState(renderState)
, mCaches(caches)
, mOpaque(opaque)
, mWideColorGamut(wideColorGamut)
- , mLightInfo(lightInfo) {
- }
+ , mLightInfo(lightInfo) {}
RenderState& renderState() { return mRenderState; }
Caches& caches() { return mCaches; }
@@ -79,9 +76,7 @@
const LightInfo& getLightInfo() const { return mLightInfo; }
void renderGlop(const BakedOpState& state, const Glop& glop) {
- renderGlop(&state.computedState.clippedBounds,
- state.computedState.getClipIfNeeded(),
- glop);
+ renderGlop(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded(), glop);
}
void renderFunctor(const FunctorOp& op, const BakedOpState& state);
@@ -97,15 +92,17 @@
// simple draw methods, to be used for end frame decoration
void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) {
- float ltrb[4] = { left, top, right, bottom };
+ float ltrb[4] = {left, top, right, bottom};
drawRects(ltrb, 4, paint);
}
void drawRects(const float* rects, int count, const SkPaint* paint);
+
protected:
GlopReceiver mGlopReceiver;
+
private:
static void DefaultGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
- const ClipBase* clip, const Glop& glop) {
+ const ClipBase* clip, const Glop& glop) {
renderer.renderGlopImpl(dirtyBounds, clip, glop);
}
void renderGlopImpl(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
@@ -148,5 +145,5 @@
const LightInfo mLightInfo;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
index 9823a02..63edf77 100644
--- a/libs/hwui/BakedOpState.cpp
+++ b/libs/hwui/BakedOpState.cpp
@@ -31,7 +31,8 @@
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture) {
+ const RecordedOp& recordedOp, bool expandForStroke,
+ bool expandForPathTexture) {
// resolvedMatrix = parentMatrix * localMatrix
transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
@@ -44,16 +45,16 @@
clippedBounds.outset(1);
}
transform.mapRect(clippedBounds);
- if (CC_UNLIKELY(expandForStroke
- && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+ if (CC_UNLIKELY(expandForStroke &&
+ (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
// account for hairline stroke when stroke may be < 1 scaled pixel
// Non translate || strokeWidth < 1 is conservative, but will cover all cases
clippedBounds.outset(0.5f);
}
// resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
- clipState = snapshot.serializeIntersectedClip(allocator,
- recordedOp.localClip, *(snapshot.transform));
+ clipState = snapshot.serializeIntersectedClip(allocator, recordedOp.localClip,
+ *(snapshot.transform));
LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
const Rect& clipRect = clipState->rect;
@@ -85,7 +86,7 @@
}
ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const Matrix4& localTransform, const ClipBase* localClip) {
+ const Matrix4& localTransform, const ClipBase* localClip) {
transform.loadMultiply(*snapshot.transform, localTransform);
clipState = snapshot.serializeIntersectedClip(allocator, localClip, *(snapshot.transform));
clippedBounds = clipState->rect;
@@ -109,11 +110,11 @@
clippedBounds.doIntersect(clipRect->rect);
}
-BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp) {
+BakedOpState* BakedOpState::tryConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, false, false);
+ BakedOpState* bakedState =
+ allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp, false, false);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
allocator.rewindIfLastAlloc(bakedState);
@@ -122,21 +123,23 @@
return bakedState;
}
-BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp) {
+BakedOpState* BakedOpState::tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
return allocator.create_trivial<BakedOpState>(allocator, snapshot, recordedOp);
}
-BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
- bool expandForPathTexture) {
+BakedOpState* BakedOpState::tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp,
+ StrokeBehavior strokeBehavior,
+ bool expandForPathTexture) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
- bool expandForStroke = (strokeBehavior == StrokeBehavior::Forced
- || (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
+ bool expandForStroke =
+ (strokeBehavior == StrokeBehavior::Forced ||
+ (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style));
BakedOpState* bakedState = allocator.create_trivial<BakedOpState>(
- allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
+ allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture);
if (bakedState->computedState.clippedBounds.isEmpty()) {
// bounds are empty, so op is rejected
// NOTE: this won't succeed if a clip was allocated
@@ -146,26 +149,25 @@
return bakedState;
}
-BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+BakedOpState* BakedOpState::tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const ShadowOp* shadowOpPtr) {
if (CC_UNLIKELY(snapshot.getRenderTargetClip().isEmpty())) return nullptr;
// clip isn't empty, so construct the op
return allocator.create_trivial<BakedOpState>(allocator, snapshot, shadowOpPtr);
}
-BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator,
- const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) {
+BakedOpState* BakedOpState::directConstruct(LinearAllocator& allocator, const ClipRect* clip,
+ const Rect& dstRect, const RecordedOp& recordedOp) {
return allocator.create_trivial<BakedOpState>(clip, dstRect, recordedOp);
}
void BakedOpState::setupOpacity(const SkPaint* paint) {
- computedState.opaqueOverClippedBounds = computedState.transform.isSimple()
- && computedState.clipState->mode == ClipMode::Rectangle
- && MathUtils::areEqual(alpha, 1.0f)
- && !roundRectClipState
- && PaintUtils::isOpaquePaint(paint);
+ computedState.opaqueOverClippedBounds = computedState.transform.isSimple() &&
+ computedState.clipState->mode == ClipMode::Rectangle &&
+ MathUtils::areEqual(alpha, 1.0f) &&
+ !roundRectClipState && PaintUtils::isOpaquePaint(paint);
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index 7b0b34f..c744755 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -26,22 +26,22 @@
namespace uirenderer {
namespace OpClipSideFlags {
- enum {
- None = 0x0,
- Left = 0x1,
- Top = 0x2,
- Right = 0x4,
- Bottom = 0x8,
- Full = 0xF,
- // ConservativeFull = 0x1F needed?
- };
+enum {
+ None = 0x0,
+ Left = 0x1,
+ Top = 0x2,
+ Right = 0x4,
+ Bottom = 0x8,
+ Full = 0xF,
+ // ConservativeFull = 0x1F needed?
+};
}
/**
* Holds a list of BakedOpStates of ops that can be drawn together
*/
struct MergedBakedOpList {
- const BakedOpState*const* states;
+ const BakedOpState* const* states;
size_t count;
int clipSideFlags;
Rect clip;
@@ -53,11 +53,12 @@
class ResolvedRenderState {
public:
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture);
+ const RecordedOp& recordedOp, bool expandForStroke,
+ bool expandForPathTexture);
// Constructor for unbounded ops *with* transform/clip
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
- const Matrix4& localTransform, const ClipBase* localClip);
+ const Matrix4& localTransform, const ClipBase* localClip);
// Constructor for unbounded ops without transform/clip (namely shadows)
ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
@@ -74,19 +75,15 @@
return outClip;
}
- const Rect& clipRect() const {
- return clipState->rect;
- }
+ const Rect& clipRect() const { return clipState->rect; }
bool requiresClip() const {
- return clipSideFlags != OpClipSideFlags::None
- || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
+ return clipSideFlags != OpClipSideFlags::None ||
+ CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
}
// returns the clip if it's needed to draw the operation, otherwise nullptr
- const ClipBase* getClipIfNeeded() const {
- return requiresClip() ? clipState : nullptr;
- }
+ const ClipBase* getClipIfNeeded() const { return requiresClip() ? clipState : nullptr; }
Matrix4 transform;
const ClipBase* clipState = nullptr;
@@ -103,11 +100,11 @@
*/
class BakedOpState {
public:
- static BakedOpState* tryConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp);
+ static BakedOpState* tryConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp);
- static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp);
+ static BakedOpState* tryConstructUnbounded(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp);
enum class StrokeBehavior {
// stroking is forced, regardless of style on paint (such as for lines)
@@ -116,15 +113,16 @@
StyleDefined,
};
- static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior,
- bool expandForPathTexture);
+ static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const RecordedOp& recordedOp,
+ StrokeBehavior strokeBehavior,
+ bool expandForPathTexture);
- static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
- Snapshot& snapshot, const ShadowOp* shadowOpPtr);
+ static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator, Snapshot& snapshot,
+ const ShadowOp* shadowOpPtr);
- static BakedOpState* directConstruct(LinearAllocator& allocator,
- const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp);
+ static BakedOpState* directConstruct(LinearAllocator& allocator, const ClipRect* clip,
+ const Rect& dstRect, const RecordedOp& recordedOp);
// Set opaqueOverClippedBounds. If this method isn't called, the op is assumed translucent.
void setupOpacity(const SkPaint* paint);
@@ -140,8 +138,8 @@
private:
friend class LinearAllocator;
- BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
- const RecordedOp& recordedOp, bool expandForStroke, bool expandForPathTexture)
+ BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const RecordedOp& recordedOp,
+ bool expandForStroke, bool expandForPathTexture)
: computedState(allocator, snapshot, recordedOp, expandForStroke, expandForPathTexture)
, alpha(snapshot.alpha)
, roundRectClipState(snapshot.roundRectClipState)
@@ -167,7 +165,7 @@
, op(&recordedOp) {}
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BAKED_OP_STATE_H
+#endif // ANDROID_HWUI_BAKED_OP_STATE_H
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 0700d1f..3c774a3 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -19,8 +19,8 @@
#include "GammaFontRenderer.h"
#include "GlLayer.h"
#include "Properties.h"
-#include "renderstate/RenderState.h"
#include "ShadowTessellator.h"
+#include "renderstate/RenderState.h"
#ifdef BUGREPORT_FONT_CACHE_USAGE
#include "font/FontCacheHistoryTracker.h"
#endif
@@ -40,9 +40,9 @@
///////////////////////////////////////////////////////////////////////////////
#if DEBUG_CACHE_FLUSH
- #define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
+#define FLUSH_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define FLUSH_LOGD(...)
+#define FLUSH_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -98,8 +98,8 @@
void Caches::initStaticProperties() {
// OpenGL ES 3.0+ specific features
- gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects()
- && property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
+ gpuPixelBuffersEnabled = extensions().hasPixelBufferObjects() &&
+ property_get_bool(PROPERTY_ENABLE_GPU_PIXEL_BUFFERS, true);
}
void Caches::terminate() {
@@ -143,10 +143,8 @@
///////////////////////////////////////////////////////////////////////////////
uint32_t Caches::getOverdrawColor(uint32_t amount) const {
- static uint32_t sOverdrawColors[2][4] = {
- { 0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000 },
- { 0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000 }
- };
+ static uint32_t sOverdrawColors[2][4] = {{0x2f0000ff, 0x2f00ff00, 0x3fff0000, 0x7fff0000},
+ {0x2f0000ff, 0x4fffff00, 0x5fff8ad8, 0x7fff0000}};
if (amount < 1) amount = 1;
if (amount > 4) amount = 4;
@@ -160,46 +158,44 @@
ALOGD("%s", stringLog.string());
}
-void Caches::dumpMemoryUsage(String8 &log) {
+void Caches::dumpMemoryUsage(String8& log) {
uint32_t total = 0;
log.appendFormat("Current memory usage / total memory usage (bytes):\n");
- log.appendFormat(" TextureCache %8d / %8d\n",
- textureCache.getSize(), textureCache.getMaxSize());
+ log.appendFormat(" TextureCache %8d / %8d\n", textureCache.getSize(),
+ textureCache.getMaxSize());
if (mRenderState) {
int memused = 0;
for (std::set<Layer*>::iterator it = mRenderState->mActiveLayers.begin();
- it != mRenderState->mActiveLayers.end(); it++) {
+ it != mRenderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL);
const GlLayer* glLayer = static_cast<const GlLayer*>(layer);
- log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n",
- layer->getWidth(), layer->getHeight(),
- glLayer->getTextureId(),
- layer->getStrongCount());
+ log.appendFormat(" GlLayer size %dx%d; texid=%u refs=%d\n", layer->getWidth(),
+ layer->getHeight(), glLayer->getTextureId(), layer->getStrongCount());
memused += layer->getWidth() * layer->getHeight() * 4;
}
- log.appendFormat(" Layers total %8d (numLayers = %zu)\n",
- memused, mRenderState->mActiveLayers.size());
+ log.appendFormat(" Layers total %8d (numLayers = %zu)\n", memused,
+ mRenderState->mActiveLayers.size());
total += memused;
}
- log.appendFormat(" RenderBufferCache %8d / %8d\n",
- renderBufferCache.getSize(), renderBufferCache.getMaxSize());
- log.appendFormat(" GradientCache %8d / %8d\n",
- gradientCache.getSize(), gradientCache.getMaxSize());
- log.appendFormat(" PathCache %8d / %8d\n",
- pathCache.getSize(), pathCache.getMaxSize());
- log.appendFormat(" TessellationCache %8d / %8d\n",
- tessellationCache.getSize(), tessellationCache.getMaxSize());
+ log.appendFormat(" RenderBufferCache %8d / %8d\n", renderBufferCache.getSize(),
+ renderBufferCache.getMaxSize());
+ log.appendFormat(" GradientCache %8d / %8d\n", gradientCache.getSize(),
+ gradientCache.getMaxSize());
+ log.appendFormat(" PathCache %8d / %8d\n", pathCache.getSize(),
+ pathCache.getMaxSize());
+ log.appendFormat(" TessellationCache %8d / %8d\n", tessellationCache.getSize(),
+ tessellationCache.getMaxSize());
log.appendFormat(" TextDropShadowCache %8d / %8d\n", dropShadowCache.getSize(),
- dropShadowCache.getMaxSize());
- log.appendFormat(" PatchCache %8d / %8d\n",
- patchCache.getSize(), patchCache.getMaxSize());
+ dropShadowCache.getMaxSize());
+ log.appendFormat(" PatchCache %8d / %8d\n", patchCache.getSize(),
+ patchCache.getMaxSize());
fontRenderer.dumpMemoryUsage(log);
log.appendFormat("Other:\n");
- log.appendFormat(" FboCache %8d / %8d\n",
- fboCache.getSize(), fboCache.getMaxSize());
+ log.appendFormat(" FboCache %8d / %8d\n", fboCache.getSize(),
+ fboCache.getMaxSize());
total += textureCache.getSize();
total += renderBufferCache.getSize();
@@ -238,13 +234,13 @@
gradientCache.clear();
fontRenderer.clear();
fboCache.clear();
- // fall through
+ // fall through
case FlushMode::Moderate:
fontRenderer.flush();
textureCache.flush();
pathCache.clear();
tessellationCache.clear();
- // fall through
+ // fall through
case FlushMode::Layers:
renderBufferCache.clear();
break;
@@ -274,5 +270,5 @@
// Temporary Properties
///////////////////////////////////////////////////////////////////////////////
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 29eddde..9732832 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -22,20 +22,20 @@
#include "GammaFontRenderer.h"
#include "GradientCache.h"
#include "PatchCache.h"
-#include "ProgramCache.h"
#include "PathCache.h"
+#include "ProgramCache.h"
#include "RenderBufferCache.h"
-#include "renderstate/PixelBufferState.h"
-#include "renderstate/TextureState.h"
#include "ResourceCache.h"
#include "TessellationCache.h"
#include "TextDropShadowCache.h"
#include "TextureCache.h"
-#include "thread/TaskProcessor.h"
+#include "renderstate/PixelBufferState.h"
+#include "renderstate/TextureState.h"
#include "thread/TaskManager.h"
+#include "thread/TaskProcessor.h"
-#include <vector>
#include <memory>
+#include <vector>
#include <GLES3/gl3.h>
@@ -70,19 +70,14 @@
return *sInstance;
}
- static bool hasInstance() {
- return sInstance != nullptr;
- }
+ static bool hasInstance() { return sInstance != nullptr; }
+
private:
explicit Caches(RenderState& renderState);
static Caches* sInstance;
public:
- enum class FlushMode {
- Layers = 0,
- Moderate,
- Full
- };
+ enum class FlushMode { Layers = 0, Moderate, Full };
/**
* Initialize caches.
@@ -181,9 +176,9 @@
void initConstraints();
void initStaticProperties();
- static void eventMarkNull(GLsizei length, const GLchar* marker) { }
- static void startMarkNull(GLsizei length, const GLchar* marker) { }
- static void endMarkNull() { }
+ static void eventMarkNull(GLsizei length, const GLchar* marker) {}
+ static void startMarkNull(GLsizei length, const GLchar* marker) {}
+ static void endMarkNull() {}
RenderState* mRenderState;
@@ -198,9 +193,9 @@
// TODO: move below to RenderState
PixelBufferState* mPixelBufferState = nullptr;
TextureState* mTextureState = nullptr;
- Program* mProgram = nullptr; // note: object owned by ProgramCache
+ Program* mProgram = nullptr; // note: object owned by ProgramCache
-}; // class Caches
+}; // class Caches
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/CanvasProperty.h b/libs/hwui/CanvasProperty.h
index 56671bb..fc76e8b 100644
--- a/libs/hwui/CanvasProperty.h
+++ b/libs/hwui/CanvasProperty.h
@@ -27,6 +27,7 @@
class CanvasPropertyPrimitive : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPrimitive);
+
public:
explicit CanvasPropertyPrimitive(float initialValue) : value(initialValue) {}
@@ -35,6 +36,7 @@
class CanvasPropertyPaint : public VirtualLightRefBase {
PREVENT_COPY_AND_ASSIGN(CanvasPropertyPaint);
+
public:
explicit CanvasPropertyPaint(const SkPaint& initialValue) : value(initialValue) {}
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index 9c068b0..d18c4ab 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -21,14 +21,8 @@
namespace android {
namespace uirenderer {
-
CanvasState::CanvasState(CanvasStateClient& renderer)
- : mWidth(-1)
- , mHeight(-1)
- , mSaveCount(1)
- , mCanvas(renderer)
- , mSnapshot(&mFirstSnapshot) {
-}
+ : mWidth(-1), mHeight(-1), mSaveCount(1), mCanvas(renderer), mSnapshot(&mFirstSnapshot) {}
CanvasState::~CanvasState() {
// First call freeSnapshot on all but mFirstSnapshot
@@ -57,10 +51,9 @@
mSaveCount = 1;
}
-void CanvasState::initializeSaveStack(
- int viewportWidth, int viewportHeight,
- float clipLeft, float clipTop,
- float clipRight, float clipBottom, const Vector3& lightCenter) {
+void CanvasState::initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft,
+ float clipTop, float clipRight, float clipBottom,
+ const Vector3& lightCenter) {
if (mWidth != viewportWidth || mHeight != viewportHeight) {
mWidth = viewportWidth;
mHeight = viewportHeight;
@@ -92,7 +85,7 @@
snapshot->~Snapshot();
// Arbitrary number, just don't let this grown unbounded
if (mSnapshotPoolCount > 10) {
- free((void*) snapshot);
+ free((void*)snapshot);
} else {
snapshot->previous = mSnapshotPool;
mSnapshotPool = snapshot;
@@ -215,7 +208,7 @@
void CanvasState::setClippingOutline(LinearAllocator& allocator, const Outline* outline) {
Rect bounds;
float radius;
- if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
+ if (!outline->getAsRoundRect(&bounds, &radius)) return; // only RR supported
bool outlineIsRounded = MathUtils::isPositive(radius);
if (!outlineIsRounded || currentTransform()->isSimple()) {
@@ -241,10 +234,9 @@
* @param snapOut if set, the geometry will be treated as having an AA ramp.
* See Rect::snapGeometryToPixelBoundaries()
*/
-bool CanvasState::calculateQuickRejectForScissor(float left, float top,
- float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired,
- bool snapOut) const {
+bool CanvasState::calculateQuickRejectForScissor(float left, float top, float right, float bottom,
+ bool* clipRequired, bool* roundRectClipRequired,
+ bool snapOut) const {
if (bottom <= top || right <= left) {
return true;
}
@@ -265,21 +257,20 @@
// round rect clip is required if RR clip exists, and geometry intersects its corners
if (roundRectClipRequired) {
- *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr
- && mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
+ *roundRectClipRequired = mSnapshot->roundRectClipState != nullptr &&
+ mSnapshot->roundRectClipState->areaRequiresRoundRectClip(r);
}
return false;
}
-bool CanvasState::quickRejectConservative(float left, float top,
- float right, float bottom) const {
+bool CanvasState::quickRejectConservative(float left, float top, float right, float bottom) const {
if (bottom <= top || right <= left) {
return true;
}
Rect r(left, top, right, bottom);
currentTransform()->mapRect(r);
- r.roundOut(); // rounded out to be conservative
+ r.roundOut(); // rounded out to be conservative
Rect clipRect(currentRenderTargetClip());
clipRect.snapToPixelBoundaries();
@@ -289,5 +280,5 @@
return false;
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index b1fe09e..9ac35ff 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -32,8 +32,8 @@
*/
class CanvasStateClient {
public:
- CanvasStateClient() { }
- virtual ~CanvasStateClient() { }
+ CanvasStateClient() {}
+ virtual ~CanvasStateClient() {}
/**
* Callback allowing embedder to take actions in the middle of a
@@ -53,7 +53,7 @@
*/
virtual GLuint getTargetFbo() const = 0;
-}; // class CanvasStateClient
+}; // class CanvasStateClient
/**
* Implements Canvas state methods on behalf of Renderers.
@@ -86,13 +86,10 @@
* Initializes the first snapshot, computing the projection matrix,
* and stores the dimensions of the render target.
*/
- void initializeSaveStack(int viewportWidth, int viewportHeight,
- float clipLeft, float clipTop, float clipRight, float clipBottom,
- const Vector3& lightCenter);
+ void initializeSaveStack(int viewportWidth, int viewportHeight, float clipLeft, float clipTop,
+ float clipRight, float clipBottom, const Vector3& lightCenter);
- bool hasRectToRectTransform() const {
- return CC_LIKELY(currentTransform()->rectToRect());
- }
+ bool hasRectToRectTransform() const { return CC_LIKELY(currentTransform()->rectToRect()); }
// Save (layer)
int getSaveCount() const { return mSaveCount; }
@@ -112,9 +109,9 @@
void skew(float sx, float sy);
void setMatrix(const SkMatrix& matrix);
- void setMatrix(const Matrix4& matrix); // internal only convenience method
+ void setMatrix(const Matrix4& matrix); // internal only convenience method
void concatMatrix(const SkMatrix& matrix);
- void concatMatrix(const Matrix4& matrix); // internal only convenience method
+ void concatMatrix(const Matrix4& matrix); // internal only convenience method
// Clip
const Rect& getLocalClipBounds() const { return mSnapshot->getLocalClip(); }
@@ -132,13 +129,11 @@
* outline.
*/
void setClippingOutline(LinearAllocator& allocator, const Outline* outline);
- void setClippingRoundRect(LinearAllocator& allocator,
- const Rect& rect, float radius, bool highPriority = true) {
+ void setClippingRoundRect(LinearAllocator& allocator, const Rect& rect, float radius,
+ bool highPriority = true) {
mSnapshot->setClippingRoundRect(allocator, rect, radius, highPriority);
}
- void setProjectionPathMask(const SkPath* path) {
- mSnapshot->setProjectionPathMask(path);
- }
+ void setProjectionPathMask(const SkPath* path) { mSnapshot->setProjectionPathMask(path); }
/**
* Returns true if drawing in the rectangle (left, top, right, bottom)
@@ -146,14 +141,19 @@
* perfect tests would return true.
*/
bool calculateQuickRejectForScissor(float left, float top, float right, float bottom,
- bool* clipRequired, bool* roundRectClipRequired, bool snapOut) const;
+ bool* clipRequired, bool* roundRectClipRequired,
+ bool snapOut) const;
void scaleAlpha(float alpha) { mSnapshot->alpha *= alpha; }
inline const mat4* currentTransform() const { return currentSnapshot()->transform; }
- inline const Rect& currentRenderTargetClip() const { return currentSnapshot()->getRenderTargetClip(); }
+ inline const Rect& currentRenderTargetClip() const {
+ return currentSnapshot()->getRenderTargetClip();
+ }
inline int currentFlags() const { return currentSnapshot()->flags; }
- const Vector3& currentLightCenter() const { return currentSnapshot()->getRelativeLightCenter(); }
+ const Vector3& currentLightCenter() const {
+ return currentSnapshot()->getRelativeLightCenter();
+ }
int getViewportWidth() const { return currentSnapshot()->getViewportWidth(); }
int getViewportHeight() const { return currentSnapshot()->getViewportHeight(); }
int getWidth() const { return mWidth; }
@@ -189,7 +189,7 @@
Snapshot* mSnapshotPool = nullptr;
int mSnapshotPoolCount = 0;
-}; // class CanvasState
+}; // class CanvasState
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 84451ba..27d93cf 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -33,7 +33,7 @@
Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform) {
const float kMinFloat = std::numeric_limits<float>::lowest();
const float kMaxFloat = std::numeric_limits<float>::max();
- Rect transformedBounds = { kMaxFloat, kMaxFloat, kMinFloat, kMinFloat };
+ Rect transformedBounds = {kMaxFloat, kMaxFloat, kMinFloat, kMinFloat};
handlePoint(transformedBounds, transform, r.left, r.top);
handlePoint(transformedBounds, transform, r.right, r.top);
handlePoint(transformedBounds, transform, r.left, r.bottom);
@@ -49,18 +49,12 @@
* TransformedRectangle
*/
-TransformedRectangle::TransformedRectangle() {
-}
+TransformedRectangle::TransformedRectangle() {}
-TransformedRectangle::TransformedRectangle(const Rect& bounds,
- const Matrix4& transform)
- : mBounds(bounds)
- , mTransform(transform) {
-}
+TransformedRectangle::TransformedRectangle(const Rect& bounds, const Matrix4& transform)
+ : mBounds(bounds), mTransform(transform) {}
-bool TransformedRectangle::canSimplyIntersectWith(
- const TransformedRectangle& other) const {
-
+bool TransformedRectangle::canSimplyIntersectWith(const TransformedRectangle& other) const {
return mTransform == other.mTransform;
}
@@ -76,9 +70,7 @@
* RectangleList
*/
-RectangleList::RectangleList()
- : mTransformedRectanglesCount(0) {
-}
+RectangleList::RectangleList() : mTransformedRectanglesCount(0) {}
bool RectangleList::isEmpty() const {
if (mTransformedRectanglesCount < 1) {
@@ -110,8 +102,7 @@
mTransformedRectangles[0] = TransformedRectangle(bounds, transform);
}
-bool RectangleList::intersectWith(const Rect& bounds,
- const Matrix4& transform) {
+bool RectangleList::intersectWith(const Rect& bounds, const Matrix4& transform) {
TransformedRectangle newRectangle(bounds, transform);
// Try to find a rectangle with a compatible transformation
@@ -148,8 +139,7 @@
return bounds;
}
-static SkPath pathFromTransformedRectangle(const Rect& bounds,
- const Matrix4& transform) {
+static SkPath pathFromTransformedRectangle(const Rect& bounds, const Matrix4& transform) {
SkPath rectPath;
SkPath rectPathTransformed;
rectPath.addRect(bounds.left, bounds.top, bounds.right, bounds.bottom);
@@ -163,8 +153,8 @@
SkRegion rectangleListAsRegion;
for (int index = 0; index < mTransformedRectanglesCount; index++) {
const TransformedRectangle& tr(mTransformedRectangles[index]);
- SkPath rectPathTransformed = pathFromTransformedRectangle(
- tr.getBounds(), tr.getTransform());
+ SkPath rectPathTransformed =
+ pathFromTransformedRectangle(tr.getBounds(), tr.getTransform());
if (index == 0) {
rectangleListAsRegion.setPath(rectPathTransformed, clip);
} else {
@@ -186,9 +176,7 @@
* ClipArea
*/
-ClipArea::ClipArea()
- : mMode(ClipMode::Rectangle) {
-}
+ClipArea::ClipArea() : mMode(ClipMode::Rectangle) {}
/*
* Interface
@@ -215,21 +203,20 @@
mClipRegion.setEmpty();
}
-void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op) {
+void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op) {
if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
onClipUpdated();
switch (mMode) {
- case ClipMode::Rectangle:
- rectangleModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::RectangleList:
- rectangleListModeClipRectWithTransform(r, transform, op);
- break;
- case ClipMode::Region:
- regionModeClipRectWithTransform(r, transform, op);
- break;
+ case ClipMode::Rectangle:
+ rectangleModeClipRectWithTransform(r, transform, op);
+ break;
+ case ClipMode::RectangleList:
+ rectangleListModeClipRectWithTransform(r, transform, op);
+ break;
+ case ClipMode::Region:
+ regionModeClipRectWithTransform(r, transform, op);
+ break;
}
}
@@ -242,8 +229,7 @@
onClipRegionUpdated();
}
-void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
- SkRegion::Op op) {
+void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op) {
if (op == SkRegion::kReplace_Op) mReplaceOpObserved = true;
if (!mPostViewportClipObserved && op == SkRegion::kIntersect_Op) op = SkRegion::kReplace_Op;
onClipUpdated();
@@ -269,9 +255,8 @@
mMode = ClipMode::Rectangle;
}
-void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op) {
-
+void ClipArea::rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
if (op == SkRegion::kReplace_Op && transform->rectToRect()) {
mClipRect = r;
transform->mapRect(mClipRect);
@@ -306,10 +291,9 @@
mRectangleList.set(mClipRect, Matrix4::identity());
}
-void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op) {
- if (op != SkRegion::kIntersect_Op
- || !mRectangleList.intersectWith(r, *transform)) {
+void ClipArea::rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
+ if (op != SkRegion::kIntersect_Op || !mRectangleList.intersectWith(r, *transform)) {
enterRegionMode();
regionModeClipRectWithTransform(r, transform, op);
}
@@ -332,8 +316,8 @@
}
}
-void ClipArea::regionModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op) {
+void ClipArea::regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op) {
SkPath transformedRect = pathFromTransformedRectangle(r, *transform);
SkRegion transformedRectRegion;
regionFromPath(transformedRect, transformedRectRegion);
@@ -365,24 +349,24 @@
}
static_assert(std::is_trivially_destructible<Rect>::value,
- "expect Rect to be trivially destructible");
+ "expect Rect to be trivially destructible");
static_assert(std::is_trivially_destructible<RectangleList>::value,
- "expect RectangleList to be trivially destructible");
+ "expect RectangleList to be trivially destructible");
if (mLastSerialization == nullptr) {
ClipBase* serialization = nullptr;
switch (mMode) {
- case ClipMode::Rectangle:
- serialization = allocator.create<ClipRect>(mClipRect);
- break;
- case ClipMode::RectangleList:
- serialization = allocator.create<ClipRectList>(mRectangleList);
- serialization->rect = mRectangleList.calculateBounds();
- break;
- case ClipMode::Region:
- serialization = allocator.create<ClipRegion>(mClipRegion);
- serialization->rect.set(mClipRegion.getBounds());
- break;
+ case ClipMode::Rectangle:
+ serialization = allocator.create<ClipRect>(mClipRect);
+ break;
+ case ClipMode::RectangleList:
+ serialization = allocator.create<ClipRectList>(mRectangleList);
+ serialization->rect = mRectangleList.calculateBounds();
+ break;
+ case ClipMode::Region:
+ serialization = allocator.create<ClipRegion>(mClipRegion);
+ serialization->rect.set(mClipRegion.getBounds());
+ break;
}
serialization->intersectWithRoot = mReplaceOpObserved;
// TODO: this is only done for draw time, should eventually avoid for record time
@@ -404,81 +388,79 @@
// For simplicity, doesn't account for rect merging
static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
int currentRectCount = clipArea.isRectangleList()
- ? clipArea.getRectangleList().getTransformedRectanglesCount()
- : 1;
+ ? clipArea.getRectangleList().getTransformedRectanglesCount()
+ : 1;
int recordedRectCount = (scb->mode == ClipMode::RectangleList)
- ? getRectList(scb).getTransformedRectanglesCount()
- : 1;
+ ? getRectList(scb).getTransformedRectanglesCount()
+ : 1;
return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
}
static const ClipRect sEmptyClipRect(Rect(0, 0));
const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
-
+ const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform) {
// if no recordedClip passed, just serialize current state
if (!recordedClip) return serializeClip(allocator);
// if either is empty, clip is empty
- if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
+ if (CC_UNLIKELY(recordedClip->rect.isEmpty()) || mClipRect.isEmpty()) return &sEmptyClipRect;
- if (!mLastResolutionResult
- || recordedClip != mLastResolutionClip
- || recordedClipTransform != mLastResolutionTransform) {
+ if (!mLastResolutionResult || recordedClip != mLastResolutionClip ||
+ recordedClipTransform != mLastResolutionTransform) {
mLastResolutionClip = recordedClip;
mLastResolutionTransform = recordedClipTransform;
- if (CC_LIKELY(mMode == ClipMode::Rectangle
- && recordedClip->mode == ClipMode::Rectangle
- && recordedClipTransform.rectToRect())) {
+ if (CC_LIKELY(mMode == ClipMode::Rectangle && recordedClip->mode == ClipMode::Rectangle &&
+ recordedClipTransform.rectToRect())) {
// common case - result is a single rectangle
auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
recordedClipTransform.mapRect(rectClip->rect);
rectClip->rect.doIntersect(mClipRect);
rectClip->rect.snapToPixelBoundaries();
mLastResolutionResult = rectClip;
- } else if (CC_UNLIKELY(mMode == ClipMode::Region
- || recordedClip->mode == ClipMode::Region
- || cannotFitInRectangleList(*this, recordedClip))) {
+ } else if (CC_UNLIKELY(mMode == ClipMode::Region ||
+ recordedClip->mode == ClipMode::Region ||
+ cannotFitInRectangleList(*this, recordedClip))) {
// region case
SkRegion other;
switch (recordedClip->mode) {
- case ClipMode::Rectangle:
- if (CC_LIKELY(recordedClipTransform.rectToRect())) {
- // simple transform, skip creating SkPath
- Rect resultClip(recordedClip->rect);
- recordedClipTransform.mapRect(resultClip);
- other.setRect(resultClip.toSkIRect());
- } else {
- SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
- recordedClipTransform);
- other.setPath(transformedRect, createViewportRegion());
+ case ClipMode::Rectangle:
+ if (CC_LIKELY(recordedClipTransform.rectToRect())) {
+ // simple transform, skip creating SkPath
+ Rect resultClip(recordedClip->rect);
+ recordedClipTransform.mapRect(resultClip);
+ other.setRect(resultClip.toSkIRect());
+ } else {
+ SkPath transformedRect = pathFromTransformedRectangle(
+ recordedClip->rect, recordedClipTransform);
+ other.setPath(transformedRect, createViewportRegion());
+ }
+ break;
+ case ClipMode::RectangleList: {
+ RectangleList transformedList(getRectList(recordedClip));
+ transformedList.transform(recordedClipTransform);
+ other = transformedList.convertToRegion(createViewportRegion());
+ break;
}
- break;
- case ClipMode::RectangleList: {
- RectangleList transformedList(getRectList(recordedClip));
- transformedList.transform(recordedClipTransform);
- other = transformedList.convertToRegion(createViewportRegion());
- break;
- }
- case ClipMode::Region:
- other = getRegion(recordedClip);
- applyTransformToRegion(recordedClipTransform, &other);
+ case ClipMode::Region:
+ other = getRegion(recordedClip);
+ applyTransformToRegion(recordedClipTransform, &other);
}
ClipRegion* regionClip = allocator.create<ClipRegion>();
switch (mMode) {
- case ClipMode::Rectangle:
- regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::RectangleList:
- regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
- other, SkRegion::kIntersect_Op);
- break;
- case ClipMode::Region:
- regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
- break;
+ case ClipMode::Rectangle:
+ regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::RectangleList:
+ regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
+ other, SkRegion::kIntersect_Op);
+ break;
+ case ClipMode::Region:
+ regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
+ break;
}
// Don't need to snap, since region's in int bounds
regionClip->rect.set(regionClip->region.getBounds());
@@ -510,7 +492,7 @@
}
void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
- if (!clip) return; // nothing to do
+ if (!clip) return; // nothing to do
if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index cf57516..a7a1180 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -39,18 +39,14 @@
bool isEmpty() const;
- const Rect& getBounds() const {
- return mBounds;
- }
+ const Rect& getBounds() const { return mBounds; }
Rect transformedBounds() const {
Rect transformedBounds(transformAndCalculateBounds(mBounds, mTransform));
return transformedBounds;
}
- const Matrix4& getTransform() const {
- return mTransform;
- }
+ const Matrix4& getTransform() const { return mTransform; }
void transform(const Matrix4& transform) {
Matrix4 t;
@@ -79,9 +75,7 @@
SkRegion convertToRegion(const SkRegion& clip) const;
Rect calculateBounds() const;
- enum {
- kMaxTransformedRectangles = 5
- };
+ enum { kMaxTransformedRectangles = 5 };
private:
int mTransformedRectanglesCount;
@@ -97,11 +91,8 @@
};
struct ClipBase {
- explicit ClipBase(ClipMode mode)
- : mode(mode) {}
- explicit ClipBase(const Rect& rect)
- : mode(ClipMode::Rectangle)
- , rect(rect) {}
+ explicit ClipBase(ClipMode mode) : mode(mode) {}
+ explicit ClipBase(const Rect& rect) : mode(ClipMode::Rectangle), rect(rect) {}
const ClipMode mode;
bool intersectWithRoot = false;
// Bounds of the clipping area, used to define the scissor, and define which
@@ -112,23 +103,18 @@
};
struct ClipRect : ClipBase {
- explicit ClipRect(const Rect& rect)
- : ClipBase(rect) {}
+ explicit ClipRect(const Rect& rect) : ClipBase(rect) {}
};
struct ClipRectList : ClipBase {
explicit ClipRectList(const RectangleList& rectList)
- : ClipBase(ClipMode::RectangleList)
- , rectList(rectList) {}
+ : ClipBase(ClipMode::RectangleList), rectList(rectList) {}
RectangleList rectList;
};
struct ClipRegion : ClipBase {
- explicit ClipRegion(const SkRegion& region)
- : ClipBase(ClipMode::Region)
- , region(region) {}
- ClipRegion()
- : ClipBase(ClipMode::Region) {}
+ explicit ClipRegion(const SkRegion& region) : ClipBase(ClipMode::Region), region(region) {}
+ ClipRegion() : ClipBase(ClipMode::Region) {}
SkRegion region;
};
@@ -138,44 +124,29 @@
void setViewportDimensions(int width, int height);
- bool isEmpty() const {
- return mClipRect.isEmpty();
- }
+ bool isEmpty() const { return mClipRect.isEmpty(); }
void setEmpty();
void setClip(float left, float top, float right, float bottom);
- void clipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op);
- void clipPathWithTransform(const SkPath& path, const mat4* transform,
- SkRegion::Op op);
+ void clipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
+ void clipPathWithTransform(const SkPath& path, const mat4* transform, SkRegion::Op op);
- const Rect& getClipRect() const {
- return mClipRect;
- }
+ const Rect& getClipRect() const { return mClipRect; }
- const SkRegion& getClipRegion() const {
- return mClipRegion;
- }
+ const SkRegion& getClipRegion() const { return mClipRegion; }
- const RectangleList& getRectangleList() const {
- return mRectangleList;
- }
+ const RectangleList& getRectangleList() const { return mRectangleList; }
- bool isRegion() const {
- return ClipMode::Region == mMode;
- }
+ bool isRegion() const { return ClipMode::Region == mMode; }
- bool isSimple() const {
- return mMode == ClipMode::Rectangle;
- }
+ bool isSimple() const { return mMode == ClipMode::Rectangle; }
- bool isRectangleList() const {
- return mMode == ClipMode::RectangleList;
- }
+ bool isRectangleList() const { return mMode == ClipMode::RectangleList; }
WARN_UNUSED_RESULT const ClipBase* serializeClip(LinearAllocator& allocator);
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+ WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
+ LinearAllocator& allocator, const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform);
void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
static void applyTransformToRegion(const Matrix4& transform, SkRegion* region);
@@ -185,14 +156,13 @@
void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
void enterRectangleListMode();
- void rectangleListModeClipRectWithTransform(const Rect& r,
- const mat4* transform, SkRegion::Op op);
+ void rectangleListModeClipRectWithTransform(const Rect& r, const mat4* transform,
+ SkRegion::Op op);
void enterRegionModeFromRectangleMode();
void enterRegionModeFromRectangleListMode();
void enterRegionMode();
- void regionModeClipRectWithTransform(const Rect& r, const mat4* transform,
- SkRegion::Op op);
+ void regionModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
void clipRegion(const SkRegion& region, SkRegion::Op op);
void ensureClipRegion();
@@ -205,9 +175,7 @@
mLastResolutionResult = nullptr;
}
- SkRegion createViewportRegion() {
- return SkRegion(mViewportBounds.toSkIRect());
- }
+ SkRegion createViewportRegion() { return SkRegion(mViewportBounds.toSkIRect()); }
void regionFromPath(const SkPath& path, SkRegion& pathAsRegion) {
// TODO: this should not mask every path to the viewport - this makes it impossible to use
diff --git a/libs/hwui/DamageAccumulator.cpp b/libs/hwui/DamageAccumulator.cpp
index 2b4fe17..cca0032 100644
--- a/libs/hwui/DamageAccumulator.cpp
+++ b/libs/hwui/DamageAccumulator.cpp
@@ -57,17 +57,18 @@
computeTransformImpl(currentFrame->prev, outMatrix);
}
switch (currentFrame->type) {
- case TransformRenderNode:
- currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
- break;
- case TransformMatrix4:
- outMatrix->multiply(*currentFrame->matrix4);
- break;
- case TransformNone:
- // nothing to be done
- break;
- default:
- LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d", currentFrame->type);
+ case TransformRenderNode:
+ currentFrame->renderNode->applyViewPropertyTransforms(*outMatrix);
+ break;
+ case TransformMatrix4:
+ outMatrix->multiply(*currentFrame->matrix4);
+ break;
+ case TransformNone:
+ // nothing to be done
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Tried to compute transform with an invalid type: %d",
+ currentFrame->type);
}
}
@@ -104,17 +105,17 @@
DirtyStack* dirtyFrame = mHead;
mHead = mHead->prev;
switch (dirtyFrame->type) {
- case TransformRenderNode:
- applyRenderNodeTransform(dirtyFrame);
- break;
- case TransformMatrix4:
- applyMatrix4Transform(dirtyFrame);
- break;
- case TransformNone:
- mHead->pendingDirty.join(dirtyFrame->pendingDirty);
- break;
- default:
- LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
+ case TransformRenderNode:
+ applyRenderNodeTransform(dirtyFrame);
+ break;
+ case TransformMatrix4:
+ applyMatrix4Transform(dirtyFrame);
+ break;
+ case TransformNone:
+ mHead->pendingDirty.join(dirtyFrame->pendingDirty);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Tried to pop an invalid type: %d", dirtyFrame->type);
}
}
@@ -168,8 +169,7 @@
if (frame) {
while (frame->prev != frame) {
frame = frame->prev;
- if (frame->type == TransformRenderNode
- && frame->renderNode->hasProjectionReceiver()) {
+ if (frame->type == TransformRenderNode && frame->renderNode->hasProjectionReceiver()) {
return frame;
}
}
@@ -233,7 +233,8 @@
}
void DamageAccumulator::finish(SkRect* totalDirty) {
- LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p", mHead->prev, mHead);
+ LOG_ALWAYS_FATAL_IF(mHead->prev != mHead, "Cannot finish, mismatched push/pop calls! %p vs. %p",
+ mHead->prev, mHead);
// Root node never has a transform, so this is the fully mapped dirty rect
*totalDirty = mHead->pendingDirty;
totalDirty->roundOut(totalDirty);
diff --git a/libs/hwui/DamageAccumulator.h b/libs/hwui/DamageAccumulator.h
index 250296e..7d0b687 100644
--- a/libs/hwui/DamageAccumulator.h
+++ b/libs/hwui/DamageAccumulator.h
@@ -26,7 +26,7 @@
// Smaller than INT_MIN/INT_MAX because we offset these values
// and thus don't want to be adding offsets to INT_MAX, that's bad
-#define DIRTY_MIN (-0x7ffffff-1)
+#define DIRTY_MIN (-0x7ffffff - 1)
#define DIRTY_MAX (0x7ffffff)
namespace android {
@@ -38,6 +38,7 @@
class DamageAccumulator {
PREVENT_COPY_AND_ASSIGN(DamageAccumulator);
+
public:
DamageAccumulator();
// mAllocator will clean everything up for us, no need for a dtor
diff --git a/libs/hwui/Debug.h b/libs/hwui/Debug.h
index e29699d..9b1ba69 100644
--- a/libs/hwui/Debug.h
+++ b/libs/hwui/Debug.h
@@ -102,9 +102,9 @@
#define DEBUG_VECTOR_DRAWABLE 0
#if DEBUG_INIT
- #define INIT_LOGD(...) ALOGD(__VA_ARGS__)
+#define INIT_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define INIT_LOGD(...)
+#define INIT_LOGD(...)
#endif
-#endif // ANDROID_HWUI_DEBUG_H
+#endif // ANDROID_HWUI_DEBUG_H
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index ff90160..be7d663 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -26,7 +26,7 @@
namespace uirenderer {
DeferredLayerUpdater::DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
- Layer::Api layerApi)
+ Layer::Api layerApi)
: mRenderState(renderState)
, mBlend(false)
, mSurfaceTexture(nullptr)
@@ -110,8 +110,8 @@
void DeferredLayerUpdater::doUpdateTexImage() {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
- "doUpdateTexImage non GL backend %x, GL %x, VK %x",
- mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+ "doUpdateTexImage non GL backend %x, GL %x, VK %x", mLayer->getApi(),
+ Layer::Api::OpenGL, Layer::Api::Vulkan);
if (mSurfaceTexture->updateTexImage() == NO_ERROR) {
float transform[16];
@@ -132,15 +132,15 @@
sp<GraphicBuffer> buffer = mSurfaceTexture->getCurrentBuffer();
if (buffer != nullptr) {
// force filtration if buffer size != layer size
- forceFilter = mWidth != static_cast<int>(buffer->getWidth())
- || mHeight != static_cast<int>(buffer->getHeight());
+ forceFilter = mWidth != static_cast<int>(buffer->getWidth()) ||
+ mHeight != static_cast<int>(buffer->getHeight());
}
- #if DEBUG_RENDERER
+#if DEBUG_RENDERER
if (dropCounter > 0) {
RENDERER_LOGD("Dropped %d frames on texture layer update", dropCounter);
}
- #endif
+#endif
mSurfaceTexture->getTransformMatrix(transform);
updateLayer(forceFilter, transform);
@@ -149,8 +149,8 @@
void DeferredLayerUpdater::doUpdateVkTexImage() {
LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::Vulkan,
- "updateLayer non Vulkan backend %x, GL %x, VK %x",
- mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
+ "updateLayer non Vulkan backend %x, GL %x, VK %x", mLayer->getApi(),
+ Layer::Api::OpenGL, Layer::Api::Vulkan);
static const mat4 identityMatrix;
updateLayer(false, identityMatrix.data);
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index 6164e47..9dc029f 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -16,10 +16,10 @@
#pragma once
-#include <cutils/compiler.h>
-#include <gui/GLConsumer.h>
#include <SkColorFilter.h>
#include <SkMatrix.h>
+#include <cutils/compiler.h>
+#include <gui/GLConsumer.h>
#include <utils/StrongPointer.h>
#include <GLES2/gl2.h>
@@ -41,10 +41,11 @@
// Note that DeferredLayerUpdater assumes it is taking ownership of the layer
// and will not call incrementRef on it as a result.
typedef std::function<Layer*(RenderState& renderState, uint32_t layerWidth,
- uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
- SkBlendMode mode, bool blend)> CreateLayerFn;
- ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState,
- CreateLayerFn createLayerFn, Layer::Api layerApi);
+ uint32_t layerHeight, SkColorFilter* colorFilter, int alpha,
+ SkBlendMode mode, bool blend)>
+ CreateLayerFn;
+ ANDROID_API explicit DeferredLayerUpdater(RenderState& renderState, CreateLayerFn createLayerFn,
+ Layer::Api layerApi);
ANDROID_API ~DeferredLayerUpdater();
@@ -74,30 +75,24 @@
GLenum target = texture->getCurrentTextureTarget();
LOG_ALWAYS_FATAL_IF(target != GL_TEXTURE_2D && target != GL_TEXTURE_EXTERNAL_OES,
- "set unsupported GLConsumer with target %x", target);
+ "set unsupported GLConsumer with target %x", target);
}
}
- ANDROID_API void updateTexImage() {
- mUpdateTexImage = true;
- }
+ ANDROID_API void updateTexImage() { mUpdateTexImage = true; }
ANDROID_API void setTransform(const SkMatrix* matrix) {
delete mTransform;
mTransform = matrix ? new SkMatrix(*matrix) : nullptr;
}
- SkMatrix* getTransform() {
- return mTransform;
- }
+ SkMatrix* getTransform() { return mTransform; }
ANDROID_API void setPaint(const SkPaint* paint);
void apply();
- Layer* backingLayer() {
- return mLayer;
- }
+ Layer* backingLayer() { return mLayer; }
void detachSurfaceTexture();
@@ -105,9 +100,7 @@
void destroyLayer();
- Layer::Api getBackingLayerApi() {
- return mLayerApi;
- }
+ Layer::Api getBackingLayerApi() { return mLayerApi; }
private:
RenderState& mRenderState;
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 37965da..e416287 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -19,8 +19,8 @@
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
-#include <thread>
#include <mutex>
+#include <thread>
#include <log/log.h>
@@ -58,8 +58,7 @@
}
void DeviceInfo::loadDisplayInfo() {
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info, error %d", status);
}
diff --git a/libs/hwui/DeviceInfo.h b/libs/hwui/DeviceInfo.h
index 5bd7b14..a0b2f06 100644
--- a/libs/hwui/DeviceInfo.h
+++ b/libs/hwui/DeviceInfo.h
@@ -18,14 +18,15 @@
#include <ui/DisplayInfo.h>
-#include "utils/Macros.h"
#include "Extensions.h"
+#include "utils/Macros.h"
namespace android {
namespace uirenderer {
class DeviceInfo {
PREVENT_COPY_AND_ASSIGN(DeviceInfo);
+
public:
// returns nullptr if DeviceInfo is not initialized yet
// Note this does not have a memory fence so it's up to the caller
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 0ff101c..aa87aea 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -44,8 +44,7 @@
, regions(stdAllocator)
, referenceHolders(stdAllocator)
, functors(stdAllocator)
- , vectorDrawables(stdAllocator) {
-}
+ , vectorDrawables(stdAllocator) {}
DisplayList::~DisplayList() {
cleanupResources();
@@ -105,14 +104,16 @@
}
}
-bool DisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+bool DisplayList::prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
info.prepareTextures = info.canvasContext.pinImages(bitmapResources);
for (auto&& op : children) {
RenderNode* childNode = op->renderNode;
info.damageAccumulator->pushTransform(&op->localMatrix);
- bool childFunctorsNeedLayer = functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
+ bool childFunctorsNeedLayer =
+ functorsNeedLayer; // TODO! || op->mRecordedWithPotentialStencilClip;
childFn(childNode, observer, info, childFunctorsNeedLayer);
info.damageAccumulator->popTransform();
}
@@ -140,5 +141,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index d22a764..0cfc3b7 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -32,8 +32,8 @@
#include <androidfw/ResourceTypes.h>
-#include "Debug.h"
#include "CanvasProperty.h"
+#include "Debug.h"
#include "GlFunctorLifecycleListener.h"
#include "Matrix.h"
#include "RenderProperties.h"
@@ -74,6 +74,7 @@
*/
class DisplayList {
friend class RecordingCanvas;
+
public:
struct Chunk {
// range of included ops in DisplayList::ops()
@@ -106,14 +107,9 @@
size_t addChild(NodeOpType* childOp);
+ void ref(VirtualLightRefBase* prop) { referenceHolders.push_back(prop); }
- void ref(VirtualLightRefBase* prop) {
- referenceHolders.push_back(prop);
- }
-
- size_t getUsedSize() {
- return allocator.usedSize();
- }
+ size_t getUsedSize() { return allocator.usedSize(); }
virtual bool isEmpty() const { return ops.empty(); }
virtual bool hasFunctor() const { return !functors.empty(); }
@@ -125,7 +121,8 @@
virtual void syncContents();
virtual void updateChildren(std::function<void(RenderNode*)> updateFn);
- virtual bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ virtual bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn);
virtual void output(std::ostream& output, uint32_t level);
@@ -148,12 +145,13 @@
LsaVector<const Res_png_9patch*> patchResources;
LsaVector<std::unique_ptr<const SkPaint>> paints;
LsaVector<std::unique_ptr<const SkRegion>> regions;
- LsaVector< sp<VirtualLightRefBase> > referenceHolders;
+ LsaVector<sp<VirtualLightRefBase>> referenceHolders;
// List of functors
LsaVector<FunctorContainer> functors;
- // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets nothing
+ // List of VectorDrawables that need to be notified of pushStaging. Note that this list gets
+ // nothing
// but a callback during sync DisplayList, unlike the list of functors defined above, which
// gets special treatment exclusive for webview.
LsaVector<VectorDrawableRoot*> vectorDrawables;
@@ -161,5 +159,5 @@
void cleanupResources();
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Extensions.cpp b/libs/hwui/Extensions.cpp
index 6b8006c..b7f1fb2 100644
--- a/libs/hwui/Extensions.cpp
+++ b/libs/hwui/Extensions.cpp
@@ -31,13 +31,14 @@
namespace uirenderer {
Extensions::Extensions() {
- if (Properties::getRenderPipelineType() != RenderPipelineType::OpenGL) {
- //Extensions class is used only by OpenGL pipeline
- //The code below will crash for SkiaVulkan, because OpenGL is not initialized
- //TODO: instantiate Extensions class only for OpenGL pipeline
+ if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+ // Extensions class is used only by OpenGL and SkiaGL pipelines
+ // The code below will crash for SkiaVulkan, because OpenGL is not initialized
+ // TODO: instantiate Extensions class only for OpenGL pipeline
+ // TODO: remove the only usage of Extensions by SkiaGL in SkiaOpenGLReadback::copyImageInto
return;
}
- const char* version = (const char*) glGetString(GL_VERSION);
+ const char* version = (const char*)glGetString(GL_VERSION);
// Section 6.1.5 of the OpenGL ES specification indicates the GL version
// string strictly follows this format:
@@ -57,7 +58,7 @@
mVersionMinor = 0;
}
- auto extensions = StringUtils::split((const char*) glGetString(GL_EXTENSIONS));
+ auto extensions = StringUtils::split((const char*)glGetString(GL_EXTENSIONS));
mHasNPot = extensions.has("GL_OES_texture_npot");
mHasFramebufferFetch = extensions.has("GL_NV_shader_framebuffer_fetch");
mHasDiscardFramebuffer = extensions.has("GL_EXT_discard_framebuffer");
@@ -65,6 +66,7 @@
mHas1BitStencil = extensions.has("GL_OES_stencil1");
mHas4BitStencil = extensions.has("GL_OES_stencil4");
mHasUnpackSubImage = extensions.has("GL_EXT_unpack_subimage");
+ mHasRenderableFloatTexture = extensions.has("GL_OES_texture_half_float");
mHasSRGB = mVersionMajor >= 3 || extensions.has("GL_EXT_sRGB");
mHasSRGBWriteControl = extensions.has("GL_EXT_sRGB_write_control");
@@ -81,5 +83,5 @@
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Extensions.h b/libs/hwui/Extensions.h
index 0ecfdb1..214ee0b 100644
--- a/libs/hwui/Extensions.h
+++ b/libs/hwui/Extensions.h
@@ -38,6 +38,9 @@
inline bool hasPixelBufferObjects() const { return mVersionMajor >= 3; }
inline bool hasOcclusionQueries() const { return mVersionMajor >= 3; }
inline bool hasFloatTextures() const { return mVersionMajor >= 3; }
+ inline bool hasRenderableFloatTextures() const {
+ return (mVersionMajor >= 3 && mVersionMinor >= 2) || mHasRenderableFloatTexture;
+ }
inline bool hasSRGB() const { return mHasSRGB; }
inline bool hasSRGBWriteControl() const { return hasSRGB() && mHasSRGBWriteControl; }
inline bool hasLinearBlending() const { return hasSRGB() && mHasLinearBlending; }
@@ -56,12 +59,13 @@
bool mHasSRGB;
bool mHasSRGBWriteControl;
bool mHasLinearBlending;
+ bool mHasRenderableFloatTexture;
int mVersionMajor;
int mVersionMinor;
-}; // class Extensions
+}; // class Extensions
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_EXTENSIONS_H
+#endif // ANDROID_HWUI_EXTENSIONS_H
diff --git a/libs/hwui/FboCache.cpp b/libs/hwui/FboCache.cpp
index a39e49f..88302cc 100644
--- a/libs/hwui/FboCache.cpp
+++ b/libs/hwui/FboCache.cpp
@@ -27,8 +27,7 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-FboCache::FboCache()
- : mMaxSize(0) {}
+FboCache::FboCache() : mMaxSize(0) {}
FboCache::~FboCache() {
clear();
@@ -79,5 +78,5 @@
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FboCache.h b/libs/hwui/FboCache.h
index ad6cc3e..5e8bb0c 100644
--- a/libs/hwui/FboCache.h
+++ b/libs/hwui/FboCache.h
@@ -71,9 +71,9 @@
private:
SortedVector<GLuint> mCache;
uint32_t mMaxSize;
-}; // class FboCache
+}; // class FboCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_FBO_CACHE_H
+#endif // ANDROID_HWUI_FBO_CACHE_H
diff --git a/libs/hwui/FloatColor.h b/libs/hwui/FloatColor.h
index a738ba4..b424f97 100644
--- a/libs/hwui/FloatColor.h
+++ b/libs/hwui/FloatColor.h
@@ -33,8 +33,8 @@
void set(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
r = a * EOCF(((color >> 16) & 0xff) / 255.0f);
- g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
- b = a * EOCF(((color ) & 0xff) / 255.0f);
+ g = a * EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = a * EOCF(((color)&0xff) / 255.0f);
}
// "color" is a gamma-encoded sRGB color
@@ -44,27 +44,18 @@
void setUnPreMultiplied(uint32_t color) {
a = ((color >> 24) & 0xff) / 255.0f;
r = EOCF(((color >> 16) & 0xff) / 255.0f);
- g = EOCF(((color >> 8) & 0xff) / 255.0f);
- b = EOCF(((color ) & 0xff) / 255.0f);
+ g = EOCF(((color >> 8) & 0xff) / 255.0f);
+ b = EOCF(((color)&0xff) / 255.0f);
}
- bool isNotBlack() {
- return a < 1.0f
- || r > 0.0f
- || g > 0.0f
- || b > 0.0f;
- }
+ bool isNotBlack() { return a < 1.0f || r > 0.0f || g > 0.0f || b > 0.0f; }
bool operator==(const FloatColor& other) const {
- return MathUtils::areEqual(r, other.r)
- && MathUtils::areEqual(g, other.g)
- && MathUtils::areEqual(b, other.b)
- && MathUtils::areEqual(a, other.a);
+ return MathUtils::areEqual(r, other.r) && MathUtils::areEqual(g, other.g) &&
+ MathUtils::areEqual(b, other.b) && MathUtils::areEqual(a, other.a);
}
- bool operator!=(const FloatColor& other) const {
- return !(*this == other);
- }
+ bool operator!=(const FloatColor& other) const { return !(*this == other); }
float r;
float g;
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 8b03468..bbcedb1 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -22,20 +22,20 @@
#include "Caches.h"
#include "Debug.h"
#include "Extensions.h"
-#include "font/Font.h"
#include "Glop.h"
#include "GlopBuilder.h"
#include "PixelBuffer.h"
#include "Rect.h"
+#include "font/Font.h"
#include "renderstate/RenderState.h"
#include "utils/Blur.h"
#include "utils/Timing.h"
-#include <algorithm>
#include <RenderScript.h>
#include <SkGlyph.h>
#include <SkUtils.h>
#include <utils/Log.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -55,8 +55,8 @@
if (linearFiltering) {
textureFillFlags |= TextureFillFlags::ForceFilter;
}
- int transformFlags = pureTranslate
- ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
+ int transformFlags =
+ pureTranslate ? TransformFlags::MeshIgnoresCanvasTransform : TransformFlags::None;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
bool gammaCorrection = true;
#else
@@ -93,7 +93,6 @@
, mDrawn(false)
, mInitialized(false)
, mLinearFiltering(false) {
-
if (sLogFontRendererCreate) {
INIT_LOGD("Creating FontRenderer");
}
@@ -118,10 +117,8 @@
if (sLogFontRendererCreate) {
INIT_LOGD(" Text cache sizes, in pixels: %i x %i, %i x %i, %i x %i, %i x %i",
- mSmallCacheWidth, mSmallCacheHeight,
- mLargeCacheWidth, mLargeCacheHeight >> 1,
- mLargeCacheWidth, mLargeCacheHeight >> 1,
- mLargeCacheWidth, mLargeCacheHeight);
+ mSmallCacheWidth, mSmallCacheHeight, mLargeCacheWidth, mLargeCacheHeight >> 1,
+ mLargeCacheWidth, mLargeCacheHeight >> 1, mLargeCacheWidth, mLargeCacheHeight);
}
sLogFontRendererCreate = false;
@@ -195,7 +192,8 @@
}
CacheTexture* FontRenderer::cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
- const SkGlyph& glyph, uint32_t* startX, uint32_t* startY) {
+ const SkGlyph& glyph, uint32_t* startX,
+ uint32_t* startY) {
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
if (cacheTextures[i]->fitBitmap(glyph, startX, startY)) {
return cacheTextures[i];
@@ -206,7 +204,7 @@
}
void FontRenderer::cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
- uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
+ uint32_t* retOriginX, uint32_t* retOriginY, bool precaching) {
checkInit();
// If the glyph bitmap is empty let's assum the glyph is valid
@@ -234,14 +232,14 @@
#if DEBUG_FONT_RENDERER
ALOGD("getCacheTexturesForFormat: unknown SkMask format %x", format);
#endif
- return;
+ return;
}
// If the glyph is too tall, don't cache it
if (glyph.fHeight + TEXTURE_BORDER_SIZE * 2 >
- (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
- ALOGE("Font size too large to fit in cache. width, height = %i, %i",
- (int) glyph.fWidth, (int) glyph.fHeight);
+ (*cacheTextures)[cacheTextures->size() - 1]->getHeight()) {
+ ALOGE("Font size too large to fit in cache. width, height = %i, %i", (int)glyph.fWidth,
+ (int)glyph.fHeight);
return;
}
@@ -285,14 +283,14 @@
}
uint8_t* cacheBuffer = cacheTexture->getPixelBuffer()->map();
- uint8_t* bitmapBuffer = (uint8_t*) glyph.fImage;
+ uint8_t* bitmapBuffer = (uint8_t*)glyph.fImage;
int srcStride = glyph.rowBytes();
// Copy the glyph image, taking the mask format into account
switch (format) {
case SkMask::kA8_Format: {
- uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
- - TEXTURE_BORDER_SIZE;
+ uint32_t row =
+ (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
// write leading border line
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
// write glyph data
@@ -337,9 +335,9 @@
memset(dstL, 0, rowSize + 2 * borderSize);
// write glyph data
while (dst < dstEnd) {
- memset(dstL += dstStride, 0, borderSize); // leading border column
- memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
- memset(dstR += dstStride, 0, borderSize); // trailing border column
+ memset(dstL += dstStride, 0, borderSize); // leading border column
+ memcpy(dst += dstStride, src += srcStride, rowSize); // glyph data
+ memset(dstR += dstStride, 0, borderSize); // trailing border column
}
// write trailing border line
memset(dstL += dstStride, 0, rowSize + 2 * borderSize);
@@ -347,9 +345,9 @@
}
case SkMask::kBW_Format: {
uint32_t cacheX = 0, cacheY = 0;
- uint32_t row = (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX
- - TEXTURE_BORDER_SIZE;
- static const uint8_t COLORS[2] = { 0, 255 };
+ uint32_t row =
+ (startY - TEXTURE_BORDER_SIZE) * cacheWidth + startX - TEXTURE_BORDER_SIZE;
+ static const uint8_t COLORS[2] = {0, 255};
// write leading border line
memset(&cacheBuffer[row], 0, glyph.fWidth + 2 * TEXTURE_BORDER_SIZE);
// write glyph data
@@ -388,7 +386,7 @@
}
CacheTexture* FontRenderer::createCacheTexture(int width, int height, GLenum format,
- bool allocate) {
+ bool allocate) {
CacheTexture* cacheTexture = new CacheTexture(width, height, format, kMaxNumberOfQuads);
if (allocate) {
@@ -405,18 +403,18 @@
clearCacheTextures(mRGBACacheTextures);
mUploadTexture = false;
- mACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
- GL_ALPHA, true));
- mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
- GL_ALPHA, false));
- mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
- GL_ALPHA, false));
- mACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight,
- GL_ALPHA, false));
- mRGBACacheTextures.push_back(createCacheTexture(mSmallCacheWidth, mSmallCacheHeight,
- GL_RGBA, false));
- mRGBACacheTextures.push_back(createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1,
- GL_RGBA, false));
+ mACacheTextures.push_back(
+ createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_ALPHA, true));
+ mACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
+ mACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_ALPHA, false));
+ mACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight, GL_ALPHA, false));
+ mRGBACacheTextures.push_back(
+ createCacheTexture(mSmallCacheWidth, mSmallCacheHeight, GL_RGBA, false));
+ mRGBACacheTextures.push_back(
+ createCacheTexture(mLargeCacheWidth, mLargeCacheHeight >> 1, GL_RGBA, false));
mCurrentCacheTexture = mACacheTextures[0];
}
@@ -432,7 +430,7 @@
}
void checkTextureUpdateForCache(Caches& caches, std::vector<CacheTexture*>& cacheTextures,
- bool& resetPixelStore, GLuint& lastTextureId) {
+ bool& resetPixelStore, GLuint& lastTextureId) {
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* cacheTexture = cacheTextures[i];
if (cacheTexture->isDirty() && cacheTexture->getPixelBuffer()) {
@@ -500,24 +498,22 @@
issueDrawCommand(mRGBACacheTextures);
}
-void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture) {
+void FontRenderer::appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2,
+ float u2, float v2, float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4,
+ CacheTexture* texture) {
if (texture != mCurrentCacheTexture) {
// Now use the new texture id
mCurrentCacheTexture = texture;
}
- mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2,
- x3, y3, u3, v3, x4, y4, u4, v4);
+ mCurrentCacheTexture->addQuad(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4);
}
-void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture) {
-
- if (mClip &&
- (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
+void FontRenderer::appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
+ float u2, float v2, float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4, CacheTexture* texture) {
+ if (mClip && (x1 > mClip->right || y1 < mClip->top || x2 < mClip->left || y4 > mClip->bottom)) {
return;
}
@@ -535,10 +531,10 @@
}
}
-void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2, float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture) {
-
+void FontRenderer::appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2,
+ float u2, float v2, float x3, float y3, float u3, float v3,
+ float x4, float y4, float u4, float v4,
+ CacheTexture* texture) {
appendMeshQuadNoClip(x1, y1, u1, v1, x2, y2, u2, v2, x3, y3, u3, v3, x4, y4, u4, v4, texture);
if (mBounds) {
@@ -557,8 +553,9 @@
mCurrentFont = Font::create(this, paint, matrix);
}
-FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t *glyphs,
- int numGlyphs, float radius, const float* positions) {
+FontRenderer::DropShadow FontRenderer::renderDropShadow(const SkPaint* paint, const glyph_t* glyphs,
+ int numGlyphs, float radius,
+ const float* positions) {
checkInit();
DropShadow image;
@@ -580,8 +577,8 @@
mCurrentFont->measure(paint, glyphs, numGlyphs, &bounds, positions);
uint32_t intRadius = Blur::convertRadiusToInt(radius);
- uint32_t paddedWidth = (uint32_t) (bounds.right - bounds.left) + 2 * intRadius;
- uint32_t paddedHeight = (uint32_t) (bounds.top - bounds.bottom) + 2 * intRadius;
+ uint32_t paddedWidth = (uint32_t)(bounds.right - bounds.left) + 2 * intRadius;
+ uint32_t paddedHeight = (uint32_t)(bounds.top - bounds.bottom) + 2 * intRadius;
uint32_t maxSize = Caches::getInstance().maxTextureSize;
if (paddedWidth > maxSize || paddedHeight > maxSize) {
@@ -593,7 +590,7 @@
paddedWidth += RS_CPU_ALLOCATION_ALIGNMENT - paddedWidth % RS_CPU_ALLOCATION_ALIGNMENT;
}
int size = paddedWidth * paddedHeight;
- uint8_t* dataBuffer = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
+ uint8_t* dataBuffer = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, size);
memset(dataBuffer, 0, size);
@@ -604,8 +601,8 @@
// text has non-whitespace, so draw and blur to create the shadow
// NOTE: bounds.isEmpty() can't be used here, since vertical coordinates are inverted
// TODO: don't draw pure whitespace in the first place, and avoid needing this check
- mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY,
- Font::BITMAP, dataBuffer, paddedWidth, paddedHeight, nullptr, positions);
+ mCurrentFont->render(paint, glyphs, numGlyphs, penX, penY, Font::BITMAP, dataBuffer,
+ paddedWidth, paddedHeight, nullptr, positions);
// Unbind any PBO we might have used
Caches::getInstance().pixelBufferState().unbind();
@@ -639,7 +636,7 @@
}
void FontRenderer::precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
- const SkMatrix& matrix) {
+ const SkMatrix& matrix) {
Font* font = Font::create(this, paint, matrix);
font->precache(paint, glyphs, numGlyphs);
}
@@ -649,8 +646,8 @@
}
bool FontRenderer::renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions,
- Rect* bounds, TextDrawFunctor* functor, bool forceFinish) {
+ int numGlyphs, int x, int y, const float* positions, Rect* bounds,
+ TextDrawFunctor* functor, bool forceFinish) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -667,8 +664,8 @@
}
bool FontRenderer::renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, const SkPath* path, float hOffset, float vOffset,
- Rect* bounds, TextDrawFunctor* functor) {
+ int numGlyphs, const SkPath* path, float hOffset, float vOffset,
+ Rect* bounds, TextDrawFunctor* functor) {
if (!mCurrentFont) {
ALOGE("No font set");
return false;
@@ -684,7 +681,7 @@
void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
uint32_t intRadius = Blur::convertRadiusToInt(radius);
if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
- uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
+ uint8_t* outImage = (uint8_t*)memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
if (mRs == nullptr) {
mRs = new RSC::RS();
@@ -700,14 +697,12 @@
}
if (mRs != nullptr) {
RSC::sp<const RSC::Type> t = RSC::Type::create(mRs, mRsElement, width, height, 0);
- RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(mRs, t,
- RS_ALLOCATION_MIPMAP_NONE,
- RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
- *image);
- RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(mRs, t,
- RS_ALLOCATION_MIPMAP_NONE,
- RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED,
- outImage);
+ RSC::sp<RSC::Allocation> ain = RSC::Allocation::createTyped(
+ mRs, t, RS_ALLOCATION_MIPMAP_NONE,
+ RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, *image);
+ RSC::sp<RSC::Allocation> aout = RSC::Allocation::createTyped(
+ mRs, t, RS_ALLOCATION_MIPMAP_NONE,
+ RS_ALLOCATION_USAGE_SCRIPT | RS_ALLOCATION_USAGE_SHARED, outImage);
mRsScript->setRadius(radius);
mRsScript->setInput(ain);
@@ -768,7 +763,7 @@
}
static void dumpTextures(String8& log, const char* tag,
- const std::vector<CacheTexture*>& cacheTextures) {
+ const std::vector<CacheTexture*>& cacheTextures) {
for (uint32_t i = 0; i < cacheTextures.size(); i++) {
CacheTexture* cacheTexture = cacheTextures[i];
if (cacheTexture && cacheTexture->getPixelBuffer()) {
@@ -803,5 +798,5 @@
return getCacheSize(GL_ALPHA) + getCacheSize(GL_RGBA);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index 329309c..6b9dec4 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -16,10 +16,10 @@
#pragma once
-#include "font/FontUtil.h"
#include "font/CacheTexture.h"
#include "font/CachedGlyphInfo.h"
#include "font/Font.h"
+#include "font/FontUtil.h"
#ifdef BUGREPORT_FONT_CACHE_USAGE
#include "font/FontCacheHistoryTracker.h"
#endif
@@ -36,10 +36,10 @@
#include "RenderScript.h"
namespace RSC {
- class Element;
- class RS;
- class ScriptIntrinsicBlur;
- class sp;
+class Element;
+class RS;
+class ScriptIntrinsicBlur;
+class sp;
}
namespace android {
@@ -51,22 +51,18 @@
class TextDrawFunctor {
public:
- TextDrawFunctor(
- BakedOpRenderer* renderer,
- const BakedOpState* bakedState,
- const ClipBase* clip,
- float x, float y, bool pureTranslate,
- int alpha, SkBlendMode mode, const SkPaint* paint)
- : renderer(renderer)
- , bakedState(bakedState)
- , clip(clip)
- , x(x)
- , y(y)
- , pureTranslate(pureTranslate)
- , alpha(alpha)
- , mode(mode)
- , paint(paint) {
- }
+ TextDrawFunctor(BakedOpRenderer* renderer, const BakedOpState* bakedState, const ClipBase* clip,
+ float x, float y, bool pureTranslate, int alpha, SkBlendMode mode,
+ const SkPaint* paint)
+ : renderer(renderer)
+ , bakedState(bakedState)
+ , clip(clip)
+ , x(x)
+ , y(y)
+ , pureTranslate(pureTranslate)
+ , alpha(alpha)
+ , mode(mode)
+ , paint(paint) {}
void draw(CacheTexture& texture, bool linearFiltering);
@@ -91,16 +87,17 @@
void setFont(const SkPaint* paint, const SkMatrix& matrix);
- void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkMatrix& matrix);
+ void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
+ const SkMatrix& matrix);
void endPrecaching();
- bool renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions,
- Rect* outBounds, TextDrawFunctor* functor, bool forceFinish = true);
+ bool renderPosText(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs, int numGlyphs,
+ int x, int y, const float* positions, Rect* outBounds,
+ TextDrawFunctor* functor, bool forceFinish = true);
bool renderTextOnPath(const SkPaint* paint, const Rect* clip, const glyph_t* glyphs,
- int numGlyphs, const SkPath* path,
- float hOffset, float vOffset, Rect* outBounds, TextDrawFunctor* functor);
+ int numGlyphs, const SkPath* path, float hOffset, float vOffset,
+ Rect* outBounds, TextDrawFunctor* functor);
struct DropShadow {
uint32_t width;
@@ -112,12 +109,10 @@
// After renderDropShadow returns, the called owns the memory in DropShadow.image
// and is responsible for releasing it when it's done with it
- DropShadow renderDropShadow(const SkPaint* paint, const glyph_t *glyphs, int numGlyphs,
- float radius, const float* positions);
+ DropShadow renderDropShadow(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
+ float radius, const float* positions);
- void setTextureFiltering(bool linearFiltering) {
- mLinearFiltering = linearFiltering;
- }
+ void setTextureFiltering(bool linearFiltering) { mLinearFiltering = linearFiltering; }
uint32_t getSize() const;
void dumpMemoryUsage(String8& log) const;
@@ -135,10 +130,10 @@
void deallocateTextureMemory(CacheTexture* cacheTexture);
void initTextTexture();
CacheTexture* createCacheTexture(int width, int height, GLenum format, bool allocate);
- void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph,
- uint32_t *retOriginX, uint32_t *retOriginY, bool precaching);
- CacheTexture* cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures, const SkGlyph& glyph,
- uint32_t* startX, uint32_t* startY);
+ void cacheBitmap(const SkGlyph& glyph, CachedGlyphInfo* cachedGlyph, uint32_t* retOriginX,
+ uint32_t* retOriginY, bool precaching);
+ CacheTexture* cacheBitmapInTexture(std::vector<CacheTexture*>& cacheTextures,
+ const SkGlyph& glyph, uint32_t* startX, uint32_t* startY);
void flushAllAndInvalidate();
@@ -148,24 +143,19 @@
void issueDrawCommand(std::vector<CacheTexture*>& cacheTextures);
void issueDrawCommand();
- void appendMeshQuadNoClip(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture);
- void appendMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture);
- void appendRotatedMeshQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4, CacheTexture* texture);
+ void appendMeshQuadNoClip(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4, CacheTexture* texture);
+ void appendMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4, CacheTexture* texture);
+ void appendRotatedMeshQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4, CacheTexture* texture);
void checkTextureUpdate();
- void setTextureDirty() {
- mUploadTexture = true;
- }
+ void setTextureDirty() { mUploadTexture = true; }
const std::vector<CacheTexture*>& cacheTexturesForFormat(GLenum format) const;
uint32_t getCacheSize(GLenum format) const;
@@ -205,14 +195,14 @@
RSC::sp<RSC::ScriptIntrinsicBlur> mRsScript;
static void computeGaussianWeights(float* weights, int32_t radius);
- static void horizontalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
- int32_t width, int32_t height);
- static void verticalBlur(float* weights, int32_t radius, const uint8_t *source, uint8_t *dest,
- int32_t width, int32_t height);
+ static void horizontalBlur(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
+ static void verticalBlur(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
// the input image handle may have its pointer replaced (to avoid copies)
void blurImage(uint8_t** image, int32_t width, int32_t height, float radius);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index 86f9a5d..ced37ed 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -20,8 +20,8 @@
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
-#include "renderstate/OffscreenBufferPool.h"
#include "hwui/Canvas.h"
+#include "renderstate/OffscreenBufferPool.h"
#include "utils/FatVector.h"
#include "utils/PaintUtils.h"
#include "utils/TraceUtils.h"
@@ -32,9 +32,8 @@
namespace android {
namespace uirenderer {
-FrameBuilder::FrameBuilder(const SkRect& clip,
- uint32_t viewportWidth, uint32_t viewportHeight,
- const LightGeometry& lightGeometry, Caches& caches)
+FrameBuilder::FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
+ const LightGeometry& lightGeometry, Caches& caches)
: mStdAllocator(mAllocator)
, mLayerBuilders(mStdAllocator)
, mLayerStack(mStdAllocator)
@@ -42,18 +41,16 @@
, mCaches(caches)
, mLightRadius(lightGeometry.radius)
, mDrawFbo0(true) {
-
// Prepare to defer Fbo0
auto fbo0 = mAllocator.create<LayerBuilder>(viewportWidth, viewportHeight, Rect(clip));
mLayerBuilders.push_back(fbo0);
mLayerStack.push_back(0);
- mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
- clip.fLeft, clip.fTop, clip.fRight, clip.fBottom,
- lightGeometry.center);
+ mCanvasState.initializeSaveStack(viewportWidth, viewportHeight, clip.fLeft, clip.fTop,
+ clip.fRight, clip.fBottom, lightGeometry.center);
}
-FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers,
- const LightGeometry& lightGeometry, Caches& caches)
+FrameBuilder::FrameBuilder(const LayerUpdateQueue& layers, const LightGeometry& lightGeometry,
+ Caches& caches)
: mStdAllocator(mAllocator)
, mLayerBuilders(mStdAllocator)
, mLayerStack(mStdAllocator)
@@ -67,9 +64,7 @@
auto fbo0 = mAllocator.create<LayerBuilder>(1, 1, Rect(1, 1));
mLayerBuilders.push_back(fbo0);
mLayerStack.push_back(0);
- mCanvasState.initializeSaveStack(1, 1,
- 0, 0, 1, 1,
- lightGeometry.center);
+ mCanvasState.initializeSaveStack(1, 1, 0, 0, 1, 1, lightGeometry.center);
deferLayers(layers);
}
@@ -84,8 +79,8 @@
// as not to lose info on what portion is damaged
OffscreenBuffer* layer = layerNode->getLayer();
if (CC_LIKELY(layer)) {
- ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u",
- layerNode->getName(), layerNode->getWidth(), layerNode->getHeight());
+ ATRACE_FORMAT("Optimize HW Layer DisplayList %s %ux%u", layerNode->getName(),
+ layerNode->getWidth(), layerNode->getHeight());
Rect layerDamage = layers.entries()[i].damage;
// TODO: ensure layer damage can't be larger than layer
@@ -96,8 +91,8 @@
Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
layer->inverseTransformInWindow.mapPoint3d(lightCenter);
- saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
- layerDamage, lightCenter, nullptr, layerNode);
+ saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0, layerDamage,
+ lightCenter, nullptr, layerNode);
if (layerNode->getDisplayList()) {
deferNodeOps(*layerNode);
@@ -121,19 +116,18 @@
mCanvasState.save(SaveFlags::MatrixClip);
mCanvasState.translate(tx, ty);
mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
- SkClipOp::kIntersect);
+ SkClipOp::kIntersect);
deferNodePropsAndOps(renderNode);
mCanvasState.restore();
}
static Rect nodeBounds(RenderNode& node) {
auto& props = node.properties();
- return Rect(props.getLeft(), props.getTop(),
- props.getRight(), props.getBottom());
+ return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
}
-void FrameBuilder::deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
- const Rect& contentDrawBounds) {
+void FrameBuilder::deferRenderNodeScene(const std::vector<sp<RenderNode> >& nodes,
+ const Rect& contentDrawBounds) {
if (nodes.size() < 1) return;
if (nodes.size() == 1) {
if (!nodes[0]->nothingToDraw()) {
@@ -170,14 +164,16 @@
// the backdrop, so this isn't necessary.
if (content.right < backdrop.right) {
// draw backdrop to right side of content
- deferRenderNode(0, 0, Rect(content.right, backdrop.top,
- backdrop.right, backdrop.bottom), *nodes[0]);
+ deferRenderNode(0, 0,
+ Rect(content.right, backdrop.top, backdrop.right, backdrop.bottom),
+ *nodes[0]);
}
if (content.bottom < backdrop.bottom) {
// draw backdrop to bottom of content
// Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
- deferRenderNode(0, 0, Rect(content.left, content.bottom,
- content.right, backdrop.bottom), *nodes[0]);
+ deferRenderNode(0, 0,
+ Rect(content.left, content.bottom, content.right, backdrop.bottom),
+ *nodes[0]);
}
}
@@ -210,11 +206,9 @@
void FrameBuilder::deferNodePropsAndOps(RenderNode& node) {
const RenderProperties& properties = node.properties();
const Outline& outline = properties.getOutline();
- if (properties.getAlpha() <= 0
- || (outline.getShouldClip() && outline.isEmpty())
- || properties.getScaleX() == 0
- || properties.getScaleY() == 0) {
- return; // rejected
+ if (properties.getAlpha() <= 0 || (outline.getShouldClip() && outline.isEmpty()) ||
+ properties.getScaleX() == 0 || properties.getScaleY() == 0) {
+ return; // rejected
}
if (properties.getLeft() != 0 || properties.getTop() != 0) {
@@ -236,12 +230,12 @@
const int width = properties.getWidth();
const int height = properties.getHeight();
- Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
+ Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
const bool isLayer = properties.effectiveLayerType() != LayerType::None;
int clipFlags = properties.getClippingFlags();
if (properties.getAlpha() < 1) {
if (isLayer) {
- clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+ clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
// simply scale rendering content's alpha
@@ -251,7 +245,7 @@
saveLayerBounds.set(0, 0, width, height);
if (clipFlags) {
properties.getClippingRectForFlags(clipFlags, &saveLayerBounds);
- clipFlags = 0; // all clipping done by savelayer
+ clipFlags = 0; // all clipping done by savelayer
}
}
@@ -265,21 +259,21 @@
Rect clipRect;
properties.getClippingRectForFlags(clipFlags, &clipRect);
mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
- SkClipOp::kIntersect);
+ SkClipOp::kIntersect);
}
if (properties.getRevealClip().willClip()) {
Rect bounds;
properties.getRevealClip().getBounds(&bounds);
- mCanvasState.setClippingRoundRect(mAllocator,
- bounds, properties.getRevealClip().getRadius());
+ mCanvasState.setClippingRoundRect(mAllocator, bounds,
+ properties.getRevealClip().getRadius());
} else if (properties.getOutline().willClip()) {
mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
}
- bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty()
- || (properties.getClipToBounds()
- && mCanvasState.quickRejectConservative(0, 0, width, height));
+ bool quickRejected = mCanvasState.currentSnapshot()->getRenderTargetClip().isEmpty() ||
+ (properties.getClipToBounds() &&
+ mCanvasState.quickRejectConservative(0, 0, width, height));
if (!quickRejected) {
// not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
if (node.getLayer()) {
@@ -296,9 +290,8 @@
SkPaint saveLayerPaint;
saveLayerPaint.setAlpha(properties.getAlpha());
deferBeginLayerOp(*mAllocator.create_trivial<BeginLayerOp>(
- saveLayerBounds,
- Matrix4::identity(),
- nullptr, // no record-time clip - need only respect defer-time one
+ saveLayerBounds, Matrix4::identity(),
+ nullptr, // no record-time clip - need only respect defer-time one
&saveLayerPaint));
deferNodeOps(node);
deferEndLayerOp(*mAllocator.create_trivial<EndLayerOp>());
@@ -311,8 +304,8 @@
typedef key_value_pair_t<float, const RenderNodeOp*> ZRenderNodeOpPair;
template <typename V>
-static void buildZSortedChildList(V* zTranslatedNodes,
- const DisplayList& displayList, const DisplayList::Chunk& chunk) {
+static void buildZSortedChildList(V* zTranslatedNodes, const DisplayList& displayList,
+ const DisplayList::Chunk& chunk) {
if (chunk.beginChildIndex == chunk.endChildIndex) return;
for (size_t i = chunk.beginChildIndex; i < chunk.endChildIndex; i++) {
@@ -343,11 +336,10 @@
template <typename V>
void FrameBuilder::defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
- const V& zTranslatedNodes) {
+ const V& zTranslatedNodes) {
const int size = zTranslatedNodes.size();
- if (size == 0
- || (mode == ChildrenSelectMode::Negative&& zTranslatedNodes[0].key > 0.0f)
- || (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
+ if (size == 0 || (mode == ChildrenSelectMode::Negative && zTranslatedNodes[0].key > 0.0f) ||
+ (mode == ChildrenSelectMode::Positive && zTranslatedNodes[size - 1].key < 0.0f)) {
// no 3d children to draw
return;
}
@@ -364,11 +356,11 @@
if (mode == ChildrenSelectMode::Negative) {
drawIndex = 0;
endIndex = nonNegativeIndex;
- shadowIndex = endIndex; // draw no shadows
+ shadowIndex = endIndex; // draw no shadows
} else {
drawIndex = nonNegativeIndex;
endIndex = size;
- shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
+ shadowIndex = drawIndex; // potentially draw shadow for each pos Z child
}
float lastCasterZ = 0.0f;
@@ -381,7 +373,7 @@
if (shadowIndex == drawIndex || casterZ - lastCasterZ < 0.1f) {
deferShadow(reorderClip, *casterNodeOp);
- lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
+ lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
shadowIndex++;
continue;
}
@@ -397,11 +389,9 @@
auto& node = *casterNodeOp.renderNode;
auto& properties = node.properties();
- if (properties.getAlpha() <= 0.0f
- || properties.getOutline().getAlpha() <= 0.0f
- || !properties.getOutline().getPath()
- || properties.getScaleX() == 0
- || properties.getScaleY() == 0) {
+ if (properties.getAlpha() <= 0.0f || properties.getOutline().getAlpha() <= 0.0f ||
+ !properties.getOutline().getPath() || properties.getScaleX() == 0 ||
+ properties.getScaleY() == 0) {
// no shadow to draw
return;
}
@@ -432,8 +422,8 @@
Rect clipBounds;
properties.getClippingRectForFlags(CLIP_TO_CLIP_BOUNDS, &clipBounds);
SkPath clipBoundsPath;
- clipBoundsPath.addRect(clipBounds.left, clipBounds.top,
- clipBounds.right, clipBounds.bottom);
+ clipBoundsPath.addRect(clipBounds.left, clipBounds.top, clipBounds.right,
+ clipBounds.bottom);
Op(*casterPath, clipBoundsPath, kIntersect_SkPathOp, frameAllocatedPath);
casterPath = frameAllocatedPath;
@@ -442,7 +432,7 @@
// apply reorder clip to shadow, so it respects clip at beginning of reorderable chunk
int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
mCanvasState.writableSnapshot()->applyClip(reorderClip,
- *mCanvasState.currentSnapshot()->transform);
+ *mCanvasState.currentSnapshot()->transform);
if (CC_LIKELY(!mCanvasState.getRenderTargetClipBounds().isEmpty())) {
Matrix4 shadowMatrixXY(casterNodeOp.localMatrix);
Matrix4 shadowMatrixZ(casterNodeOp.localMatrix);
@@ -450,13 +440,9 @@
node.applyViewPropertyTransforms(shadowMatrixZ, true);
sp<TessellationCache::ShadowTask> task = mCaches.tessellationCache.getShadowTask(
- mCanvasState.currentTransform(),
- mCanvasState.getLocalClipBounds(),
- casterAlpha >= 1.0f,
- casterPath,
- &shadowMatrixXY, &shadowMatrixZ,
- mCanvasState.currentSnapshot()->getRelativeLightCenter(),
- mLightRadius);
+ mCanvasState.currentTransform(), mCanvasState.getLocalClipBounds(),
+ casterAlpha >= 1.0f, casterPath, &shadowMatrixXY, &shadowMatrixZ,
+ mCanvasState.currentSnapshot()->getRelativeLightCenter(), mLightRadius);
ShadowOp* shadowOp = mAllocator.create<ShadowOp>(task, casterAlpha);
BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
@@ -471,15 +457,13 @@
int count = mCanvasState.save(SaveFlags::MatrixClip);
const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
- SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
+ SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
if (projectionReceiverOutline) {
// transform the mask for this projector into render target space
// TODO: consider combining both transforms by stashing transform instead of applying
SkMatrix skCurrentTransform;
mCanvasState.currentTransform()->copyTo(skCurrentTransform);
- projectionReceiverOutline->transform(
- skCurrentTransform,
- &transformedMaskPath);
+ projectionReceiverOutline->transform(skCurrentTransform, &transformedMaskPath);
mCanvasState.setProjectionPathMask(&transformedMaskPath);
}
@@ -509,10 +493,12 @@
* This allows opIds embedded in the RecordedOps to be used for dispatching to these lambdas.
* E.g. a BitmapOp op then would be dispatched to FrameBuilder::onBitmapOp(const BitmapOp&)
*/
-#define OP_RECEIVER(Type) \
- [](FrameBuilder& frameBuilder, const RecordedOp& op) { frameBuilder.defer##Type(static_cast<const Type&>(op)); },
+#define OP_RECEIVER(Type) \
+ [](FrameBuilder& frameBuilder, const RecordedOp& op) { \
+ frameBuilder.defer##Type(static_cast<const Type&>(op)); \
+ },
void FrameBuilder::deferNodeOps(const RenderNode& renderNode) {
- typedef void (*OpDispatcher) (FrameBuilder& frameBuilder, const RecordedOp& op);
+ typedef void (*OpDispatcher)(FrameBuilder & frameBuilder, const RecordedOp& op);
static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER);
// can't be null, since DL=null node rejection happens before deferNodePropsAndOps
@@ -526,9 +512,9 @@
const RecordedOp* op = displayList.getOps()[opIndex];
receivers[op->opId](*this, *op);
- if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty()
- && displayList.projectionReceiveIndex >= 0
- && static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
+ if (CC_UNLIKELY(!renderNode.mProjectedNodes.empty() &&
+ displayList.projectionReceiveIndex >= 0 &&
+ static_cast<int>(opIndex) == displayList.projectionReceiveIndex)) {
deferProjectedChildren(renderNode);
}
}
@@ -542,7 +528,7 @@
// apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
mCanvasState.writableSnapshot()->applyClip(op.localClip,
- *mCanvasState.currentSnapshot()->transform);
+ *mCanvasState.currentSnapshot()->transform);
mCanvasState.concatMatrix(op.localMatrix);
// then apply state from node properties, and defer ops
@@ -562,12 +548,12 @@
* for paint's style on the bounds being computed.
*/
BakedOpState* FrameBuilder::deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
- BakedOpState::StrokeBehavior strokeBehavior, bool expandForPathTexture) {
+ BakedOpState::StrokeBehavior strokeBehavior,
+ bool expandForPathTexture) {
// Note: here we account for stroke when baking the op
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
- mAllocator, *mCanvasState.writableSnapshot(), op,
- strokeBehavior, expandForPathTexture);
- if (!bakedState) return nullptr; // quick rejected
+ mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior, expandForPathTexture);
+ if (!bakedState) return nullptr; // quick rejected
if (op.opId == RecordedOpId::RectOp && op.paint->getStyle() != SkPaint::kStroke_Style) {
bakedState->setupOpacity(op.paint);
@@ -586,8 +572,8 @@
static batchid_t tessBatchId(const RecordedOp& op) {
const SkPaint& paint = *(op.paint);
return paint.getPathEffect()
- ? OpBatchType::AlphaMaskTexture
- : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
+ ? OpBatchType::AlphaMaskTexture
+ : (paint.isAntiAlias() ? OpBatchType::AlphaVertices : OpBatchType::Vertices);
}
void FrameBuilder::deferArcOp(const ArcOp& op) {
@@ -598,13 +584,13 @@
}
static bool hasMergeableClip(const BakedOpState& state) {
- return !state.computedState.clipState
- || state.computedState.clipState->mode == ClipMode::Rectangle;
+ return !state.computedState.clipState ||
+ state.computedState.clipState->mode == ClipMode::Rectangle;
}
void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
if (op.bitmap->isOpaque()) {
bakedState->setupOpacity(op.paint);
@@ -613,11 +599,10 @@
// Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
// Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
// MergingDrawBatch::canMergeWith()
- if (bakedState->computedState.transform.isSimple()
- && bakedState->computedState.transform.positiveScale()
- && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
- && op.bitmap->colorType() != kAlpha_8_SkColorType
- && hasMergeableClip(*bakedState)) {
+ if (bakedState->computedState.transform.isSimple() &&
+ bakedState->computedState.transform.positiveScale() &&
+ PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
+ op.bitmap->colorType() != kAlpha_8_SkColorType && hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId);
} else {
@@ -627,24 +612,21 @@
void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
void FrameBuilder::deferBitmapRectOp(const BitmapRectOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
}
void FrameBuilder::deferVectorDrawableOp(const VectorDrawableOp& op) {
Bitmap& bitmap = op.vectorDrawable->getBitmapUpdateIfDirty();
SkPaint* paint = op.vectorDrawable->getPaint();
- const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(op.unmappedBounds,
- op.localMatrix,
- op.localClip,
- paint,
- &bitmap,
+ const BitmapRectOp* resolvedOp = mAllocator.create_trivial<BitmapRectOp>(
+ op.unmappedBounds, op.localMatrix, op.localClip, paint, &bitmap,
Rect(bitmap.width(), bitmap.height()));
deferBitmapRectOp(*resolvedOp);
}
@@ -656,23 +638,20 @@
float y = *(op.y);
float radius = *(op.radius);
Rect unmappedBounds(x - radius, y - radius, x + radius, y + radius);
- const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(
- unmappedBounds,
- op.localMatrix,
- op.localClip,
- op.paint);
+ const OvalOp* resolvedOp = mAllocator.create_trivial<OvalOp>(unmappedBounds, op.localMatrix,
+ op.localClip, op.paint);
deferOvalOp(*resolvedOp);
}
void FrameBuilder::deferColorOp(const ColorOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
}
void FrameBuilder::deferFunctorOp(const FunctorOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Functor);
}
@@ -687,11 +666,11 @@
void FrameBuilder::deferPatchOp(const PatchOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
- if (bakedState->computedState.transform.isPureTranslate()
- && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
- && hasMergeableClip(*bakedState)) {
+ if (bakedState->computedState.transform.isPureTranslate() &&
+ PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
+ hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.bitmap->getGenerationID());
// Only use the MergedPatch batchId when merged, so Bitmap+Patch don't try to merge together
@@ -723,7 +702,8 @@
if (CC_LIKELY(state && !op.paint->getPathEffect())) {
// TODO: consider storing tessellation task in BakedOpState
mCaches.tessellationCache.precacheRoundRect(state->computedState.transform, *(op.paint),
- op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.rx, op.ry);
+ op.unmappedBounds.getWidth(),
+ op.unmappedBounds.getHeight(), op.rx, op.ry);
}
}
@@ -731,16 +711,14 @@
// allocate a temporary round rect op (with mAllocator, so it persists until render), so the
// renderer doesn't have to handle the RoundRectPropsOp type, and so state baking is simple.
const RoundRectOp* resolvedOp = mAllocator.create_trivial<RoundRectOp>(
- Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
- op.localMatrix,
- op.localClip,
+ Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)), op.localMatrix, op.localClip,
op.paint, *op.rx, *op.ry);
deferRoundRectOp(*resolvedOp);
}
void FrameBuilder::deferSimpleRectsOp(const SimpleRectsOp& op) {
BakedOpState* bakedState = tryBakeOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Vertices);
}
@@ -753,12 +731,12 @@
BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
mAllocator, *mCanvasState.writableSnapshot(), op,
BakedOpState::StrokeBehavior::StyleDefined, false);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
batchid_t batchId = textBatchId(*(op.paint));
- if (bakedState->computedState.transform.isPureTranslate()
- && PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver
- && hasMergeableClip(*bakedState)) {
+ if (bakedState->computedState.transform.isPureTranslate() &&
+ PaintUtils::getBlendModeDirect(op.paint) == SkBlendMode::kSrcOver &&
+ hasMergeableClip(*bakedState)) {
mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor());
currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId);
} else {
@@ -773,19 +751,19 @@
// Partial transform case, see BakedOpDispatcher::renderTextOp
float sx, sy;
totalTransform.decomposeScale(sx, sy);
- fontRenderer.precache(op.paint, op.glyphs, op.glyphCount, SkMatrix::MakeScale(
- roundf(std::max(1.0f, sx)),
- roundf(std::max(1.0f, sy))));
+ fontRenderer.precache(
+ op.paint, op.glyphs, op.glyphCount,
+ SkMatrix::MakeScale(roundf(std::max(1.0f, sx)), roundf(std::max(1.0f, sy))));
}
}
void FrameBuilder::deferTextOnPathOp(const TextOnPathOp& op) {
BakedOpState* bakedState = tryBakeUnboundedOpState(op);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, textBatchId(*(op.paint)));
- mCaches.fontRenderer.getFontRenderer().precache(
- op.paint, op.glyphs, op.glyphCount, SkMatrix::I());
+ mCaches.fontRenderer.getFontRenderer().precache(op.paint, op.glyphs, op.glyphCount,
+ SkMatrix::I());
}
void FrameBuilder::deferTextureLayerOp(const TextureLayerOp& op) {
@@ -802,28 +780,27 @@
}
BakedOpState* bakedState = tryBakeOpState(*textureLayerOp);
- if (!bakedState) return; // quick rejected
+ if (!bakedState) return; // quick rejected
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::TextureLayer);
}
-void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
- float contentTranslateX, float contentTranslateY,
- const Rect& repaintRect,
- const Vector3& lightCenter,
- const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
+void FrameBuilder::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX,
+ float contentTranslateY, const Rect& repaintRect,
+ const Vector3& lightCenter, const BeginLayerOp* beginLayerOp,
+ RenderNode* renderNode) {
mCanvasState.save(SaveFlags::MatrixClip);
mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter);
- mCanvasState.writableSnapshot()->transform->loadTranslate(
- contentTranslateX, contentTranslateY, 0);
- mCanvasState.writableSnapshot()->setClip(
- repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
+ mCanvasState.writableSnapshot()->transform->loadTranslate(contentTranslateX, contentTranslateY,
+ 0);
+ mCanvasState.writableSnapshot()->setClip(repaintRect.left, repaintRect.top, repaintRect.right,
+ repaintRect.bottom);
// create a new layer repaint, and push its index on the stack
mLayerStack.push_back(mLayerBuilders.size());
- auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight,
- repaintRect, beginLayerOp, renderNode);
+ auto newFbo = mAllocator.create<LayerBuilder>(layerWidth, layerHeight, repaintRect,
+ beginLayerOp, renderNode);
mLayerBuilders.push_back(newFbo);
}
@@ -836,8 +813,8 @@
// TODO: defer time rejection (when bounds become empty) + tests
// Option - just skip layers with no bounds at playback + defer?
void FrameBuilder::deferBeginLayerOp(const BeginLayerOp& op) {
- uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
- uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
+ uint32_t layerWidth = (uint32_t)op.unmappedBounds.getWidth();
+ uint32_t layerHeight = (uint32_t)op.unmappedBounds.getHeight();
auto previous = mCanvasState.currentSnapshot();
Vector3 lightCenter = previous->getRelativeLightCenter();
@@ -873,11 +850,8 @@
float contentTranslateX = -saveLayerBounds.left;
float contentTranslateY = -saveLayerBounds.top;
- saveForLayer(layerWidth, layerHeight,
- contentTranslateX, contentTranslateY,
- Rect(layerWidth, layerHeight),
- lightCenter,
- &op, nullptr);
+ saveForLayer(layerWidth, layerHeight, contentTranslateX, contentTranslateY,
+ Rect(layerWidth, layerHeight), lightCenter, &op, nullptr);
}
void FrameBuilder::deferEndLayerOp(const EndLayerOp& /* ignored */) {
@@ -890,8 +864,8 @@
// to translate the drawLayer by how much the contents was translated
// TODO: Unify this with beginLayerOp so we don't have to calculate this
// twice
- uint32_t layerWidth = (uint32_t) beginLayerOp.unmappedBounds.getWidth();
- uint32_t layerHeight = (uint32_t) beginLayerOp.unmappedBounds.getHeight();
+ uint32_t layerWidth = (uint32_t)beginLayerOp.unmappedBounds.getWidth();
+ uint32_t layerHeight = (uint32_t)beginLayerOp.unmappedBounds.getHeight();
auto previous = mCanvasState.currentSnapshot();
Vector3 lightCenter = previous->getRelativeLightCenter();
@@ -900,8 +874,7 @@
// parent content transform * canvas transform * bounds offset
Matrix4 contentTransform(*(previous->transform));
contentTransform.multiply(beginLayerOp.localMatrix);
- contentTransform.translate(beginLayerOp.unmappedBounds.left,
- beginLayerOp.unmappedBounds.top);
+ contentTransform.translate(beginLayerOp.unmappedBounds.left, beginLayerOp.unmappedBounds.top);
Matrix4 inverseContentTransform;
inverseContentTransform.loadInverse(contentTransform);
@@ -927,10 +900,7 @@
// record the draw operation into the previous layer's list of draw commands
// uses state from the associated beginLayerOp, since it has all the state needed for drawing
LayerOp* drawLayerOp = mAllocator.create_trivial<LayerOp>(
- beginLayerOp.unmappedBounds,
- localMatrix,
- beginLayerOp.localClip,
- beginLayerOp.paint,
+ beginLayerOp.unmappedBounds, localMatrix, beginLayerOp.localClip, beginLayerOp.paint,
&(mLayerBuilders[finishedLayerIndex]->offscreenBuffer));
BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
@@ -959,15 +929,16 @@
// Unclipped layer rejected - push a null op, so next EndUnclippedLayerOp is ignored
currentLayer().activeUnclippedSaveLayers.push_back(nullptr);
} else {
- // Allocate a holding position for the layer object (copyTo will produce, copyFrom will consume)
+ // Allocate a holding position for the layer object (copyTo will produce, copyFrom will
+ // consume)
OffscreenBuffer** layerHandle = mAllocator.create<OffscreenBuffer*>(nullptr);
/**
* First, defer an operation to copy out the content from the rendertarget into a layer.
*/
auto copyToOp = mAllocator.create_trivial<CopyToLayerOp>(op, layerHandle);
- BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator,
- &(currentLayer().repaintClip), dstRect, *copyToOp);
+ BakedOpState* bakedState = BakedOpState::directConstruct(
+ mAllocator, &(currentLayer().repaintClip), dstRect, *copyToOp);
currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer);
/**
@@ -981,8 +952,8 @@
* a balanced EndUnclippedLayerOp is seen
*/
auto copyFromOp = mAllocator.create_trivial<CopyFromLayerOp>(op, layerHandle);
- bakedState = BakedOpState::directConstruct(mAllocator,
- &(currentLayer().repaintClip), dstRect, *copyFromOp);
+ bakedState = BakedOpState::directConstruct(mAllocator, &(currentLayer().repaintClip),
+ dstRect, *copyFromOp);
currentLayer().activeUnclippedSaveLayers.push_back(bakedState);
}
}
@@ -1001,5 +972,5 @@
mCaches.fontRenderer.endPrecaching();
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/FrameBuilder.h b/libs/hwui/FrameBuilder.h
index 46048f7..974daf8 100644
--- a/libs/hwui/FrameBuilder.h
+++ b/libs/hwui/FrameBuilder.h
@@ -23,8 +23,8 @@
#include "RecordedOp.h"
#include "utils/GLUtils.h"
-#include <vector>
#include <unordered_map>
+#include <vector>
struct SkRect;
@@ -60,12 +60,11 @@
float radius;
};
- FrameBuilder(const SkRect& clip,
- uint32_t viewportWidth, uint32_t viewportHeight,
- const LightGeometry& lightGeometry, Caches& caches);
+ FrameBuilder(const SkRect& clip, uint32_t viewportWidth, uint32_t viewportHeight,
+ const LightGeometry& lightGeometry, Caches& caches);
- FrameBuilder(const LayerUpdateQueue& layerUpdateQueue,
- const LightGeometry& lightGeometry, Caches& caches);
+ FrameBuilder(const LayerUpdateQueue& layerUpdateQueue, const LightGeometry& lightGeometry,
+ Caches& caches);
void deferLayers(const LayerUpdateQueue& layers);
@@ -73,8 +72,8 @@
void deferRenderNode(float tx, float ty, Rect clipRect, RenderNode& renderNode);
- void deferRenderNodeScene(const std::vector< sp<RenderNode> >& nodes,
- const Rect& contentDrawBounds);
+ void deferRenderNodeScene(const std::vector<sp<RenderNode> >& nodes,
+ const Rect& contentDrawBounds);
virtual ~FrameBuilder() {}
@@ -88,32 +87,32 @@
void replayBakedOps(Renderer& renderer) {
std::vector<OffscreenBuffer*> temporaryLayers;
finishDefer();
- /**
- * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
- * dispatch the op via a method on a static dispatcher when the op is replayed.
- *
- * For example a BitmapOp would resolve, via the lambda lookup, to calling:
- *
- * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
- */
- #define X(Type) \
- [](void* renderer, const BakedOpState& state) { \
- StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
- static_cast<const Type&>(*(state.op)), state); \
- },
+/**
+ * Defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to
+ * dispatch the op via a method on a static dispatcher when the op is replayed.
+ *
+ * For example a BitmapOp would resolve, via the lambda lookup, to calling:
+ *
+ * StaticDispatcher::onBitmapOp(Renderer& renderer, const BitmapOp& op, const BakedOpState& state);
+ */
+#define X(Type) \
+ [](void* renderer, const BakedOpState& state) { \
+ StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \
+ static_cast<const Type&>(*(state.op)), state); \
+ },
static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
- #undef X
+#undef X
- /**
- * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
- * static dispatcher when the group of merged ops is replayed.
- */
- #define X(Type) \
- [](void* renderer, const MergedBakedOpList& opList) { \
- StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
- },
+/**
+ * Defines a LUT of lambdas which allow merged arrays of BakedOpState* to be passed to a
+ * static dispatcher when the group of merged ops is replayed.
+ */
+#define X(Type) \
+ [](void* renderer, const MergedBakedOpList& opList) { \
+ StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \
+ },
static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X);
- #undef X
+#undef X
// Relay through layers in reverse order, since layers
// later in the list will be drawn by earlier ones
@@ -168,15 +167,10 @@
private:
void finishDefer();
- enum class ChildrenSelectMode {
- Negative,
- Positive
- };
- void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
- float contentTranslateX, float contentTranslateY,
- const Rect& repaintRect,
- const Vector3& lightCenter,
- const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
+ enum class ChildrenSelectMode { Negative, Positive };
+ void saveForLayer(uint32_t layerWidth, uint32_t layerHeight, float contentTranslateX,
+ float contentTranslateY, const Rect& repaintRect, const Vector3& lightCenter,
+ const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
void restoreForLayer();
LayerBuilder& currentLayer() { return *(mLayerBuilders[mLayerStack.back()]); }
@@ -185,16 +179,16 @@
return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
}
BakedOpState* tryBakeUnboundedOpState(const RecordedOp& recordedOp) {
- return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
+ return BakedOpState::tryConstructUnbounded(mAllocator, *mCanvasState.writableSnapshot(),
+ recordedOp);
}
-
// should always be surrounded by a save/restore pair, and not called if DisplayList is null
void deferNodePropsAndOps(RenderNode& node);
template <typename V>
void defer3dChildren(const ClipBase* reorderClip, ChildrenSelectMode mode,
- const V& zTranslatedNodes);
+ const V& zTranslatedNodes);
void deferShadow(const ClipBase* reorderClip, const RenderNodeOp& casterOp);
@@ -206,20 +200,19 @@
void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers);
- SkPath* createFrameAllocatedPath() {
- return mAllocator.create<SkPath>();
- }
+ SkPath* createFrameAllocatedPath() { return mAllocator.create<SkPath>(); }
BakedOpState* deferStrokeableOp(const RecordedOp& op, batchid_t batchId,
- BakedOpState::StrokeBehavior strokeBehavior = BakedOpState::StrokeBehavior::StyleDefined,
- bool expandForPathTexture = false);
+ BakedOpState::StrokeBehavior strokeBehavior =
+ BakedOpState::StrokeBehavior::StyleDefined,
+ bool expandForPathTexture = false);
- /**
- * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
- *
- * These private methods are called from within deferImpl to defer each individual op
- * type differently.
- */
+/**
+ * Declares all FrameBuilder::deferXXXXOp() methods for every RecordedOp type.
+ *
+ * These private methods are called from within deferImpl to defer each individual op
+ * type differently.
+ */
#define X(Type) void defer##Type(const Type& op);
MAP_DEFERRABLE_OPS(X)
#undef X
@@ -254,5 +247,5 @@
const bool mDrawFbo0;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
index 826f0bb..71cc9a8 100644
--- a/libs/hwui/FrameInfo.cpp
+++ b/libs/hwui/FrameInfo.cpp
@@ -21,30 +21,30 @@
namespace uirenderer {
const std::string FrameInfoNames[] = {
- "Flags",
- "IntendedVsync",
- "Vsync",
- "OldestInputEvent",
- "NewestInputEvent",
- "HandleInputStart",
- "AnimationStart",
- "PerformTraversalsStart",
- "DrawStart",
- "SyncQueued",
- "SyncStart",
- "IssueDrawCommandsStart",
- "SwapBuffers",
- "FrameCompleted",
- "DequeueBufferDuration",
- "QueueBufferDuration",
+ "Flags",
+ "IntendedVsync",
+ "Vsync",
+ "OldestInputEvent",
+ "NewestInputEvent",
+ "HandleInputStart",
+ "AnimationStart",
+ "PerformTraversalsStart",
+ "DrawStart",
+ "SyncQueued",
+ "SyncStart",
+ "IssueDrawCommandsStart",
+ "SwapBuffers",
+ "FrameCompleted",
+ "DequeueBufferDuration",
+ "QueueBufferDuration",
};
-static_assert((sizeof(FrameInfoNames)/sizeof(FrameInfoNames[0]))
- == static_cast<int>(FrameInfoIndex::NumIndexes),
- "size mismatch: FrameInfoNames doesn't match the enum!");
+static_assert((sizeof(FrameInfoNames) / sizeof(FrameInfoNames[0])) ==
+ static_cast<int>(FrameInfoIndex::NumIndexes),
+ "size mismatch: FrameInfoNames doesn't match the enum!");
static_assert(static_cast<int>(FrameInfoIndex::NumIndexes) == 16,
- "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
+ "Must update value in FrameMetrics.java#FRAME_STATS_COUNT (and here)");
void FrameInfo::importUiThreadInfo(int64_t* info) {
memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
index bac9d12d..0aab58c 100644
--- a/libs/hwui/FrameInfo.h
+++ b/libs/hwui/FrameInfo.h
@@ -59,12 +59,12 @@
extern const std::string FrameInfoNames[];
namespace FrameInfoFlags {
- enum {
- WindowLayoutChanged = 1 << 0,
- RTAnimation = 1 << 1,
- SurfaceCanvas = 1 << 2,
- SkippedFrame = 1 << 3,
- };
+enum {
+ WindowLayoutChanged = 1 << 0,
+ RTAnimation = 1 << 1,
+ SurfaceCanvas = 1 << 2,
+ SkippedFrame = 1 << 3,
+};
};
class ANDROID_API UiFrameInfoBuilder {
@@ -91,9 +91,7 @@
}
private:
- inline int64_t& set(FrameInfoIndex index) {
- return mBuffer[static_cast<int>(index)];
- }
+ inline int64_t& set(FrameInfoIndex index) { return mBuffer[static_cast<int>(index)]; }
int64_t* mBuffer;
};
@@ -102,33 +100,23 @@
public:
void importUiThreadInfo(int64_t* info);
- void markSyncStart() {
- set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC);
- }
+ void markSyncStart() { set(FrameInfoIndex::SyncStart) = systemTime(CLOCK_MONOTONIC); }
void markIssueDrawCommandsStart() {
set(FrameInfoIndex::IssueDrawCommandsStart) = systemTime(CLOCK_MONOTONIC);
}
- void markSwapBuffers() {
- set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC);
- }
+ void markSwapBuffers() { set(FrameInfoIndex::SwapBuffers) = systemTime(CLOCK_MONOTONIC); }
- void markFrameCompleted() {
- set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC);
- }
+ void markFrameCompleted() { set(FrameInfoIndex::FrameCompleted) = systemTime(CLOCK_MONOTONIC); }
void addFlag(int frameInfoFlag) {
set(FrameInfoIndex::Flags) |= static_cast<uint64_t>(frameInfoFlag);
}
- const int64_t* data() const {
- return mFrameInfo;
- }
+ const int64_t* data() const { return mFrameInfo; }
- inline int64_t operator[](FrameInfoIndex index) const {
- return get(index);
- }
+ inline int64_t operator[](FrameInfoIndex index) const { return get(index); }
inline int64_t operator[](int index) const {
if (index < 0 || index >= static_cast<int>(FrameInfoIndex::NumIndexes)) return 0;
@@ -140,12 +128,10 @@
int64_t starttime = get(start);
int64_t gap = endtime - starttime;
gap = starttime > 0 ? gap : 0;
- if (end > FrameInfoIndex::SyncQueued &&
- start < FrameInfoIndex::SyncQueued) {
+ if (end > FrameInfoIndex::SyncQueued && start < FrameInfoIndex::SyncQueued) {
// Need to subtract out the time spent in a stalled state
// as this will be captured by the previous frame's info
- int64_t offset = get(FrameInfoIndex::SyncStart)
- - get(FrameInfoIndex::SyncQueued);
+ int64_t offset = get(FrameInfoIndex::SyncStart) - get(FrameInfoIndex::SyncQueued);
if (offset > 0) {
gap -= offset;
}
@@ -157,9 +143,7 @@
return duration(FrameInfoIndex::IntendedVsync, FrameInfoIndex::FrameCompleted);
}
- inline int64_t& set(FrameInfoIndex index) {
- return mFrameInfo[static_cast<int>(index)];
- }
+ inline int64_t& set(FrameInfoIndex index) { return mFrameInfo[static_cast<int>(index)]; }
inline int64_t get(FrameInfoIndex index) const {
if (index == FrameInfoIndex::NumIndexes) return 0;
diff --git a/libs/hwui/FrameInfoVisualizer.cpp b/libs/hwui/FrameInfoVisualizer.cpp
index d3adc32..91756e7 100644
--- a/libs/hwui/FrameInfoVisualizer.cpp
+++ b/libs/hwui/FrameInfoVisualizer.cpp
@@ -22,8 +22,10 @@
#include <cutils/compiler.h>
#include <array>
-#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == ProfileType::None)) return
-#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
+#define RETURN_IF_PROFILING_DISABLED() \
+ if (CC_LIKELY(mType == ProfileType::None)) return
+#define RETURN_IF_DISABLED() \
+ if (CC_LIKELY(mType == ProfileType::None && !mShowDirtyRegions)) return
#define PROFILE_DRAW_WIDTH 3
#define PROFILE_DRAW_THRESHOLD_STROKE_WIDTH 2
@@ -48,22 +50,22 @@
SkColor color;
};
-static const std::array<BarSegment,7> Bar {{
- { FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700 },
- { FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart, Color::Green_700 },
- { FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700 },
- { FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500 },
- { FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300 },
- { FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
- { FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
+static const std::array<BarSegment, 7> Bar{{
+ {FrameInfoIndex::IntendedVsync, FrameInfoIndex::HandleInputStart, Color::Teal_700},
+ {FrameInfoIndex::HandleInputStart, FrameInfoIndex::PerformTraversalsStart,
+ Color::Green_700},
+ {FrameInfoIndex::PerformTraversalsStart, FrameInfoIndex::DrawStart, Color::LightGreen_700},
+ {FrameInfoIndex::DrawStart, FrameInfoIndex::SyncStart, Color::Blue_500},
+ {FrameInfoIndex::SyncStart, FrameInfoIndex::IssueDrawCommandsStart, Color::LightBlue_300},
+ {FrameInfoIndex::IssueDrawCommandsStart, FrameInfoIndex::SwapBuffers, Color::Red_500},
+ {FrameInfoIndex::SwapBuffers, FrameInfoIndex::FrameCompleted, Color::Orange_500},
}};
static int dpToPx(int dp, float density) {
- return (int) (dp * density + 0.5f);
+ return (int)(dp * density + 0.5f);
}
-FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source)
- : mFrameSource(source) {
+FrameInfoVisualizer::FrameInfoVisualizer(FrameInfoSource& source) : mFrameSource(source) {
setDensity(1);
}
@@ -97,8 +99,8 @@
if (mFlashToggle) {
SkPaint paint;
paint.setColor(0x7fff0000);
- renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
- mDirtyRegion.fRight, mDirtyRegion.fBottom, paint);
+ renderer.drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop, mDirtyRegion.fRight,
+ mDirtyRegion.fBottom, paint);
}
}
@@ -169,7 +171,8 @@
void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex end) {
int fast_i = (mNumFastRects - 1) * 4;
- int janky_i = (mNumJankyRects - 1) * 4;;
+ int janky_i = (mNumJankyRects - 1) * 4;
+ ;
for (size_t fi = 0; fi < mFrameSource.size(); fi++) {
if (mFrameSource[fi][FrameInfoIndex::Flags] & FrameInfoFlags::SkippedFrame) {
continue;
@@ -210,11 +213,8 @@
SkPaint paint;
paint.setColor(THRESHOLD_COLOR);
float yLocation = renderer.getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
- renderer.drawRect(0.0f,
- yLocation - mThresholdStroke/2,
- renderer.getViewportWidth(),
- yLocation + mThresholdStroke/2,
- paint);
+ renderer.drawRect(0.0f, yLocation - mThresholdStroke / 2, renderer.getViewportWidth(),
+ yLocation + mThresholdStroke / 2, paint);
}
bool FrameInfoVisualizer::consumeProperties() {
@@ -245,7 +245,7 @@
// last call to dumpData(). In other words if there's a dumpData(), draw frame,
// dumpData(), the last dumpData() should only log 1 frame.
- FILE *file = fdopen(fd, "a");
+ FILE* file = fdopen(fd, "a");
fprintf(file, "\n\tDraw\tPrepare\tProcess\tExecute\n");
for (size_t i = 0; i < mFrameSource.size(); i++) {
diff --git a/libs/hwui/FrameMetricsObserver.h b/libs/hwui/FrameMetricsObserver.h
index 4f81c86..ba72e93 100644
--- a/libs/hwui/FrameMetricsObserver.h
+++ b/libs/hwui/FrameMetricsObserver.h
@@ -26,5 +26,5 @@
virtual void notify(const int64_t* buffer);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/FrameMetricsReporter.h b/libs/hwui/FrameMetricsReporter.h
index c1cd0a92..d920a99 100644
--- a/libs/hwui/FrameMetricsReporter.h
+++ b/libs/hwui/FrameMetricsReporter.h
@@ -16,8 +16,8 @@
#pragma once
-#include <utils/RefBase.h>
#include <utils/Log.h>
+#include <utils/RefBase.h>
#include "FrameInfo.h"
#include "FrameMetricsObserver.h"
@@ -32,9 +32,7 @@
public:
FrameMetricsReporter() {}
- void addObserver(FrameMetricsObserver* observer) {
- mObservers.push_back(observer);
- }
+ void addObserver(FrameMetricsObserver* observer) { mObservers.push_back(observer); }
bool removeObserver(FrameMetricsObserver* observer) {
for (size_t i = 0; i < mObservers.size(); i++) {
@@ -46,9 +44,7 @@
return false;
}
- bool hasObservers() {
- return mObservers.size() > 0;
- }
+ bool hasObservers() { return mObservers.size() > 0; }
void reportFrameMetrics(const int64_t* stats) {
for (size_t i = 0; i < mObservers.size(); i++) {
@@ -57,9 +53,8 @@
}
private:
- std::vector< sp<FrameMetricsObserver> > mObservers;
+ std::vector<sp<FrameMetricsObserver> > mObservers;
};
-}; // namespace uirenderer
-}; // namespace android
-
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GammaFontRenderer.cpp b/libs/hwui/GammaFontRenderer.cpp
index 8aff0a2..88fb162 100644
--- a/libs/hwui/GammaFontRenderer.cpp
+++ b/libs/hwui/GammaFontRenderer.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "Debug.h"
#include "GammaFontRenderer.h"
+#include "Debug.h"
#include "Properties.h"
namespace android {
@@ -39,5 +39,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GammaFontRenderer.h b/libs/hwui/GammaFontRenderer.h
index c9cf69b..e900244 100644
--- a/libs/hwui/GammaFontRenderer.h
+++ b/libs/hwui/GammaFontRenderer.h
@@ -26,9 +26,7 @@
public:
GammaFontRenderer();
- void clear() {
- mRenderer.reset(nullptr);
- }
+ void clear() { mRenderer.reset(nullptr); }
void flush() {
if (mRenderer) {
@@ -55,9 +53,7 @@
}
}
- uint32_t getSize() const {
- return mRenderer ? mRenderer->getSize() : 0;
- }
+ uint32_t getSize() const { return mRenderer ? mRenderer->getSize() : 0; }
void endPrecaching();
@@ -68,7 +64,7 @@
#endif
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
+#endif // ANDROID_HWUI_GAMMA_FONT_RENDERER_H
diff --git a/libs/hwui/GlFunctorLifecycleListener.h b/libs/hwui/GlFunctorLifecycleListener.h
index 357090e..5d07b46 100644
--- a/libs/hwui/GlFunctorLifecycleListener.h
+++ b/libs/hwui/GlFunctorLifecycleListener.h
@@ -28,5 +28,5 @@
virtual void onGlFunctorReleased(Functor* functor) = 0;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GlLayer.cpp b/libs/hwui/GlLayer.cpp
index 070e954..32a3014 100644
--- a/libs/hwui/GlLayer.cpp
+++ b/libs/hwui/GlLayer.cpp
@@ -23,17 +23,16 @@
#include <utils/Log.h>
-#define ATRACE_LAYER_WORK(label) \
- ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", \
- label, \
- (renderNode.get() != NULL) ? renderNode->getName() : "", \
- getWidth(), getHeight())
+#define ATRACE_LAYER_WORK(label) \
+ ATRACE_FORMAT("%s HW Layer DisplayList %s %ux%u", label, \
+ (renderNode.get() != NULL) ? renderNode->getName() : "", getWidth(), \
+ getHeight())
namespace android {
namespace uirenderer {
GlLayer::GlLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend)
: Layer(renderState, Api::OpenGL, colorFilter, alpha, mode)
, caches(Caches::getInstance())
, texture(caches) {
@@ -73,5 +72,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GlLayer.h b/libs/hwui/GlLayer.h
index c4f7fe2..1b09191 100644
--- a/libs/hwui/GlLayer.h
+++ b/libs/hwui/GlLayer.h
@@ -35,42 +35,26 @@
SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend);
virtual ~GlLayer();
- uint32_t getWidth() const override {
- return texture.mWidth;
- }
+ uint32_t getWidth() const override { return texture.mWidth; }
- uint32_t getHeight() const override {
- return texture.mHeight;
- }
+ uint32_t getHeight() const override { return texture.mHeight; }
void setSize(uint32_t width, uint32_t height) override {
texture.updateLayout(width, height, texture.internalFormat(), texture.format(),
- texture.target());
+ texture.target());
}
- void setBlend(bool blend) override {
- texture.blend = blend;
- }
+ void setBlend(bool blend) override { texture.blend = blend; }
- bool isBlend() const override {
- return texture.blend;
- }
+ bool isBlend() const override { return texture.blend; }
- inline GLuint getTextureId() const {
- return texture.id();
- }
+ inline GLuint getTextureId() const { return texture.id(); }
- inline Texture& getTexture() {
- return texture;
- }
+ inline Texture& getTexture() { return texture; }
- inline GLenum getRenderTarget() const {
- return texture.target();
- }
+ inline GLenum getRenderTarget() const { return texture.target(); }
- inline bool isRenderable() const {
- return texture.target() != GL_NONE;
- }
+ inline bool isRenderable() const { return texture.target() != GL_NONE; }
void setRenderTarget(GLenum renderTarget);
@@ -89,7 +73,7 @@
* The texture backing this layer.
*/
Texture texture;
-}; // struct GlLayer
+}; // struct GlLayer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index e91c08d..c68d516 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -41,34 +41,34 @@
*/
namespace VertexAttribFlags {
- enum {
- // Mesh is pure x,y vertex pairs
- None = 0,
- // Mesh has texture coordinates embedded. Note that texture can exist without this flag
- // being set, if coordinates passed to sampler are determined another way.
- TextureCoord = 1 << 0,
- // Mesh has color embedded (to export to varying)
- Color = 1 << 1,
- // Mesh has alpha embedded (to export to varying)
- Alpha = 1 << 2,
- };
+enum {
+ // Mesh is pure x,y vertex pairs
+ None = 0,
+ // Mesh has texture coordinates embedded. Note that texture can exist without this flag
+ // being set, if coordinates passed to sampler are determined another way.
+ TextureCoord = 1 << 0,
+ // Mesh has color embedded (to export to varying)
+ Color = 1 << 1,
+ // Mesh has alpha embedded (to export to varying)
+ Alpha = 1 << 2,
+};
};
/*
* Enumerates transform features
*/
namespace TransformFlags {
- enum {
- None = 0,
+enum {
+ None = 0,
- // offset the eventual drawing matrix by a tiny amount to
- // disambiguate sampling patterns with non-AA rendering
- OffsetByFudgeFactor = 1 << 0,
+ // offset the eventual drawing matrix by a tiny amount to
+ // disambiguate sampling patterns with non-AA rendering
+ OffsetByFudgeFactor = 1 << 0,
- // Canvas transform isn't applied to the mesh at draw time,
- // since it's already built in.
- MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
- };
+ // Canvas transform isn't applied to the mesh at draw time,
+ // since it's already built in.
+ MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
+};
};
/**
@@ -86,10 +86,11 @@
*/
struct Glop {
PREVENT_COPY_AND_ASSIGN(Glop);
+
public:
- Glop() { }
+ Glop() {}
struct Mesh {
- GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
+ GLuint primitiveMode; // GL_TRIANGLES and GL_TRIANGLE_STRIP supported
// buffer object and void* are mutually exclusive.
// Only GL_UNSIGNED_SHORT supported.
@@ -110,7 +111,7 @@
} vertices;
int elementCount;
- int vertexCount; // only used for meshes (for glDrawRangeElements)
+ int vertexCount; // only used for meshes (for glDrawRangeElements)
TextureVertex mappedVertices[4];
} mesh;
@@ -148,10 +149,11 @@
Matrix4 canvas;
int transformFlags;
- const Matrix4& meshTransform() const {
- return (transformFlags & TransformFlags::MeshIgnoresCanvasTransform)
- ? Matrix4::identity() : canvas;
- }
+ const Matrix4& meshTransform() const {
+ return (transformFlags & TransformFlags::MeshIgnoresCanvasTransform)
+ ? Matrix4::identity()
+ : canvas;
+ }
} transform;
const RoundRectClipState* roundRectClipState = nullptr;
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 8727a1d..2f107a0 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -22,12 +22,12 @@
#include "Matrix.h"
#include "Patch.h"
#include "PathCache.h"
-#include "renderstate/MeshState.h"
-#include "renderstate/RenderState.h"
#include "SkiaShader.h"
#include "Texture.h"
-#include "utils/PaintUtils.h"
#include "VertexBuffer.h"
+#include "renderstate/MeshState.h"
+#include "renderstate/RenderState.h"
+#include "utils/PaintUtils.h"
#include <GLES2/gl2.h>
#include <SkPaint.h>
@@ -36,13 +36,13 @@
#if DEBUG_GLOP_BUILDER
-#define TRIGGER_STAGE(stageFlag) \
- LOG_ALWAYS_FATAL_IF((stageFlag) & mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
+#define TRIGGER_STAGE(stageFlag) \
+ LOG_ALWAYS_FATAL_IF((stageFlag)&mStageFlags, "Stage %d cannot be run twice", (stageFlag)); \
mStageFlags = static_cast<StageFlags>(mStageFlags | (stageFlag))
-#define REQUIRE_STAGES(requiredFlags) \
+#define REQUIRE_STAGES(requiredFlags) \
LOG_ALWAYS_FATAL_IF((mStageFlags & (requiredFlags)) != (requiredFlags), \
- "not prepared for current stage")
+ "not prepared for current stage")
#else
@@ -62,10 +62,7 @@
}
GlopBuilder::GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop)
- : mRenderState(renderState)
- , mCaches(caches)
- , mShader(nullptr)
- , mOutGlop(outGlop) {
+ : mRenderState(renderState), mCaches(caches), mShader(nullptr), mOutGlop(outGlop) {
mStageFlags = kInitialStage;
}
@@ -77,12 +74,10 @@
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
- mOutGlop->mesh.vertices = {
- vbo,
- VertexAttribFlags::TextureCoord,
- nullptr, (const void*) kMeshTextureOffset, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
+ mOutGlop->mesh.vertices = {vbo, VertexAttribFlags::TextureCoord,
+ nullptr, (const void*)kMeshTextureOffset,
+ nullptr, kTextureVertexStride};
mOutGlop->mesh.elementCount = elementCount;
return *this;
}
@@ -91,12 +86,13 @@
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- mRenderState.meshState().getUnitQuadVBO(),
- VertexAttribFlags::None,
- nullptr, nullptr, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(),
+ VertexAttribFlags::None,
+ nullptr,
+ nullptr,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = 4;
return *this;
}
@@ -110,12 +106,13 @@
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- mRenderState.meshState().getUnitQuadVBO(),
- VertexAttribFlags::TextureCoord,
- nullptr, (const void*) kMeshTextureOffset, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {mRenderState.meshState().getUnitQuadVBO(),
+ VertexAttribFlags::TextureCoord,
+ nullptr,
+ (const void*)kMeshTextureOffset,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = 4;
return *this;
}
@@ -130,12 +127,13 @@
const TextureVertex* textureVertex = mOutGlop->mesh.mappedVertices;
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::TextureCoord,
- &textureVertex[0].x, &textureVertex[0].u, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {0,
+ VertexAttribFlags::TextureCoord,
+ &textureVertex[0].x,
+ &textureVertex[0].u,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = 4;
return *this;
}
@@ -144,12 +142,9 @@
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::None,
- vertexData, nullptr, nullptr,
- kVertexStride };
+ 0, VertexAttribFlags::None, vertexData, nullptr, nullptr, kVertexStride};
mOutGlop->mesh.elementCount = 6 * quadCount;
return *this;
}
@@ -158,26 +153,29 @@
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
- mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::TextureCoord,
- &vertexData[0].x, &vertexData[0].u, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
+ mOutGlop->mesh.vertices = {0,
+ VertexAttribFlags::TextureCoord,
+ &vertexData[0].x,
+ &vertexData[0].u,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = elementCount;
return *this;
}
-GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount) {
+GlopBuilder& GlopBuilder::setMeshColoredTexturedMesh(ColorTextureVertex* vertexData,
+ int elementCount) {
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { 0, nullptr };
- mOutGlop->mesh.vertices = {
- 0,
- VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
- &vertexData[0].x, &vertexData[0].u, &vertexData[0].r,
- kColorTextureVertexStride };
+ mOutGlop->mesh.indices = {0, nullptr};
+ mOutGlop->mesh.vertices = {0,
+ VertexAttribFlags::TextureCoord | VertexAttribFlags::Color,
+ &vertexData[0].x,
+ &vertexData[0].u,
+ &vertexData[0].r,
+ kColorTextureVertexStride};
mOutGlop->mesh.elementCount = elementCount;
return *this;
}
@@ -191,15 +189,16 @@
bool indices = flags & VertexBuffer::kIndices;
mOutGlop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
- mOutGlop->mesh.indices = { 0, vertexBuffer.getIndices() };
- mOutGlop->mesh.vertices = {
- 0,
- alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
- vertexBuffer.getBuffer(), nullptr, nullptr,
- alphaVertex ? kAlphaVertexStride : kVertexStride };
- mOutGlop->mesh.elementCount = indices
- ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
- mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
+ mOutGlop->mesh.indices = {0, vertexBuffer.getIndices()};
+ mOutGlop->mesh.vertices = {0,
+ alphaVertex ? VertexAttribFlags::Alpha : VertexAttribFlags::None,
+ vertexBuffer.getBuffer(),
+ nullptr,
+ nullptr,
+ alphaVertex ? kAlphaVertexStride : kVertexStride};
+ mOutGlop->mesh.elementCount =
+ indices ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+ mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
return *this;
}
@@ -207,12 +206,13 @@
TRIGGER_STAGE(kMeshStage);
mOutGlop->mesh.primitiveMode = GL_TRIANGLES;
- mOutGlop->mesh.indices = { mRenderState.meshState().getQuadListIBO(), nullptr };
- mOutGlop->mesh.vertices = {
- mCaches.patchCache.getMeshBuffer(),
- VertexAttribFlags::TextureCoord,
- (void*)patch.positionOffset, (void*)patch.textureOffset, nullptr,
- kTextureVertexStride };
+ mOutGlop->mesh.indices = {mRenderState.meshState().getQuadListIBO(), nullptr};
+ mOutGlop->mesh.vertices = {mCaches.patchCache.getMeshBuffer(),
+ VertexAttribFlags::TextureCoord,
+ (void*)patch.positionOffset,
+ (void*)patch.textureOffset,
+ nullptr,
+ kTextureVertexStride};
mOutGlop->mesh.elementCount = patch.indexCount;
return *this;
}
@@ -221,9 +221,9 @@
// Fill
////////////////////////////////////////////////////////////////////////////////
-void GlopBuilder::setFill(int color, float alphaScale,
- SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
- const SkShader* shader, const SkColorFilter* colorFilter) {
+void GlopBuilder::setFill(int color, float alphaScale, SkBlendMode mode,
+ Blend::ModeOrderSwap modeUsage, const SkShader* shader,
+ const SkColorFilter* colorFilter) {
if (mode != SkBlendMode::kClear) {
if (!shader) {
FloatColor c;
@@ -235,23 +235,20 @@
mOutGlop->fill.color = c;
} else {
float alpha = (SkColorGetA(color) / 255.0f) * alphaScale;
- mOutGlop->fill.color = { 1, 1, 1, alpha };
+ mOutGlop->fill.color = {1, 1, 1, alpha};
}
} else {
- mOutGlop->fill.color = { 0, 0, 0, 1 };
+ mOutGlop->fill.color = {0, 0, 0, 1};
}
- mOutGlop->blend = { GL_ZERO, GL_ZERO };
- if (mOutGlop->fill.color.a < 1.0f
- || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
- || (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend)
- || mOutGlop->roundRectClipState
- || PaintUtils::isBlendedShader(shader)
- || PaintUtils::isBlendedColorFilter(colorFilter)
- || mode != SkBlendMode::kSrcOver) {
+ mOutGlop->blend = {GL_ZERO, GL_ZERO};
+ if (mOutGlop->fill.color.a < 1.0f ||
+ (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) ||
+ (mOutGlop->fill.texture.texture && mOutGlop->fill.texture.texture->blend) ||
+ mOutGlop->roundRectClipState || PaintUtils::isBlendedShader(shader) ||
+ PaintUtils::isBlendedColorFilter(colorFilter) || mode != SkBlendMode::kSrcOver) {
if (CC_LIKELY(mode <= SkBlendMode::kScreen)) {
- Blend::getFactors(mode, modeUsage,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ Blend::getFactors(mode, modeUsage, &mOutGlop->blend.src, &mOutGlop->blend.dst);
} else {
// These blend modes are not supported by OpenGL directly and have
// to be implemented using shaders. Since the shader will perform
@@ -264,23 +261,25 @@
// blending in shader, don't enable
} else {
// unsupported
- Blend::getFactors(SkBlendMode::kSrcOver, modeUsage,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ Blend::getFactors(SkBlendMode::kSrcOver, modeUsage, &mOutGlop->blend.src,
+ &mOutGlop->blend.dst);
}
}
}
- mShader = shader; // shader resolved in ::build()
+ mShader = shader; // shader resolved in ::build()
if (colorFilter) {
SkColor color;
SkBlendMode bmode;
SkScalar srcColorMatrix[20];
if (colorFilter->asColorMode(&color, &bmode)) {
- mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Blend;
+ mOutGlop->fill.filterMode = mDescription.colorOp =
+ ProgramDescription::ColorFilterMode::Blend;
mDescription.colorMode = bmode;
mOutGlop->fill.filter.color.set(color);
} else if (colorFilter->asColorMatrix(srcColorMatrix)) {
- mOutGlop->fill.filterMode = mDescription.colorOp = ProgramDescription::ColorFilterMode::Matrix;
+ mOutGlop->fill.filterMode = mDescription.colorOp =
+ ProgramDescription::ColorFilterMode::Matrix;
float* colorMatrix = mOutGlop->fill.filter.matrix.matrix;
memcpy(colorMatrix, srcColorMatrix, 4 * sizeof(float));
@@ -291,10 +290,10 @@
// Skia uses the range [0..255] for the addition vector, but we need
// the [0..1] range to apply the vector in GLSL
float* colorVector = mOutGlop->fill.filter.matrix.vector;
- colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
- colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
+ colorVector[0] = EOCF(srcColorMatrix[4] / 255.0f);
+ colorVector[1] = EOCF(srcColorMatrix[9] / 255.0f);
colorVector[2] = EOCF(srcColorMatrix[14] / 255.0f);
- colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
+ colorVector[3] = srcColorMatrix[19] / 255.0f; // alpha is linear
} else {
ALOGE("unsupported ColorFilter type: %s", colorFilter->getTypeName());
LOG_ALWAYS_FATAL("unsupported ColorFilter");
@@ -304,14 +303,15 @@
}
}
-GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture,
- const int textureFillFlags, const SkPaint* paint, float alphaScale) {
+GlopBuilder& GlopBuilder::setFillTexturePaint(Texture& texture, const int textureFillFlags,
+ const SkPaint* paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
GLenum filter = (textureFillFlags & TextureFillFlags::ForceFilter)
- ? GL_LINEAR : PaintUtils::getFilter(paint);
- mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, nullptr };
+ ? GL_LINEAR
+ : PaintUtils::getFilter(paint);
+ mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, nullptr};
if (paint) {
int color = paint->getColor();
@@ -322,20 +322,17 @@
color |= 0x00FFFFFF;
shader = nullptr;
}
- setFill(color, alphaScale,
- paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap,
- shader, paint->getColorFilter());
+ setFill(color, alphaScale, paint->getBlendMode(), Blend::ModeOrderSwap::NoSwap, shader,
+ paint->getColorFilter());
} else {
- mOutGlop->fill.color = { alphaScale, alphaScale, alphaScale, alphaScale };
+ mOutGlop->fill.color = {alphaScale, alphaScale, alphaScale, alphaScale};
- if (alphaScale < 1.0f
- || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
- || texture.blend
- || mOutGlop->roundRectClipState) {
+ if (alphaScale < 1.0f || (mOutGlop->mesh.vertices.attribFlags & VertexAttribFlags::Alpha) ||
+ texture.blend || mOutGlop->roundRectClipState) {
Blend::getFactors(SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
- &mOutGlop->blend.src, &mOutGlop->blend.dst);
+ &mOutGlop->blend.src, &mOutGlop->blend.dst);
} else {
- mOutGlop->blend = { GL_ZERO, GL_ZERO };
+ mOutGlop->blend = {GL_ZERO, GL_ZERO};
}
}
@@ -353,32 +350,28 @@
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
if (CC_LIKELY(!shadowInterp)) {
- mOutGlop->fill.texture = {
- nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
} else {
- mOutGlop->fill.texture = {
- mCaches.textureState().getShadowLutTexture(),
- GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ mOutGlop->fill.texture = {mCaches.textureState().getShadowLutTexture(), GL_INVALID_ENUM,
+ GL_INVALID_ENUM, nullptr};
}
- setFill(paint.getColor(), alphaScale,
- paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
+ setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
paint.getShader(), paint.getColorFilter());
mDescription.useShadowAlphaInterp = shadowInterp;
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
return *this;
}
-GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture,
- const SkPaint& paint, float alphaScale) {
+GlopBuilder& GlopBuilder::setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint,
+ float alphaScale) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- //specify invalid filter/clamp, since these are always static for PathTextures
- mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ // specify invalid filter/clamp, since these are always static for PathTextures
+ mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
- setFill(paint.getColor(), alphaScale,
- paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
+ setFill(paint.getColor(), alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
paint.getShader(), paint.getColorFilter());
mDescription.hasAlpha8Texture = true;
@@ -387,12 +380,12 @@
}
GlopBuilder& GlopBuilder::setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
- const SkPaint& paint, float alphaScale) {
+ const SkPaint& paint, float alphaScale) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- //specify invalid filter/clamp, since these are always static for ShadowTextures
- mOutGlop->fill.texture = { &texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ // specify invalid filter/clamp, since these are always static for ShadowTextures
+ mOutGlop->fill.texture = {&texture, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
const int ALPHA_BITMASK = SK_ColorBLACK;
const int COLOR_BITMASK = ~ALPHA_BITMASK;
@@ -401,8 +394,7 @@
shadowColor &= paint.getColor() | COLOR_BITMASK;
}
- setFill(shadowColor, alphaScale,
- paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
+ setFill(shadowColor, alphaScale, paint.getBlendMode(), Blend::ModeOrderSwap::NoSwap,
paint.getShader(), paint.getColorFilter());
mDescription.hasAlpha8Texture = true;
@@ -414,9 +406,9 @@
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
- setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap,
- nullptr, nullptr);
+ mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
+ setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kSrcOver, Blend::ModeOrderSwap::NoSwap, nullptr,
+ nullptr);
return *this;
}
@@ -424,18 +416,19 @@
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
- setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap,
- nullptr, nullptr);
+ mOutGlop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
+ setFill(SK_ColorBLACK, 1.0f, SkBlendMode::kClear, Blend::ModeOrderSwap::NoSwap, nullptr,
+ nullptr);
return *this;
}
GlopBuilder& GlopBuilder::setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
- float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage) {
+ float alpha, SkBlendMode mode,
+ Blend::ModeOrderSwap modeUsage) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { &texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr };
+ mOutGlop->fill.texture = {&texture, GL_LINEAR, GL_CLAMP_TO_EDGE, nullptr};
setFill(SK_ColorWHITE, alpha, mode, modeUsage, nullptr, colorFilter);
@@ -447,11 +440,11 @@
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
- mOutGlop->fill.texture = { &(layer.getTexture()),
- GL_LINEAR, GL_CLAMP_TO_EDGE, &layer.getTexTransform() };
+ mOutGlop->fill.texture = {&(layer.getTexture()), GL_LINEAR, GL_CLAMP_TO_EDGE,
+ &layer.getTexTransform()};
- setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap,
- nullptr, layer.getColorFilter());
+ setFill(SK_ColorWHITE, alpha, layer.getMode(), Blend::ModeOrderSwap::NoSwap, nullptr,
+ layer.getColorFilter());
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mDescription.hasTextureTransform = true;
@@ -459,15 +452,14 @@
}
GlopBuilder& GlopBuilder::setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
- bool requiresFilter) {
+ bool requiresFilter) {
TRIGGER_STAGE(kFillStage);
REQUIRE_STAGES(kMeshStage | kRoundRectClipStage);
GLenum filter = requiresFilter ? GL_LINEAR : GL_NEAREST;
- mOutGlop->fill.texture = { &texture, filter, GL_CLAMP_TO_EDGE, &textureTransform };
+ mOutGlop->fill.texture = {&texture, filter, GL_CLAMP_TO_EDGE, &textureTransform};
- setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap,
- nullptr, nullptr);
+ setFill(SK_ColorWHITE, 1.0f, SkBlendMode::kSrc, Blend::ModeOrderSwap::NoSwap, nullptr, nullptr);
mDescription.modulate = mOutGlop->fill.color.a < 1.0f;
mDescription.hasTextureTransform = true;
@@ -518,8 +510,8 @@
const float translateX = meshTransform.getTranslateX();
const float translateY = meshTransform.getTranslateY();
- left = (int) floorf(left + translateX + 0.5f) - translateX;
- top = (int) floorf(top + translateY + 0.5f) - translateY;
+ left = (int)floorf(left + translateX + 0.5f) - translateX;
+ top = (int)floorf(top + translateY + 0.5f) - translateY;
mOutGlop->fill.texture.filter = GL_NEAREST;
}
@@ -535,7 +527,8 @@
return *this;
}
-GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source) {
+GlopBuilder& GlopBuilder::setModelViewOffsetRectSnap(float offsetX, float offsetY,
+ const Rect source) {
TRIGGER_STAGE(kModelViewStage);
REQUIRE_STAGES(kTransformStage | kFillStage);
@@ -545,8 +538,8 @@
const float translateX = meshTransform.getTranslateX();
const float translateY = meshTransform.getTranslateY();
- offsetX = (int) floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
- offsetY = (int) floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
+ offsetX = (int)floorf(offsetX + translateX + source.left + 0.5f) - translateX - source.left;
+ offsetY = (int)floorf(offsetY + translateY + source.top + 0.5f) - translateY - source.top;
mOutGlop->fill.texture.filter = GL_NEAREST;
}
@@ -572,27 +565,25 @@
void verify(const ProgramDescription& description, const Glop& glop) {
if (glop.fill.texture.texture != nullptr) {
- LOG_ALWAYS_FATAL_IF(((description.hasTexture && description.hasExternalTexture)
- || (!description.hasTexture
- && !description.hasExternalTexture
- && !description.useShadowAlphaInterp)
- || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0
- && !description.useShadowAlphaInterp)),
- "Texture %p, hT%d, hET %d, attribFlags %x",
- glop.fill.texture.texture,
+ LOG_ALWAYS_FATAL_IF(
+ ((description.hasTexture && description.hasExternalTexture) ||
+ (!description.hasTexture && !description.hasExternalTexture &&
+ !description.useShadowAlphaInterp) ||
+ ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) == 0 &&
+ !description.useShadowAlphaInterp)),
+ "Texture %p, hT%d, hET %d, attribFlags %x", glop.fill.texture.texture,
description.hasTexture, description.hasExternalTexture,
glop.mesh.vertices.attribFlags);
} else {
- LOG_ALWAYS_FATAL_IF((description.hasTexture
- || description.hasExternalTexture
- || ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
- "No texture, hT%d, hET %d, attribFlags %x",
- description.hasTexture, description.hasExternalTexture,
- glop.mesh.vertices.attribFlags);
+ LOG_ALWAYS_FATAL_IF(
+ (description.hasTexture || description.hasExternalTexture ||
+ ((glop.mesh.vertices.attribFlags & VertexAttribFlags::TextureCoord) != 0)),
+ "No texture, hT%d, hET %d, attribFlags %x", description.hasTexture,
+ description.hasExternalTexture, glop.mesh.vertices.attribFlags);
}
- if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha)
- && glop.mesh.vertices.bufferObject) {
+ if ((glop.mesh.vertices.attribFlags & VertexAttribFlags::Alpha) &&
+ glop.mesh.vertices.bufferObject) {
LOG_ALWAYS_FATAL("VBO and alpha attributes are not currently compatible");
}
@@ -621,9 +612,10 @@
// Enable debug highlight when what we're about to draw is tested against
// the stencil buffer and if stencil highlight debugging is on
- mDescription.hasDebugHighlight = !Properties::debugOverdraw
- && Properties::debugStencilClip == StencilClipDebug::ShowHighlight
- && mRenderState.stencil().isTestEnabled();
+ mDescription.hasDebugHighlight =
+ !Properties::debugOverdraw &&
+ Properties::debugStencilClip == StencilClipDebug::ShowHighlight &&
+ mRenderState.stencil().isTestEnabled();
// serialize shader info into ShaderData
GLuint textureUnit = mOutGlop->fill.texture.texture ? 1 : 0;
@@ -640,15 +632,13 @@
} else {
shaderMatrix = mOutGlop->transform.modelView;
}
- SkiaShader::store(mCaches, *mShader, shaderMatrix,
- &textureUnit, &mDescription, &(mOutGlop->fill.skiaShaderData));
+ SkiaShader::store(mCaches, *mShader, shaderMatrix, &textureUnit, &mDescription,
+ &(mOutGlop->fill.skiaShaderData));
}
// duplicates ProgramCache's definition of color uniform presence
- const bool singleColor = !mDescription.hasTexture
- && !mDescription.hasExternalTexture
- && !mDescription.hasGradient
- && !mDescription.hasBitmap;
+ const bool singleColor = !mDescription.hasTexture && !mDescription.hasExternalTexture &&
+ !mDescription.hasGradient && !mDescription.hasBitmap;
mOutGlop->fill.colorEnabled = mDescription.modulate || singleColor;
verify(mDescription, *mOutGlop);
@@ -661,31 +651,31 @@
ALOGD("Glop Mesh");
const Glop::Mesh& mesh = glop.mesh;
ALOGD(" primitive mode: %d", mesh.primitiveMode);
- ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject, mesh.indices.indices);
+ ALOGD(" indices: buffer obj %x, indices %p", mesh.indices.bufferObject,
+ mesh.indices.indices);
const Glop::Mesh::Vertices& vertices = glop.mesh.vertices;
ALOGD(" vertices: buffer obj %x, flags %x, pos %p, tex %p, clr %p, stride %d",
- vertices.bufferObject, vertices.attribFlags,
- vertices.position, vertices.texCoord, vertices.color, vertices.stride);
+ vertices.bufferObject, vertices.attribFlags, vertices.position, vertices.texCoord,
+ vertices.color, vertices.stride);
ALOGD(" element count: %d", mesh.elementCount);
ALOGD("Glop Fill");
const Glop::Fill& fill = glop.fill;
ALOGD(" program %p", fill.program);
if (fill.texture.texture) {
- ALOGD(" texture %p, target %d, filter %d, clamp %d",
- fill.texture.texture, fill.texture.texture->target(),
- fill.texture.filter, fill.texture.clamp);
+ ALOGD(" texture %p, target %d, filter %d, clamp %d", fill.texture.texture,
+ fill.texture.texture->target(), fill.texture.filter, fill.texture.clamp);
if (fill.texture.textureTransform) {
fill.texture.textureTransform->dump("texture transform");
}
}
- ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f",
- fill.color.a, fill.color.r, fill.color.g, fill.color.b);
- ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None,
- " filterMode %d", (int)fill.filterMode);
+ ALOGD_IF(fill.colorEnabled, " color (argb) %.2f %.2f %.2f %.2f", fill.color.a, fill.color.r,
+ fill.color.g, fill.color.b);
+ ALOGD_IF(fill.filterMode != ProgramDescription::ColorFilterMode::None, " filterMode %d",
+ (int)fill.filterMode);
ALOGD_IF(fill.skiaShaderData.skiaShaderType, " shader type %d",
- fill.skiaShaderData.skiaShaderType);
+ fill.skiaShaderData.skiaShaderType);
ALOGD("Glop transform");
glop.transform.modelView.dump(" model view");
diff --git a/libs/hwui/GlopBuilder.h b/libs/hwui/GlopBuilder.h
index 6d11da1..dac3822 100644
--- a/libs/hwui/GlopBuilder.h
+++ b/libs/hwui/GlopBuilder.h
@@ -39,15 +39,16 @@
struct ShadowTexture;
namespace TextureFillFlags {
- enum {
- None = 0,
- IsAlphaMaskTexture = 1 << 0,
- ForceFilter = 1 << 1,
- };
+enum {
+ None = 0,
+ IsAlphaMaskTexture = 1 << 0,
+ ForceFilter = 1 << 1,
+};
}
class GlopBuilder {
PREVENT_COPY_AND_ASSIGN(GlopBuilder);
+
public:
GlopBuilder(RenderState& renderState, Caches& caches, Glop* outGlop);
@@ -57,26 +58,29 @@
GlopBuilder& setMeshTexturedUvQuad(const UvMapper* uvMapper, const Rect uvs);
GlopBuilder& setMeshVertexBuffer(const VertexBuffer& vertexBuffer);
GlopBuilder& setMeshIndexedQuads(Vertex* vertexData, int quadCount);
- GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData, int elementCount); // TODO: use indexed quads
- GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData, int elementCount); // TODO: take quadCount
+ GlopBuilder& setMeshColoredTexturedMesh(ColorTextureVertex* vertexData,
+ int elementCount); // TODO: use indexed quads
+ GlopBuilder& setMeshTexturedIndexedQuads(TextureVertex* vertexData,
+ int elementCount); // TODO: take quadCount
GlopBuilder& setMeshPatchQuads(const Patch& patch);
- GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale, bool shadowInterp = false); // TODO: avoid boolean with default
+ GlopBuilder& setFillPaint(const SkPaint& paint, float alphaScale,
+ bool shadowInterp = false); // TODO: avoid boolean with default
GlopBuilder& setFillTexturePaint(Texture& texture, const int textureFillFlags,
- const SkPaint* paint, float alphaScale);
- GlopBuilder& setFillPathTexturePaint(PathTexture& texture,
- const SkPaint& paint, float alphaScale);
+ const SkPaint* paint, float alphaScale);
+ GlopBuilder& setFillPathTexturePaint(PathTexture& texture, const SkPaint& paint,
+ float alphaScale);
GlopBuilder& setFillShadowTexturePaint(ShadowTexture& texture, int shadowColor,
- const SkPaint& paint, float alphaScale);
+ const SkPaint& paint, float alphaScale);
GlopBuilder& setFillBlack();
GlopBuilder& setFillClear();
- GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter,
- float alpha, SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
+ GlopBuilder& setFillLayer(Texture& texture, const SkColorFilter* colorFilter, float alpha,
+ SkBlendMode mode, Blend::ModeOrderSwap modeUsage);
GlopBuilder& setFillTextureLayer(GlLayer& layer, float alpha);
// TODO: setFillLayer normally forces its own wrap & filter mode,
// which isn't always correct.
GlopBuilder& setFillExternalTexture(Texture& texture, Matrix4& textureTransform,
- bool requiresFilter);
+ bool requiresFilter);
GlopBuilder& setTransform(const Matrix4& canvas, const int transformFlags);
@@ -91,8 +95,8 @@
}
GlopBuilder& setModelViewOffsetRect(float offsetX, float offsetY, const Rect source);
GlopBuilder& setModelViewOffsetRectSnap(float offsetX, float offsetY, const Rect source);
- GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap,
- float offsetX, float offsetY, const Rect& source) {
+ GlopBuilder& setModelViewOffsetRectOptionalSnap(bool snap, float offsetX, float offsetY,
+ const Rect& source) {
if (snap) {
return setModelViewOffsetRectSnap(offsetX, offsetY, source);
} else {
@@ -111,10 +115,10 @@
void build();
static void dump(const Glop& glop);
+
private:
- void setFill(int color, float alphaScale,
- SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
- const SkShader* shader, const SkColorFilter* colorFilter);
+ void setFill(int color, float alphaScale, SkBlendMode mode, Blend::ModeOrderSwap modeUsage,
+ const SkShader* shader, const SkColorFilter* colorFilter);
enum StageFlags {
kInitialStage = 0,
@@ -123,7 +127,8 @@
kModelViewStage = 1 << 2,
kFillStage = 1 << 3,
kRoundRectClipStage = 1 << 4,
- kAllStages = kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
+ kAllStages =
+ kMeshStage | kFillStage | kTransformStage | kModelViewStage | kRoundRectClipStage,
} mStageFlags;
ProgramDescription mDescription;
diff --git a/libs/hwui/GpuMemoryTracker.cpp b/libs/hwui/GpuMemoryTracker.cpp
index a52ec87..612bfde 100644
--- a/libs/hwui/GpuMemoryTracker.cpp
+++ b/libs/hwui/GpuMemoryTracker.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "utils/StringUtils.h"
#include "Texture.h"
+#include "utils/StringUtils.h"
-#include <cutils/compiler.h>
#include <GpuMemoryTracker.h>
+#include <cutils/compiler.h>
#include <utils/Trace.h>
#include <array>
#include <sstream>
@@ -33,9 +33,7 @@
#define NUM_TYPES static_cast<int>(GpuObjectType::TypeCount)
const char* TYPE_NAMES[] = {
- "Texture",
- "OffscreenBuffer",
- "Layer",
+ "Texture", "OffscreenBuffer", "Layer",
};
struct TypeStats {
@@ -55,21 +53,22 @@
void GpuMemoryTracker::startTrackingObject() {
auto result = gObjectSet.insert(this);
LOG_ALWAYS_FATAL_IF(!result.second,
- "startTrackingObject() on %p failed, already being tracked!", this);
+ "startTrackingObject() on %p failed, already being tracked!", this);
gObjectStats[static_cast<int>(mType)].count++;
}
void GpuMemoryTracker::stopTrackingObject() {
size_t removed = gObjectSet.erase(this);
- LOG_ALWAYS_FATAL_IF(removed != 1,
- "stopTrackingObject removed %zd, is %p not being tracked?",
- removed, this);
+ LOG_ALWAYS_FATAL_IF(removed != 1, "stopTrackingObject removed %zd, is %p not being tracked?",
+ removed, this);
gObjectStats[static_cast<int>(mType)].count--;
}
void GpuMemoryTracker::onGpuContextCreated() {
- LOG_ALWAYS_FATAL_IF(gGpuThread != 0, "We already have a gpu thread? "
- "current = %lu, gpu thread = %lu", pthread_self(), gGpuThread);
+ LOG_ALWAYS_FATAL_IF(gGpuThread != 0,
+ "We already have a gpu thread? "
+ "current = %lu, gpu thread = %lu",
+ pthread_self(), gGpuThread);
gGpuThread = pthread_self();
}
@@ -124,8 +123,8 @@
if (obj->objectType() == GpuObjectType::Texture) {
const Texture* texture = static_cast<Texture*>(obj);
if (texture->cleanup) {
- ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u",
- texture->id(), texture->width(), texture->height());
+ ALOGE("Leaked texture marked for cleanup! id=%u, size %ux%u", texture->id(),
+ texture->width(), texture->height());
freeList.push_back(texture);
}
}
@@ -136,5 +135,5 @@
}
}
-} // namespace uirenderer
-} // namespace android;
+} // namespace uirenderer
+} // namespace android;
diff --git a/libs/hwui/GpuMemoryTracker.h b/libs/hwui/GpuMemoryTracker.h
index 18e2330..de3ca99 100644
--- a/libs/hwui/GpuMemoryTracker.h
+++ b/libs/hwui/GpuMemoryTracker.h
@@ -25,11 +25,11 @@
extern pthread_t gGpuThread;
-#define ASSERT_GPU_THREAD() LOG_ALWAYS_FATAL_IF( \
- !pthread_equal(gGpuThread, pthread_self()), \
- "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
- "!= gpu thread %lu", this, static_cast<int>(mType), mSize, \
- pthread_self(), gGpuThread)
+#define ASSERT_GPU_THREAD() \
+ LOG_ALWAYS_FATAL_IF(!pthread_equal(gGpuThread, pthread_self()), \
+ "Error, %p of type %d (size=%d) used on wrong thread! cur thread %lu " \
+ "!= gpu thread %lu", \
+ this, static_cast<int>(mType), mSize, pthread_self(), gGpuThread)
enum class GpuObjectType {
Texture = 0,
@@ -73,5 +73,5 @@
GpuObjectType mType;
};
-} // namespace uirenderer
-} // namespace android;
+} // namespace uirenderer
+} // namespace android;
diff --git a/libs/hwui/GradientCache.cpp b/libs/hwui/GradientCache.cpp
index 2026234..21e3c73 100644
--- a/libs/hwui/GradientCache.cpp
+++ b/libs/hwui/GradientCache.cpp
@@ -18,9 +18,9 @@
#include "Caches.h"
#include "Debug.h"
+#include "DeviceInfo.h"
#include "GradientCache.h"
#include "Properties.h"
-#include "DeviceInfo.h"
#include <cutils/properties.h>
@@ -31,7 +31,7 @@
// Functions
///////////////////////////////////////////////////////////////////////////////
-template<typename T>
+template <typename T>
static inline T min(T a, T b) {
return a < b ? a : b;
}
@@ -122,8 +122,7 @@
mCache.clear();
}
-void GradientCache::getGradientInfo(const uint32_t* colors, const int count,
- GradientInfo& info) {
+void GradientCache::getGradientInfo(const uint32_t* colors, const int count, GradientInfo& info) {
uint32_t width = 256 * (count - 1);
// If the npot extension is not supported we cannot use non-clamp
@@ -145,9 +144,8 @@
info.hasAlpha = hasAlpha;
}
-Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count) {
-
+Texture* GradientCache::addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors,
+ float* positions, int count) {
GradientInfo info;
getGradientInfo(colors, count, info);
@@ -159,18 +157,19 @@
const uint32_t size = info.width * 2 * bytesPerPixel();
while (getSize() + size > mMaxSize) {
LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
- "Ran out of things to remove from the cache? getSize() = %" PRIu32
- ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
- getSize(), size, mMaxSize, info.width);
+ "Ran out of things to remove from the cache? getSize() = %" PRIu32
+ ", size = %" PRIu32 ", mMaxSize = %" PRIu32 ", width = %" PRIu32,
+ getSize(), size, mMaxSize, info.width);
}
generateTexture(colors, positions, info.width, 2, texture);
mSize += size;
LOG_ALWAYS_FATAL_IF((int)size != texture->objectSize(),
- "size != texture->objectSize(), size %" PRIu32 ", objectSize %d"
- " width = %" PRIu32 " bytesPerPixel() = %zu",
- size, texture->objectSize(), info.width, bytesPerPixel());
+ "size != texture->objectSize(), size %" PRIu32
+ ", objectSize %d"
+ " width = %" PRIu32 " bytesPerPixel() = %zu",
+ size, texture->objectSize(), info.width, bytesPerPixel());
mCache.put(gradient, texture);
return texture;
@@ -186,8 +185,8 @@
return 4 * (mUseFloatTexture ? sizeof(float) : sizeof(uint8_t));
}
-void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const {
+void GradientCache::mixBytes(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
float a = start.a * oppAmount + end.a * amount;
*dst++ = uint8_t(OECF(start.r * oppAmount + end.r * amount) * 255.0f);
@@ -196,11 +195,11 @@
*dst++ = uint8_t(a * 255.0f);
}
-void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const {
+void GradientCache::mixFloats(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const {
float oppAmount = 1.0f - amount;
float a = start.a * oppAmount + end.a * amount;
- float* d = (float*) dst;
+ float* d = (float*)dst;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
// We want to stay linear
*d++ = (start.r * oppAmount + end.r * amount);
@@ -215,8 +214,8 @@
dst += 4 * sizeof(float);
}
-void GradientCache::generateTexture(uint32_t* colors, float* positions,
- const uint32_t width, const uint32_t height, Texture* texture) {
+void GradientCache::generateTexture(uint32_t* colors, float* positions, const uint32_t width,
+ const uint32_t height, Texture* texture) {
const GLsizei rowBytes = width * sourceBytesPerPixel();
uint8_t pixels[rowBytes * height];
@@ -269,5 +268,5 @@
texture->setWrap(GL_CLAMP_TO_EDGE);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/GradientCache.h b/libs/hwui/GradientCache.h
index d95589c..ff426cd 100644
--- a/libs/hwui/GradientCache.h
+++ b/libs/hwui/GradientCache.h
@@ -60,13 +60,9 @@
static int compare(const GradientCacheEntry& lhs, const GradientCacheEntry& rhs);
- bool operator==(const GradientCacheEntry& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const GradientCacheEntry& other) const { return compare(*this, other) == 0; }
- bool operator!=(const GradientCacheEntry& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const GradientCacheEntry& other) const { return compare(*this, other) != 0; }
std::unique_ptr<uint32_t[]> colors;
std::unique_ptr<float[]> positions;
@@ -82,7 +78,7 @@
memcpy(this->positions.get(), positions, count * sizeof(float));
}
-}; // GradientCacheEntry
+}; // GradientCacheEntry
// Caching support
@@ -103,7 +99,7 @@
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
-class GradientCache: public OnEntryRemoved<GradientCacheEntry, Texture*> {
+class GradientCache : public OnEntryRemoved<GradientCacheEntry, Texture*> {
public:
explicit GradientCache(const Extensions& extensions);
~GradientCache();
@@ -138,11 +134,11 @@
* Adds a new linear gradient to the cache. The generated texture is
* returned.
*/
- Texture* addLinearGradient(GradientCacheEntry& gradient,
- uint32_t* colors, float* positions, int count);
+ Texture* addLinearGradient(GradientCacheEntry& gradient, uint32_t* colors, float* positions,
+ int count);
- void generateTexture(uint32_t* colors, float* positions,
- const uint32_t width, const uint32_t height, Texture* texture);
+ void generateTexture(uint32_t* colors, float* positions, const uint32_t width,
+ const uint32_t height, Texture* texture);
struct GradientInfo {
uint32_t width;
@@ -155,12 +151,12 @@
size_t sourceBytesPerPixel() const;
typedef void (GradientCache::*ChannelMixer)(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const;
+ float amount, uint8_t*& dst) const;
- void mixBytes(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const;
- void mixFloats(const FloatColor& start, const FloatColor& end,
- float amount, uint8_t*& dst) const;
+ void mixBytes(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const;
+ void mixFloats(const FloatColor& start, const FloatColor& end, float amount,
+ uint8_t*& dst) const;
LruCache<GradientCacheEntry, Texture*> mCache;
@@ -173,9 +169,9 @@
bool mHasLinearBlending;
mutable Mutex mLock;
-}; // class GradientCache
+}; // class GradientCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_GRADIENT_CACHE_H
+#endif // ANDROID_HWUI_GRADIENT_CACHE_H
diff --git a/libs/hwui/IProfileRenderer.h b/libs/hwui/IProfileRenderer.h
index 947ed34..935ab4e 100644
--- a/libs/hwui/IProfileRenderer.h
+++ b/libs/hwui/IProfileRenderer.h
@@ -22,7 +22,7 @@
class IProfileRenderer {
public:
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
virtual void drawRects(const float* rects, int count, const SkPaint& paint) = 0;
virtual uint32_t getViewportWidth() = 0;
virtual uint32_t getViewportHeight() = 0;
diff --git a/libs/hwui/Image.cpp b/libs/hwui/Image.cpp
index 68a356b..d30796d 100644
--- a/libs/hwui/Image.cpp
+++ b/libs/hwui/Image.cpp
@@ -25,11 +25,11 @@
Image::Image(sp<GraphicBuffer> buffer) {
// Create the EGLImage object that maps the GraphicBuffer
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
- EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+ mImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ attrs);
if (mImage == EGL_NO_IMAGE_KHR) {
ALOGW("Error creating image (%#x)", eglGetError());
@@ -57,5 +57,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Image.h b/libs/hwui/Image.h
index b8f5a5b..989b6ff 100644
--- a/libs/hwui/Image.h
+++ b/libs/hwui/Image.h
@@ -45,23 +45,19 @@
* Returns the name of the GL texture that can be used to sample
* from this image.
*/
- GLuint getTexture() const {
- return mTexture;
- }
+ GLuint getTexture() const { return mTexture; }
/**
* Returns the name of the EGL image represented by this object.
*/
- EGLImageKHR getImage() const {
- return mImage;
- }
+ EGLImageKHR getImage() const { return mImage; }
private:
GLuint mTexture;
EGLImageKHR mImage;
-}; // class Image
+}; // class Image
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_IMAGE_H
+#endif // ANDROID_HWUI_IMAGE_H
diff --git a/libs/hwui/Interpolator.cpp b/libs/hwui/Interpolator.cpp
index d740c03..7bdca2e 100644
--- a/libs/hwui/Interpolator.cpp
+++ b/libs/hwui/Interpolator.cpp
@@ -54,8 +54,10 @@
}
float AnticipateOvershootInterpolator::interpolate(float t) {
- if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
- else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
+ if (t < 0.5f)
+ return 0.5f * a(t * 2.0f, mTension);
+ else
+ return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
}
static float bounce(float t) {
@@ -64,10 +66,14 @@
float BounceInterpolator::interpolate(float t) {
t *= 1.1226f;
- if (t < 0.3535f) return bounce(t);
- else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
- else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
- else return bounce(t - 1.0435f) + 0.95f;
+ if (t < 0.3535f)
+ return bounce(t);
+ else if (t < 0.7408f)
+ return bounce(t - 0.54719f) + 0.7f;
+ else if (t < 0.9644f)
+ return bounce(t - 0.8526f) + 0.9f;
+ else
+ return bounce(t - 1.0435f) + 0.95f;
}
float CycleInterpolator::interpolate(float input) {
@@ -119,16 +125,11 @@
float startY = mY[startIndex];
float endY = mY[endIndex];
return startY + (fraction * (endY - startY));
-
}
-LUTInterpolator::LUTInterpolator(float* values, size_t size)
- : mValues(values)
- , mSize(size) {
-}
+LUTInterpolator::LUTInterpolator(float* values, size_t size) : mValues(values), mSize(size) {}
-LUTInterpolator::~LUTInterpolator() {
-}
+LUTInterpolator::~LUTInterpolator() {}
float LUTInterpolator::interpolate(float input) {
// lut position should only be at the end of the table when input is 1f.
@@ -140,10 +141,12 @@
float ipart, weight;
weight = modff(lutpos, &ipart);
- int i1 = (int) ipart;
- int i2 = std::min(i1 + 1, (int) mSize - 1);
+ int i1 = (int)ipart;
+ int i2 = std::min(i1 + 1, (int)mSize - 1);
- LOG_ALWAYS_FATAL_IF(i1 < 0 || i2 < 0, "negatives in interpolation!"
+ LOG_ALWAYS_FATAL_IF(
+ i1 < 0 || i2 < 0,
+ "negatives in interpolation!"
" i1=%d, i2=%d, input=%f, lutpos=%f, size=%zu, values=%p, ipart=%f, weight=%f",
i1, i2, input, lutpos, mSize, mValues.get(), ipart, weight);
@@ -153,6 +156,5 @@
return MathUtils::lerp(v1, v2, weight);
}
-
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/Interpolator.h b/libs/hwui/Interpolator.h
index 224cee7..452988f 100644
--- a/libs/hwui/Interpolator.h
+++ b/libs/hwui/Interpolator.h
@@ -44,8 +44,9 @@
class ANDROID_API AccelerateInterpolator : public Interpolator {
public:
- explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor*2) {}
+ explicit AccelerateInterpolator(float factor) : mFactor(factor), mDoubleFactor(factor * 2) {}
virtual float interpolate(float input) override;
+
private:
const float mFactor;
const float mDoubleFactor;
@@ -55,6 +56,7 @@
public:
explicit AnticipateInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
+
private:
const float mTension;
};
@@ -63,6 +65,7 @@
public:
explicit AnticipateOvershootInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
+
private:
const float mTension;
};
@@ -76,6 +79,7 @@
public:
explicit CycleInterpolator(float cycles) : mCycles(cycles) {}
virtual float interpolate(float input) override;
+
private:
const float mCycles;
};
@@ -84,6 +88,7 @@
public:
explicit DecelerateInterpolator(float factor) : mFactor(factor) {}
virtual float interpolate(float input) override;
+
private:
const float mFactor;
};
@@ -97,15 +102,16 @@
public:
explicit OvershootInterpolator(float tension) : mTension(tension) {}
virtual float interpolate(float input) override;
+
private:
const float mTension;
};
class ANDROID_API PathInterpolator : public Interpolator {
public:
- explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y)
- : mX (x), mY(y) {}
+ explicit PathInterpolator(std::vector<float>&& x, std::vector<float>&& y) : mX(x), mY(y) {}
virtual float interpolate(float input) override;
+
private:
std::vector<float> mX;
std::vector<float> mY;
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 9d11828..5b67693 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -106,25 +106,23 @@
mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
-
}
void JankTracker::finishFrame(const FrameInfo& frame) {
// Fast-path for jank-free frames
int64_t totalDuration = frame.duration(sFrameStart, FrameInfoIndex::FrameCompleted);
- if (mDequeueTimeForgiveness
- && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
- nsecs_t expectedDequeueDuration =
- mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync]
- - frame[FrameInfoIndex::IssueDrawCommandsStart];
+ if (mDequeueTimeForgiveness && frame[FrameInfoIndex::DequeueBufferDuration] > 500_us) {
+ nsecs_t expectedDequeueDuration = mDequeueTimeForgiveness + frame[FrameInfoIndex::Vsync] -
+ frame[FrameInfoIndex::IssueDrawCommandsStart];
if (expectedDequeueDuration > 0) {
// Forgive only up to the expected amount, but not more than
// the actual time spent blocked.
- nsecs_t forgiveAmount = std::min(expectedDequeueDuration,
- frame[FrameInfoIndex::DequeueBufferDuration]);
+ nsecs_t forgiveAmount =
+ std::min(expectedDequeueDuration, frame[FrameInfoIndex::DequeueBufferDuration]);
LOG_ALWAYS_FATAL_IF(forgiveAmount >= totalDuration,
- "Impossible dequeue duration! dequeue duration reported %" PRId64
- ", total duration %" PRId64, forgiveAmount, totalDuration);
+ "Impossible dequeue duration! dequeue duration reported %" PRId64
+ ", total duration %" PRId64,
+ forgiveAmount, totalDuration);
totalDuration -= forgiveAmount;
}
}
@@ -148,13 +146,14 @@
for (int i = 0; i < NUM_BUCKETS; i++) {
int64_t delta = frame.duration(COMPARISONS[i].start, COMPARISONS[i].end);
if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
- mData->reportJankType((JankType) i);
- (*mGlobalData)->reportJankType((JankType) i);
+ mData->reportJankType((JankType)i);
+ (*mGlobalData)->reportJankType((JankType)i);
}
}
}
-void JankTracker::dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data) {
+void JankTracker::dumpData(int fd, const ProfileDataDescription* description,
+ const ProfileData* data) {
if (description) {
switch (description->type) {
case JankTrackerType::Generic:
@@ -199,9 +198,8 @@
mFrames.clear();
mData->reset();
(*mGlobalData)->reset();
- sFrameStart = Properties::filterOutTestOverhead
- ? FrameInfoIndex::HandleInputStart
- : FrameInfoIndex::IntendedVsync;
+ sFrameStart = Properties::filterOutTestOverhead ? FrameInfoIndex::HandleInputStart
+ : FrameInfoIndex::IntendedVsync;
}
} /* namespace uirenderer */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
index e56c079..dc6a7ff 100644
--- a/libs/hwui/JankTracker.h
+++ b/libs/hwui/JankTracker.h
@@ -70,7 +70,8 @@
private:
void setFrameInterval(nsecs_t frameIntervalNanos);
- static void dumpData(int fd, const ProfileDataDescription* description, const ProfileData* data);
+ static void dumpData(int fd, const ProfileDataDescription* description,
+ const ProfileData* data);
std::array<int64_t, NUM_BUCKETS> mThresholds;
int64_t mFrameInterval;
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index b58dfce..86950d5 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -24,7 +24,7 @@
namespace uirenderer {
Layer::Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
- SkBlendMode mode)
+ SkBlendMode mode)
: GpuMemoryTracker(GpuObjectType::Layer)
, mRenderState(renderState)
, mApi(api)
@@ -52,5 +52,5 @@
mRenderState.postDecStrong(this);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index e5520ea..6921381 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -16,11 +16,11 @@
#pragma once
-#include <utils/RefBase.h>
#include <GpuMemoryTracker.h>
+#include <utils/RefBase.h>
-#include <SkPaint.h>
#include <SkBlendMode.h>
+#include <SkPaint.h>
#include "Matrix.h"
@@ -43,9 +43,7 @@
Vulkan = 1,
};
- Api getApi() const {
- return mApi;
- }
+ Api getApi() const { return mApi; }
~Layer();
@@ -59,44 +57,28 @@
virtual bool isBlend() const = 0;
- inline void setForceFilter(bool forceFilter) {
- this->forceFilter = forceFilter;
- }
+ inline void setForceFilter(bool forceFilter) { this->forceFilter = forceFilter; }
- inline bool getForceFilter() const {
- return forceFilter;
- }
+ inline bool getForceFilter() const { return forceFilter; }
- inline void setAlpha(int alpha) {
- this->alpha = alpha;
- }
+ inline void setAlpha(int alpha) { this->alpha = alpha; }
inline void setAlpha(int alpha, SkBlendMode mode) {
this->alpha = alpha;
this->mode = mode;
}
- inline int getAlpha() const {
- return alpha;
- }
+ inline int getAlpha() const { return alpha; }
- inline SkBlendMode getMode() const {
- return mode;
- }
+ inline SkBlendMode getMode() const { return mode; }
- inline SkColorFilter* getColorFilter() const {
- return colorFilter;
- }
+ inline SkColorFilter* getColorFilter() const { return colorFilter; }
void setColorFilter(SkColorFilter* filter);
- inline mat4& getTexTransform() {
- return texTransform;
- }
+ inline mat4& getTexTransform() { return texTransform; }
- inline mat4& getTransform() {
- return transform;
- }
+ inline mat4& getTransform() { return transform; }
/**
* Posts a decStrong call to the appropriate thread.
@@ -106,7 +88,7 @@
protected:
Layer(RenderState& renderState, Api api, SkColorFilter* colorFilter, int alpha,
- SkBlendMode mode);
+ SkBlendMode mode);
RenderState& mRenderState;
@@ -143,7 +125,7 @@
*/
mat4 transform;
-}; // struct Layer
+}; // struct Layer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/LayerBuilder.cpp b/libs/hwui/LayerBuilder.cpp
index c5d5492..15ede4c 100644
--- a/libs/hwui/LayerBuilder.cpp
+++ b/libs/hwui/LayerBuilder.cpp
@@ -29,8 +29,7 @@
class BatchBase {
public:
BatchBase(batchid_t batchId, BakedOpState* op, bool merging)
- : mBatchId(batchId)
- , mMerging(merging) {
+ : mBatchId(batchId), mMerging(merging) {
mBounds = op->computedState.clippedBounds;
mOps.push_back(op);
}
@@ -52,9 +51,10 @@
const std::vector<BakedOpState*>& getOps() const { return mOps; }
void dump() const {
- ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING,
- this, mBatchId, mMerging, (int) mOps.size(), RECT_ARGS(mBounds));
+ ALOGD(" Batch %p, id %d, merging %d, count %d, bounds " RECT_STRING, this, mBatchId,
+ mMerging, (int)mOps.size(), RECT_ARGS(mBounds));
}
+
protected:
batchid_t mBatchId;
Rect mBounds;
@@ -64,9 +64,7 @@
class OpBatch : public BatchBase {
public:
- OpBatch(batchid_t batchId, BakedOpState* op)
- : BatchBase(batchId, op, false) {
- }
+ OpBatch(batchid_t batchId, BakedOpState* op) : BatchBase(batchId, op, false) {}
void batchOp(BakedOpState* op) {
mBounds.unionWith(op->computedState.clippedBounds);
@@ -77,16 +75,14 @@
class MergingOpBatch : public BatchBase {
public:
MergingOpBatch(batchid_t batchId, BakedOpState* op)
- : BatchBase(batchId, op, true)
- , mClipSideFlags(op->computedState.clipSideFlags) {
- }
+ : BatchBase(batchId, op, true), mClipSideFlags(op->computedState.clipSideFlags) {}
/*
* Helper for determining if a new op can merge with a MergingDrawBatch based on their bounds
* and clip side flags. Positive bounds delta means new bounds fit in old.
*/
static inline bool checkSide(const int currentFlags, const int newFlags, const int side,
- float boundsDelta) {
+ float boundsDelta) {
bool currentClipExists = currentFlags & side;
bool newClipExists = newFlags & side;
@@ -100,16 +96,14 @@
}
static bool paintIsDefault(const SkPaint& paint) {
- return paint.getAlpha() == 255
- && paint.getColorFilter() == nullptr
- && paint.getShader() == nullptr;
+ return paint.getAlpha() == 255 && paint.getColorFilter() == nullptr &&
+ paint.getShader() == nullptr;
}
static bool paintsAreEquivalent(const SkPaint& a, const SkPaint& b) {
// Note: don't check color, since all currently mergeable ops can merge across colors
- return a.getAlpha() == b.getAlpha()
- && a.getColorFilter() == b.getColorFilter()
- && a.getShader() == b.getShader();
+ return a.getAlpha() == b.getAlpha() && a.getColorFilter() == b.getColorFilter() &&
+ a.getShader() == b.getShader();
}
/*
@@ -123,8 +117,8 @@
* dropped, so we make simplifying qualifications on the ops that can merge, per op type.
*/
bool canMergeWith(BakedOpState* op) const {
- bool isTextBatch = getBatchId() == OpBatchType::Text
- || getBatchId() == OpBatchType::ColorText;
+ bool isTextBatch =
+ getBatchId() == OpBatchType::Text || getBatchId() == OpBatchType::ColorText;
// Overlapping other operations is only allowed for text without shadow. For other ops,
// multiDraw isn't guaranteed to overdraw correctly
@@ -142,8 +136,9 @@
if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
// Local masks prevent merge, since they're potentially in different coordinate spaces
- if (lhs->computedState.localProjectionPathMask
- || rhs->computedState.localProjectionPathMask) return false;
+ if (lhs->computedState.localProjectionPathMask ||
+ rhs->computedState.localProjectionPathMask)
+ return false;
/* Clipping compatibility check
*
@@ -155,15 +150,18 @@
if (currentFlags != OpClipSideFlags::None || newFlags != OpClipSideFlags::None) {
const Rect& opBounds = op->computedState.clippedBounds;
float boundsDelta = mBounds.left - opBounds.left;
- if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta)) return false;
+ if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Left, boundsDelta))
+ return false;
boundsDelta = mBounds.top - opBounds.top;
if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Top, boundsDelta)) return false;
// right and bottom delta calculation reversed to account for direction
boundsDelta = opBounds.right - mBounds.right;
- if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta)) return false;
+ if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Right, boundsDelta))
+ return false;
boundsDelta = opBounds.bottom - mBounds.bottom;
- if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta)) return false;
+ if (!checkSide(currentFlags, newFlags, OpClipSideFlags::Bottom, boundsDelta))
+ return false;
}
const SkPaint* newPaint = op->op->paint;
@@ -197,8 +195,8 @@
int mClipSideFlags;
};
-LayerBuilder::LayerBuilder(uint32_t width, uint32_t height,
- const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
+LayerBuilder::LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect,
+ const BeginLayerOp* beginLayerOp, RenderNode* renderNode)
: width(width)
, height(height)
, repaintRect(repaintRect)
@@ -210,7 +208,7 @@
// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still iterate to find similar batch to insert after
void LayerBuilder::locateInsertIndex(int batchId, const Rect& clippedBounds,
- BatchBase** targetBatch, size_t* insertBatchIndex) const {
+ BatchBase** targetBatch, size_t* insertBatchIndex) const {
for (int i = mBatches.size() - 1; i >= 0; i--) {
BatchBase* overBatch = mBatches[i];
@@ -219,7 +217,7 @@
// TODO: also consider shader shared between batch types
if (batchId == overBatch->getBatchId()) {
*insertBatchIndex = i + 1;
- if (!*targetBatch) break; // found insert position, quit
+ if (!*targetBatch) break; // found insert position, quit
}
if (overBatch->intersects(clippedBounds)) {
@@ -242,10 +240,10 @@
// and issue them together in one draw.
flushLayerClears(allocator);
- if (CC_UNLIKELY(activeUnclippedSaveLayers.empty()
- && bakedState->computedState.opaqueOverClippedBounds
- && bakedState->computedState.clippedBounds.contains(repaintRect)
- && !Properties::debugOverdraw)) {
+ if (CC_UNLIKELY(activeUnclippedSaveLayers.empty() &&
+ bakedState->computedState.opaqueOverClippedBounds &&
+ bakedState->computedState.clippedBounds.contains(repaintRect) &&
+ !Properties::debugOverdraw)) {
// discard all deferred drawing ops, since new one will occlude them
clear();
}
@@ -258,7 +256,7 @@
// put the verts in the frame allocator, since
// 1) SimpleRectsOps needs verts, not rects
// 2) even if mClearRects stored verts, std::vectors will move their contents
- Vertex* const verts = (Vertex*) allocator.create_trivial_array<Vertex>(vertCount);
+ Vertex* const verts = (Vertex*)allocator.create_trivial_array<Vertex>(vertCount);
Vertex* currentVert = verts;
Rect bounds = mClearRects[0];
@@ -269,35 +267,34 @@
Vertex::set(currentVert++, rect.left, rect.bottom);
Vertex::set(currentVert++, rect.right, rect.bottom);
}
- mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
+ mClearRects.clear(); // discard rects before drawing so this method isn't reentrant
// One or more unclipped saveLayers have been enqueued, with deferred clears.
// Flush all of these clears with a single draw
SkPaint* paint = allocator.create<SkPaint>();
paint->setBlendMode(SkBlendMode::kClear);
- SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(bounds,
- Matrix4::identity(), nullptr, paint,
- verts, vertCount);
- BakedOpState* bakedState = BakedOpState::directConstruct(allocator,
- &repaintClip, bounds, *op);
+ SimpleRectsOp* op = allocator.create_trivial<SimpleRectsOp>(
+ bounds, Matrix4::identity(), nullptr, paint, verts, vertCount);
+ BakedOpState* bakedState =
+ BakedOpState::directConstruct(allocator, &repaintClip, bounds, *op);
deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices);
}
}
-void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator,
- BakedOpState* op, batchid_t batchId) {
+void LayerBuilder::deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op,
+ batchid_t batchId) {
onDeferOp(allocator, op);
OpBatch* targetBatch = mBatchLookup[batchId];
size_t insertBatchIndex = mBatches.size();
if (targetBatch) {
- locateInsertIndex(batchId, op->computedState.clippedBounds,
- (BatchBase**)(&targetBatch), &insertBatchIndex);
+ locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch),
+ &insertBatchIndex);
}
if (targetBatch) {
targetBatch->batchOp(op);
- } else {
+ } else {
// new non-merging batch
targetBatch = allocator.create<OpBatch>(batchId, op);
mBatchLookup[batchId] = targetBatch;
@@ -305,8 +302,8 @@
}
}
-void LayerBuilder::deferMergeableOp(LinearAllocator& allocator,
- BakedOpState* op, batchid_t batchId, mergeid_t mergeId) {
+void LayerBuilder::deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId,
+ mergeid_t mergeId) {
onDeferOp(allocator, op);
MergingOpBatch* targetBatch = nullptr;
@@ -320,12 +317,12 @@
}
size_t insertBatchIndex = mBatches.size();
- locateInsertIndex(batchId, op->computedState.clippedBounds,
- (BatchBase**)(&targetBatch), &insertBatchIndex);
+ locateInsertIndex(batchId, op->computedState.clippedBounds, (BatchBase**)(&targetBatch),
+ &insertBatchIndex);
if (targetBatch) {
targetBatch->mergeOp(op);
- } else {
+ } else {
// new merging batch
targetBatch = allocator.create<MergingOpBatch>(batchId, op);
mMergingBatchLookup[batchId].insert(std::make_pair(mergeId, targetBatch));
@@ -334,11 +331,11 @@
}
}
-void LayerBuilder::replayBakedOpsImpl(void* arg,
- BakedOpReceiver* unmergedReceivers, MergedOpReceiver* mergedReceivers) const {
+void LayerBuilder::replayBakedOpsImpl(void* arg, BakedOpReceiver* unmergedReceivers,
+ MergedOpReceiver* mergedReceivers) const {
if (renderNode) {
- ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u",
- renderNode->getName(), width, height);
+ ATRACE_FORMAT_BEGIN("Issue HW Layer DisplayList %s %ux%u", renderNode->getName(), width,
+ height);
} else {
ATRACE_BEGIN("flush drawing commands");
}
@@ -348,12 +345,9 @@
if (size > 1 && batch->isMerging()) {
int opId = batch->getOps()[0]->op->opId;
const MergingOpBatch* mergingBatch = static_cast<const MergingOpBatch*>(batch);
- MergedBakedOpList data = {
- batch->getOps().data(),
- size,
- mergingBatch->getClipSideFlags(),
- mergingBatch->getClipRect()
- };
+ MergedBakedOpList data = {batch->getOps().data(), size,
+ mergingBatch->getClipSideFlags(),
+ mergingBatch->getClipRect()};
mergedReceivers[opId](arg, data);
} else {
for (const BakedOpState* op : batch->getOps()) {
@@ -373,13 +367,12 @@
}
void LayerBuilder::dump() const {
- ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)",
- this, width, height, offscreenBuffer, beginLayerOp,
- renderNode, renderNode ? renderNode->getName() : "-");
+ ALOGD("LayerBuilder %p, %ux%u buffer %p, blo %p, rn %p (%s)", this, width, height,
+ offscreenBuffer, beginLayerOp, renderNode, renderNode ? renderNode->getName() : "-");
for (const BatchBase* batch : mBatches) {
batch->dump();
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/LayerBuilder.h b/libs/hwui/LayerBuilder.h
index 4de432c..c799d48 100644
--- a/libs/hwui/LayerBuilder.h
+++ b/libs/hwui/LayerBuilder.h
@@ -20,8 +20,8 @@
#include "Rect.h"
#include "utils/Macros.h"
-#include <vector>
#include <unordered_map>
+#include <vector>
struct SkRect;
@@ -42,22 +42,22 @@
typedef const void* mergeid_t;
namespace OpBatchType {
- enum {
- Bitmap,
- MergedPatch,
- AlphaVertices,
- Vertices,
- AlphaMaskTexture,
- Text,
- ColorText,
- Shadow,
- TextureLayer,
- Functor,
- CopyToLayer,
- CopyFromLayer,
+enum {
+ Bitmap,
+ MergedPatch,
+ AlphaVertices,
+ Vertices,
+ AlphaMaskTexture,
+ Text,
+ ColorText,
+ Shadow,
+ TextureLayer,
+ Functor,
+ CopyToLayer,
+ CopyFromLayer,
- Count // must be last
- };
+ Count // must be last
+};
}
typedef void (*BakedOpReceiver)(void*, const BakedOpState&);
@@ -68,37 +68,36 @@
* for a single FBO/layer.
*/
class LayerBuilder {
-// Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
-PREVENT_COPY_AND_ASSIGN(LayerBuilder);
+ // Prevent copy/assign because users may stash pointer to offscreenBuffer and viewportClip
+ PREVENT_COPY_AND_ASSIGN(LayerBuilder);
+
public:
// Create LayerBuilder for Fbo0
LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect)
- : LayerBuilder(width, height, repaintRect, nullptr, nullptr) {};
+ : LayerBuilder(width, height, repaintRect, nullptr, nullptr){};
// Create LayerBuilder for an offscreen layer, where beginLayerOp is present for a
// saveLayer, renderNode is present for a HW layer.
- LayerBuilder(uint32_t width, uint32_t height,
- const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
+ LayerBuilder(uint32_t width, uint32_t height, const Rect& repaintRect,
+ const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
// iterate back toward target to see if anything drawn since should overlap the new op
// if no target, merging ops still iterate to find similar batch to insert after
- void locateInsertIndex(int batchId, const Rect& clippedBounds,
- BatchBase** targetBatch, size_t* insertBatchIndex) const;
+ void locateInsertIndex(int batchId, const Rect& clippedBounds, BatchBase** targetBatch,
+ size_t* insertBatchIndex) const;
void deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId);
// insertion point of a new batch, will hopefully be immediately after similar batch
// (generally, should be similar shader)
- void deferMergeableOp(LinearAllocator& allocator,
- BakedOpState* op, batchid_t batchId, mergeid_t mergeId);
+ void deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId,
+ mergeid_t mergeId);
void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const;
void deferLayerClear(const Rect& dstRect);
- bool empty() const {
- return mBatches.empty();
- }
+ bool empty() const { return mBatches.empty(); }
void clear();
@@ -114,6 +113,7 @@
// list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps
std::vector<BakedOpState*> activeUnclippedSaveLayers;
+
private:
void onDeferOp(LinearAllocator& allocator, const BakedOpState* bakedState);
void flushLayerClears(LinearAllocator& allocator);
@@ -128,10 +128,10 @@
std::unordered_map<mergeid_t, MergingOpBatch*> mMergingBatchLookup[OpBatchType::Count];
// Maps batch ids to the most recent *non-merging* batch of that id
- OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr };
+ OpBatch* mBatchLookup[OpBatchType::Count] = {nullptr};
std::vector<Rect> mClearRects;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/LayerUpdateQueue.cpp b/libs/hwui/LayerUpdateQueue.cpp
index 95f5cfb..fd5c661 100644
--- a/libs/hwui/LayerUpdateQueue.cpp
+++ b/libs/hwui/LayerUpdateQueue.cpp
@@ -39,5 +39,5 @@
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/LayerUpdateQueue.h b/libs/hwui/LayerUpdateQueue.h
index 38f3596..b14b80c 100644
--- a/libs/hwui/LayerUpdateQueue.h
+++ b/libs/hwui/LayerUpdateQueue.h
@@ -17,12 +17,12 @@
#ifndef ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
#define ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
+#include <utils/StrongPointer.h>
#include "Rect.h"
#include "utils/Macros.h"
-#include <utils/StrongPointer.h>
-#include <vector>
#include <unordered_map>
+#include <vector>
namespace android {
namespace uirenderer {
@@ -31,11 +31,11 @@
class LayerUpdateQueue {
PREVENT_COPY_AND_ASSIGN(LayerUpdateQueue);
+
public:
struct Entry {
Entry(RenderNode* renderNode, const Rect& damage)
- : renderNode(renderNode)
- , damage(damage) {}
+ : renderNode(renderNode), damage(damage) {}
sp<RenderNode> renderNode;
Rect damage;
};
@@ -44,11 +44,12 @@
void enqueueLayerWithDamage(RenderNode* renderNode, Rect dirty);
void clear();
const std::vector<Entry>& entries() const { return mEntries; }
+
private:
std::vector<Entry> mEntries;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
+#endif // ANDROID_HWUI_LAYER_UPDATE_QUEUE_H
diff --git a/libs/hwui/Matrix.cpp b/libs/hwui/Matrix.cpp
index a936661..d84ed32 100644
--- a/libs/hwui/Matrix.cpp
+++ b/libs/hwui/Matrix.cpp
@@ -43,24 +43,24 @@
}
void Matrix4::loadIdentity() {
- data[kScaleX] = 1.0f;
- data[kSkewY] = 0.0f;
- data[2] = 0.0f;
+ data[kScaleX] = 1.0f;
+ data[kSkewY] = 0.0f;
+ data[2] = 0.0f;
data[kPerspective0] = 0.0f;
- data[kSkewX] = 0.0f;
- data[kScaleY] = 1.0f;
- data[6] = 0.0f;
+ data[kSkewX] = 0.0f;
+ data[kScaleY] = 1.0f;
+ data[6] = 0.0f;
data[kPerspective1] = 0.0f;
- data[8] = 0.0f;
- data[9] = 0.0f;
- data[kScaleZ] = 1.0f;
- data[11] = 0.0f;
+ data[8] = 0.0f;
+ data[9] = 0.0f;
+ data[kScaleZ] = 1.0f;
+ data[11] = 0.0f;
- data[kTranslateX] = 0.0f;
- data[kTranslateY] = 0.0f;
- data[kTranslateZ] = 0.0f;
+ data[kTranslateX] = 0.0f;
+ data[kTranslateY] = 0.0f;
+ data[kTranslateZ] = 0.0f;
data[kPerspective2] = 1.0f;
mType = kTypeIdentity | kTypeRectToRect;
@@ -75,7 +75,7 @@
mType = kTypeIdentity;
if (data[kPerspective0] != 0.0f || data[kPerspective1] != 0.0f ||
- data[kPerspective2] != 1.0f) {
+ data[kPerspective2] != 1.0f) {
mType |= kTypePerspective;
}
@@ -105,7 +105,7 @@
// it doesn't preserve rectangles.
if (!(mType & kTypePerspective)) {
if ((isZero(m00) && isZero(m11) && !isZero(m01) && !isZero(m10)) ||
- (isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) {
+ (isZero(m01) && isZero(m10) && !isZero(m00) && !isZero(m11))) {
mType |= kTypeRectToRect;
}
}
@@ -155,17 +155,17 @@
void Matrix4::load(const SkMatrix& v) {
memset(data, 0, sizeof(data));
- data[kScaleX] = v[SkMatrix::kMScaleX];
- data[kSkewX] = v[SkMatrix::kMSkewX];
+ data[kScaleX] = v[SkMatrix::kMScaleX];
+ data[kSkewX] = v[SkMatrix::kMSkewX];
data[kTranslateX] = v[SkMatrix::kMTransX];
- data[kSkewY] = v[SkMatrix::kMSkewY];
- data[kScaleY] = v[SkMatrix::kMScaleY];
+ data[kSkewY] = v[SkMatrix::kMSkewY];
+ data[kScaleY] = v[SkMatrix::kMScaleY];
data[kTranslateY] = v[SkMatrix::kMTransY];
- data[kPerspective0] = v[SkMatrix::kMPersp0];
- data[kPerspective1] = v[SkMatrix::kMPersp1];
- data[kPerspective2] = v[SkMatrix::kMPersp2];
+ data[kPerspective0] = v[SkMatrix::kMPersp0];
+ data[kPerspective1] = v[SkMatrix::kMPersp1];
+ data[kPerspective2] = v[SkMatrix::kMPersp2];
data[kScaleZ] = 1.0f;
@@ -183,10 +183,10 @@
v.reset();
v.set(SkMatrix::kMScaleX, data[kScaleX]);
- v.set(SkMatrix::kMSkewX, data[kSkewX]);
+ v.set(SkMatrix::kMSkewX, data[kSkewX]);
v.set(SkMatrix::kMTransX, data[kTranslateX]);
- v.set(SkMatrix::kMSkewY, data[kSkewY]);
+ v.set(SkMatrix::kMSkewY, data[kSkewY]);
v.set(SkMatrix::kMScaleY, data[kScaleY]);
v.set(SkMatrix::kMTransY, data[kTranslateY]);
@@ -201,13 +201,13 @@
// Reset the matrix
// Unnamed fields are never written to except by
// loadIdentity(), they don't need to be reset
- data[kScaleX] = 1.0f;
- data[kSkewX] = 0.0f;
+ data[kScaleX] = 1.0f;
+ data[kSkewX] = 0.0f;
- data[kScaleY] = 1.0f;
- data[kSkewY] = 0.0f;
+ data[kScaleY] = 1.0f;
+ data[kSkewY] = 0.0f;
- data[kScaleZ] = 1.0f;
+ data[kScaleZ] = 1.0f;
data[kPerspective0] = 0.0f;
data[kPerspective1] = 0.0f;
@@ -215,43 +215,48 @@
// No need to deal with kTranslateZ because isPureTranslate()
// only returns true when the kTranslateZ component is 0
- data[kTranslateX] = -v.data[kTranslateX];
- data[kTranslateY] = -v.data[kTranslateY];
- data[kTranslateZ] = 0.0f;
+ data[kTranslateX] = -v.data[kTranslateX];
+ data[kTranslateY] = -v.data[kTranslateY];
+ data[kTranslateZ] = 0.0f;
// A "pure translate" matrix can be identity or translation
mType = v.getType();
return;
}
- double scale = 1.0 /
- (v.data[kScaleX] * ((double) v.data[kScaleY] * v.data[kPerspective2] -
- (double) v.data[kTranslateY] * v.data[kPerspective1]) +
- v.data[kSkewX] * ((double) v.data[kTranslateY] * v.data[kPerspective0] -
- (double) v.data[kSkewY] * v.data[kPerspective2]) +
- v.data[kTranslateX] * ((double) v.data[kSkewY] * v.data[kPerspective1] -
- (double) v.data[kScaleY] * v.data[kPerspective0]));
+ double scale = 1.0 / (v.data[kScaleX] * ((double)v.data[kScaleY] * v.data[kPerspective2] -
+ (double)v.data[kTranslateY] * v.data[kPerspective1]) +
+ v.data[kSkewX] * ((double)v.data[kTranslateY] * v.data[kPerspective0] -
+ (double)v.data[kSkewY] * v.data[kPerspective2]) +
+ v.data[kTranslateX] * ((double)v.data[kSkewY] * v.data[kPerspective1] -
+ (double)v.data[kScaleY] * v.data[kPerspective0]));
data[kScaleX] = (v.data[kScaleY] * v.data[kPerspective2] -
- v.data[kTranslateY] * v.data[kPerspective1]) * scale;
- data[kSkewX] = (v.data[kTranslateX] * v.data[kPerspective1] -
- v.data[kSkewX] * v.data[kPerspective2]) * scale;
- data[kTranslateX] = (v.data[kSkewX] * v.data[kTranslateY] -
- v.data[kTranslateX] * v.data[kScaleY]) * scale;
+ v.data[kTranslateY] * v.data[kPerspective1]) *
+ scale;
+ data[kSkewX] =
+ (v.data[kTranslateX] * v.data[kPerspective1] - v.data[kSkewX] * v.data[kPerspective2]) *
+ scale;
+ data[kTranslateX] =
+ (v.data[kSkewX] * v.data[kTranslateY] - v.data[kTranslateX] * v.data[kScaleY]) * scale;
- data[kSkewY] = (v.data[kTranslateY] * v.data[kPerspective0] -
- v.data[kSkewY] * v.data[kPerspective2]) * scale;
+ data[kSkewY] =
+ (v.data[kTranslateY] * v.data[kPerspective0] - v.data[kSkewY] * v.data[kPerspective2]) *
+ scale;
data[kScaleY] = (v.data[kScaleX] * v.data[kPerspective2] -
- v.data[kTranslateX] * v.data[kPerspective0]) * scale;
- data[kTranslateY] = (v.data[kTranslateX] * v.data[kSkewY] -
- v.data[kScaleX] * v.data[kTranslateY]) * scale;
+ v.data[kTranslateX] * v.data[kPerspective0]) *
+ scale;
+ data[kTranslateY] =
+ (v.data[kTranslateX] * v.data[kSkewY] - v.data[kScaleX] * v.data[kTranslateY]) * scale;
- data[kPerspective0] = (v.data[kSkewY] * v.data[kPerspective1] -
- v.data[kScaleY] * v.data[kPerspective0]) * scale;
- data[kPerspective1] = (v.data[kSkewX] * v.data[kPerspective0] -
- v.data[kScaleX] * v.data[kPerspective1]) * scale;
- data[kPerspective2] = (v.data[kScaleX] * v.data[kScaleY] -
- v.data[kSkewX] * v.data[kSkewY]) * scale;
+ data[kPerspective0] =
+ (v.data[kSkewY] * v.data[kPerspective1] - v.data[kScaleY] * v.data[kPerspective0]) *
+ scale;
+ data[kPerspective1] =
+ (v.data[kSkewX] * v.data[kPerspective0] - v.data[kScaleX] * v.data[kPerspective1]) *
+ scale;
+ data[kPerspective2] =
+ (v.data[kScaleX] * v.data[kScaleY] - v.data[kSkewX] * v.data[kSkewY]) * scale;
mType = kTypeUnknown;
}
@@ -298,13 +303,13 @@
void Matrix4::loadSkew(float sx, float sy) {
loadIdentity();
- data[kScaleX] = 1.0f;
- data[kSkewX] = sx;
- data[kTranslateX] = 0.0f;
+ data[kScaleX] = 1.0f;
+ data[kSkewX] = sx;
+ data[kTranslateX] = 0.0f;
- data[kSkewY] = sy;
- data[kScaleY] = 1.0f;
- data[kTranslateY] = 0.0f;
+ data[kSkewY] = sy;
+ data[kScaleY] = 1.0f;
+ data[kTranslateY] = 0.0f;
data[kPerspective0] = 0.0f;
data[kPerspective1] = 0.0f;
@@ -320,23 +325,23 @@
loadIdentity();
- data[kScaleX] = c;
- data[kSkewX] = -s;
+ data[kScaleX] = c;
+ data[kSkewX] = -s;
- data[kSkewY] = s;
- data[kScaleY] = c;
+ data[kSkewY] = s;
+ data[kScaleY] = c;
mType = kTypeUnknown;
}
void Matrix4::loadRotate(float angle, float x, float y, float z) {
- data[kPerspective0] = 0.0f;
- data[kPerspective1] = 0.0f;
- data[11] = 0.0f;
- data[kTranslateX] = 0.0f;
- data[kTranslateY] = 0.0f;
- data[kTranslateZ] = 0.0f;
- data[kPerspective2] = 1.0f;
+ data[kPerspective0] = 0.0f;
+ data[kPerspective1] = 0.0f;
+ data[11] = 0.0f;
+ data[kTranslateX] = 0.0f;
+ data[kTranslateY] = 0.0f;
+ data[kTranslateZ] = 0.0f;
+ data[kPerspective2] = 1.0f;
angle *= float(M_PI / 180.0f);
float c = cosf(angle);
@@ -356,27 +361,27 @@
const float ys = y * s;
const float zs = z * s;
- data[kScaleX] = x * x * nc + c;
- data[kSkewX] = xy * nc - zs;
- data[8] = zx * nc + ys;
- data[kSkewY] = xy * nc + zs;
- data[kScaleY] = y * y * nc + c;
- data[9] = yz * nc - xs;
- data[2] = zx * nc - ys;
- data[6] = yz * nc + xs;
- data[kScaleZ] = z * z * nc + c;
+ data[kScaleX] = x * x * nc + c;
+ data[kSkewX] = xy * nc - zs;
+ data[8] = zx * nc + ys;
+ data[kSkewY] = xy * nc + zs;
+ data[kScaleY] = y * y * nc + c;
+ data[9] = yz * nc - xs;
+ data[2] = zx * nc - ys;
+ data[6] = yz * nc + xs;
+ data[kScaleZ] = z * z * nc + c;
mType = kTypeUnknown;
}
void Matrix4::loadMultiply(const Matrix4& u, const Matrix4& v) {
- for (int i = 0 ; i < 4 ; i++) {
+ for (int i = 0; i < 4; i++) {
float x = 0;
float y = 0;
float z = 0;
float w = 0;
- for (int j = 0 ; j < 4 ; j++) {
+ for (int j = 0; j < 4; j++) {
const float e = v.get(i, j);
x += u.get(j, 0) * e;
y += u.get(j, 1) * e;
@@ -412,7 +417,7 @@
}
void Matrix4::mapPoint3d(Vector3& vec) const {
- //TODO: optimize simple case
+ // TODO: optimize simple case
const Vector3 orig(vec);
vec.x = orig.x * data[kScaleX] + orig.y * data[kSkewX] + orig.z * data[8] + data[kTranslateX];
vec.y = orig.x * data[kSkewY] + orig.y * data[kScaleY] + orig.z * data[9] + data[kTranslateY];
@@ -469,16 +474,11 @@
return;
}
- float vertices[] = {
- r.left, r.top,
- r.right, r.top,
- r.right, r.bottom,
- r.left, r.bottom
- };
+ float vertices[] = {r.left, r.top, r.right, r.top, r.right, r.bottom, r.left, r.bottom};
float x, y, z;
- for (int i = 0; i < 8; i+= 2) {
+ for (int i = 0; i < 8; i += 2) {
float px = vertices[i];
float py = vertices[i + 1];
@@ -498,10 +498,14 @@
x = vertices[i];
y = vertices[i + 1];
- if (x < r.left) r.left = x;
- else if (x > r.right) r.right = x;
- if (y < r.top) r.top = y;
- else if (y > r.bottom) r.bottom = y;
+ if (x < r.left)
+ r.left = x;
+ else if (x > r.right)
+ r.right = x;
+ if (y < r.top)
+ r.top = y;
+ else if (y > r.bottom)
+ r.bottom = y;
}
}
@@ -522,5 +526,5 @@
ALOGD("]");
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Matrix.h b/libs/hwui/Matrix.h
index ba9cbbe..f0a3a95 100644
--- a/libs/hwui/Matrix.h
+++ b/libs/hwui/Matrix.h
@@ -18,27 +18,26 @@
#include "Rect.h"
+#include <SkMatrix.h>
#include <cutils/compiler.h>
#include <iomanip>
#include <ostream>
-#include <SkMatrix.h>
namespace android {
namespace uirenderer {
#define SK_MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
-#define SK_MATRIX_ARGS(m) \
- (m)->get(0), (m)->get(1), (m)->get(2), \
- (m)->get(3), (m)->get(4), (m)->get(5), \
- (m)->get(6), (m)->get(7), (m)->get(8)
+#define SK_MATRIX_ARGS(m) \
+ (m)->get(0), (m)->get(1), (m)->get(2), (m)->get(3), (m)->get(4), (m)->get(5), (m)->get(6), \
+ (m)->get(7), (m)->get(8)
-#define MATRIX_4_STRING "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
+#define MATRIX_4_STRING \
+ "[%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]" \
" [%.2f %.2f %.2f %.2f] [%.2f %.2f %.2f %.2f]"
-#define MATRIX_4_ARGS(m) \
- (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], \
- (m)->data[1], (m)->data[5], (m)->data[9], (m)->data[13], \
- (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
- (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15] \
+#define MATRIX_4_ARGS(m) \
+ (m)->data[0], (m)->data[4], (m)->data[8], (m)->data[12], (m)->data[1], (m)->data[5], \
+ (m)->data[9], (m)->data[13], (m)->data[2], (m)->data[6], (m)->data[10], (m)->data[14], \
+ (m)->data[3], (m)->data[7], (m)->data[11], (m)->data[15]
///////////////////////////////////////////////////////////////////////////////
// Classes
@@ -77,21 +76,15 @@
static const int sGeometryMask = 0xf;
- Matrix4() {
- loadIdentity();
- }
+ Matrix4() { loadIdentity(); }
- explicit Matrix4(const float* v) {
- load(v);
- }
+ explicit Matrix4(const float* v) { load(v); }
Matrix4(const SkMatrix& v) { // NOLINT, implicit
load(v);
}
- float operator[](int index) const {
- return data[index];
- }
+ float operator[](int index) const { return data[index]; }
float& operator[](int index) {
mType = kTypeUnknown;
@@ -107,9 +100,7 @@
return !memcmp(&a.data[0], &b.data[0], 16 * sizeof(float));
}
- friend bool operator!=(const Matrix4& a, const Matrix4& b) {
- return !(a == b);
- }
+ friend bool operator!=(const Matrix4& a, const Matrix4& b) { return !(a == b); }
void loadIdentity();
@@ -126,9 +117,7 @@
void loadMultiply(const Matrix4& u, const Matrix4& v);
void loadOrtho(float left, float right, float bottom, float top, float near, float far);
- void loadOrtho(int width, int height) {
- loadOrtho(0, width, height, 0, -1, 1);
- }
+ void loadOrtho(int width, int height) { loadOrtho(0, width, height, 0, -1, 1); }
uint8_t getType() const;
@@ -208,8 +197,8 @@
float mapZ(const Vector3& orig) const;
void mapPoint3d(Vector3& vec) const;
- void mapPoint(float& x, float& y) const; // 2d only
- void mapRect(Rect& r) const; // 2d only
+ void mapPoint(float& x, float& y) const; // 2d only
+ void mapRect(Rect& r) const; // 2d only
float getTranslateX() const;
float getTranslateY() const;
@@ -241,17 +230,13 @@
private:
mutable uint8_t mType;
- inline float get(int i, int j) const {
- return data[i * 4 + j];
- }
+ inline float get(int i, int j) const { return data[i * 4 + j]; }
- inline void set(int i, int j, float v) {
- data[i * 4 + j] = v;
- }
+ inline void set(int i, int j, float v) { data[i * 4 + j] = v; }
uint8_t getGeometryType() const;
-}; // class Matrix4
+}; // class Matrix4
///////////////////////////////////////////////////////////////////////////////
// Types
@@ -259,6 +244,5 @@
typedef Matrix4 mat4;
-}; // namespace uirenderer
-}; // namespace android
-
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/NinePatchUtils.h b/libs/hwui/NinePatchUtils.h
index e989a46..8f866f5 100644
--- a/libs/hwui/NinePatchUtils.h
+++ b/libs/hwui/NinePatchUtils.h
@@ -20,7 +20,7 @@
namespace NinePatchUtils {
static inline void SetLatticeDivs(SkCanvas::Lattice* lattice, const Res_png_9patch& chunk,
- int width, int height) {
+ int width, int height) {
lattice->fXCount = chunk.numXDivs;
lattice->fYCount = chunk.numYDivs;
lattice->fXDivs = chunk.getXDivs();
@@ -54,7 +54,7 @@
}
static inline void SetLatticeFlags(SkCanvas::Lattice* lattice, SkCanvas::Lattice::Flags* flags,
- int numFlags, const Res_png_9patch& chunk) {
+ int numFlags, const Res_png_9patch& chunk) {
lattice->fFlags = flags;
sk_bzero(flags, numFlags * sizeof(SkCanvas::Lattice::Flags));
@@ -92,5 +92,5 @@
}
}
-}; // namespace NinePatchUtils
-}; // namespace android
+}; // namespace NinePatchUtils
+}; // namespace android
diff --git a/libs/hwui/OpDumper.cpp b/libs/hwui/OpDumper.cpp
index f4b7ee0..5d2ccc7 100644
--- a/libs/hwui/OpDumper.cpp
+++ b/libs/hwui/OpDumper.cpp
@@ -34,14 +34,13 @@
op.localMatrix.mapRect(localBounds);
output << sOpNameLut[op.opId] << " " << localBounds;
- if (op.localClip
- && (!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) {
- output << std::fixed << std::setprecision(0)
- << " clip=" << op.localClip->rect
- << " mode=" << (int)op.localClip->mode;
+ if (op.localClip &&
+ (!op.localClip->rect.contains(localBounds) || op.localClip->intersectWithRoot)) {
+ output << std::fixed << std::setprecision(0) << " clip=" << op.localClip->rect
+ << " mode=" << (int)op.localClip->mode;
if (op.localClip->intersectWithRoot) {
- output << " iwr";
+ output << " iwr";
}
}
}
@@ -50,5 +49,5 @@
return sOpNameLut[op.opId];
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpDumper.h b/libs/hwui/OpDumper.h
index a82289c..edbe381 100644
--- a/libs/hwui/OpDumper.h
+++ b/libs/hwui/OpDumper.h
@@ -29,5 +29,5 @@
static const char* opName(const RecordedOp& op);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index 2687410..11432d6 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -17,30 +17,29 @@
#include "OpenGLReadback.h"
#include "Caches.h"
-#include "Image.h"
-#include "GlopBuilder.h"
#include "GlLayer.h"
+#include "GlopBuilder.h"
+#include "Image.h"
#include "renderstate/RenderState.h"
#include "renderthread/EglManager.h"
#include "utils/GLUtils.h"
#include <GLES2/gl2.h>
+#include <gui/Surface.h>
#include <ui/Fence.h>
#include <ui/GraphicBuffer.h>
-#include <gui/Surface.h>
namespace android {
namespace uirenderer {
CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) {
+ SkBitmap* bitmap) {
ATRACE_CALL();
// Setup the source
sp<GraphicBuffer> sourceBuffer;
sp<Fence> sourceFence;
Matrix4 texTransform;
- status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence,
- texTransform.data);
+ status_t err = surface.getLastQueuedBuffer(&sourceBuffer, &sourceFence, texTransform.data);
texTransform.invalidateType();
if (err != NO_ERROR) {
ALOGW("Failed to get last queued buffer, error = %d", err);
@@ -64,7 +63,8 @@
}
CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) {
+ Matrix4& texTransform, const Rect& srcRect,
+ SkBitmap* bitmap) {
mRenderThread.eglManager().initialize();
// TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
// GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
@@ -72,11 +72,11 @@
// Create the EGLImage object that maps the GraphicBuffer
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer();
- EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)graphicBuffer->getNativeBuffer();
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
- EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+ EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, attrs);
if (sourceImage == EGL_NO_IMAGE_KHR) {
ALOGW("eglCreateImageKHR failed (%#x)", eglGetError());
@@ -85,8 +85,8 @@
uint32_t width = graphicBuffer->getWidth();
uint32_t height = graphicBuffer->getHeight();
- CopyResult copyResult = copyImageInto(sourceImage, texTransform, width, height,
- srcRect, bitmap);
+ CopyResult copyResult =
+ copyImageInto(sourceImage, texTransform, width, height, srcRect, bitmap);
// All we're flushing & finishing is the deletion of the texture since
// copyImageInto already did a major flush & finish as an implicit
@@ -105,10 +105,7 @@
}
static float sFlipVInit[16] = {
- 1, 0, 0, 0,
- 0, -1, 0, 0,
- 0, 0, 1, 0,
- 0, 1, 0, 1,
+ 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1,
};
static const Matrix4 sFlipV(sFlipVInit);
@@ -116,19 +113,19 @@
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
-inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState,
- Texture& sourceTexture, const Matrix4& texTransform, const Rect& srcRect,
- SkBitmap* bitmap) {
+inline CopyResult copyTextureInto(Caches& caches, RenderState& renderState, Texture& sourceTexture,
+ const Matrix4& texTransform, const Rect& srcRect,
+ SkBitmap* bitmap) {
int destWidth = bitmap->width();
int destHeight = bitmap->height();
- if (destWidth > caches.maxTextureSize
- || destHeight > caches.maxTextureSize) {
- ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d",
- destWidth, destHeight, caches.maxTextureSize);
+ if (destWidth > caches.maxTextureSize || destHeight > caches.maxTextureSize) {
+ ALOGW("Can't copy surface into bitmap, %dx%d exceeds max texture size %d", destWidth,
+ destHeight, caches.maxTextureSize);
return CopyResult::DestinationInvalid;
}
- if (bitmap->colorType() == kRGBA_F16_SkColorType && !caches.extensions().hasFloatTextures()) {
+ if (bitmap->colorType() == kRGBA_F16_SkColorType &&
+ !caches.extensions().hasRenderableFloatTextures()) {
ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
return CopyResult::DestinationInvalid;
}
@@ -188,10 +185,8 @@
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight,
- 0, format, type, nullptr);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
- GL_TEXTURE_2D, texture, 0);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, destWidth, destHeight, 0, format, type, nullptr);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
{
bool requiresFilter;
@@ -208,15 +203,15 @@
// GLES coordinates.
croppedTexTransform.multiply(sFlipV);
croppedTexTransform.translate(srcRect.left / sourceTexture.width(),
- srcRect.top / sourceTexture.height(), 0);
+ srcRect.top / sourceTexture.height(), 0);
croppedTexTransform.scale(srcRect.getWidth() / sourceTexture.width(),
- srcRect.getHeight() / sourceTexture.height(), 1);
+ srcRect.getHeight() / sourceTexture.height(), 1);
croppedTexTransform.multiply(sFlipV);
- requiresFilter = srcRect.getWidth() != (float) destWidth
- || srcRect.getHeight() != (float) destHeight;
+ requiresFilter = srcRect.getWidth() != (float)destWidth ||
+ srcRect.getHeight() != (float)destHeight;
} else {
- requiresFilter = sourceTexture.width() != (uint32_t) destWidth
- || sourceTexture.height() != (uint32_t) destHeight;
+ requiresFilter = sourceTexture.width() != (uint32_t)destWidth ||
+ sourceTexture.height() != (uint32_t)destHeight;
}
Glop glop;
GlopBuilder(renderState, caches, &glop)
@@ -231,8 +226,7 @@
renderState.render(glop, ortho, false);
// TODO: We should convert to linear space when the target is RGBA16F
- glReadPixels(0, 0, bitmap->width(), bitmap->height(), format,
- type, bitmap->getPixels());
+ glReadPixels(0, 0, bitmap->width(), bitmap->height(), format, type, bitmap->getPixels());
bitmap->notifyPixelsChanged();
}
@@ -245,10 +239,9 @@
return CopyResult::Success;
}
-CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage,
- const Matrix4& imgTransform, int imgWidth, int imgHeight, const Rect& srcRect,
- SkBitmap* bitmap) {
-
+CopyResult OpenGLReadbackImpl::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) {
// If this is a 90 or 270 degree rotation we need to swap width/height
// This is a fuzzy way of checking that.
if (imgTransform[Matrix4::kSkewX] >= 0.5f || imgTransform[Matrix4::kSkewX] <= -0.5f) {
@@ -270,26 +263,25 @@
Texture sourceTexture(caches);
sourceTexture.wrap(sourceTexId, imgWidth, imgHeight, 0, 0 /* total lie */,
- GL_TEXTURE_EXTERNAL_OES);
+ GL_TEXTURE_EXTERNAL_OES);
- CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(),
- sourceTexture, imgTransform, srcRect, bitmap);
+ CopyResult copyResult = copyTextureInto(caches, mRenderThread.renderState(), sourceTexture,
+ imgTransform, srcRect, bitmap);
sourceTexture.deleteTexture();
return copyResult;
}
-bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
- GlLayer& layer, SkBitmap* bitmap) {
+bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
+ SkBitmap* bitmap) {
if (!layer.isRenderable()) {
// layer has never been updated by DeferredLayerUpdater, abort copy
return false;
}
- return CopyResult::Success == copyTextureInto(Caches::getInstance(),
- renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
- Rect(), bitmap);
+ return CopyResult::Success == copyTextureInto(Caches::getInstance(), renderThread.renderState(),
+ layer.getTexture(), layer.getTexTransform(),
+ Rect(), bitmap);
}
-
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/OpenGLReadback.h b/libs/hwui/OpenGLReadback.h
index 403f2e3..ca40738 100644
--- a/libs/hwui/OpenGLReadback.h
+++ b/libs/hwui/OpenGLReadback.h
@@ -30,19 +30,21 @@
class OpenGLReadback : public Readback {
public:
virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) override;
+ SkBitmap* bitmap) override;
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
- SkBitmap* bitmap) override;
+ SkBitmap* bitmap) override;
protected:
explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
virtual ~OpenGLReadback() {}
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) = 0;
+
private:
CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
- const Rect& srcRect, SkBitmap* bitmap);
+ const Rect& srcRect, SkBitmap* bitmap);
};
class OpenGLReadbackImpl : public OpenGLReadback {
@@ -53,12 +55,13 @@
* Copies the layer's contents into the provided bitmap.
*/
static bool copyLayerInto(renderthread::RenderThread& renderThread, GlLayer& layer,
- SkBitmap* bitmap);
+ SkBitmap* bitmap);
protected:
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) override;
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index 922ff7c..77d7bef 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -26,27 +26,14 @@
class Outline {
public:
- enum class Type {
- None = 0,
- Empty = 1,
- ConvexPath = 2,
- RoundRect = 3
- };
+ enum class Type { None = 0, Empty = 1, ConvexPath = 2, RoundRect = 3 };
- Outline()
- : mShouldClip(false)
- , mType(Type::None)
- , mRadius(0)
- , mAlpha(0.0f) {}
+ Outline() : mShouldClip(false), mType(Type::None), mRadius(0), mAlpha(0.0f) {}
void setRoundRect(int left, int top, int right, int bottom, float radius, float alpha) {
mAlpha = alpha;
- if (mType == Type::RoundRect
- && left == mBounds.left
- && right == mBounds.right
- && top == mBounds.top
- && bottom == mBounds.bottom
- && radius == mRadius) {
+ if (mType == Type::RoundRect && left == mBounds.left && right == mBounds.right &&
+ top == mBounds.top && bottom == mBounds.bottom && radius == mRadius) {
// nothing to change, don't do any work
return;
}
@@ -58,8 +45,7 @@
// update mPath to reflect new outline
mPath.reset();
if (MathUtils::isPositive(radius)) {
- mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom),
- radius, radius);
+ mPath.addRoundRect(SkRect::MakeLTRB(left, top, right, bottom), radius, radius);
} else {
mPath.addRect(left, top, right, bottom);
}
@@ -88,21 +74,13 @@
mAlpha = 0.0f;
}
- bool isEmpty() const {
- return mType == Type::Empty;
- }
+ bool isEmpty() const { return mType == Type::Empty; }
- float getAlpha() const {
- return mAlpha;
- }
+ float getAlpha() const { return mAlpha; }
- void setShouldClip(bool clip) {
- mShouldClip = clip;
- }
+ void setShouldClip(bool clip) { mShouldClip = clip; }
- bool getShouldClip() const {
- return mShouldClip;
- }
+ bool getShouldClip() const { return mShouldClip; }
bool willClip() const {
// only round rect outlines can be used for clipping
@@ -129,17 +107,11 @@
return &mPath;
}
- Type getType() const {
- return mType;
- }
+ Type getType() const { return mType; }
- const Rect& getBounds() const {
- return mBounds;
- }
+ const Rect& getBounds() const { return mBounds; }
- float getRadius() const {
- return mRadius;
- }
+ float getRadius() const { return mRadius; }
private:
bool mShouldClip;
diff --git a/libs/hwui/Patch.cpp b/libs/hwui/Patch.cpp
index b471e78..c243dad 100644
--- a/libs/hwui/Patch.cpp
+++ b/libs/hwui/Patch.cpp
@@ -21,8 +21,8 @@
#include "UvMapper.h"
#include "utils/MathUtils.h"
-#include <algorithm>
#include <utils/Log.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -35,10 +35,9 @@
return verticesCount * sizeof(TextureVertex);
}
-Patch::Patch(const float bitmapWidth, const float bitmapHeight,
- float width, float height, const UvMapper& mapper, const Res_png_9patch* patch)
+Patch::Patch(const float bitmapWidth, const float bitmapHeight, float width, float height,
+ const UvMapper& mapper, const Res_png_9patch* patch)
: mColors(patch->getColors()) {
-
int8_t emptyQuads = 0;
const int8_t numColors = patch->numColors;
if (uint8_t(numColors) < sizeof(uint32_t) * 4) {
@@ -121,8 +120,8 @@
v1 += vOffset / bitmapHeight;
if (stepY > 0.0f) {
- generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX,
- width, bitmapWidth, quadCount);
+ generateRow(xDivs, xCount, vertex, y1, y2, v1, v2, stretchX, rescaleX, width,
+ bitmapWidth, quadCount);
}
y1 = y2;
@@ -133,8 +132,8 @@
if (previousStepY != bitmapHeight) {
y2 = height;
- generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX,
- width, bitmapWidth, quadCount);
+ generateRow(xDivs, xCount, vertex, y1, y2, v1, 1.0f, stretchX, rescaleX, width, bitmapWidth,
+ quadCount);
}
if (verticesCount != maxVertices) {
@@ -144,9 +143,9 @@
}
}
-void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
- float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
- float width, float bitmapWidth, uint32_t& quadCount) {
+void Patch::generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1,
+ float y2, float v1, float v2, float stretchX, float rescaleX, float width,
+ float bitmapWidth, uint32_t& quadCount) {
float previousStepX = 0.0f;
float x1 = 0.0f;
@@ -184,8 +183,8 @@
}
}
-void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
- float u1, float v1, float u2, float v2, uint32_t& quadCount) {
+void Patch::generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1,
+ float v1, float u2, float v2, uint32_t& quadCount) {
const uint32_t oldQuadCount = quadCount;
quadCount++;
@@ -226,5 +225,5 @@
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Patch.h b/libs/hwui/Patch.h
index f04416c..a659ed2 100644
--- a/libs/hwui/Patch.h
+++ b/libs/hwui/Patch.h
@@ -39,9 +39,8 @@
class Patch {
public:
- Patch(const float bitmapWidth, const float bitmapHeight,
- float width, float height,
- const UvMapper& mapper, const Res_png_9patch* patch);
+ Patch(const float bitmapWidth, const float bitmapHeight, float width, float height,
+ const UvMapper& mapper, const Res_png_9patch* patch);
/**
* Returns the size of this patch's mesh in bytes.
@@ -58,17 +57,17 @@
GLintptr textureOffset = 0;
private:
- void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex,
- float y1, float y2, float v1, float v2, float stretchX, float rescaleX,
- float width, float bitmapWidth, uint32_t& quadCount);
- void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2,
- float u1, float v1, float u2, float v2, uint32_t& quadCount);
+ void generateRow(const int32_t* xDivs, uint32_t xCount, TextureVertex*& vertex, float y1,
+ float y2, float v1, float v2, float stretchX, float rescaleX, float width,
+ float bitmapWidth, uint32_t& quadCount);
+ void generateQuad(TextureVertex*& vertex, float x1, float y1, float x2, float y2, float u1,
+ float v1, float u2, float v2, uint32_t& quadCount);
const uint32_t* mColors;
UvMapper mUvMapper;
-}; // struct Patch
+}; // struct Patch
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PATCH_H
+#endif // ANDROID_HWUI_PATCH_H
diff --git a/libs/hwui/PatchCache.cpp b/libs/hwui/PatchCache.cpp
index 78c7eb9..673d73c 100644
--- a/libs/hwui/PatchCache.cpp
+++ b/libs/hwui/PatchCache.cpp
@@ -56,7 +56,7 @@
}
int PatchCache::PatchDescription::compare(const PatchCache::PatchDescription& lhs,
- const PatchCache::PatchDescription& rhs) {
+ const PatchCache::PatchDescription& rhs) {
return memcmp(&lhs, &rhs, sizeof(PatchDescription));
}
@@ -115,7 +115,7 @@
void PatchCache::clearGarbage() {
Vector<patch_pair_t> patchesToRemove;
- { // scope for the mutex
+ { // scope for the mutex
Mutex::Autolock _l(mLock);
size_t count = mGarbage.size();
for (size_t i = 0; i < count; i++) {
@@ -123,7 +123,7 @@
remove(patchesToRemove, patch);
// A Res_png_9patch is actually an array of byte that's larger
// than sizeof(Res_png_9patch). It must be freed as an array.
- delete[] (int8_t*) patch;
+ delete[](int8_t*) patch;
}
mGarbage.clear();
}
@@ -153,8 +153,8 @@
}
void PatchCache::createVertexBuffer() {
- mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer,
- mMaxSize, nullptr, GL_DYNAMIC_DRAW);
+ mRenderState.meshState().genOrUpdateMeshBuffer(&mMeshBuffer, mMaxSize, nullptr,
+ GL_DYNAMIC_DRAW);
mSize = 0;
mFreeBlocks = new BufferBlock(0, mMaxSize);
}
@@ -198,11 +198,11 @@
}
// Copy the 9patch mesh in the VBO
- newMesh->positionOffset = (GLintptr) (block->offset);
+ newMesh->positionOffset = (GLintptr)(block->offset);
newMesh->textureOffset = newMesh->positionOffset + kMeshTextureOffset;
mRenderState.meshState().updateMeshBufferSubData(mMeshBuffer, newMesh->positionOffset, size,
- newMesh->vertices.get());
+ newMesh->vertices.get());
// Remove the block since we've used it entirely
if (block->size == size) {
@@ -223,15 +223,15 @@
static const UvMapper sIdentity;
-const Patch* PatchCache::get( const uint32_t bitmapWidth, const uint32_t bitmapHeight,
- const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch) {
-
+const Patch* PatchCache::get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
+ const float pixelWidth, const float pixelHeight,
+ const Res_png_9patch* patch) {
const PatchDescription description(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, patch);
const Patch* mesh = mCache.get(description);
if (!mesh) {
- Patch* newMesh = new Patch(bitmapWidth, bitmapHeight,
- pixelWidth, pixelHeight, sIdentity, patch);
+ Patch* newMesh =
+ new Patch(bitmapWidth, bitmapHeight, pixelWidth, pixelHeight, sIdentity, patch);
if (newMesh->vertices) {
setupMesh(newMesh);
@@ -260,5 +260,5 @@
}
#endif
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PatchCache.h b/libs/hwui/PatchCache.h
index aa746c7..273c3f5 100644
--- a/libs/hwui/PatchCache.h
+++ b/libs/hwui/PatchCache.h
@@ -36,9 +36,9 @@
// Debug
#if DEBUG_PATCHES
- #define PATCH_LOGD(...) ALOGD(__VA_ARGS__)
+#define PATCH_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define PATCH_LOGD(...)
+#define PATCH_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -54,20 +54,14 @@
~PatchCache();
const Patch* get(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
- const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
+ const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch);
void clear();
- uint32_t getSize() const {
- return mSize;
- }
+ uint32_t getSize() const { return mSize; }
- uint32_t getMaxSize() const {
- return mMaxSize;
- }
+ uint32_t getMaxSize() const { return mMaxSize; }
- GLuint getMeshBuffer() const {
- return mMeshBuffer;
- }
+ GLuint getMeshBuffer() const { return mMeshBuffer; }
/**
* Removes the entries associated with the specified 9-patch. This is meant
@@ -81,18 +75,23 @@
*/
void clearGarbage();
-
private:
struct PatchDescription {
- PatchDescription(): mPatch(nullptr), mBitmapWidth(0), mBitmapHeight(0),
- mPixelWidth(0), mPixelHeight(0) {
- }
+ PatchDescription()
+ : mPatch(nullptr)
+ , mBitmapWidth(0)
+ , mBitmapHeight(0)
+ , mPixelWidth(0)
+ , mPixelHeight(0) {}
PatchDescription(const uint32_t bitmapWidth, const uint32_t bitmapHeight,
- const float pixelWidth, const float pixelHeight, const Res_png_9patch* patch):
- mPatch(patch), mBitmapWidth(bitmapWidth), mBitmapHeight(bitmapHeight),
- mPixelWidth(pixelWidth), mPixelHeight(pixelHeight) {
- }
+ const float pixelWidth, const float pixelHeight,
+ const Res_png_9patch* patch)
+ : mPatch(patch)
+ , mBitmapWidth(bitmapWidth)
+ , mBitmapHeight(bitmapHeight)
+ , mPixelWidth(pixelWidth)
+ , mPixelHeight(pixelHeight) {}
hash_t hash() const;
@@ -100,27 +99,20 @@
static int compare(const PatchDescription& lhs, const PatchDescription& rhs);
- bool operator==(const PatchDescription& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const PatchDescription& other) const { return compare(*this, other) == 0; }
- bool operator!=(const PatchDescription& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const PatchDescription& other) const { return compare(*this, other) != 0; }
friend inline int strictly_order_type(const PatchDescription& lhs,
- const PatchDescription& rhs) {
+ const PatchDescription& rhs) {
return PatchDescription::compare(lhs, rhs) < 0;
}
- friend inline int compare_type(const PatchDescription& lhs,
- const PatchDescription& rhs) {
+ friend inline int compare_type(const PatchDescription& lhs, const PatchDescription& rhs) {
return PatchDescription::compare(lhs, rhs);
}
- friend inline hash_t hash_type(const PatchDescription& entry) {
- return entry.hash();
- }
+ friend inline hash_t hash_type(const PatchDescription& entry) { return entry.hash(); }
private:
const Res_png_9patch* mPatch;
@@ -129,7 +121,7 @@
float mPixelWidth;
float mPixelHeight;
- }; // struct PatchDescription
+ }; // struct PatchDescription
/**
* A buffer block represents an empty range in the mesh buffer
@@ -139,14 +131,13 @@
* to track available regions of memory in the VBO.
*/
struct BufferBlock {
- BufferBlock(uint32_t offset, uint32_t size): offset(offset), size(size), next(nullptr) {
- }
+ BufferBlock(uint32_t offset, uint32_t size) : offset(offset), size(size), next(nullptr) {}
uint32_t offset;
uint32_t size;
BufferBlock* next;
- }; // struct BufferBlock
+ }; // struct BufferBlock
typedef Pair<const PatchDescription*, Patch*> patch_pair_t;
@@ -174,7 +165,7 @@
// Garbage tracking, required to handle GC events on the VM side
Vector<Res_png_9patch*> mGarbage;
mutable Mutex mLock;
-}; // class PatchCache
+}; // class PatchCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathCache.cpp b/libs/hwui/PathCache.cpp
index 8d4ae1b..e67c5bd 100644
--- a/libs/hwui/PathCache.cpp
+++ b/libs/hwui/PathCache.cpp
@@ -46,13 +46,14 @@
}
static bool compareRoundRects(const PathDescription::Shape::RoundRect& lhs,
- const PathDescription::Shape::RoundRect& rhs) {
+ const PathDescription::Shape::RoundRect& rhs) {
return compareWidthHeight(lhs, rhs) && lhs.mRx == rhs.mRx && lhs.mRy == rhs.mRy;
}
-static bool compareArcs(const PathDescription::Shape::Arc& lhs, const PathDescription::Shape::Arc& rhs) {
+static bool compareArcs(const PathDescription::Shape::Arc& lhs,
+ const PathDescription::Shape::Arc& rhs) {
return compareWidthHeight(lhs, rhs) && lhs.mStartAngle == rhs.mStartAngle &&
- lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
+ lhs.mSweepAngle == rhs.mSweepAngle && lhs.mUseCenter == rhs.mUseCenter;
}
///////////////////////////////////////////////////////////////////////////////
@@ -91,7 +92,7 @@
hash = JenkinsHashMix(hash, android::hash_type(miter));
hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
hash = JenkinsHashMix(hash, android::hash_type(pathEffect));
- hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape));
return JenkinsHashWhiten(hash);
}
@@ -126,7 +127,7 @@
///////////////////////////////////////////////////////////////////////////////
static void computePathBounds(const SkPath* path, const SkPaint* paint, PathTexture* texture,
- uint32_t& width, uint32_t& height) {
+ uint32_t& width, uint32_t& height) {
const SkRect& bounds = path->getBounds();
const float pathWidth = std::max(bounds.width(), 1.0f);
const float pathHeight = std::max(bounds.height(), 1.0f);
@@ -134,7 +135,7 @@
texture->left = floorf(bounds.fLeft);
texture->top = floorf(bounds.fTop);
- texture->offset = (int) floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
+ texture->offset = (int)floorf(std::max(paint->getStrokeWidth(), 1.0f) * 1.5f + 0.5f);
width = uint32_t(pathWidth + texture->offset * 2.0 + 0.5);
height = uint32_t(pathHeight + texture->offset * 2.0 + 0.5);
@@ -152,12 +153,12 @@
}
static sk_sp<Bitmap> drawPath(const SkPath* path, const SkPaint* paint, PathTexture* texture,
- uint32_t maxTextureSize) {
+ uint32_t maxTextureSize) {
uint32_t width, height;
computePathBounds(path, paint, texture, width, height);
if (width > maxTextureSize || height > maxTextureSize) {
- ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)",
- width, height, maxTextureSize, maxTextureSize);
+ ALOGW("Shape too large to be rendered into a texture (%dx%d, max=%dx%d)", width, height,
+ maxTextureSize, maxTextureSize);
return nullptr;
}
@@ -230,13 +231,13 @@
// to the cache and the size wasn't increased
if (size > mSize) {
ALOGE("Removing path texture of size %d will leave "
- "the cache in an inconsistent state", size);
+ "the cache in an inconsistent state",
+ size);
}
mSize -= size;
}
- PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d",
- texture->id, size, mSize);
+ PATH_LOGD("PathCache::delete name, size, mSize = %d, %d, %d", texture->id, size, mSize);
if (mDebugEnabled) {
ALOGD("Shape deleted, size = %d", size);
}
@@ -258,14 +259,16 @@
void PathCache::trim() {
while (mSize > mMaxSize || mCache.size() > PATH_CACHE_COUNT_LIMIT) {
- LOG_ALWAYS_FATAL_IF(!mCache.size(), "Inconsistent mSize! Ran out of items to remove!"
- " mSize = %u, mMaxSize = %u", mSize, mMaxSize);
+ LOG_ALWAYS_FATAL_IF(!mCache.size(),
+ "Inconsistent mSize! Ran out of items to remove!"
+ " mSize = %u, mMaxSize = %u",
+ mSize, mMaxSize);
mCache.removeOldest();
}
}
-PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath *path,
- const SkPaint* paint) {
+PathTexture* PathCache::addTexture(const PathDescription& entry, const SkPath* path,
+ const SkPaint* paint) {
ATRACE_NAME("Generate Path Texture");
PathTexture* texture = new PathTexture(Caches::getInstance(), path->getGenerationID());
@@ -280,8 +283,8 @@
return texture;
}
-void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap,
- PathTexture* texture, bool addToCache) {
+void PathCache::generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture,
+ bool addToCache) {
generateTexture(bitmap, texture);
// Note here that we upload to a texture even if it's bigger than mMaxSize.
@@ -289,8 +292,7 @@
// immediately on trim, or on any other Path entering the cache.
uint32_t size = texture->width() * texture->height();
mSize += size;
- PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d",
- texture->id, size, mSize);
+ PATH_LOGD("PathCache::get/create: name, size, mSize = %d, %d, %d", texture->id, size, mSize);
if (mDebugEnabled) {
ALOGD("Shape created, size = %d", size);
}
@@ -313,9 +315,8 @@
// Path precaching
///////////////////////////////////////////////////////////////////////////////
-PathCache::PathProcessor::PathProcessor(Caches& caches):
- TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {
-}
+PathCache::PathProcessor::PathProcessor(Caches& caches)
+ : TaskProcessor<sk_sp<Bitmap> >(&caches.tasks), mMaxTextureSize(caches.maxTextureSize) {}
void PathCache::PathProcessor::onProcess(const sp<Task<sk_sp<Bitmap> > >& task) {
PathTask* t = static_cast<PathTask*>(task.get());
@@ -336,7 +337,7 @@
void PathCache::clearGarbage() {
Vector<PathDescription> pathsToRemove;
- { // scope for the mutex
+ { // scope for the mutex
Mutex::Autolock l(mLock);
for (const uint32_t generationID : mGarbage) {
LruCache<PathDescription, PathTexture*>::Iterator iter(mCache);
@@ -433,8 +434,8 @@
// Rounded rects
///////////////////////////////////////////////////////////////////////////////
-PathTexture* PathCache::getRoundRect(float width, float height,
- float rx, float ry, const SkPaint* paint) {
+PathTexture* PathCache::getRoundRect(float width, float height, float rx, float ry,
+ const SkPaint* paint) {
PathDescription entry(ShapeType::RoundRect, paint);
entry.shape.roundRect.mWidth = width;
entry.shape.roundRect.mHeight = height;
@@ -525,8 +526,8 @@
// Arcs
///////////////////////////////////////////////////////////////////////////////
-PathTexture* PathCache::getArc(float width, float height,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint) {
+PathTexture* PathCache::getArc(float width, float height, float startAngle, float sweepAngle,
+ bool useCenter, const SkPaint* paint) {
PathDescription entry(ShapeType::Arc, paint);
entry.shape.arc.mWidth = width;
entry.shape.arc.mHeight = height;
@@ -554,5 +555,5 @@
return texture;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathCache.h b/libs/hwui/PathCache.h
index 7bd190d..28c8bbb 100644
--- a/libs/hwui/PathCache.h
+++ b/libs/hwui/PathCache.h
@@ -47,9 +47,9 @@
// Debug
#if DEBUG_PATHS
- #define PATH_LOGD(...) ALOGD(__VA_ARGS__)
+#define PATH_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define PATH_LOGD(...)
+#define PATH_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -57,11 +57,10 @@
///////////////////////////////////////////////////////////////////////////////
struct PathTexture;
-class PathTask: public Task<sk_sp<Bitmap>> {
+class PathTask : public Task<sk_sp<Bitmap>> {
public:
- PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture):
- path(*path), paint(*paint), texture(texture) {
- }
+ PathTask(const SkPath* path, const SkPaint* paint, PathTexture* texture)
+ : path(*path), paint(*paint), texture(texture) {}
// copied, since input path not guaranteed to survive for duration of task
const SkPath path;
@@ -74,15 +73,10 @@
/**
* Alpha texture used to represent a path.
*/
-struct PathTexture: public Texture {
- PathTexture(Caches& caches, int generation)
- : Texture(caches) {
- this->generation = generation;
- }
+struct PathTexture : public Texture {
+ PathTexture(Caches& caches, int generation) : Texture(caches) { this->generation = generation; }
- ~PathTexture() {
- clearTask();
- }
+ ~PathTexture() { clearTask(); }
/**
* Left coordinate of the path bounds.
@@ -97,13 +91,9 @@
*/
float offset = 0;
- sp<PathTask> task() const {
- return mTask;
- }
+ sp<PathTask> task() const { return mTask; }
- void setTask(const sp<PathTask>& task) {
- mTask = task;
- }
+ void setTask(const sp<PathTask>& task) { mTask = task; }
void clearTask() {
if (mTask != nullptr) {
@@ -113,17 +103,9 @@
private:
sp<PathTask> mTask;
-}; // struct PathTexture
+}; // struct PathTexture
-enum class ShapeType {
- None,
- Rect,
- RoundRect,
- Circle,
- Oval,
- Arc,
- Path
-};
+enum class ShapeType { None, Rect, RoundRect, Circle, Oval, Arc, Path };
struct PathDescription {
HASHABLE_TYPE(PathDescription);
@@ -173,7 +155,7 @@
* Any texture added to the cache causing the cache to grow beyond the maximum
* allowed size will also cause the oldest texture to be kicked out.
*/
-class PathCache: public OnEntryRemoved<PathDescription, PathTexture*> {
+class PathCache : public OnEntryRemoved<PathDescription, PathTexture*> {
public:
PathCache();
~PathCache();
@@ -203,9 +185,9 @@
PathTexture* getOval(float width, float height, const SkPaint* paint);
PathTexture* getRect(float width, float height, const SkPaint* paint);
PathTexture* getArc(float width, float height, float startAngle, float sweepAngle,
- bool useCenter, const SkPaint* paint);
+ bool useCenter, const SkPaint* paint);
PathTexture* get(const SkPath* path, const SkPaint* paint);
- void remove(const SkPath* path, const SkPaint* paint);
+ void remove(const SkPath* path, const SkPaint* paint);
/**
* Removes the specified path. This is meant to be called from threads
@@ -234,19 +216,16 @@
void precache(const SkPath* path, const SkPaint* paint);
private:
- PathTexture* addTexture(const PathDescription& entry,
- const SkPath *path, const SkPaint* paint);
+ PathTexture* addTexture(const PathDescription& entry, const SkPath* path, const SkPaint* paint);
/**
* Generates the texture from a bitmap into the specified texture structure.
*/
void generateTexture(Bitmap& bitmap, Texture* texture);
void generateTexture(const PathDescription& entry, Bitmap& bitmap, PathTexture* texture,
- bool addToCache = true);
+ bool addToCache = true);
- PathTexture* get(const PathDescription& entry) {
- return mCache.get(entry);
- }
+ PathTexture* get(const PathDescription& entry) { return mCache.get(entry); }
/**
* Ensures there is enough space in the cache for a texture of the specified
@@ -258,13 +237,12 @@
void init();
-
- class PathProcessor: public TaskProcessor<sk_sp<Bitmap> > {
+ class PathProcessor : public TaskProcessor<sk_sp<Bitmap>> {
public:
explicit PathProcessor(Caches& caches);
- ~PathProcessor() { }
+ ~PathProcessor() {}
- virtual void onProcess(const sp<Task<sk_sp<Bitmap> > >& task) override;
+ virtual void onProcess(const sp<Task<sk_sp<Bitmap>>>& task) override;
private:
uint32_t mMaxTextureSize;
@@ -281,9 +259,9 @@
std::vector<uint32_t> mGarbage;
mutable Mutex mLock;
-}; // class PathCache
+}; // class PathCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PATH_CACHE_H
+#endif // ANDROID_HWUI_PATH_CACHE_H
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index 2179f14..a48fdfc 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -19,9 +19,9 @@
#include "jni.h"
#include <errno.h>
+#include <stdlib.h>
#include <utils/Log.h>
#include <sstream>
-#include <stdlib.h>
#include <string>
#include <vector>
@@ -36,8 +36,8 @@
// used for floating point numbers' scientific notation.
// Therefore, when searching for next command, we should ignore 'e'
// and 'E'.
- if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0))
- && c != 'e' && c != 'E') {
+ if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) && c != 'e' &&
+ c != 'E') {
return index;
}
index++;
@@ -52,7 +52,8 @@
* @param result the result of the extraction, including the position of the
* the starting position of next number, whether it is ending with a '-'.
*/
-static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s, int start, int end) {
+static void extract(int* outEndPosition, bool* outEndWithNegOrDot, const char* s, int start,
+ int end) {
// Now looking for ' ', ',', '.' or '-' from the start.
int currentIndex = start;
bool foundSeparator = false;
@@ -64,30 +65,30 @@
isExponential = false;
char currentChar = s[currentIndex];
switch (currentChar) {
- case ' ':
- case ',':
- foundSeparator = true;
- break;
- case '-':
- // The negative sign following a 'e' or 'E' is not a separator.
- if (currentIndex != start && !isPrevExponential) {
+ case ' ':
+ case ',':
foundSeparator = true;
- *outEndWithNegOrDot = true;
- }
- break;
- case '.':
- if (!secondDot) {
- secondDot = true;
- } else {
- // This is the second dot, and it is considered as a separator.
- foundSeparator = true;
- *outEndWithNegOrDot = true;
- }
- break;
- case 'e':
- case 'E':
- isExponential = true;
- break;
+ break;
+ case '-':
+ // The negative sign following a 'e' or 'E' is not a separator.
+ if (currentIndex != start && !isPrevExponential) {
+ foundSeparator = true;
+ *outEndWithNegOrDot = true;
+ }
+ break;
+ case '.':
+ if (!secondDot) {
+ secondDot = true;
+ } else {
+ // This is the second dot, and it is considered as a separator.
+ foundSeparator = true;
+ *outEndWithNegOrDot = true;
+ }
+ break;
+ case 'e':
+ case 'E':
+ isExponential = true;
+ break;
}
if (foundSeparator) {
break;
@@ -98,7 +99,8 @@
*outEndPosition = currentIndex;
}
-static float parseFloat(PathParser::ParseResult* result, const char* startPtr, size_t expectedLength) {
+static float parseFloat(PathParser::ParseResult* result, const char* startPtr,
+ size_t expectedLength) {
char* endPtr = NULL;
float currentValue = strtof(startPtr, &endPtr);
if ((currentValue == HUGE_VALF || currentValue == -HUGE_VALF) && errno == ERANGE) {
@@ -122,8 +124,7 @@
* @return true on success
*/
static void getFloats(std::vector<float>* outPoints, PathParser::ParseResult* result,
- const char* pathStr, int start, int end) {
-
+ const char* pathStr, int start, int end) {
if (pathStr[start] == 'z' || pathStr[start] == 'Z') {
return;
}
@@ -138,8 +139,7 @@
extract(&endPosition, &endWithNegOrDot, pathStr, startPosition, end);
if (startPosition < endPosition) {
- float currentValue = parseFloat(result, &pathStr[startPosition],
- end - startPosition);
+ float currentValue = parseFloat(result, &pathStr[startPosition], end - startPosition);
if (result->failureOccurred) {
return;
}
@@ -158,12 +158,12 @@
bool PathParser::isVerbValid(char verb) {
verb = tolower(verb);
- return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q'
- || verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
+ return verb == 'a' || verb == 'c' || verb == 'h' || verb == 'l' || verb == 'm' || verb == 'q' ||
+ verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
}
void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
- const char* pathStr, size_t strLen) {
+ const char* pathStr, size_t strLen) {
if (pathStr == NULL) {
result->failureOccurred = true;
result->failureMessage = "Path string cannot be NULL.";
@@ -188,8 +188,8 @@
getFloats(&points, result, pathStr, start, end);
if (!isVerbValid(pathStr[start])) {
result->failureOccurred = true;
- result->failureMessage = "Invalid pathData. Failure occurred at position "
- + std::to_string(start) + " of path: " + pathStr;
+ result->failureMessage = "Invalid pathData. Failure occurred at position " +
+ std::to_string(start) + " of path: " + pathStr;
}
// If either verb or points is not valid, return immediately.
if (result->failureOccurred) {
@@ -205,8 +205,8 @@
if ((end - start) == 1 && start < strLen) {
if (!isVerbValid(pathStr[start])) {
result->failureOccurred = true;
- result->failureMessage = "Invalid pathData. Failure occurred at position "
- + std::to_string(start) + " of path: " + pathStr;
+ result->failureMessage = "Invalid pathData. Failure occurred at position " +
+ std::to_string(start) + " of path: " + pathStr;
return;
}
data->verbs.push_back(pathStr[start]);
@@ -235,7 +235,8 @@
ALOGD("points are : %s", os.str().c_str());
}
-void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
+void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr,
+ size_t strLen) {
PathData pathData;
getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
if (result->failureOccurred) {
@@ -252,5 +253,5 @@
return;
}
-}; // namespace uirenderer
-}; //namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 5578e8d..e4ec7be 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -20,16 +20,15 @@
#include "VectorDrawable.h"
#include "utils/VectorDrawableUtils.h"
-#include <jni.h>
#include <android/log.h>
#include <cutils/compiler.h>
+#include <jni.h>
#include <string>
namespace android {
namespace uirenderer {
-
class PathParser {
public:
struct ANDROID_API ParseResult {
@@ -40,13 +39,13 @@
* Parse the string literal and create a Skia Path. Return true on success.
*/
ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
- const char* pathStr, size_t strLength);
+ const char* pathStr, size_t strLength);
ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
- const char* pathStr, size_t strLength);
+ const char* pathStr, size_t strLength);
static void dump(const PathData& data);
static bool isVerbValid(char verb);
};
-}; // namespace uirenderer
-}; // namespace android
-#endif //ANDROID_HWUI_PATHPARSER_H
+}; // namespace uirenderer
+}; // namespace android
+#endif // ANDROID_HWUI_PATHPARSER_H
diff --git a/libs/hwui/PathTessellator.cpp b/libs/hwui/PathTessellator.cpp
index 64b2c45..973b1d1 100644
--- a/libs/hwui/PathTessellator.cpp
+++ b/libs/hwui/PathTessellator.cpp
@@ -18,13 +18,12 @@
#define VERTEX_DEBUG 0
#if VERTEX_DEBUG
-#define DEBUG_DUMP_ALPHA_BUFFER() \
- for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
- ALOGD("point %d at %f %f, alpha %f", \
- i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
+#define DEBUG_DUMP_ALPHA_BUFFER() \
+ for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
+ ALOGD("point %d at %f %f, alpha %f", i, buffer[i].x, buffer[i].y, buffer[i].alpha); \
}
-#define DEBUG_DUMP_BUFFER() \
- for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
+#define DEBUG_DUMP_BUFFER() \
+ for (unsigned int i = 0; i < vertexBuffer.getSize(); i++) { \
ALOGD("point %d at %f %f", i, buffer[i].x, buffer[i].y); \
}
#else
@@ -41,13 +40,13 @@
#include <algorithm>
-#include <SkPath.h>
+#include <SkGeometry.h> // WARNING: Internal Skia Header
#include <SkPaint.h>
+#include <SkPath.h>
#include <SkPoint.h>
-#include <SkGeometry.h> // WARNING: Internal Skia Header
-#include <stdlib.h>
#include <stdint.h>
+#include <stdlib.h>
#include <sys/types.h>
#include <utils/Log.h>
@@ -64,8 +63,8 @@
/**
* Extracts the x and y scale from the transform as positive values, and clamps them
*/
-void PathTessellator::extractTessellationScales(const Matrix4& transform,
- float* scaleX, float* scaleY) {
+void PathTessellator::extractTessellationScales(const Matrix4& transform, float* scaleX,
+ float* scaleY) {
if (CC_LIKELY(transform.isPureTranslate())) {
*scaleX = 1.0f;
*scaleY = 1.0f;
@@ -98,9 +97,12 @@
*/
struct PaintInfo {
public:
- PaintInfo(const SkPaint* paint, const mat4& transform) :
- style(paint->getStyle()), cap(paint->getStrokeCap()), isAA(paint->isAntiAlias()),
- halfStrokeWidth(paint->getStrokeWidth() * 0.5f), maxAlpha(1.0f) {
+ PaintInfo(const SkPaint* paint, const mat4& transform)
+ : style(paint->getStyle())
+ , cap(paint->getStrokeCap())
+ , isAA(paint->isAntiAlias())
+ , halfStrokeWidth(paint->getStrokeWidth() * 0.5f)
+ , maxAlpha(1.0f) {
// compute inverse scales
if (CC_LIKELY(transform.isPureTranslate())) {
inverseScaleX = 1.0f;
@@ -113,7 +115,7 @@
}
if (isAA && halfStrokeWidth != 0 && inverseScaleX == inverseScaleY &&
- 2 * halfStrokeWidth < inverseScaleX) {
+ 2 * halfStrokeWidth < inverseScaleX) {
// AA, with non-hairline stroke, width < 1 pixel. Scale alpha and treat as hairline.
maxAlpha *= (2 * halfStrokeWidth) / inverseScaleX;
halfStrokeWidth = 0.0f;
@@ -171,17 +173,17 @@
if (halfStrokeWidth == 0) {
// hairline, outset by (0.5f + fudge factor) in post-scaling space
bounds->outset(fabs(inverseScaleX) * (0.5f + Vertex::GeometryFudgeFactor()),
- fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
+ fabs(inverseScaleY) * (0.5f + Vertex::GeometryFudgeFactor()));
} else {
// non hairline, outset by half stroke width pre-scaled, and fudge factor post scaled
bounds->outset(halfStrokeWidth + fabs(inverseScaleX) * Vertex::GeometryFudgeFactor(),
- halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
+ halfStrokeWidth + fabs(inverseScaleY) * Vertex::GeometryFudgeFactor());
}
}
};
void getFillVerticesFromPerimeter(const std::vector<Vertex>& perimeter,
- VertexBuffer& vertexBuffer) {
+ VertexBuffer& vertexBuffer) {
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size());
int currentIndex = 0;
@@ -206,7 +208,8 @@
* (for a total of perimeter.size() * 2 + 2 vertices)
*/
void getStrokeVerticesFromPerimeter(const PaintInfo& paintInfo,
- const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
+ const std::vector<Vertex>& perimeter,
+ VertexBuffer& vertexBuffer) {
Vertex* buffer = vertexBuffer.alloc<Vertex>(perimeter.size() * 2 + 2);
int currentIndex = 0;
@@ -222,13 +225,11 @@
Vector2 totalOffset = totalOffsetFromNormals(lastNormal, nextNormal);
paintInfo.scaleOffsetForStrokeWidth(totalOffset);
- Vertex::set(&buffer[currentIndex++],
- current->x + totalOffset.x,
- current->y + totalOffset.y);
+ Vertex::set(&buffer[currentIndex++], current->x + totalOffset.x,
+ current->y + totalOffset.y);
- Vertex::set(&buffer[currentIndex++],
- current->x - totalOffset.x,
- current->y - totalOffset.y);
+ Vertex::set(&buffer[currentIndex++], current->x - totalOffset.x,
+ current->y - totalOffset.y);
current = next;
lastNormal = nextNormal;
@@ -242,7 +243,8 @@
}
static inline void storeBeginEnd(const PaintInfo& paintInfo, const Vertex& center,
- const Vector2& normal, Vertex* buffer, int& currentIndex, bool begin) {
+ const Vector2& normal, Vertex* buffer, int& currentIndex,
+ bool begin) {
Vector2 strokeOffset = normal;
paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
@@ -264,7 +266,8 @@
* 2 - can zig-zag across 'extra' vertices at either end, to create round caps
*/
void getStrokeVerticesFromUnclosedVertices(const PaintInfo& paintInfo,
- const std::vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
+ const std::vector<Vertex>& vertices,
+ VertexBuffer& vertexBuffer) {
const int extra = paintInfo.capExtraDivisions();
const int allocSize = (vertices.size() + extra) * 2;
Vertex* buffer = vertexBuffer.alloc<Vertex>(allocSize);
@@ -272,12 +275,9 @@
const int lastIndex = vertices.size() - 1;
if (extra > 0) {
// tessellate both round caps
- float beginTheta = atan2(
- - (vertices[0].x - vertices[1].x),
- vertices[0].y - vertices[1].y);
- float endTheta = atan2(
- - (vertices[lastIndex].x - vertices[lastIndex - 1].x),
- vertices[lastIndex].y - vertices[lastIndex - 1].y);
+ float beginTheta = atan2(-(vertices[0].x - vertices[1].x), vertices[0].y - vertices[1].y);
+ float endTheta = atan2(-(vertices[lastIndex].x - vertices[lastIndex - 1].x),
+ vertices[lastIndex].y - vertices[lastIndex - 1].y);
const float dTheta = PI / (extra + 1);
int capOffset;
@@ -291,16 +291,15 @@
beginTheta += dTheta;
Vector2 beginRadialOffset = {cosf(beginTheta), sinf(beginTheta)};
paintInfo.scaleOffsetForStrokeWidth(beginRadialOffset);
- Vertex::set(&buffer[capOffset],
- vertices[0].x + beginRadialOffset.x,
- vertices[0].y + beginRadialOffset.y);
+ Vertex::set(&buffer[capOffset], vertices[0].x + beginRadialOffset.x,
+ vertices[0].y + beginRadialOffset.y);
endTheta += dTheta;
Vector2 endRadialOffset = {cosf(endTheta), sinf(endTheta)};
paintInfo.scaleOffsetForStrokeWidth(endRadialOffset);
Vertex::set(&buffer[allocSize - 1 - capOffset],
- vertices[lastIndex].x + endRadialOffset.x,
- vertices[lastIndex].y + endRadialOffset.y);
+ vertices[lastIndex].x + endRadialOffset.x,
+ vertices[lastIndex].y + endRadialOffset.y);
}
}
@@ -317,7 +316,7 @@
Vector2 nextNormal = {next->y - current->y, current->x - next->x};
nextNormal.normalize();
- Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal);
+ Vector2 strokeOffset = totalOffsetFromNormals(lastNormal, nextNormal);
paintInfo.scaleOffsetForStrokeWidth(strokeOffset);
Vector2 center = {current->x, current->y};
@@ -344,8 +343,8 @@
* 3 - zig zag back and forth inside the shape to fill it (using perimeter.size() vertices)
*/
void getFillVerticesFromPerimeterAA(const PaintInfo& paintInfo,
- const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer,
- float maxAlpha = 1.0f) {
+ const std::vector<Vertex>& perimeter,
+ VertexBuffer& vertexBuffer, float maxAlpha = 1.0f) {
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(perimeter.size() * 3 + 2);
// generate alpha points - fill Alpha vertex gaps in between each point with
@@ -362,16 +361,13 @@
// AA point offset from original point is that point's normal, such that each side is offset
// by .5 pixels
- Vector2 totalOffset = paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
+ Vector2 totalOffset =
+ paintInfo.deriveAAOffset(totalOffsetFromNormals(lastNormal, nextNormal));
- AlphaVertex::set(&buffer[currentIndex++],
- current->x + totalOffset.x,
- current->y + totalOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[currentIndex++],
- current->x - totalOffset.x,
- current->y - totalOffset.y,
- maxAlpha);
+ AlphaVertex::set(&buffer[currentIndex++], current->x + totalOffset.x,
+ current->y + totalOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[currentIndex++], current->x - totalOffset.x,
+ current->y - totalOffset.y, maxAlpha);
current = next;
lastNormal = nextNormal;
@@ -404,12 +400,11 @@
* getStrokeVerticesFromUnclosedVerticesAA() below.
*/
inline static void storeCapAA(const PaintInfo& paintInfo, const std::vector<Vertex>& vertices,
- AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
+ AlphaVertex* buffer, bool isFirst, Vector2 normal, int offset) {
const int extra = paintInfo.capExtraDivisions();
const int extraOffset = (extra + 1) / 2;
- const int capIndex = isFirst
- ? 2 * offset + 6 + 2 * (extra + extraOffset)
- : offset + 2 + 2 * extraOffset;
+ const int capIndex =
+ isFirst ? 2 * offset + 6 + 2 * (extra + extraOffset) : offset + 2 + 2 * extraOffset;
if (isFirst) normal *= -1;
// TODO: this normal should be scaled by radialScale if extra != 0, see totalOffsetFromNormals()
@@ -437,26 +432,18 @@
referencePoint += rotated;
}
- AlphaVertex::set(&buffer[capIndex + 0],
- referencePoint.x + outerOffset.x + capAAOffset.x,
- referencePoint.y + outerOffset.y + capAAOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[capIndex + 1],
- referencePoint.x + innerOffset.x - capAAOffset.x,
- referencePoint.y + innerOffset.y - capAAOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[capIndex + 0], referencePoint.x + outerOffset.x + capAAOffset.x,
+ referencePoint.y + outerOffset.y + capAAOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[capIndex + 1], referencePoint.x + innerOffset.x - capAAOffset.x,
+ referencePoint.y + innerOffset.y - capAAOffset.y, paintInfo.maxAlpha);
bool isRound = paintInfo.cap == SkPaint::kRound_Cap;
const int postCapIndex = (isRound && isFirst) ? (2 * extraOffset - 2) : capIndex + (2 * extra);
- AlphaVertex::set(&buffer[postCapIndex + 2],
- referencePoint.x - outerOffset.x + capAAOffset.x,
- referencePoint.y - outerOffset.y + capAAOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[postCapIndex + 3],
- referencePoint.x - innerOffset.x - capAAOffset.x,
- referencePoint.y - innerOffset.y - capAAOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[postCapIndex + 2], referencePoint.x - outerOffset.x + capAAOffset.x,
+ referencePoint.y - outerOffset.y + capAAOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[postCapIndex + 3], referencePoint.x - innerOffset.x - capAAOffset.x,
+ referencePoint.y - innerOffset.y - capAAOffset.y, paintInfo.maxAlpha);
if (isRound) {
const float dTheta = PI / (extra + 1);
@@ -475,20 +462,18 @@
AAOffset = paintInfo.deriveAAOffset(radialOffset);
paintInfo.scaleOffsetForStrokeWidth(radialOffset);
AlphaVertex::set(&buffer[capPerimIndex++],
- referencePoint.x + radialOffset.x + AAOffset.x,
- referencePoint.y + radialOffset.y + AAOffset.y,
- 0.0f);
+ referencePoint.x + radialOffset.x + AAOffset.x,
+ referencePoint.y + radialOffset.y + AAOffset.y, 0.0f);
AlphaVertex::set(&buffer[capPerimIndex++],
- referencePoint.x + radialOffset.x - AAOffset.x,
- referencePoint.y + radialOffset.y - AAOffset.y,
- paintInfo.maxAlpha);
+ referencePoint.x + radialOffset.x - AAOffset.x,
+ referencePoint.y + radialOffset.y - AAOffset.y, paintInfo.maxAlpha);
if (isFirst && i == extra - extraOffset) {
- //copy most recent two points to first two points
+ // copy most recent two points to first two points
buffer[0] = buffer[capPerimIndex - 2];
buffer[1] = buffer[capPerimIndex - 1];
- capPerimIndex = 2; // start writing the rest of the round cap at index 2
+ capPerimIndex = 2; // start writing the rest of the round cap at index 2
}
}
@@ -513,7 +498,7 @@
if (isFirst) {
buffer[0] = buffer[postCapIndex + 2];
buffer[1] = buffer[postCapIndex + 3];
- buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
+ buffer[postCapIndex + 4] = buffer[1]; // degenerate tris (the only two!)
buffer[postCapIndex + 5] = buffer[postCapIndex + 1];
} else {
buffer[6 * vertices.size()] = buffer[postCapIndex + 1];
@@ -574,8 +559,8 @@
= 2 + 6 * pts + 6 * roundDivs
*/
void getStrokeVerticesFromUnclosedVerticesAA(const PaintInfo& paintInfo,
- const std::vector<Vertex>& vertices, VertexBuffer& vertexBuffer) {
-
+ const std::vector<Vertex>& vertices,
+ VertexBuffer& vertexBuffer) {
const int extra = paintInfo.capExtraDivisions();
const int allocSize = 6 * vertices.size() + 2 + 6 * extra;
@@ -609,32 +594,20 @@
Vector2 outerOffset = innerOffset + AAOffset;
innerOffset -= AAOffset;
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + outerOffset.x,
- current->y + outerOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + outerOffset.x,
+ current->y + outerOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentAAInnerIndex--],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentAAInnerIndex--],
- current->x - outerOffset.x,
- current->y - outerOffset.y,
- 0.0f);
+ AlphaVertex::set(&buffer[currentAAInnerIndex--], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentAAInnerIndex--], current->x - outerOffset.x,
+ current->y - outerOffset.y, 0.0f);
current = next;
lastNormal = nextNormal;
@@ -646,9 +619,9 @@
DEBUG_DUMP_ALPHA_BUFFER();
}
-
void getStrokeVerticesFromPerimeterAA(const PaintInfo& paintInfo,
- const std::vector<Vertex>& perimeter, VertexBuffer& vertexBuffer) {
+ const std::vector<Vertex>& perimeter,
+ VertexBuffer& vertexBuffer) {
AlphaVertex* buffer = vertexBuffer.alloc<AlphaVertex>(6 * perimeter.size() + 8);
int offset = 2 * perimeter.size() + 3;
@@ -673,32 +646,20 @@
Vector2 outerOffset = innerOffset + AAOffset;
innerOffset -= AAOffset;
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + outerOffset.x,
- current->y + outerOffset.y,
- 0.0f);
- AlphaVertex::set(&buffer[currentAAOuterIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + outerOffset.x,
+ current->y + outerOffset.y, 0.0f);
+ AlphaVertex::set(&buffer[currentAAOuterIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x + innerOffset.x,
- current->y + innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentStrokeIndex++],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x + innerOffset.x,
+ current->y + innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentStrokeIndex++], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentAAInnerIndex++],
- current->x - innerOffset.x,
- current->y - innerOffset.y,
- paintInfo.maxAlpha);
- AlphaVertex::set(&buffer[currentAAInnerIndex++],
- current->x - outerOffset.x,
- current->y - outerOffset.y,
- 0.0f);
+ AlphaVertex::set(&buffer[currentAAInnerIndex++], current->x - innerOffset.x,
+ current->y - innerOffset.y, paintInfo.maxAlpha);
+ AlphaVertex::set(&buffer[currentAAInnerIndex++], current->x - outerOffset.x,
+ current->y - outerOffset.y, 0.0f);
current = next;
lastNormal = nextNormal;
@@ -720,8 +681,8 @@
DEBUG_DUMP_ALPHA_BUFFER();
}
-void PathTessellator::tessellatePath(const SkPath &path, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer) {
+void PathTessellator::tessellatePath(const SkPath& path, const SkPaint* paint,
+ const mat4& transform, VertexBuffer& vertexBuffer) {
ATRACE_CALL();
const PaintInfo paintInfo(paint, transform);
@@ -742,9 +703,9 @@
// force close if we're filling the path, since fill path expects closed perimeter.
bool forceClose = paintInfo.style != SkPaint::kStroke_Style;
PathApproximationInfo approximationInfo(threshInvScaleX, threshInvScaleY,
- OUTLINE_REFINE_THRESHOLD);
- bool wasClosed = approximatePathOutlineVertices(path, forceClose,
- approximationInfo, tempVertices);
+ OUTLINE_REFINE_THRESHOLD);
+ bool wasClosed =
+ approximatePathOutlineVertices(path, forceClose, approximationInfo, tempVertices);
if (!tempVertices.size()) {
// path was empty, return without allocating vertex buffer
@@ -753,8 +714,7 @@
#if VERTEX_DEBUG
for (unsigned int i = 0; i < tempVertices.size(); i++) {
- ALOGD("orig path: point at %f %f",
- tempVertices[i].x, tempVertices[i].y);
+ ALOGD("orig path: point at %f %f", tempVertices[i].x, tempVertices[i].y);
}
#endif
@@ -790,8 +750,8 @@
}
template <class TYPE>
-static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer,
- const float* points, int count, Rect& bounds) {
+static void instanceVertices(VertexBuffer& srcBuffer, VertexBuffer& dstBuffer, const float* points,
+ int count, Rect& bounds) {
bounds.set(points[0], points[1], points[0], points[1]);
int numPoints = count / 2;
@@ -806,7 +766,7 @@
}
void PathTessellator::tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
const PaintInfo paintInfo(paint, transform);
// determine point shape
@@ -823,7 +783,7 @@
// calculate outline
std::vector<Vertex> outlineVertices;
PathApproximationInfo approximationInfo(paintInfo.inverseScaleX, paintInfo.inverseScaleY,
- OUTLINE_REFINE_THRESHOLD);
+ OUTLINE_REFINE_THRESHOLD);
approximatePathOutlineVertices(path, true, approximationInfo, outlineVertices);
if (!outlineVertices.size()) return;
@@ -847,7 +807,7 @@
}
void PathTessellator::tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer) {
+ const mat4& transform, VertexBuffer& vertexBuffer) {
ATRACE_CALL();
const PaintInfo paintInfo(paint, transform);
@@ -900,7 +860,7 @@
///////////////////////////////////////////////////////////////////////////////
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, float threshold,
- std::vector<Vertex>& outputVertices) {
+ std::vector<Vertex>& outputVertices) {
PathApproximationInfo approximationInfo(1.0f, 1.0f, threshold);
return approximatePathOutlineVertices(path, true, approximationInfo, outputVertices);
}
@@ -932,6 +892,7 @@
}
}
}
+
private:
bool initialized = false;
double lastX = 0;
@@ -940,7 +901,8 @@
};
bool PathTessellator::approximatePathOutlineVertices(const SkPath& path, bool forceClose,
- const PathApproximationInfo& approximationInfo, std::vector<Vertex>& outputVertices) {
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices) {
ATRACE_CALL();
// TODO: to support joins other than sharp miter, join vertices should be labelled in the
@@ -950,7 +912,7 @@
SkPath::Verb v;
ClockwiseEnforcer clockwiseEnforcer;
while (SkPath::kDone_Verb != (v = iter.next(pts))) {
- switch (v) {
+ switch (v) {
case SkPath::kMove_Verb:
outputVertices.push_back(Vertex{pts[0].x(), pts[0].y()});
ALOGV("Move to pos %f %f", pts[0].x(), pts[0].y());
@@ -967,22 +929,17 @@
break;
case SkPath::kQuad_Verb:
ALOGV("kQuad_Verb");
- recursiveQuadraticBezierVertices(
- pts[0].x(), pts[0].y(),
- pts[2].x(), pts[2].y(),
- pts[1].x(), pts[1].y(),
- approximationInfo, outputVertices);
+ recursiveQuadraticBezierVertices(pts[0].x(), pts[0].y(), pts[2].x(), pts[2].y(),
+ pts[1].x(), pts[1].y(), approximationInfo,
+ outputVertices);
clockwiseEnforcer.addPoint(pts[1]);
clockwiseEnforcer.addPoint(pts[2]);
break;
case SkPath::kCubic_Verb:
ALOGV("kCubic_Verb");
- recursiveCubicBezierVertices(
- pts[0].x(), pts[0].y(),
- pts[1].x(), pts[1].y(),
- pts[3].x(), pts[3].y(),
- pts[2].x(), pts[2].y(),
- approximationInfo, outputVertices);
+ recursiveCubicBezierVertices(pts[0].x(), pts[0].y(), pts[1].x(), pts[1].y(),
+ pts[3].x(), pts[3].y(), pts[2].x(), pts[2].y(),
+ approximationInfo, outputVertices);
clockwiseEnforcer.addPoint(pts[1]);
clockwiseEnforcer.addPoint(pts[2]);
clockwiseEnforcer.addPoint(pts[3]);
@@ -990,37 +947,33 @@
case SkPath::kConic_Verb: {
ALOGV("kConic_Verb");
SkAutoConicToQuads converter;
- const SkPoint* quads = converter.computeQuads(pts, iter.conicWeight(),
- approximationInfo.thresholdForConicQuads);
+ const SkPoint* quads = converter.computeQuads(
+ pts, iter.conicWeight(), approximationInfo.thresholdForConicQuads);
for (int i = 0; i < converter.countQuads(); ++i) {
const int offset = 2 * i;
- recursiveQuadraticBezierVertices(
- quads[offset].x(), quads[offset].y(),
- quads[offset+2].x(), quads[offset+2].y(),
- quads[offset+1].x(), quads[offset+1].y(),
- approximationInfo, outputVertices);
+ recursiveQuadraticBezierVertices(quads[offset].x(), quads[offset].y(),
+ quads[offset + 2].x(), quads[offset + 2].y(),
+ quads[offset + 1].x(), quads[offset + 1].y(),
+ approximationInfo, outputVertices);
}
clockwiseEnforcer.addPoint(pts[1]);
clockwiseEnforcer.addPoint(pts[2]);
break;
}
default:
- static_assert(SkPath::kMove_Verb == 0
- && SkPath::kLine_Verb == 1
- && SkPath::kQuad_Verb == 2
- && SkPath::kConic_Verb == 3
- && SkPath::kCubic_Verb == 4
- && SkPath::kClose_Verb == 5
- && SkPath::kDone_Verb == 6,
- "Path enum changed, new types may have been added");
+ static_assert(SkPath::kMove_Verb == 0 && SkPath::kLine_Verb == 1 &&
+ SkPath::kQuad_Verb == 2 && SkPath::kConic_Verb == 3 &&
+ SkPath::kCubic_Verb == 4 && SkPath::kClose_Verb == 5 &&
+ SkPath::kDone_Verb == 6,
+ "Path enum changed, new types may have been added");
break;
- }
+ }
}
bool wasClosed = false;
int size = outputVertices.size();
if (size >= 2 && outputVertices[0].x == outputVertices[size - 1].x &&
- outputVertices[0].y == outputVertices[size - 1].y) {
+ outputVertices[0].y == outputVertices[size - 1].y) {
outputVertices.pop_back();
wasClosed = true;
}
@@ -1045,19 +998,17 @@
return info.thresholdSquared * scale;
}
-void PathTessellator::recursiveCubicBezierVertices(
- float p1x, float p1y, float c1x, float c1y,
- float p2x, float p2y, float c2x, float c2y,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex>& outputVertices, int depth) {
+void PathTessellator::recursiveCubicBezierVertices(float p1x, float p1y, float c1x, float c1y,
+ float p2x, float p2y, float c2x, float c2y,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices, int depth) {
float dx = p2x - p1x;
float dy = p2y - p1y;
float d1 = fabs((c1x - p2x) * dy - (c1y - p2y) * dx);
float d2 = fabs((c2x - p2x) * dy - (c2y - p2y) * dx);
float d = d1 + d2;
- if (depth >= MAX_DEPTH
- || d * d <= getThreshold(approximationInfo, dx, dy)) {
+ if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) {
// below thresh, draw line by adding endpoint
outputVertices.push_back(Vertex{p2x, p2y});
} else {
@@ -1078,30 +1029,23 @@
float mx = (p1c1c2x + p2c1c2x) * 0.5f;
float my = (p1c1c2y + p2c1c2y) * 0.5f;
- recursiveCubicBezierVertices(
- p1x, p1y, p1c1x, p1c1y,
- mx, my, p1c1c2x, p1c1c2y,
- approximationInfo, outputVertices, depth + 1);
- recursiveCubicBezierVertices(
- mx, my, p2c1c2x, p2c1c2y,
- p2x, p2y, p2c2x, p2c2y,
- approximationInfo, outputVertices, depth + 1);
+ recursiveCubicBezierVertices(p1x, p1y, p1c1x, p1c1y, mx, my, p1c1c2x, p1c1c2y,
+ approximationInfo, outputVertices, depth + 1);
+ recursiveCubicBezierVertices(mx, my, p2c1c2x, p2c1c2y, p2x, p2y, p2c2x, p2c2y,
+ approximationInfo, outputVertices, depth + 1);
}
}
void PathTessellator::recursiveQuadraticBezierVertices(
- float ax, float ay,
- float bx, float by,
- float cx, float cy,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex>& outputVertices, int depth) {
+ float ax, float ay, float bx, float by, float cx, float cy,
+ const PathApproximationInfo& approximationInfo, std::vector<Vertex>& outputVertices,
+ int depth) {
float dx = bx - ax;
float dy = by - ay;
// d is the cross product of vector (B-A) and (C-B).
float d = (cx - bx) * dy - (cy - by) * dx;
- if (depth >= MAX_DEPTH
- || d * d <= getThreshold(approximationInfo, dx, dy)) {
+ if (depth >= MAX_DEPTH || d * d <= getThreshold(approximationInfo, dx, dy)) {
// below thresh, draw line by adding endpoint
outputVertices.push_back(Vertex{bx, by});
} else {
@@ -1114,12 +1058,12 @@
float mx = (acx + bcx) * 0.5f;
float my = (acy + bcy) * 0.5f;
- recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy,
- approximationInfo, outputVertices, depth + 1);
- recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy,
- approximationInfo, outputVertices, depth + 1);
+ recursiveQuadraticBezierVertices(ax, ay, mx, my, acx, acy, approximationInfo,
+ outputVertices, depth + 1);
+ recursiveQuadraticBezierVertices(mx, my, bx, by, bcx, bcy, approximationInfo,
+ outputVertices, depth + 1);
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PathTessellator.h b/libs/hwui/PathTessellator.h
index cddfb04..ed26832 100644
--- a/libs/hwui/PathTessellator.h
+++ b/libs/hwui/PathTessellator.h
@@ -39,11 +39,10 @@
*/
struct PathApproximationInfo {
PathApproximationInfo(float invScaleX, float invScaleY, float pixelThreshold)
- : thresholdSquared(pixelThreshold * pixelThreshold)
- , sqrInvScaleX(invScaleX * invScaleX)
- , sqrInvScaleY(invScaleY * invScaleY)
- , thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f) {
- };
+ : thresholdSquared(pixelThreshold * pixelThreshold)
+ , sqrInvScaleX(invScaleX * invScaleX)
+ , sqrInvScaleY(invScaleY * invScaleY)
+ , thresholdForConicQuads(pixelThreshold * std::min(invScaleX, invScaleY) / 2.0f){};
const float thresholdSquared;
const float sqrInvScaleX;
@@ -64,7 +63,8 @@
static void extractTessellationScales(const Matrix4& transform, float* scaleX, float* scaleY);
/**
- * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a single
+ * Populates a VertexBuffer with a tessellated approximation of the input convex path, as a
+ * single
* triangle strip. Note: joins are not currently supported.
*
* @param path The path to be approximated
@@ -74,8 +74,8 @@
* vertex approximation, and correct AA ramp offsetting.
* @param vertexBuffer The output buffer
*/
- static void tessellatePath(const SkPath& path, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer);
+ static void tessellatePath(const SkPath& path, const SkPaint* paint, const mat4& transform,
+ VertexBuffer& vertexBuffer);
/**
* Populates a VertexBuffer with a tessellated approximation of points as a single triangle
@@ -84,12 +84,13 @@
* @param points The center vertices of the points to be drawn
* @param count The number of floats making up the point vertices
* @param paint The paint the points will be drawn with indicating AA, stroke width & cap
- * @param transform The transform the points will be drawn with, used to drive stretch-aware path
+ * @param transform The transform the points will be drawn with, used to drive stretch-aware
+ * path
* vertex approximation, and correct AA ramp offsetting
* @param vertexBuffer The output buffer
*/
static void tessellatePoints(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer);
+ const mat4& transform, VertexBuffer& vertexBuffer);
/**
* Populates a VertexBuffer with a tessellated approximation of lines as a single triangle
@@ -98,12 +99,13 @@
* @param points Pairs of endpoints defining the lines to be drawn
* @param count The number of floats making up the line vertices
* @param paint The paint the lines will be drawn with indicating AA, stroke width & cap
- * @param transform The transform the points will be drawn with, used to drive stretch-aware path
+ * @param transform The transform the points will be drawn with, used to drive stretch-aware
+ * path
* vertex approximation, and correct AA ramp offsetting
* @param vertexBuffer The output buffer
*/
static void tessellateLines(const float* points, int count, const SkPaint* paint,
- const mat4& transform, VertexBuffer& vertexBuffer);
+ const mat4& transform, VertexBuffer& vertexBuffer);
/**
* Approximates a convex outline into a clockwise Vector of 2d vertices.
@@ -112,38 +114,35 @@
* @param threshold The threshold of acceptable error (in pixels) when approximating
* @param outputVertices An empty Vector which will be populated with the output
*/
- static bool approximatePathOutlineVertices(const SkPath &path, float threshold,
- std::vector<Vertex> &outputVertices);
+ static bool approximatePathOutlineVertices(const SkPath& path, float threshold,
+ std::vector<Vertex>& outputVertices);
private:
- static bool approximatePathOutlineVertices(const SkPath &path, bool forceClose,
- const PathApproximationInfo& approximationInfo, std::vector<Vertex> &outputVertices);
+ static bool approximatePathOutlineVertices(const SkPath& path, bool forceClose,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices);
-/*
- endpoints a & b,
- control c
- */
- static void recursiveQuadraticBezierVertices(
- float ax, float ay,
- float bx, float by,
- float cx, float cy,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex> &outputVertices, int depth = 0);
+ /*
+ endpoints a & b,
+ control c
+ */
+ static void recursiveQuadraticBezierVertices(float ax, float ay, float bx, float by, float cx,
+ float cy,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices,
+ int depth = 0);
-/*
- endpoints p1, p2
- control c1, c2
- */
- static void recursiveCubicBezierVertices(
- float p1x, float p1y,
- float c1x, float c1y,
- float p2x, float p2y,
- float c2x, float c2y,
- const PathApproximationInfo& approximationInfo,
- std::vector<Vertex> &outputVertices, int depth = 0);
+ /*
+ endpoints p1, p2
+ control c1, c2
+ */
+ static void recursiveCubicBezierVertices(float p1x, float p1y, float c1x, float c1y, float p2x,
+ float p2y, float c2x, float c2y,
+ const PathApproximationInfo& approximationInfo,
+ std::vector<Vertex>& outputVertices, int depth = 0);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PATH_TESSELLATOR_H
+#endif // ANDROID_HWUI_PATH_TESSELLATOR_H
diff --git a/libs/hwui/PixelBuffer.cpp b/libs/hwui/PixelBuffer.cpp
index 2a96b69..910a988 100644
--- a/libs/hwui/PixelBuffer.cpp
+++ b/libs/hwui/PixelBuffer.cpp
@@ -31,7 +31,7 @@
// CPU pixel buffer
///////////////////////////////////////////////////////////////////////////////
-class CpuPixelBuffer: public PixelBuffer {
+class CpuPixelBuffer : public PixelBuffer {
public:
CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
@@ -48,8 +48,7 @@
CpuPixelBuffer::CpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
: PixelBuffer(format, width, height)
- , mBuffer(new uint8_t[width * height * formatSize(format)]) {
-}
+ , mBuffer(new uint8_t[width * height * formatSize(format)]) {}
uint8_t* CpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
@@ -63,15 +62,15 @@
}
void CpuPixelBuffer::upload(uint32_t x, uint32_t y, uint32_t width, uint32_t height, int offset) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height,
- mFormat, GL_UNSIGNED_BYTE, &mBuffer[offset]);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
+ &mBuffer[offset]);
}
///////////////////////////////////////////////////////////////////////////////
// GPU pixel buffer
///////////////////////////////////////////////////////////////////////////////
-class GpuPixelBuffer: public PixelBuffer {
+class GpuPixelBuffer : public PixelBuffer {
public:
GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height);
~GpuPixelBuffer();
@@ -89,11 +88,10 @@
Caches& mCaches;
};
-GpuPixelBuffer::GpuPixelBuffer(GLenum format,
- uint32_t width, uint32_t height)
+GpuPixelBuffer::GpuPixelBuffer(GLenum format, uint32_t width, uint32_t height)
: PixelBuffer(format, width, height)
, mMappedPointer(nullptr)
- , mCaches(Caches::getInstance()){
+ , mCaches(Caches::getInstance()) {
glGenBuffers(1, &mBuffer);
mCaches.pixelBufferState().bind(mBuffer);
@@ -108,7 +106,7 @@
uint8_t* GpuPixelBuffer::map(AccessMode mode) {
if (mAccessMode == kAccessMode_None) {
mCaches.pixelBufferState().bind(mBuffer);
- mMappedPointer = (uint8_t*) glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
+ mMappedPointer = (uint8_t*)glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, getSize(), mode);
if (CC_UNLIKELY(!mMappedPointer)) {
GLUtils::dumpGLErrors();
LOG_ALWAYS_FATAL("Failed to map PBO");
@@ -138,8 +136,8 @@
// If the buffer is not mapped, unmap() will not bind it
mCaches.pixelBufferState().bind(mBuffer);
unmap();
- glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat,
- GL_UNSIGNED_BYTE, reinterpret_cast<void*>(offset));
+ glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, width, height, mFormat, GL_UNSIGNED_BYTE,
+ reinterpret_cast<void*>(offset));
mCaches.pixelBufferState().unbind();
}
@@ -147,13 +145,12 @@
// Factory
///////////////////////////////////////////////////////////////////////////////
-PixelBuffer* PixelBuffer::create(GLenum format,
- uint32_t width, uint32_t height, BufferType type) {
+PixelBuffer* PixelBuffer::create(GLenum format, uint32_t width, uint32_t height, BufferType type) {
if (type == kBufferType_Auto && Caches::getInstance().gpuPixelBuffersEnabled) {
return new GpuPixelBuffer(format, width, height);
}
return new CpuPixelBuffer(format, width, height);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/PixelBuffer.h b/libs/hwui/PixelBuffer.h
index 77d5e41..e7e341b 100644
--- a/libs/hwui/PixelBuffer.h
+++ b/libs/hwui/PixelBuffer.h
@@ -45,10 +45,7 @@
*/
class PixelBuffer {
public:
- enum BufferType {
- kBufferType_Auto,
- kBufferType_CPU
- };
+ enum BufferType { kBufferType_Auto, kBufferType_CPU };
enum AccessMode {
kAccessMode_None = 0,
@@ -66,17 +63,14 @@
* a CPU or GPU buffer.
*/
static PixelBuffer* create(GLenum format, uint32_t width, uint32_t height,
- BufferType type = kBufferType_Auto);
+ BufferType type = kBufferType_Auto);
- virtual ~PixelBuffer() {
- }
+ virtual ~PixelBuffer() {}
/**
* Returns the format of this render buffer.
*/
- GLenum getFormat() const {
- return mFormat;
- }
+ GLenum getFormat() const { return mFormat; }
/**
* Maps this before with the specified access mode. This method
@@ -95,9 +89,7 @@
* Returns the current access mode for this buffer. If the buffer
* is not mapped, this method returns kAccessMode_None.
*/
- AccessMode getAccessMode() const {
- return mAccessMode;
- }
+ AccessMode getAccessMode() const { return mAccessMode; }
/**
* Upload the specified rectangle of this pixel buffer as a
@@ -121,23 +113,17 @@
/**
* Returns the width of the render buffer in pixels.
*/
- uint32_t getWidth() const {
- return mWidth;
- }
+ uint32_t getWidth() const { return mWidth; }
/**
* Returns the height of the render buffer in pixels.
*/
- uint32_t getHeight() const {
- return mHeight;
- }
+ uint32_t getHeight() const { return mHeight; }
/**
* Returns the size of this pixel buffer in bytes.
*/
- uint32_t getSize() const {
- return mWidth * mHeight * formatSize(mFormat);
- }
+ uint32_t getSize() const { return mWidth * mHeight * formatSize(mFormat); }
/**
* Returns the offset of a pixel in this pixel buffer, in bytes.
@@ -178,7 +164,7 @@
return 3;
}
- ALOGE("unsupported format: %d",format);
+ ALOGE("unsupported format: %d", format);
return 0;
}
@@ -187,9 +173,8 @@
* Creates a new render buffer in the specified format and dimensions.
* The format must be GL_ALPHA or GL_RGBA.
*/
- PixelBuffer(GLenum format, uint32_t width, uint32_t height):
- mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {
- }
+ PixelBuffer(GLenum format, uint32_t width, uint32_t height)
+ : mFormat(format), mWidth(width), mHeight(height), mAccessMode(kAccessMode_None) {}
/**
* Unmaps this buffer, if needed. After the buffer is unmapped,
@@ -205,9 +190,9 @@
AccessMode mAccessMode;
-}; // class PixelBuffer
+}; // class PixelBuffer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PIXEL_BUFFER_H
+#endif // ANDROID_HWUI_PIXEL_BUFFER_H
diff --git a/libs/hwui/ProfileData.cpp b/libs/hwui/ProfileData.cpp
index a295c5d..b392ecd 100644
--- a/libs/hwui/ProfileData.cpp
+++ b/libs/hwui/ProfileData.cpp
@@ -22,11 +22,8 @@
namespace uirenderer {
static const char* JANK_TYPE_NAMES[] = {
- "Missed Vsync",
- "High input latency",
- "Slow UI thread",
- "Slow bitmap uploads",
- "Slow issue draw commands",
+ "Missed Vsync", "High input latency", "Slow UI thread",
+ "Slow bitmap uploads", "Slow issue draw commands",
};
// The bucketing algorithm controls so to speak
@@ -54,10 +51,8 @@
// index = threshold + (amountAboveThreshold / 2)
// However if index is <= this will do nothing. It will underflow, do
// a right shift by 0 (no-op), then overflow back to the original value
- index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals))
- + kBucket4msIntervals;
- index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals))
- + kBucket2msIntervals;
+ index = ((index - kBucket4msIntervals) >> (index > kBucket4msIntervals)) + kBucket4msIntervals;
+ index = ((index - kBucket2msIntervals) >> (index > kBucket2msIntervals)) + kBucket2msIntervals;
// If index was < minThreshold at the start of all this it's going to
// be a pretty garbage value right now. However, mask is 0 so we'll end
// up with the desired result of 0.
@@ -101,8 +96,7 @@
mJankFrameCount += other.mJankFrameCount;
mTotalFrameCount >>= divider;
mTotalFrameCount += other.mTotalFrameCount;
- if (mStatStartTime > other.mStatStartTime
- || mStatStartTime == 0) {
+ if (mStatStartTime > other.mStatStartTime || mStatStartTime == 0) {
mStatStartTime = other.mStatStartTime;
}
}
@@ -111,7 +105,7 @@
dprintf(fd, "\nStats since: %" PRIu64 "ns", mStatStartTime);
dprintf(fd, "\nTotal frames rendered: %u", mTotalFrameCount);
dprintf(fd, "\nJanky frames: %u (%.2f%%)", mJankFrameCount,
- (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+ (float)mJankFrameCount / (float)mTotalFrameCount * 100.0f);
dprintf(fd, "\n50th percentile: %ums", findPercentile(50));
dprintf(fd, "\n90th percentile: %ums", findPercentile(90));
dprintf(fd, "\n95th percentile: %ums", findPercentile(95));
diff --git a/libs/hwui/ProfileData.h b/libs/hwui/ProfileData.h
index d53ee29..1e688ab 100644
--- a/libs/hwui/ProfileData.h
+++ b/libs/hwui/ProfileData.h
@@ -70,8 +70,8 @@
void histogramForEach(const std::function<void(HistogramEntry)>& callback) const;
constexpr static int HistogramSize() {
- return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value
- + std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
+ return std::tuple_size<decltype(ProfileData::mFrameCounts)>::value +
+ std::tuple_size<decltype(ProfileData::mSlowFrameCounts)>::value;
}
// Visible for testing
@@ -82,7 +82,7 @@
// Open our guts up to unit tests
friend class MockProfileData;
- std::array <uint32_t, NUM_BUCKETS> mJankTypeCounts;
+ std::array<uint32_t, NUM_BUCKETS> mJankTypeCounts;
// See comments on kBucket* constants for what this holds
std::array<uint32_t, 57> mFrameCounts;
// Holds a histogram of frame times in 50ms increments from 150ms to 5s
@@ -106,4 +106,3 @@
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/ProfileDataContainer.cpp b/libs/hwui/ProfileDataContainer.cpp
index 70a77ed..8e0b4e2 100644
--- a/libs/hwui/ProfileDataContainer.cpp
+++ b/libs/hwui/ProfileDataContainer.cpp
@@ -18,8 +18,8 @@
#include <errno.h>
-#include <log/log.h>
#include <cutils/ashmem.h>
+#include <log/log.h>
#include <sys/mman.h>
@@ -52,21 +52,20 @@
int regionSize = ashmem_get_size_region(ashmemfd);
if (regionSize < 0) {
int err = errno;
- ALOGW("Failed to get ashmem region size from fd %d, err %d %s", ashmemfd, err, strerror(err));
+ ALOGW("Failed to get ashmem region size from fd %d, err %d %s", ashmemfd, err,
+ strerror(err));
return;
}
if (regionSize < static_cast<int>(sizeof(ProfileData))) {
- ALOGW("Ashmem region is too small! Received %d, required %u",
- regionSize, static_cast<unsigned int>(sizeof(ProfileData)));
+ ALOGW("Ashmem region is too small! Received %d, required %u", regionSize,
+ static_cast<unsigned int>(sizeof(ProfileData)));
return;
}
ProfileData* newData = reinterpret_cast<ProfileData*>(
- mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE,
- MAP_SHARED, ashmemfd, 0));
+ mmap(NULL, sizeof(ProfileData), PROT_READ | PROT_WRITE, MAP_SHARED, ashmemfd, 0));
if (newData == MAP_FAILED) {
int err = errno;
- ALOGW("Failed to move profile data to ashmem fd %d, error = %d",
- ashmemfd, err);
+ ALOGW("Failed to move profile data to ashmem fd %d, error = %d", ashmemfd, err);
return;
}
diff --git a/libs/hwui/ProfileDataContainer.h b/libs/hwui/ProfileDataContainer.h
index d2de241..a398694 100644
--- a/libs/hwui/ProfileDataContainer.h
+++ b/libs/hwui/ProfileDataContainer.h
@@ -24,6 +24,7 @@
class ProfileDataContainer {
PREVENT_COPY_AND_ASSIGN(ProfileDataContainer);
+
public:
explicit ProfileDataContainer() {}
diff --git a/libs/hwui/ProfileRenderer.cpp b/libs/hwui/ProfileRenderer.cpp
index 0ad484c..8a00ffa 100644
--- a/libs/hwui/ProfileRenderer.cpp
+++ b/libs/hwui/ProfileRenderer.cpp
@@ -20,7 +20,7 @@
namespace uirenderer {
void ProfileRenderer::drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) {
+ const SkPaint& paint) {
mRenderer.drawRect(left, top, right, bottom, &paint);
}
diff --git a/libs/hwui/ProfileRenderer.h b/libs/hwui/ProfileRenderer.h
index b9e586f..5c8bb25 100644
--- a/libs/hwui/ProfileRenderer.h
+++ b/libs/hwui/ProfileRenderer.h
@@ -23,9 +23,7 @@
class ProfileRenderer : public IProfileRenderer {
public:
- ProfileRenderer(BakedOpRenderer& renderer)
- : mRenderer(renderer) {
- }
+ ProfileRenderer(BakedOpRenderer& renderer) : mRenderer(renderer) {}
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/Program.cpp b/libs/hwui/Program.cpp
index e43b80d..052798b 100644
--- a/libs/hwui/Program.cpp
+++ b/libs/hwui/Program.cpp
@@ -151,7 +151,7 @@
}
void Program::set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
- const mat4& transformMatrix, bool offset) {
+ const mat4& transformMatrix, bool offset) {
if (projectionMatrix != mProjection || offset != mOffset) {
if (CC_LIKELY(!offset)) {
glUniformMatrix4fv(projection, 1, GL_FALSE, &projectionMatrix.data[0]);
@@ -195,5 +195,5 @@
mUse = false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h
index 2becfcb..dcc2bd4 100644
--- a/libs/hwui/Program.h
+++ b/libs/hwui/Program.h
@@ -39,25 +39,25 @@
// Debug
#if DEBUG_PROGRAMS
- #define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
+#define PROGRAM_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define PROGRAM_LOGD(...)
+#define PROGRAM_LOGD(...)
#endif
#define COLOR_COMPONENT_THRESHOLD 1.0f
#define COLOR_COMPONENT_INV_THRESHOLD 0.0f
-#define PROGRAM_KEY_TEXTURE 0x01
-#define PROGRAM_KEY_A8_TEXTURE 0x02
-#define PROGRAM_KEY_BITMAP 0x04
-#define PROGRAM_KEY_GRADIENT 0x08
-#define PROGRAM_KEY_BITMAP_FIRST 0x10
-#define PROGRAM_KEY_COLOR_MATRIX 0x20
-#define PROGRAM_KEY_COLOR_BLEND 0x40
-#define PROGRAM_KEY_BITMAP_NPOT 0x80
-#define PROGRAM_KEY_BITMAP_EXTERNAL 0x100
+#define PROGRAM_KEY_TEXTURE 0x01
+#define PROGRAM_KEY_A8_TEXTURE 0x02
+#define PROGRAM_KEY_BITMAP 0x04
+#define PROGRAM_KEY_GRADIENT 0x08
+#define PROGRAM_KEY_BITMAP_FIRST 0x10
+#define PROGRAM_KEY_COLOR_MATRIX 0x20
+#define PROGRAM_KEY_COLOR_BLEND 0x40
+#define PROGRAM_KEY_BITMAP_NPOT 0x80
+#define PROGRAM_KEY_BITMAP_EXTERNAL 0x100
-#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
+#define PROGRAM_KEY_BITMAP_WRAPS_MASK 0x600
#define PROGRAM_KEY_BITMAP_WRAPT_MASK 0x1800
#define PROGRAM_KEY_SWAP_SRC_DST_SHIFT 13
@@ -71,7 +71,7 @@
#define PROGRAM_BITMAP_WRAPS_SHIFT 9
#define PROGRAM_BITMAP_WRAPT_SHIFT 11
-#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
+#define PROGRAM_GRADIENT_TYPE_SHIFT 33 // 2 bits for gradient type
#define PROGRAM_MODULATE_SHIFT 35
#define PROGRAM_HAS_VERTEX_ALPHA_SHIFT 36
@@ -91,7 +91,7 @@
#define PROGRAM_HAS_LINEAR_TEXTURE 45
#define PROGRAM_HAS_COLOR_SPACE_CONVERSION 46
-#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
+#define PROGRAM_TRANSFER_FUNCTION 47 // 2 bits for transfer function
#define PROGRAM_HAS_TRANSLUCENT_CONVERSION 49
///////////////////////////////////////////////////////////////////////////////
@@ -110,21 +110,11 @@
* A ProgramDescription must be used in conjunction with a ProgramCache.
*/
struct ProgramDescription {
- enum class ColorFilterMode : int8_t {
- None = 0,
- Matrix,
- Blend
- };
+ enum class ColorFilterMode : int8_t { None = 0, Matrix, Blend };
- enum Gradient : int8_t {
- kGradientLinear = 0,
- kGradientCircular,
- kGradientSweep
- };
+ enum Gradient : int8_t { kGradientLinear = 0, kGradientCircular, kGradientSweep };
- ProgramDescription() {
- reset();
- }
+ ProgramDescription() { reset(); }
// Texturing
bool hasTexture;
@@ -243,7 +233,7 @@
*/
bool setAlpha8ColorModulate(const float r, const float g, const float b, const float a) {
modulate = a < COLOR_COMPONENT_THRESHOLD || r > COLOR_COMPONENT_INV_THRESHOLD ||
- g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
+ g > COLOR_COMPONENT_INV_THRESHOLD || b > COLOR_COMPONENT_INV_THRESHOLD;
return modulate;
}
@@ -277,12 +267,12 @@
break;
case ColorFilterMode::Blend:
key |= PROGRAM_KEY_COLOR_BLEND;
- key |= ((int) colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
+ key |= ((int)colorMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_COLOR_OP_SHIFT;
break;
case ColorFilterMode::None:
break;
}
- key |= ((int) framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
+ key |= ((int)framebufferMode & PROGRAM_MAX_XFERMODE) << PROGRAM_XFERMODE_FRAMEBUFFER_SHIFT;
key |= programid(swapSrcDst) << PROGRAM_KEY_SWAP_SRC_DST_SHIFT;
key |= programid(modulate) << PROGRAM_MODULATE_SHIFT;
key |= programid(hasVertexAlpha) << PROGRAM_HAS_VERTEX_ALPHA_SHIFT;
@@ -307,8 +297,7 @@
void log(const char* message) const {
#if DEBUG_PROGRAMS
programid k = key();
- PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32),
- uint32_t(k & 0xffffffff));
+ PROGRAM_LOGD("%s (key = 0x%.8x%.8x)", message, uint32_t(k >> 32), uint32_t(k & 0xffffffff));
#endif
}
@@ -325,7 +314,7 @@
return 0;
}
-}; // struct ProgramDescription
+}; // struct ProgramDescription
/**
* A program holds a vertex and a fragment shader. It offers several utility
@@ -333,10 +322,7 @@
*/
class Program {
public:
- enum ShaderBindings {
- kBindingPosition,
- kBindingTexCoords
- };
+ enum ShaderBindings { kBindingPosition, kBindingTexCoords };
/**
* Creates a new program with the specified vertex and fragment
@@ -370,23 +356,19 @@
* Indicates whether this program is currently in use with
* the GL context.
*/
- inline bool isInUse() const {
- return mUse;
- }
+ inline bool isInUse() const { return mUse; }
/**
* Indicates whether this program was correctly compiled and linked.
*/
- inline bool isInitialized() const {
- return mInitialized;
- }
+ inline bool isInitialized() const { return mInitialized; }
/**
* Binds the program with the specified projection, modelView and
* transform matrices.
*/
- void set(const mat4& projectionMatrix, const mat4& modelViewMatrix,
- const mat4& transformMatrix, bool offset = false);
+ void set(const mat4& projectionMatrix, const mat4& modelViewMatrix, const mat4& transformMatrix,
+ bool offset = false);
/**
* Sets the color associated with this shader.
@@ -456,9 +438,9 @@
mat4 mProjection;
bool mOffset;
-}; // class Program
+}; // class Program
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PROGRAM_H
+#endif // ANDROID_HWUI_PROGRAM_H
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index b767046..1164ebf 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -41,19 +41,14 @@
const char* gVS_Header_Start =
"#version 100\n"
"attribute vec4 position;\n";
-const char* gVS_Header_Attributes_TexCoords =
- "attribute vec2 texCoords;\n";
-const char* gVS_Header_Attributes_Colors =
- "attribute vec4 colors;\n";
-const char* gVS_Header_Attributes_VertexAlphaParameters =
- "attribute float vtxAlpha;\n";
-const char* gVS_Header_Uniforms_TextureTransform =
- "uniform mat4 mainTextureTransform;\n";
+const char* gVS_Header_Attributes_TexCoords = "attribute vec2 texCoords;\n";
+const char* gVS_Header_Attributes_Colors = "attribute vec4 colors;\n";
+const char* gVS_Header_Attributes_VertexAlphaParameters = "attribute float vtxAlpha;\n";
+const char* gVS_Header_Uniforms_TextureTransform = "uniform mat4 mainTextureTransform;\n";
const char* gVS_Header_Uniforms =
- "uniform mat4 projection;\n" \
+ "uniform mat4 projection;\n"
"uniform mat4 transform;\n";
-const char* gVS_Header_Uniforms_HasGradient =
- "uniform mat4 screenSpace;\n";
+const char* gVS_Header_Uniforms_HasGradient = "uniform mat4 screenSpace;\n";
const char* gVS_Header_Uniforms_HasBitmap =
"uniform mat4 textureTransform;\n"
"uniform mediump vec2 textureDimension;\n";
@@ -61,35 +56,24 @@
"uniform mat4 roundRectInvTransform;\n"
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
"uniform mediump float roundRectRadius;\n";
-const char* gVS_Header_Varyings_HasTexture =
- "varying vec2 outTexCoords;\n";
-const char* gVS_Header_Varyings_HasColors =
- "varying vec4 outColors;\n";
-const char* gVS_Header_Varyings_HasVertexAlpha =
- "varying float alpha;\n";
-const char* gVS_Header_Varyings_HasBitmap =
- "varying highp vec2 outBitmapTexCoords;\n";
+const char* gVS_Header_Varyings_HasTexture = "varying vec2 outTexCoords;\n";
+const char* gVS_Header_Varyings_HasColors = "varying vec4 outColors;\n";
+const char* gVS_Header_Varyings_HasVertexAlpha = "varying float alpha;\n";
+const char* gVS_Header_Varyings_HasBitmap = "varying highp vec2 outBitmapTexCoords;\n";
const char* gVS_Header_Varyings_HasGradient[6] = {
// Linear
- "varying highp vec2 linear;\n",
- "varying float linear;\n",
+ "varying highp vec2 linear;\n", "varying float linear;\n",
// Circular
- "varying highp vec2 circular;\n",
- "varying highp vec2 circular;\n",
+ "varying highp vec2 circular;\n", "varying highp vec2 circular;\n",
// Sweep
- "varying highp vec2 sweep;\n",
- "varying highp vec2 sweep;\n",
+ "varying highp vec2 sweep;\n", "varying highp vec2 sweep;\n",
};
-const char* gVS_Header_Varyings_HasRoundRectClip =
- "varying mediump vec2 roundRectPos;\n";
-const char* gVS_Main =
- "\nvoid main(void) {\n";
-const char* gVS_Main_OutTexCoords =
- " outTexCoords = texCoords;\n";
-const char* gVS_Main_OutColors =
- " outColors = colors;\n";
+const char* gVS_Header_Varyings_HasRoundRectClip = "varying mediump vec2 roundRectPos;\n";
+const char* gVS_Main = "\nvoid main(void) {\n";
+const char* gVS_Main_OutTexCoords = " outTexCoords = texCoords;\n";
+const char* gVS_Main_OutColors = " outColors = colors;\n";
const char* gVS_Main_OutTransformedTexCoords =
" outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
const char* gVS_Main_OutGradient[6] = {
@@ -102,53 +86,42 @@
" circular = (screenSpace * position).xy;\n",
// Sweep
- " sweep = (screenSpace * position).xy;\n",
- " sweep = (screenSpace * position).xy;\n"
-};
+ " sweep = (screenSpace * position).xy;\n", " sweep = (screenSpace * position).xy;\n"};
const char* gVS_Main_OutBitmapTexCoords =
" outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
const char* gVS_Main_Position =
" vec4 transformedPosition = projection * transform * position;\n"
" gl_Position = transformedPosition;\n";
-const char* gVS_Main_VertexAlpha =
- " alpha = vtxAlpha;\n";
+const char* gVS_Main_VertexAlpha = " alpha = vtxAlpha;\n";
const char* gVS_Main_HasRoundRectClip =
- " roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - roundRectInnerRectLTWH.xy;\n";
-const char* gVS_Footer =
- "}\n\n";
+ " roundRectPos = ((roundRectInvTransform * transformedPosition).xy / roundRectRadius) - "
+ "roundRectInnerRectLTWH.xy;\n";
+const char* gVS_Footer = "}\n\n";
///////////////////////////////////////////////////////////////////////////////
// Fragment shaders snippets
///////////////////////////////////////////////////////////////////////////////
-const char* gFS_Header_Start =
- "#version 100\n";
+const char* gFS_Header_Start = "#version 100\n";
const char* gFS_Header_Extension_FramebufferFetch =
"#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
const char* gFS_Header_Extension_ExternalTexture =
"#extension GL_OES_EGL_image_external : require\n\n";
-const char* gFS_Header =
- "precision mediump float;\n\n";
-const char* gFS_Uniforms_Color =
- "uniform vec4 color;\n";
-const char* gFS_Uniforms_TextureSampler =
- "uniform sampler2D baseSampler;\n";
-const char* gFS_Uniforms_ExternalTextureSampler =
- "uniform samplerExternalOES baseSampler;\n";
+const char* gFS_Header = "precision mediump float;\n\n";
+const char* gFS_Uniforms_Color = "uniform vec4 color;\n";
+const char* gFS_Uniforms_TextureSampler = "uniform sampler2D baseSampler;\n";
+const char* gFS_Uniforms_ExternalTextureSampler = "uniform samplerExternalOES baseSampler;\n";
const char* gFS_Uniforms_GradientSampler[2] = {
"uniform vec2 screenSize;\n"
"uniform sampler2D gradientSampler;\n",
"uniform vec2 screenSize;\n"
"uniform vec4 startColor;\n"
- "uniform vec4 endColor;\n"
-};
-const char* gFS_Uniforms_BitmapSampler =
- "uniform sampler2D bitmapSampler;\n";
-const char* gFS_Uniforms_BitmapExternalSampler =
- "uniform samplerExternalOES bitmapSampler;\n";
+ "uniform vec4 endColor;\n"};
+const char* gFS_Uniforms_BitmapSampler = "uniform sampler2D bitmapSampler;\n";
+const char* gFS_Uniforms_BitmapExternalSampler = "uniform samplerExternalOES bitmapSampler;\n";
const char* gFS_Uniforms_ColorOp[3] = {
// None
"",
@@ -156,8 +129,7 @@
"uniform mat4 colorMatrix;\n"
"uniform vec4 colorMatrixVector;\n",
// PorterDuff
- "uniform vec4 colorBlend;\n"
-};
+ "uniform vec4 colorBlend;\n"};
const char* gFS_Uniforms_HasRoundRectClip =
"uniform mediump vec4 roundRectInnerRectLTWH;\n"
@@ -172,11 +144,8 @@
// In this order: g, a, b, c, d, e, f
// See ColorSpace::TransferParameters
// We'll use hardware sRGB conversion as much as possible
- "",
- "uniform float transferFunction[7];\n",
- "uniform float transferFunction[5];\n",
- "uniform float transferFunctionGamma;\n"
-};
+ "", "uniform float transferFunction[7];\n", "uniform float transferFunction[5];\n",
+ "uniform float transferFunctionGamma;\n"};
const char* gFS_OETF[2] = {
R"__SHADER__(
@@ -189,8 +158,7 @@
vec4 OETF(const vec4 linear) {
return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);
}
- )__SHADER__"
-};
+ )__SHADER__"};
const char* gFS_ColorConvert[3] = {
// Just OETF
@@ -274,8 +242,7 @@
pow(x.g, transferFunctionGamma),
pow(x.b, transferFunctionGamma));
}
- )__SHADER__"
-};
+ )__SHADER__"};
// Dithering must be done in the quantization space
// When we are writing to an sRGB framebuffer, we must do the following:
@@ -327,16 +294,12 @@
"\nvoid main(void) {\n"
" vec4 fragColor;\n";
-const char* gFS_Main_AddDither =
- " fragColor = dither(fragColor);\n";
+const char* gFS_Main_AddDither = " fragColor = dither(fragColor);\n";
// General case
-const char* gFS_Main_FetchColor =
- " fragColor = color;\n";
-const char* gFS_Main_ModulateColor =
- " fragColor *= color.a;\n";
-const char* gFS_Main_ApplyVertexAlphaLinearInterp =
- " fragColor *= alpha;\n";
+const char* gFS_Main_FetchColor = " fragColor = color;\n";
+const char* gFS_Main_ModulateColor = " fragColor *= color.a;\n";
+const char* gFS_Main_ApplyVertexAlphaLinearInterp = " fragColor *= alpha;\n";
const char* gFS_Main_ApplyVertexAlphaShadowInterp =
// map alpha through shadow alpha sampler
" fragColor *= texture2D(baseSampler, vec2(alpha, 0.5)).a;\n";
@@ -344,8 +307,7 @@
// Don't modulate
" fragColor = colorConvert(texture2D(baseSampler, outTexCoords));\n",
// Modulate
- " fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"
-};
+ " fragColor = color * colorConvert(texture2D(baseSampler, outTexCoords));\n"};
const char* gFS_Main_FetchA8Texture[4] = {
// Don't modulate
" fragColor = texture2D(baseSampler, outTexCoords);\n",
@@ -370,53 +332,46 @@
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n",
" highp float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
- " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, 1.0));\n"
-};
+ " vec4 gradientColor = mix(startColor, endColor, clamp(index - floor(index), 0.0, "
+ "1.0));\n"};
const char* gFS_Main_FetchBitmap =
" vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, outBitmapTexCoords));\n";
const char* gFS_Main_FetchBitmapNpot =
- " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, wrap(outBitmapTexCoords)));\n";
-const char* gFS_Main_BlendShadersBG =
- " fragColor = blendShaders(gradientColor, bitmapColor)";
-const char* gFS_Main_BlendShadersGB =
- " fragColor = blendShaders(bitmapColor, gradientColor)";
+ " vec4 bitmapColor = colorConvert(texture2D(bitmapSampler, "
+ "wrap(outBitmapTexCoords)));\n";
+const char* gFS_Main_BlendShadersBG = " fragColor = blendShaders(gradientColor, bitmapColor)";
+const char* gFS_Main_BlendShadersGB = " fragColor = blendShaders(bitmapColor, gradientColor)";
const char* gFS_Main_BlendShaders_Modulate[6] = {
// Don't modulate
- ";\n",
- ";\n",
+ ";\n", ";\n",
// Modulate
- " * color.a;\n",
- " * color.a;\n",
+ " * color.a;\n", " * color.a;\n",
// Modulate with alpha 8 texture
" * texture2D(baseSampler, outTexCoords).a;\n",
" * gamma(texture2D(baseSampler, outTexCoords).a, color.rgb);\n",
};
const char* gFS_Main_GradientShader_Modulate[6] = {
// Don't modulate
- " fragColor = gradientColor;\n",
- " fragColor = gradientColor;\n",
+ " fragColor = gradientColor;\n", " fragColor = gradientColor;\n",
// Modulate
- " fragColor = gradientColor * color.a;\n",
- " fragColor = gradientColor * color.a;\n",
+ " fragColor = gradientColor * color.a;\n", " fragColor = gradientColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = gradientColor * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, gradientColor.rgb);\n",
- };
+ " fragColor = gradientColor * gamma(texture2D(baseSampler, outTexCoords).a, "
+ "gradientColor.rgb);\n",
+};
const char* gFS_Main_BitmapShader_Modulate[6] = {
// Don't modulate
- " fragColor = bitmapColor;\n",
- " fragColor = bitmapColor;\n",
+ " fragColor = bitmapColor;\n", " fragColor = bitmapColor;\n",
// Modulate
- " fragColor = bitmapColor * color.a;\n",
- " fragColor = bitmapColor * color.a;\n",
+ " fragColor = bitmapColor * color.a;\n", " fragColor = bitmapColor * color.a;\n",
// Modulate with alpha 8 texture
" fragColor = bitmapColor * texture2D(baseSampler, outTexCoords).a;\n",
- " fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, bitmapColor.rgb);\n",
- };
-const char* gFS_Main_FragColor =
- " gl_FragColor = fragColor;\n";
-const char* gFS_Main_FragColor_HasColors =
- " gl_FragColor *= outColors;\n";
+ " fragColor = bitmapColor * gamma(texture2D(baseSampler, outTexCoords).a, "
+ "bitmapColor.rgb);\n",
+};
+const char* gFS_Main_FragColor = " gl_FragColor = fragColor;\n";
+const char* gFS_Main_FragColor_HasColors = " gl_FragColor *= outColors;\n";
const char* gFS_Main_FragColor_Blend =
" gl_FragColor = blendFramebuffer(fragColor, gl_LastFragColor);\n";
const char* gFS_Main_FragColor_Blend_Swap =
@@ -425,13 +380,12 @@
// None
"",
// Matrix
- " fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
+ " fragColor.rgb /= (fragColor.a + 0.0019);\n" // un-premultiply
" fragColor *= colorMatrix;\n"
" fragColor += colorMatrixVector;\n"
- " fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
+ " fragColor.rgb *= (fragColor.a + 0.0019);\n", // re-premultiply
// PorterDuff
- " fragColor = blendColors(colorBlend, fragColor);\n"
-};
+ " fragColor = blendColors(colorBlend, fragColor);\n"};
// Note: LTWH (left top width height) -> xyzw
// roundRectPos is now divided by roundRectRadius in vertex shader
@@ -443,13 +397,12 @@
// since distance is divided by radius, it's in [0;1] so precision is not an issue
// this also lets us clamp(0.0, 1.0) instead of max() which is cheaper on GPUs
" mediump vec2 dist = clamp(max(fragToLT, fragFromRB), 0.0, 1.0);\n"
- " mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), 0.0, 1.0);\n"
+ " mediump float linearDist = clamp(roundRectRadius - (length(dist) * roundRectRadius), "
+ "0.0, 1.0);\n"
" gl_FragColor *= linearDist;\n";
-const char* gFS_Main_DebugHighlight =
- " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
-const char* gFS_Footer =
- "}\n\n";
+const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n";
+const char* gFS_Footer = "}\n\n";
///////////////////////////////////////////////////////////////////////////////
// PorterDuff snippets
@@ -480,7 +433,7 @@
"return vec4(dst.rgb * src.a + (1.0 - dst.a) * src.rgb, src.a);\n",
// Xor
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb, "
- "src.a + dst.a - 2.0 * src.a * dst.a);\n",
+ "src.a + dst.a - 2.0 * src.a * dst.a);\n",
// Plus
"return min(src + dst, 1.0);\n",
// Modulate
@@ -489,16 +442,17 @@
"return src + dst - src * dst;\n",
// Overlay
"return clamp(vec4(mix("
- "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
- "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
- "step(dst.a, 2.0 * dst.rgb)), "
- "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
+ "2.0 * src.rgb * dst.rgb + src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a), "
+ "src.a * dst.a - 2.0 * (dst.a - dst.rgb) * (src.a - src.rgb) + src.rgb * (1.0 - dst.a) + "
+ "dst.rgb * (1.0 - src.a), "
+ "step(dst.a, 2.0 * dst.rgb)), "
+ "src.a + dst.a - src.a * dst.a), 0.0, 1.0);\n",
// Darken
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
- "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
+ "min(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
// Lighten
"return vec4(src.rgb * (1.0 - dst.a) + (1.0 - src.a) * dst.rgb + "
- "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
+ "max(src.rgb * dst.a, dst.rgb * src.a), src.a + dst.a - src.a * dst.a);\n",
};
///////////////////////////////////////////////////////////////////////////////
@@ -507,8 +461,7 @@
ProgramCache::ProgramCache(const Extensions& extensions)
: mHasES3(extensions.getMajorGlVersion() >= 3)
- , mHasLinearBlending(extensions.hasLinearBlending()) {
-}
+ , mHasLinearBlending(extensions.hasLinearBlending()) {}
ProgramCache::~ProgramCache() {
clear();
@@ -605,7 +558,8 @@
}
// Begin the shader
- shader.append(gVS_Main); {
+ shader.append(gVS_Main);
+ {
if (description.hasTextureTransform) {
shader.append(gVS_Main_OutTransformedTexCoords);
} else if (description.hasTexture || description.hasExternalTexture) {
@@ -637,8 +591,8 @@
return shader;
}
-static bool shaderOp(const ProgramDescription& description, String8& shader,
- const int modulateOp, const char** snippets) {
+static bool shaderOp(const ProgramDescription& description, String8& shader, const int modulateOp,
+ const char** snippets) {
int op = description.hasAlpha8Texture ? MODULATE_OP_MODULATE_A8 : modulateOp;
op = op * 2 + description.hasGammaCorrection;
shader.append(snippets[op]);
@@ -652,8 +606,8 @@
if (blendFramebuffer) {
shader.append(gFS_Header_Extension_FramebufferFetch);
}
- if (description.hasExternalTexture
- || (description.hasBitmap && description.isShaderBitmapExternal)) {
+ if (description.hasExternalTexture ||
+ (description.hasBitmap && description.isShaderBitmapExternal)) {
shader.append(gFS_Header_Extension_ExternalTexture);
}
@@ -682,7 +636,7 @@
// Uniforms
int modulateOp = MODULATE_OP_NO_MODULATE;
const bool singleColor = !description.hasTexture && !description.hasExternalTexture &&
- !description.hasGradient && !description.hasBitmap;
+ !description.hasGradient && !description.hasBitmap;
if (description.modulate || singleColor) {
shader.append(gFS_Uniforms_Color);
@@ -701,7 +655,8 @@
}
if (description.hasGammaCorrection) {
- shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma, 1.0f / Properties::textGamma);
+ shader.appendFormat(gFS_Gamma_Preamble, Properties::textGamma,
+ 1.0f / Properties::textGamma);
}
if (description.hasBitmap) {
@@ -731,17 +686,19 @@
if (description.useShaderBasedWrap) {
generateTextureWrap(shader, description.bitmapWrapS, description.bitmapWrapT);
}
- if (description.hasGradient || description.hasLinearTexture
- || description.hasColorSpaceConversion) {
+ if (description.hasGradient || description.hasLinearTexture ||
+ description.hasColorSpaceConversion) {
shader.append(gFS_sRGB_TransferFunctions);
}
if (description.hasBitmap || ((description.hasTexture || description.hasExternalTexture) &&
- !description.hasAlpha8Texture)) {
+ !description.hasAlpha8Texture)) {
shader.append(gFS_TransferFunction[static_cast<int>(description.transferFunction)]);
- shader.append(gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion)
- && !mHasLinearBlending]);
+ shader.append(
+ gFS_OETF[(description.hasLinearTexture || description.hasColorSpaceConversion) &&
+ !mHasLinearBlending]);
shader.append(gFS_ColorConvert[description.hasColorSpaceConversion
- ? 1 + description.hasTranslucentConversion : 0]);
+ ? 1 + description.hasTranslucentConversion
+ : 0]);
}
if (description.hasGradient) {
shader.append(gFS_GradientFunctions);
@@ -749,13 +706,14 @@
}
// Begin the shader
- shader.append(gFS_Main); {
+ shader.append(gFS_Main);
+ {
// Stores the result in fragColor directly
if (description.hasTexture || description.hasExternalTexture) {
if (description.hasAlpha8Texture) {
if (!description.hasGradient && !description.hasBitmap) {
- shader.append(
- gFS_Main_FetchA8Texture[modulateOp * 2 + description.hasGammaCorrection]);
+ shader.append(gFS_Main_FetchA8Texture[modulateOp * 2 +
+ description.hasGammaCorrection]);
}
} else {
shader.append(gFS_Main_FetchTexture[modulateOp]);
@@ -783,15 +741,15 @@
} else {
shader.append(gFS_Main_BlendShadersGB);
}
- applyModulate = shaderOp(description, shader, modulateOp,
- gFS_Main_BlendShaders_Modulate);
+ applyModulate =
+ shaderOp(description, shader, modulateOp, gFS_Main_BlendShaders_Modulate);
} else {
if (description.hasGradient) {
- applyModulate = shaderOp(description, shader, modulateOp,
- gFS_Main_GradientShader_Modulate);
+ applyModulate =
+ shaderOp(description, shader, modulateOp, gFS_Main_GradientShader_Modulate);
} else if (description.hasBitmap) {
- applyModulate = shaderOp(description, shader, modulateOp,
- gFS_Main_BitmapShader_Modulate);
+ applyModulate =
+ shaderOp(description, shader, modulateOp, gFS_Main_BitmapShader_Modulate);
}
}
@@ -818,8 +776,8 @@
if (!blendFramebuffer) {
shader.append(gFS_Main_FragColor);
} else {
- shader.append(!description.swapSrcDst ?
- gFS_Main_FragColor_Blend : gFS_Main_FragColor_Blend_Swap);
+ shader.append(!description.swapSrcDst ? gFS_Main_FragColor_Blend
+ : gFS_Main_FragColor_Blend_Swap);
}
if (description.hasColors) {
shader.append(gFS_Main_FragColor_HasColors);
@@ -835,8 +793,8 @@
shader.append(gFS_Footer);
#if DEBUG_PROGRAMS
- PROGRAM_LOGD("*** Generated fragment shader:\n\n");
- printLongString(shader);
+ PROGRAM_LOGD("*** Generated fragment shader:\n\n");
+ printLongString(shader);
#endif
return shader;
@@ -903,5 +861,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ProgramCache.h b/libs/hwui/ProgramCache.h
index ee76f22..488a499 100644
--- a/libs/hwui/ProgramCache.h
+++ b/libs/hwui/ProgramCache.h
@@ -60,9 +60,9 @@
const bool mHasES3;
const bool mHasLinearBlending;
-}; // class ProgramCache
+}; // class ProgramCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PROGRAM_CACHE_H
+#endif // ANDROID_HWUI_PROGRAM_CACHE_H
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 588c4de..d90caf9 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -61,7 +61,9 @@
bool Properties::skpCaptureEnabled = false;
static int property_get_int(const char* key, int defaultValue) {
- char buf[PROPERTY_VALUE_MAX] = {'\0',};
+ char buf[PROPERTY_VALUE_MAX] = {
+ '\0',
+ };
if (property_get(key, buf, "") > 0) {
return atoi(buf);
@@ -121,7 +123,7 @@
showDirtyRegions = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false);
- debugLevel = (DebugLevel) property_get_int(PROPERTY_DEBUG, kDebugDisabled);
+ debugLevel = (DebugLevel)property_get_int(PROPERTY_DEBUG, kDebugDisabled);
skipEmptyFrames = property_get_bool(PROPERTY_SKIP_EMPTY_DAMAGE, true);
useBufferAge = property_get_bool(PROPERTY_USE_BUFFER_AGE, true);
@@ -129,12 +131,11 @@
filterOutTestOverhead = property_get_bool(PROPERTY_FILTER_TEST_OVERHEAD, false);
- skpCaptureEnabled = property_get_bool("ro.debuggable", false)
- && property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false);
+ skpCaptureEnabled = property_get_bool("ro.debuggable", false) &&
+ property_get_bool(PROPERTY_CAPTURE_SKP_ENABLED, false);
- return (prevDebugLayersUpdates != debugLayersUpdates)
- || (prevDebugOverdraw != debugOverdraw)
- || (prevDebugStencilClip != debugStencilClip);
+ return (prevDebugLayersUpdates != debugLayersUpdates) || (prevDebugOverdraw != debugOverdraw) ||
+ (prevDebugStencilClip != debugStencilClip);
}
void Properties::overrideProperty(const char* name, const char* value) {
@@ -182,13 +183,13 @@
}
char prop[PROPERTY_VALUE_MAX];
property_get(PROPERTY_RENDERER, prop, "skiagl");
- if (!strcmp(prop, "skiagl") ) {
+ if (!strcmp(prop, "skiagl")) {
ALOGD("Skia GL Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaGL;
- } else if (!strcmp(prop, "skiavk") ) {
+ } else if (!strcmp(prop, "skiavk")) {
ALOGD("Skia Vulkan Pipeline");
sRenderPipelineType = RenderPipelineType::SkiaVulkan;
- } else { //"opengl"
+ } else { //"opengl"
ALOGD("HWUI GL Pipeline");
sRenderPipelineType = RenderPipelineType::OpenGL;
}
@@ -203,9 +204,8 @@
bool Properties::isSkiaEnabled() {
auto renderType = getRenderPipelineType();
- return RenderPipelineType::SkiaGL == renderType
- || RenderPipelineType::SkiaVulkan == renderType;
+ return RenderPipelineType::SkiaGL == renderType || RenderPipelineType::SkiaVulkan == renderType;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index 077e7ae..fbd9b7a 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -170,11 +170,10 @@
*/
#define PROPERTY_CAPTURE_SKP_ENABLED "debug.hwui.capture_skp_enabled"
-
/**
* Defines how many frames in a sequence to capture.
*/
-#define PROPERTY_CAPTURE_SKP_FRAMES "debug.hwui.capture_skp_frames"
+#define PROPERTY_CAPTURE_SKP_FRAMES "debug.hwui.capture_skp_frames"
/**
* File name and location, where a SKP recording will be saved.
@@ -186,33 +185,17 @@
///////////////////////////////////////////////////////////////////////////////
// Converts a number of mega-bytes into bytes
-#define MB(s) ((s) * 1024 * 1024)
+#define MB(s) ((s)*1024 * 1024)
// Converts a number of kilo-bytes into bytes
-#define KB(s) ((s) * 1024)
+#define KB(s) ((s)*1024)
-enum class ProfileType {
- None,
- Console,
- Bars
-};
+enum class ProfileType { None, Console, Bars };
-enum class OverdrawColorSet {
- Default = 0,
- Deuteranomaly
-};
+enum class OverdrawColorSet { Default = 0, Deuteranomaly };
-enum class StencilClipDebug {
- Hide,
- ShowHighlight,
- ShowRegion
-};
+enum class StencilClipDebug { Hide, ShowHighlight, ShowRegion };
-enum class RenderPipelineType {
- OpenGL = 0,
- SkiaGL,
- SkiaVulkan,
- NotInitialized = 128
-};
+enum class RenderPipelineType { OpenGL = 0, SkiaGL, SkiaVulkan, NotInitialized = 128 };
/**
* Renderthread-only singleton which manages several static rendering properties. Most of these
@@ -251,7 +234,7 @@
static int overrideSpotShadowStrength;
static ProfileType getProfileType();
- static RenderPipelineType getRenderPipelineType();
+ ANDROID_API static RenderPipelineType getRenderPipelineType();
static bool isSkiaEnabled();
ANDROID_API static bool enableHighContrastText;
@@ -272,7 +255,7 @@
static bool skpCaptureEnabled;
- // Used for testing only to change the render pipeline.
+// Used for testing only to change the render pipeline.
#ifdef HWUI_GLES_WRAP_ENABLED
static void overrideRenderPipelineType(RenderPipelineType);
#endif
@@ -281,9 +264,9 @@
static ProfileType sProfileType;
static bool sDisableProfileBars;
static RenderPipelineType sRenderPipelineType;
-}; // class Caches
+}; // class Caches
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_PROPERTIES_H
+#endif // ANDROID_HWUI_PROPERTIES_H
diff --git a/libs/hwui/PropertyValuesAnimatorSet.cpp b/libs/hwui/PropertyValuesAnimatorSet.cpp
index e3258e3..65a5aa4 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.cpp
+++ b/libs/hwui/PropertyValuesAnimatorSet.cpp
@@ -23,11 +23,11 @@
namespace uirenderer {
void PropertyValuesAnimatorSet::addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
- Interpolator* interpolator, nsecs_t startDelay, nsecs_t duration, int repeatCount,
- RepeatMode repeatMode) {
-
- PropertyAnimator* animator = new PropertyAnimator(propertyValuesHolder,
- interpolator, startDelay, duration, repeatCount, repeatMode);
+ Interpolator* interpolator, nsecs_t startDelay,
+ nsecs_t duration, int repeatCount,
+ RepeatMode repeatMode) {
+ PropertyAnimator* animator = new PropertyAnimator(
+ propertyValuesHolder, interpolator, startDelay, duration, repeatCount, repeatMode);
mAnimators.emplace_back(animator);
// Check whether any child animator is infinite after adding it them to the set.
@@ -36,8 +36,7 @@
}
}
-PropertyValuesAnimatorSet::PropertyValuesAnimatorSet()
- : BaseRenderNodeAnimator(1.0f) {
+PropertyValuesAnimatorSet::PropertyValuesAnimatorSet() : BaseRenderNodeAnimator(1.0f) {
setStartValue(0);
mLastFraction = 0.0f;
setInterpolator(new LinearInterpolator());
@@ -77,7 +76,7 @@
// have the final say on what the property value should be.
(*it)->setFraction(0, 0);
}
- } else {
+ } else {
for (auto& anim : mAnimators) {
anim->setCurrentPlayTime(playTime);
}
@@ -116,9 +115,8 @@
// Sort the animators by their total duration. Note that all the animators in the set start at
// the same time, so the ones with longer total duration (which includes start delay) will
// be the ones that end later.
- std::sort(mAnimators.begin(), mAnimators.end(), [](auto& a, auto&b) {
- return a->getTotalDuration() < b->getTotalDuration();
- });
+ std::sort(mAnimators.begin(), mAnimators.end(),
+ [](auto& a, auto& b) { return a->getTotalDuration() < b->getTotalDuration(); });
mDuration = mAnimators.empty() ? 0 : mAnimators[mAnimators.size() - 1]->getTotalDuration();
mInitialized = true;
}
@@ -128,17 +126,19 @@
}
PropertyAnimator::PropertyAnimator(PropertyValuesHolder* holder, Interpolator* interpolator,
- nsecs_t startDelay, nsecs_t duration, int repeatCount,
- RepeatMode repeatMode)
- : mPropertyValuesHolder(holder), mInterpolator(interpolator), mStartDelay(startDelay),
- mDuration(duration) {
+ nsecs_t startDelay, nsecs_t duration, int repeatCount,
+ RepeatMode repeatMode)
+ : mPropertyValuesHolder(holder)
+ , mInterpolator(interpolator)
+ , mStartDelay(startDelay)
+ , mDuration(duration) {
if (repeatCount < 0) {
mRepeatCount = UINT32_MAX;
} else {
mRepeatCount = repeatCount;
}
mRepeatMode = repeatMode;
- mTotalDuration = ((nsecs_t) mRepeatCount + 1) * mDuration + mStartDelay;
+ mTotalDuration = ((nsecs_t)mRepeatCount + 1) * mDuration + mStartDelay;
}
void PropertyAnimator::setCurrentPlayTime(nsecs_t playTime) {
@@ -155,7 +155,7 @@
} else {
// play time here is in range [mStartDelay, mTotalDuration)
iteration = (playTime - mStartDelay) / mDuration;
- currentIterationFraction = ((playTime - mStartDelay) % mDuration) / (float) mDuration;
+ currentIterationFraction = ((playTime - mStartDelay) % mDuration) / (float)mDuration;
}
setFraction(currentIterationFraction, iteration);
}
@@ -182,6 +182,5 @@
void PropertyAnimatorSetListener::onAnimationFinished(BaseRenderNodeAnimator* animator) {
mSet->onFinished(animator);
}
-
}
}
diff --git a/libs/hwui/PropertyValuesAnimatorSet.h b/libs/hwui/PropertyValuesAnimatorSet.h
index a5d9e86..e4214b2 100644
--- a/libs/hwui/PropertyValuesAnimatorSet.h
+++ b/libs/hwui/PropertyValuesAnimatorSet.h
@@ -17,8 +17,8 @@
#pragma once
#include "Animator.h"
-#include "PropertyValuesHolder.h"
#include "Interpolator.h"
+#include "PropertyValuesHolder.h"
namespace android {
namespace uirenderer {
@@ -26,11 +26,9 @@
class PropertyAnimator {
public:
PropertyAnimator(PropertyValuesHolder* holder, Interpolator* interpolator, nsecs_t startDelay,
- nsecs_t duration, int repeatCount, RepeatMode repeatMode);
+ nsecs_t duration, int repeatCount, RepeatMode repeatMode);
void setCurrentPlayTime(nsecs_t playTime);
- nsecs_t getTotalDuration() {
- return mTotalDuration;
- }
+ nsecs_t getTotalDuration() { return mTotalDuration; }
// fraction range: [0, 1], iteration range [0, repeatCount]
void setFraction(float fraction, long iteration);
@@ -57,8 +55,8 @@
virtual void end() override;
void addPropertyAnimator(PropertyValuesHolder* propertyValuesHolder,
- Interpolator* interpolators, int64_t startDelays,
- nsecs_t durations, int repeatCount, RepeatMode repeatMode);
+ Interpolator* interpolators, int64_t startDelays, nsecs_t durations,
+ int repeatCount, RepeatMode repeatMode);
virtual uint32_t dirtyMask();
bool isInfinite() { return mIsInfinite; }
void setVectorDrawable(VectorDrawableRoot* vd) { mVectorDrawable = vd; }
@@ -77,7 +75,7 @@
void onFinished(BaseRenderNodeAnimator* animator);
// Listener set from outside
sp<AnimationListener> mOneShotListener;
- std::vector< std::unique_ptr<PropertyAnimator> > mAnimators;
+ std::vector<std::unique_ptr<PropertyAnimator> > mAnimators;
float mLastFraction = 0.0f;
bool mInitialized = false;
sp<VectorDrawableRoot> mVectorDrawable;
@@ -96,5 +94,5 @@
PropertyValuesAnimatorSet* mSet;
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/PropertyValuesHolder.cpp b/libs/hwui/PropertyValuesHolder.cpp
index 2a03e6a..3552625 100644
--- a/libs/hwui/PropertyValuesHolder.cpp
+++ b/libs/hwui/PropertyValuesHolder.cpp
@@ -27,7 +27,7 @@
using namespace VectorDrawable;
inline constexpr float lerp(float fromValue, float toValue, float fraction) {
- return float (fromValue * (1 - fraction) + toValue * fraction);
+ return float(fromValue * (1 - fraction) + toValue * fraction);
}
inline constexpr float linearize(U8CPU component) {
@@ -35,25 +35,23 @@
}
// TODO: Add a test for this
-void ColorEvaluator::evaluate(SkColor* outColor,
- const SkColor& fromColor, const SkColor& toColor, float fraction) const {
+void ColorEvaluator::evaluate(SkColor* outColor, const SkColor& fromColor, const SkColor& toColor,
+ float fraction) const {
float a = lerp(SkColorGetA(fromColor) / 255.0f, SkColorGetA(toColor) / 255.0f, fraction);
float r = lerp(linearize(SkColorGetR(fromColor)), linearize(SkColorGetR(toColor)), fraction);
float g = lerp(linearize(SkColorGetG(fromColor)), linearize(SkColorGetG(toColor)), fraction);
float b = lerp(linearize(SkColorGetB(fromColor)), linearize(SkColorGetB(toColor)), fraction);
- *outColor = SkColorSetARGB(
- (U8CPU) roundf(a * 255.0f),
- (U8CPU) roundf(OECF_sRGB(r) * 255.0f),
- (U8CPU) roundf(OECF_sRGB(g) * 255.0f),
- (U8CPU) roundf(OECF_sRGB(b) * 255.0f));
+ *outColor = SkColorSetARGB((U8CPU)roundf(a * 255.0f), (U8CPU)roundf(OECF_sRGB(r) * 255.0f),
+ (U8CPU)roundf(OECF_sRGB(g) * 255.0f),
+ (U8CPU)roundf(OECF_sRGB(b) * 255.0f));
}
-void PathEvaluator::evaluate(PathData* out,
- const PathData& from, const PathData& to, float fraction) const {
+void PathEvaluator::evaluate(PathData* out, const PathData& from, const PathData& to,
+ float fraction) const {
VectorDrawableUtils::interpolatePaths(out, from, to, fraction);
}
-template<typename T>
+template <typename T>
const T PropertyValuesHolderImpl<T>::getValueFromData(float fraction) const {
if (mDataSource.size() == 0) {
LOG_ALWAYS_FATAL("No data source is defined");
@@ -75,7 +73,7 @@
return value;
}
-template<typename T>
+template <typename T>
const T PropertyValuesHolderImpl<T>::calculateAnimatedValue(float fraction) const {
if (mDataSource.size() > 0) {
return getValueFromData(fraction);
@@ -111,5 +109,5 @@
mTree->mutateProperties()->setRootAlpha(animatedValue);
}
-} // namepace uirenderer
-} // namespace android
+} // namepace uirenderer
+} // namespace android
diff --git a/libs/hwui/PropertyValuesHolder.h b/libs/hwui/PropertyValuesHolder.h
index 432f8ba..0a799d3 100644
--- a/libs/hwui/PropertyValuesHolder.h
+++ b/libs/hwui/PropertyValuesHolder.h
@@ -43,8 +43,8 @@
class FloatEvaluator : public Evaluator<float> {
public:
- virtual void evaluate(float* out, const float& from, const float& to, float fraction)
- const override {
+ virtual void evaluate(float* out, const float& from, const float& to,
+ float fraction) const override {
*out = from * (1 - fraction) + to * fraction;
}
};
@@ -52,20 +52,19 @@
class ANDROID_API ColorEvaluator : public Evaluator<SkColor> {
public:
virtual void evaluate(SkColor* outColor, const SkColor& from, const SkColor& to,
- float fraction) const override;
+ float fraction) const override;
};
class ANDROID_API PathEvaluator : public Evaluator<PathData> {
- virtual void evaluate(PathData* out, const PathData& from, const PathData& to, float fraction)
- const override;
+ virtual void evaluate(PathData* out, const PathData& from, const PathData& to,
+ float fraction) const override;
};
template <typename T>
class ANDROID_API PropertyValuesHolderImpl : public PropertyValuesHolder {
public:
PropertyValuesHolderImpl(const T& startValue, const T& endValue)
- : mStartValue(startValue)
- , mEndValue(endValue) {}
+ : mStartValue(startValue), mEndValue(endValue) {}
void setPropertyDataSource(T* dataSource, int length) {
mDataSource.insert(mDataSource.begin(), dataSource, dataSource + length);
}
@@ -74,27 +73,27 @@
// Convenient method to favor getting animated value from data source. If no data source is set
// fall back to linear interpolation.
const T calculateAnimatedValue(float fraction) const;
+
protected:
- std::unique_ptr<Evaluator<T>> mEvaluator = nullptr;
- // This contains uniformly sampled data throughout the animation duration. The first element
- // should be the start value and the last should be the end value of the animation. When the
- // data source is set, we'll favor data source over the linear interpolation of start/end value
- // for calculation of animated value.
- std::vector<T> mDataSource;
- T mStartValue;
- T mEndValue;
+ std::unique_ptr<Evaluator<T>> mEvaluator = nullptr;
+ // This contains uniformly sampled data throughout the animation duration. The first element
+ // should be the start value and the last should be the end value of the animation. When the
+ // data source is set, we'll favor data source over the linear interpolation of start/end value
+ // for calculation of animated value.
+ std::vector<T> mDataSource;
+ T mStartValue;
+ T mEndValue;
};
class ANDROID_API GroupPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
GroupPropertyValuesHolder(VectorDrawable::Group* ptr, int propertyId, float startValue,
- float endValue)
- : PropertyValuesHolderImpl(startValue, endValue)
- , mGroup(ptr)
- , mPropertyId(propertyId) {
+ float endValue)
+ : PropertyValuesHolderImpl(startValue, endValue), mGroup(ptr), mPropertyId(propertyId) {
mEvaluator.reset(new FloatEvaluator());
}
void setFraction(float fraction) override;
+
private:
VectorDrawable::Group* mGroup;
int mPropertyId;
@@ -103,7 +102,7 @@
class ANDROID_API FullPathColorPropertyValuesHolder : public PropertyValuesHolderImpl<SkColor> {
public:
FullPathColorPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId,
- SkColor startValue, SkColor endValue)
+ SkColor startValue, SkColor endValue)
: PropertyValuesHolderImpl(startValue, endValue)
, mFullPath(ptr)
, mPropertyId(propertyId) {
@@ -111,6 +110,7 @@
}
void setFraction(float fraction) override;
static SkColor interpolateColors(SkColor fromColor, SkColor toColor, float fraction);
+
private:
VectorDrawable::FullPath* mFullPath;
int mPropertyId;
@@ -119,13 +119,14 @@
class ANDROID_API FullPathPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
FullPathPropertyValuesHolder(VectorDrawable::FullPath* ptr, int propertyId, float startValue,
- float endValue)
+ float endValue)
: PropertyValuesHolderImpl(startValue, endValue)
, mFullPath(ptr)
, mPropertyId(propertyId) {
mEvaluator.reset(new FloatEvaluator());
};
void setFraction(float fraction) override;
+
private:
VectorDrawable::FullPath* mFullPath;
int mPropertyId;
@@ -134,12 +135,12 @@
class ANDROID_API PathDataPropertyValuesHolder : public PropertyValuesHolderImpl<PathData> {
public:
PathDataPropertyValuesHolder(VectorDrawable::Path* ptr, PathData* startValue,
- PathData* endValue)
- : PropertyValuesHolderImpl(*startValue, *endValue)
- , mPath(ptr) {
+ PathData* endValue)
+ : PropertyValuesHolderImpl(*startValue, *endValue), mPath(ptr) {
mEvaluator.reset(new PathEvaluator());
};
void setFraction(float fraction) override;
+
private:
VectorDrawable::Path* mPath;
PathData mPathData;
@@ -148,11 +149,11 @@
class ANDROID_API RootAlphaPropertyValuesHolder : public PropertyValuesHolderImpl<float> {
public:
RootAlphaPropertyValuesHolder(VectorDrawable::Tree* tree, float startValue, float endValue)
- : PropertyValuesHolderImpl(startValue, endValue)
- , mTree(tree) {
+ : PropertyValuesHolderImpl(startValue, endValue), mTree(tree) {
mEvaluator.reset(new FloatEvaluator());
}
void setFraction(float fraction) override;
+
private:
VectorDrawable::Tree* mTree;
};
diff --git a/libs/hwui/Readback.h b/libs/hwui/Readback.h
index 7cf4262..ad3a8b6 100644
--- a/libs/hwui/Readback.h
+++ b/libs/hwui/Readback.h
@@ -16,8 +16,8 @@
#pragma once
-#include "renderthread/RenderThread.h"
#include "Rect.h"
+#include "renderthread/RenderThread.h"
#include <SkBitmap.h>
@@ -41,8 +41,7 @@
/**
* Copies the surface's most recently queued buffer into the provided bitmap.
*/
- virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
- SkBitmap* bitmap) = 0;
+ virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect, SkBitmap* bitmap) = 0;
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0;
protected:
@@ -52,5 +51,5 @@
renderthread::RenderThread& mRenderThread;
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index 3b87aef..2d0185a 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -16,15 +16,15 @@
#pragma once
-#include "font/FontUtil.h"
#include "GlLayer.h"
#include "Matrix.h"
#include "Rect.h"
#include "RenderNode.h"
#include "TessellationCache.h"
+#include "Vector.h"
+#include "font/FontUtil.h"
#include "utils/LinearAllocator.h"
#include "utils/PaintUtils.h"
-#include "Vector.h"
#include <androidfw/ResourceTypes.h>
@@ -73,39 +73,40 @@
* MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged
* under certain circumstances.
*/
-#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, MERGEABLE_OP_FN) \
- PRE_RENDER_OP_FN(RenderNodeOp) \
- PRE_RENDER_OP_FN(CirclePropsOp) \
- PRE_RENDER_OP_FN(RoundRectPropsOp) \
- PRE_RENDER_OP_FN(BeginLayerOp) \
- PRE_RENDER_OP_FN(EndLayerOp) \
- PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \
- PRE_RENDER_OP_FN(EndUnclippedLayerOp) \
- PRE_RENDER_OP_FN(VectorDrawableOp) \
- \
- RENDER_ONLY_OP_FN(ShadowOp) \
- RENDER_ONLY_OP_FN(LayerOp) \
- RENDER_ONLY_OP_FN(CopyToLayerOp) \
- RENDER_ONLY_OP_FN(CopyFromLayerOp) \
- \
- UNMERGEABLE_OP_FN(ArcOp) \
- UNMERGEABLE_OP_FN(BitmapMeshOp) \
- UNMERGEABLE_OP_FN(BitmapRectOp) \
- UNMERGEABLE_OP_FN(ColorOp) \
- UNMERGEABLE_OP_FN(FunctorOp) \
- UNMERGEABLE_OP_FN(LinesOp) \
- UNMERGEABLE_OP_FN(OvalOp) \
- UNMERGEABLE_OP_FN(PathOp) \
- UNMERGEABLE_OP_FN(PointsOp) \
- UNMERGEABLE_OP_FN(RectOp) \
- UNMERGEABLE_OP_FN(RoundRectOp) \
- UNMERGEABLE_OP_FN(SimpleRectsOp) \
- UNMERGEABLE_OP_FN(TextOnPathOp) \
- UNMERGEABLE_OP_FN(TextureLayerOp) \
- \
- MERGEABLE_OP_FN(BitmapOp) \
- MERGEABLE_OP_FN(PatchOp) \
- MERGEABLE_OP_FN(TextOp)
+#define MAP_OPS_BASED_ON_TYPE(PRE_RENDER_OP_FN, RENDER_ONLY_OP_FN, UNMERGEABLE_OP_FN, \
+ MERGEABLE_OP_FN) \
+ PRE_RENDER_OP_FN(RenderNodeOp) \
+ PRE_RENDER_OP_FN(CirclePropsOp) \
+ PRE_RENDER_OP_FN(RoundRectPropsOp) \
+ PRE_RENDER_OP_FN(BeginLayerOp) \
+ PRE_RENDER_OP_FN(EndLayerOp) \
+ PRE_RENDER_OP_FN(BeginUnclippedLayerOp) \
+ PRE_RENDER_OP_FN(EndUnclippedLayerOp) \
+ PRE_RENDER_OP_FN(VectorDrawableOp) \
+ \
+ RENDER_ONLY_OP_FN(ShadowOp) \
+ RENDER_ONLY_OP_FN(LayerOp) \
+ RENDER_ONLY_OP_FN(CopyToLayerOp) \
+ RENDER_ONLY_OP_FN(CopyFromLayerOp) \
+ \
+ UNMERGEABLE_OP_FN(ArcOp) \
+ UNMERGEABLE_OP_FN(BitmapMeshOp) \
+ UNMERGEABLE_OP_FN(BitmapRectOp) \
+ UNMERGEABLE_OP_FN(ColorOp) \
+ UNMERGEABLE_OP_FN(FunctorOp) \
+ UNMERGEABLE_OP_FN(LinesOp) \
+ UNMERGEABLE_OP_FN(OvalOp) \
+ UNMERGEABLE_OP_FN(PathOp) \
+ UNMERGEABLE_OP_FN(PointsOp) \
+ UNMERGEABLE_OP_FN(RectOp) \
+ UNMERGEABLE_OP_FN(RoundRectOp) \
+ UNMERGEABLE_OP_FN(SimpleRectsOp) \
+ UNMERGEABLE_OP_FN(TextOnPathOp) \
+ UNMERGEABLE_OP_FN(TextureLayerOp) \
+ \
+ MERGEABLE_OP_FN(BitmapOp) \
+ MERGEABLE_OP_FN(PatchOp) \
+ MERGEABLE_OP_FN(TextOp)
/**
* LUT generators, which will insert nullptr for unsupported ops
@@ -113,16 +114,16 @@
#define NULLPTR_OP_FN(Type) nullptr,
#define BUILD_DEFERRABLE_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, NULLPTR_OP_FN, OP_FN, OP_FN) }
#define BUILD_MERGEABLE_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, NULLPTR_OP_FN, NULLPTR_OP_FN, OP_FN) }
#define BUILD_RENDERABLE_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(NULLPTR_OP_FN, OP_FN, OP_FN, OP_FN) }
#define BUILD_FULL_OP_LUT(OP_FN) \
- { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
+ { MAP_OPS_BASED_ON_TYPE(OP_FN, OP_FN, OP_FN, OP_FN) }
/**
* Op mapping functions, which skip unsupported ops.
@@ -131,30 +132,29 @@
*/
#define NULL_OP_FN(Type)
-#define MAP_DEFERRABLE_OPS(OP_FN) \
- MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
+#define MAP_DEFERRABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(OP_FN, NULL_OP_FN, OP_FN, OP_FN)
-#define MAP_MERGEABLE_OPS(OP_FN) \
- MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
+#define MAP_MERGEABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, NULL_OP_FN, NULL_OP_FN, OP_FN)
-#define MAP_RENDERABLE_OPS(OP_FN) \
- MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
+#define MAP_RENDERABLE_OPS(OP_FN) MAP_OPS_BASED_ON_TYPE(NULL_OP_FN, OP_FN, OP_FN, OP_FN)
// Generate OpId enum
#define IDENTITY_FN(Type) Type,
namespace RecordedOpId {
- enum {
- MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN)
- Count,
- };
+enum {
+ MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN) Count,
+};
}
-static_assert(RecordedOpId::RenderNodeOp == 0,
- "First index must be zero for LUTs to work");
+static_assert(RecordedOpId::RenderNodeOp == 0, "First index must be zero for LUTs to work");
-#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
-#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
+#define BASE_PARAMS \
+ const Rect &unmappedBounds, const Matrix4 &localMatrix, const ClipBase *localClip, \
+ const SkPaint *paint
+#define BASE_PARAMS_PAINTLESS \
+ const Rect &unmappedBounds, const Matrix4 &localMatrix, const ClipBase *localClip
#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
-#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
+#define SUPER_PAINTLESS(Type) \
+ RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
struct RecordedOp {
/* ID from RecordedOpId - generally used for jumping into function tables */
@@ -171,6 +171,7 @@
/* optional paint, stored in base object to simplify merging logic */
const SkPaint* paint;
+
protected:
RecordedOp(unsigned int opId, BASE_PARAMS)
: opId(opId)
@@ -182,9 +183,8 @@
struct RenderNodeOp : RecordedOp {
RenderNodeOp(BASE_PARAMS_PAINTLESS, RenderNode* renderNode)
- : SUPER_PAINTLESS(RenderNodeOp)
- , renderNode(renderNode) {}
- RenderNode * renderNode; // not const, since drawing modifies it
+ : SUPER_PAINTLESS(RenderNodeOp), renderNode(renderNode) {}
+ RenderNode* renderNode; // not const, since drawing modifies it
/**
* Holds the transformation between the projection surface ViewGroup and this RenderNode
@@ -204,25 +204,20 @@
struct ArcOp : RecordedOp {
ArcOp(BASE_PARAMS, float startAngle, float sweepAngle, bool useCenter)
- : SUPER(ArcOp)
- , startAngle(startAngle)
- , sweepAngle(sweepAngle)
- , useCenter(useCenter) {}
+ : SUPER(ArcOp), startAngle(startAngle), sweepAngle(sweepAngle), useCenter(useCenter) {}
const float startAngle;
const float sweepAngle;
const bool useCenter;
};
struct BitmapOp : RecordedOp {
- BitmapOp(BASE_PARAMS, Bitmap* bitmap)
- : SUPER(BitmapOp)
- , bitmap(bitmap) {}
+ BitmapOp(BASE_PARAMS, Bitmap* bitmap) : SUPER(BitmapOp), bitmap(bitmap) {}
Bitmap* bitmap;
};
struct BitmapMeshOp : RecordedOp {
- BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors)
+ BitmapMeshOp(BASE_PARAMS, Bitmap* bitmap, int meshWidth, int meshHeight, const float* vertices,
+ const int* colors)
: SUPER(BitmapMeshOp)
, bitmap(bitmap)
, meshWidth(meshWidth)
@@ -238,16 +233,14 @@
struct BitmapRectOp : RecordedOp {
BitmapRectOp(BASE_PARAMS, Bitmap* bitmap, const Rect& src)
- : SUPER(BitmapRectOp)
- , bitmap(bitmap)
- , src(src) {}
+ : SUPER(BitmapRectOp), bitmap(bitmap), src(src) {}
Bitmap* bitmap;
const Rect src;
};
struct CirclePropsOp : RecordedOp {
CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
- float* x, float* y, float* radius)
+ float* x, float* y, float* radius)
: RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
, x(x)
, y(y)
@@ -278,60 +271,47 @@
struct LinesOp : RecordedOp {
LinesOp(BASE_PARAMS, const float* points, const int floatCount)
- : SUPER(LinesOp)
- , points(points)
- , floatCount(floatCount) {}
+ : SUPER(LinesOp), points(points), floatCount(floatCount) {}
const float* points;
const int floatCount;
};
struct OvalOp : RecordedOp {
- OvalOp(BASE_PARAMS)
- : SUPER(OvalOp) {}
+ OvalOp(BASE_PARAMS) : SUPER(OvalOp) {}
};
struct PatchOp : RecordedOp {
PatchOp(BASE_PARAMS, Bitmap* bitmap, const Res_png_9patch* patch)
- : SUPER(PatchOp)
- , bitmap(bitmap)
- , patch(patch) {}
+ : SUPER(PatchOp), bitmap(bitmap), patch(patch) {}
Bitmap* bitmap;
const Res_png_9patch* patch;
};
struct PathOp : RecordedOp {
- PathOp(BASE_PARAMS, const SkPath* path)
- : SUPER(PathOp)
- , path(path) {}
+ PathOp(BASE_PARAMS, const SkPath* path) : SUPER(PathOp), path(path) {}
const SkPath* path;
};
struct PointsOp : RecordedOp {
PointsOp(BASE_PARAMS, const float* points, const int floatCount)
- : SUPER(PointsOp)
- , points(points)
- , floatCount(floatCount) {}
+ : SUPER(PointsOp), points(points), floatCount(floatCount) {}
const float* points;
const int floatCount;
};
struct RectOp : RecordedOp {
- RectOp(BASE_PARAMS)
- : SUPER(RectOp) {}
+ RectOp(BASE_PARAMS) : SUPER(RectOp) {}
};
struct RoundRectOp : RecordedOp {
- RoundRectOp(BASE_PARAMS, float rx, float ry)
- : SUPER(RoundRectOp)
- , rx(rx)
- , ry(ry) {}
+ RoundRectOp(BASE_PARAMS, float rx, float ry) : SUPER(RoundRectOp), rx(rx), ry(ry) {}
const float rx;
const float ry;
};
struct RoundRectPropsOp : RecordedOp {
RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
- float* left, float* top, float* right, float* bottom, float *rx, float *ry)
+ float* left, float* top, float* right, float* bottom, float* rx, float* ry)
: RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
, left(left)
, top(top)
@@ -349,8 +329,7 @@
struct VectorDrawableOp : RecordedOp {
VectorDrawableOp(VectorDrawable::Tree* tree, BASE_PARAMS_PAINTLESS)
- : SUPER_PAINTLESS(VectorDrawableOp)
- , vectorDrawable(tree) {}
+ : SUPER_PAINTLESS(VectorDrawableOp), vectorDrawable(tree) {}
VectorDrawable::Tree* vectorDrawable;
};
@@ -366,24 +345,21 @@
ShadowOp(sp<TessellationCache::ShadowTask>& shadowTask, float casterAlpha)
: RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
, shadowTask(shadowTask)
- , casterAlpha(casterAlpha) {
- };
+ , casterAlpha(casterAlpha){};
sp<TessellationCache::ShadowTask> shadowTask;
const float casterAlpha;
};
-struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
+struct SimpleRectsOp : RecordedOp { // Filled, no AA (TODO: better name?)
SimpleRectsOp(BASE_PARAMS, Vertex* vertices, size_t vertexCount)
- : SUPER(SimpleRectsOp)
- , vertices(vertices)
- , vertexCount(vertexCount) {}
+ : SUPER(SimpleRectsOp), vertices(vertices), vertexCount(vertexCount) {}
Vertex* vertices;
const size_t vertexCount;
};
struct TextOp : RecordedOp {
- TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount,
- float x, float y)
+ TextOp(BASE_PARAMS, const glyph_t* glyphs, const float* positions, int glyphCount, float x,
+ float y)
: SUPER(TextOp)
, glyphs(glyphs)
, positions(positions)
@@ -400,7 +376,8 @@
struct TextOnPathOp : RecordedOp {
// TODO: explicitly define bounds
TextOnPathOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
- const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset, float vOffset)
+ const glyph_t* glyphs, int glyphCount, const SkPath* path, float hOffset,
+ float vOffset)
: RecordedOp(RecordedOpId::TextOnPathOp, Rect(), localMatrix, localClip, paint)
, glyphs(glyphs)
, glyphCount(glyphCount)
@@ -417,16 +394,13 @@
struct TextureLayerOp : RecordedOp {
TextureLayerOp(BASE_PARAMS_PAINTLESS, DeferredLayerUpdater* layer)
- : SUPER_PAINTLESS(TextureLayerOp)
- , layerHandle(layer) {}
+ : SUPER_PAINTLESS(TextureLayerOp), layerHandle(layer) {}
// Copy an existing TextureLayerOp, replacing the underlying matrix
TextureLayerOp(const TextureLayerOp& op, const Matrix4& replacementMatrix)
: RecordedOp(RecordedOpId::TextureLayerOp, op.unmappedBounds, replacementMatrix,
- op.localClip, op.paint)
- , layerHandle(op.layerHandle) {
-
- }
+ op.localClip, op.paint)
+ , layerHandle(op.layerHandle) {}
DeferredLayerUpdater* layerHandle;
};
@@ -439,8 +413,7 @@
* and that commands following will render into it.
*/
struct BeginLayerOp : RecordedOp {
- BeginLayerOp(BASE_PARAMS)
- : SUPER(BeginLayerOp) {}
+ BeginLayerOp(BASE_PARAMS) : SUPER(BeginLayerOp) {}
};
/**
@@ -455,22 +428,20 @@
};
struct BeginUnclippedLayerOp : RecordedOp {
- BeginUnclippedLayerOp(BASE_PARAMS)
- : SUPER(BeginUnclippedLayerOp) {}
+ BeginUnclippedLayerOp(BASE_PARAMS) : SUPER(BeginUnclippedLayerOp) {}
};
struct EndUnclippedLayerOp : RecordedOp {
EndUnclippedLayerOp()
- : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
+ : RecordedOp(RecordedOpId::EndUnclippedLayerOp, Rect(), Matrix4::identity(), nullptr,
+ nullptr) {}
};
struct CopyToLayerOp : RecordedOp {
CopyToLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
- : RecordedOp(RecordedOpId::CopyToLayerOp,
- op.unmappedBounds,
- op.localMatrix,
- nullptr, // clip intentionally ignored
- op.paint)
+ : RecordedOp(RecordedOpId::CopyToLayerOp, op.unmappedBounds, op.localMatrix,
+ nullptr, // clip intentionally ignored
+ op.paint)
, layerHandle(layerHandle) {}
// Records a handle to the Layer object, since the Layer itself won't be
@@ -478,15 +449,12 @@
OffscreenBuffer** layerHandle;
};
-
// draw the parameter layer underneath
struct CopyFromLayerOp : RecordedOp {
CopyFromLayerOp(const RecordedOp& op, OffscreenBuffer** layerHandle)
- : RecordedOp(RecordedOpId::CopyFromLayerOp,
- op.unmappedBounds,
- op.localMatrix,
- nullptr, // clip intentionally ignored
- op.paint)
+ : RecordedOp(RecordedOpId::CopyFromLayerOp, op.unmappedBounds, op.localMatrix,
+ nullptr, // clip intentionally ignored
+ op.paint)
, layerHandle(layerHandle) {}
// Records a handle to the Layer object, since the Layer itself won't be
@@ -510,7 +478,8 @@
, colorFilter(paint ? paint->getColorFilter() : nullptr) {}
explicit LayerOp(RenderNode& node)
- : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
+ : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()),
+ Matrix4::identity(), nullptr, nullptr)
, layerHandle(node.getLayerHandle())
, alpha(node.properties().layerProperties().alpha() / 255.0f)
, mode(node.properties().layerProperties().xferMode())
@@ -527,5 +496,5 @@
SkColorFilter* colorFilter;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index d966372..3fb1c0d 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -26,19 +26,16 @@
namespace uirenderer {
RecordingCanvas::RecordingCanvas(size_t width, size_t height)
- : mState(*this)
- , mResourceCache(ResourceCache::getInstance()) {
+ : mState(*this), mResourceCache(ResourceCache::getInstance()) {
resetRecording(width, height);
}
RecordingCanvas::~RecordingCanvas() {
- LOG_ALWAYS_FATAL_IF(mDisplayList,
- "Destroyed a RecordingCanvas during a record!");
+ LOG_ALWAYS_FATAL_IF(mDisplayList, "Destroyed a RecordingCanvas during a record!");
}
void RecordingCanvas::resetRecording(int width, int height, RenderNode* node) {
- LOG_ALWAYS_FATAL_IF(mDisplayList,
- "prepareDirty called a second time during a recording!");
+ LOG_ALWAYS_FATAL_IF(mDisplayList, "prepareDirty called a second time during a recording!");
mDisplayList = new DisplayList();
mState.initializeRecordingSaveStack(width, height);
@@ -68,8 +65,7 @@
}
SkCanvas* RecordingCanvas::asSkCanvas() {
- LOG_ALWAYS_FATAL_IF(!mDisplayList,
- "attempting to get an SkCanvas when we are not recording!");
+ LOG_ALWAYS_FATAL_IF(!mDisplayList, "attempting to get an SkCanvas when we are not recording!");
if (!mSkiaCanvasProxy) {
mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
}
@@ -88,8 +84,7 @@
// CanvasStateClient implementation
// ----------------------------------------------------------------------------
-void RecordingCanvas::onViewportInitialized() {
-}
+void RecordingCanvas::onViewportInitialized() {}
void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
if (removed.flags & Snapshot::kFlagIsFboLayer) {
@@ -104,7 +99,7 @@
// ----------------------------------------------------------------------------
// Save (layer)
int RecordingCanvas::save(SaveFlags::Flags flags) {
- return mState.save((int) flags);
+ return mState.save((int)flags);
}
void RecordingCanvas::RecordingCanvas::restore() {
@@ -116,7 +111,7 @@
}
int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) {
+ const SkPaint* paint, SaveFlags::Flags flags) {
// force matrix/clip isolation for layer
flags |= SaveFlags::MatrixClip;
bool clippedLayer = flags & SaveFlags::ClipToLayer;
@@ -134,9 +129,8 @@
Rect visibleBounds = unmappedBounds;
previous.transform->mapRect(visibleBounds);
- if (CC_UNLIKELY(!clippedLayer
- && previous.transform->rectToRect()
- && visibleBounds.contains(previous.getRenderTargetClip()))) {
+ if (CC_UNLIKELY(!clippedLayer && previous.transform->rectToRect() &&
+ visibleBounds.contains(previous.getRenderTargetClip()))) {
// unlikely case where an unclipped savelayer is recorded with a clip it can use,
// as none of its unaffected/unclipped area is visible
clippedLayer = true;
@@ -157,18 +151,18 @@
layerBounds.doIntersect(unmappedBounds);
}
- int saveValue = mState.save((int) flags);
+ int saveValue = mState.save((int)flags);
Snapshot& snapshot = *mState.writableSnapshot();
// layerBounds is in original bounds space, but clipped by current recording clip
if (!layerBounds.isEmpty() && !unmappedBounds.isEmpty()) {
if (CC_LIKELY(clippedLayer)) {
- auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed
+ auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed
if (addOp(alloc().create_trivial<BeginLayerOp>(
- unmappedBounds,
- *previous.transform, // transform to *draw* with
- previousClip, // clip to *draw* with
- refPaint(paint))) >= 0) {
+ unmappedBounds,
+ *previous.transform, // transform to *draw* with
+ previousClip, // clip to *draw* with
+ refPaint(paint))) >= 0) {
snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer;
snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight());
snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f);
@@ -181,10 +175,8 @@
}
} else {
if (addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
- unmappedBounds,
- *mState.currentSnapshot()->transform,
- getRecordedClip(),
- refPaint(paint))) >= 0) {
+ unmappedBounds, *mState.currentSnapshot()->transform, getRecordedClip(),
+ refPaint(paint))) >= 0) {
snapshot.flags |= Snapshot::kFlagIsLayer;
return saveValue;
}
@@ -245,10 +237,7 @@
// android/graphics/Canvas draw operations
// ----------------------------------------------------------------------------
void RecordingCanvas::drawColor(int color, SkBlendMode mode) {
- addOp(alloc().create_trivial<ColorOp>(
- getRecordedClip(),
- color,
- mode));
+ addOp(alloc().create_trivial<ColorOp>(getRecordedClip(), color, mode));
}
void RecordingCanvas::drawPaint(const SkPaint& paint) {
@@ -269,40 +258,35 @@
// Geometry
void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) {
if (CC_UNLIKELY(floatCount < 2 || paint.nothingToDraw())) return;
- floatCount &= ~0x1; // round down to nearest two
+ floatCount &= ~0x1; // round down to nearest two
addOp(alloc().create_trivial<PointsOp>(
- calcBoundsOfPoints(points, floatCount),
- *mState.currentSnapshot()->transform,
- getRecordedClip(),
- refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
+ calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform,
+ getRecordedClip(), refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) {
if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return;
- floatCount &= ~0x3; // round down to nearest four
+ floatCount &= ~0x3; // round down to nearest four
addOp(alloc().create_trivial<LinesOp>(
- calcBoundsOfPoints(points, floatCount),
- *mState.currentSnapshot()->transform,
- getRecordedClip(),
- refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
+ calcBoundsOfPoints(points, floatCount), *mState.currentSnapshot()->transform,
+ getRecordedClip(), refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
}
-void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
+void RecordingCanvas::drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- addOp(alloc().create_trivial<RectOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint)));
+ addOp(alloc().create_trivial<RectOp>(Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint)));
}
void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
if (rects == nullptr) return;
- Vertex* rectData = (Vertex*) mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
+ Vertex* rectData = (Vertex*)mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
Vertex* vertex = rectData;
float left = FLT_MAX;
@@ -326,17 +310,15 @@
bottom = std::max(bottom, b);
}
addOp(alloc().create_trivial<SimpleRectsOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), rectData, vertexCount));
+ Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), rectData, vertexCount));
}
void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- if (paint.getStyle() == SkPaint::kFill_Style
- && (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
+ if (paint.getStyle() == SkPaint::kFill_Style &&
+ (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
int count = 0;
Vector<float> rects;
SkRegion::Iterator it(region);
@@ -360,26 +342,23 @@
}
}
-void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) {
+void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx,
+ float ry, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) {
- addOp(alloc().create_trivial<RoundRectOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), rx, ry));
+ addOp(alloc().create_trivial<RoundRectOp>(Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(&paint), rx, ry));
} else {
drawRect(left, top, right, bottom, paint);
}
}
-void RecordingCanvas::drawRoundRect(
- CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
- CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
- CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
- CanvasPropertyPaint* paint) {
+void RecordingCanvas::drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
+ CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
+ CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
+ CanvasPropertyPaint* paint) {
mDisplayList->ref(left);
mDisplayList->ref(top);
mDisplayList->ref(right);
@@ -389,11 +368,8 @@
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
addOp(alloc().create_trivial<RoundRectPropsOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- &paint->value,
- &left->value, &top->value, &right->value, &bottom->value,
- &rx->value, &ry->value));
+ *(mState.currentSnapshot()->transform), getRecordedClip(), &paint->value, &left->value,
+ &top->value, &right->value, &bottom->value, &rx->value, &ry->value));
}
void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
@@ -403,65 +379,54 @@
drawOval(x - radius, y - radius, x + radius, y + radius, paint);
}
-void RecordingCanvas::drawCircle(
- CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
- CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
+void RecordingCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
mDisplayList->ref(x);
mDisplayList->ref(y);
mDisplayList->ref(radius);
mDisplayList->ref(paint);
refBitmapsInShader(paint->value.getShader());
- addOp(alloc().create_trivial<CirclePropsOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- &paint->value,
- &x->value, &y->value, &radius->value));
+ addOp(alloc().create_trivial<CirclePropsOp>(*(mState.currentSnapshot()->transform),
+ getRecordedClip(), &paint->value, &x->value,
+ &y->value, &radius->value));
}
-void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
+void RecordingCanvas::drawOval(float left, float top, float right, float bottom,
+ const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- addOp(alloc().create_trivial<OvalOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint)));
+ addOp(alloc().create_trivial<OvalOp>(Rect(left, top, right, bottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint)));
}
-void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+void RecordingCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
if (fabs(sweepAngle) >= 360.0f) {
drawOval(left, top, right, bottom, paint);
} else {
addOp(alloc().create_trivial<ArcOp>(
- Rect(left, top, right, bottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint),
- startAngle, sweepAngle, useCenter));
+ Rect(left, top, right, bottom), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(&paint), startAngle, sweepAngle, useCenter));
}
}
void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
- addOp(alloc().create_trivial<PathOp>(
- Rect(path.getBounds()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), refPath(&path)));
+ addOp(alloc().create_trivial<PathOp>(Rect(path.getBounds()),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint), refPath(&path)));
}
void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
mDisplayList->ref(tree);
mDisplayList->vectorDrawables.push_back(tree);
addOp(alloc().create_trivial<VectorDrawableOp>(
- tree,
- Rect(tree->stagingProperties()->getBounds()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip()));
+ tree, Rect(tree->stagingProperties()->getBounds()),
+ *(mState.currentSnapshot()->transform), getRecordedClip()));
}
// Bitmap-based
@@ -472,20 +437,19 @@
restore();
}
-void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) {
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
if (matrix.isIdentity()) {
drawBitmap(bitmap, paint);
- } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
- && MathUtils::isPositive(matrix.getScaleX())
- && MathUtils::isPositive(matrix.getScaleY())) {
+ } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) &&
+ MathUtils::isPositive(matrix.getScaleX()) &&
+ MathUtils::isPositive(matrix.getScaleY())) {
// SkMatrix::isScaleTranslate() not available in L
SkRect src;
SkRect dst;
bitmap.getBounds(&src);
matrix.mapRect(&dst, src);
- drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
- dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop,
+ dst.fRight, dst.fBottom, paint);
} else {
save(SaveFlags::Matrix);
concat(matrix);
@@ -494,14 +458,11 @@
}
}
-void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) {
- if (srcLeft == 0 && srcTop == 0
- && srcRight == bitmap.width()
- && srcBottom == bitmap.height()
- && (srcBottom - srcTop == dstBottom - dstTop)
- && (srcRight - srcLeft == dstRight - dstLeft)) {
+void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) {
+ if (srcLeft == 0 && srcTop == 0 && srcRight == bitmap.width() && srcBottom == bitmap.height() &&
+ (srcBottom - srcTop == dstBottom - dstTop) && (srcRight - srcLeft == dstRight - dstLeft)) {
// transform simple rect to rect drawing case into position bitmap ops, since they merge
save(SaveFlags::Matrix);
translate(dstLeft, dstTop);
@@ -509,56 +470,50 @@
restore();
} else {
addOp(alloc().create_trivial<BitmapRectOp>(
- Rect(dstLeft, dstTop, dstRight, dstBottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap),
+ Rect(dstLeft, dstTop, dstRight, dstBottom), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), refBitmap(bitmap),
Rect(srcLeft, srcTop, srcRight, srcBottom)));
}
}
void RecordingCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) {
+ const float* vertices, const int* colors,
+ const SkPaint* paint) {
int vertexCount = (meshWidth + 1) * (meshHeight + 1);
addOp(alloc().create_trivial<BitmapMeshOp>(
- calcBoundsOfPoints(vertices, vertexCount * 2),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
- refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
- refBuffer<int>(colors, vertexCount))); // 1 color per vertex
+ calcBoundsOfPoints(vertices, vertexCount * 2), *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
+ refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
+ refBuffer<int>(colors, vertexCount))); // 1 color per vertex
}
void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& patch,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) {
- addOp(alloc().create_trivial<PatchOp>(
- Rect(dstLeft, dstTop, dstRight, dstBottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) {
+ addOp(alloc().create_trivial<PatchOp>(Rect(dstLeft, dstTop, dstRight, dstBottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
}
// Text
void RecordingCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int glyphCount, const SkPaint& paint,
- float x, float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) {
+ float x, float y, float boundsLeft, float boundsTop,
+ float boundsRight, float boundsBottom, float totalAdvance) {
if (glyphCount <= 0 || paint.nothingToDraw()) return;
uint16_t* glyphs = (glyph_t*)alloc().alloc<glyph_t>(glyphCount * sizeof(glyph_t));
float* positions = (float*)alloc().alloc<float>(2 * glyphCount * sizeof(float));
glyphFunc(glyphs, positions);
// TODO: either must account for text shadow in bounds, or record separate ops for text shadows
- addOp(alloc().create_trivial<TextOp>(
- Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), glyphs, positions, glyphCount, x, y));
+ addOp(alloc().create_trivial<TextOp>(Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
+ *(mState.currentSnapshot()->transform), getRecordedClip(),
+ refPaint(&paint), glyphs, positions, glyphCount, x, y));
drawTextDecorations(x, y, totalAdvance, paint);
}
void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) {
uint16_t glyphs[1];
for (size_t i = start; i < end; i++) {
glyphs[0] = layout.getGlyphId(i);
@@ -566,28 +521,23 @@
float y = vOffset + layout.getY(i);
if (paint.nothingToDraw()) return;
const uint16_t* tempGlyphs = refBuffer<glyph_t>(glyphs, 1);
- addOp(alloc().create_trivial<TextOnPathOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(&paint), tempGlyphs, 1, refPath(&path), x, y));
+ addOp(alloc().create_trivial<TextOnPathOp>(*(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(&paint), tempGlyphs,
+ 1, refPath(&path), x, y));
}
}
void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkPaint* paint) {
- addOp(alloc().create_trivial<BitmapOp>(
- Rect(bitmap.width(), bitmap.height()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- refPaint(paint), refBitmap(bitmap)));
+ addOp(alloc().create_trivial<BitmapOp>(Rect(bitmap.width(), bitmap.height()),
+ *(mState.currentSnapshot()->transform),
+ getRecordedClip(), refPaint(paint), refBitmap(bitmap)));
}
void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
auto&& stagingProps = renderNode->stagingProperties();
RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
Rect(stagingProps.getWidth(), stagingProps.getHeight()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- renderNode);
+ *(mState.currentSnapshot()->transform), getRecordedClip(), renderNode);
int opIndex = addOp(op);
if (CC_LIKELY(opIndex >= 0)) {
int childIndex = mDisplayList->addChild(op);
@@ -612,18 +562,14 @@
// its width, height, transform, etc...!
addOp(alloc().create_trivial<TextureLayerOp>(
Rect(layerHandle->getWidth(), layerHandle->getHeight()),
- *(mState.currentSnapshot()->transform),
- getRecordedClip(), layerHandle));
+ *(mState.currentSnapshot()->transform), getRecordedClip(), layerHandle));
}
-void RecordingCanvas::callDrawGLFunction(Functor* functor,
- GlFunctorLifecycleListener* listener) {
+void RecordingCanvas::callDrawGLFunction(Functor* functor, GlFunctorLifecycleListener* listener) {
mDisplayList->functors.push_back({functor, listener});
mDisplayList->ref(listener);
- addOp(alloc().create_trivial<FunctorOp>(
- *(mState.currentSnapshot()->transform),
- getRecordedClip(),
- functor));
+ addOp(alloc().create_trivial<FunctorOp>(*(mState.currentSnapshot()->transform),
+ getRecordedClip(), functor));
}
int RecordingCanvas::addOp(RecordedOp* op) {
@@ -676,5 +622,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 79db496..3087db0 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -40,49 +40,50 @@
class DeferredLayerUpdater;
struct RecordedOp;
-class ANDROID_API RecordingCanvas: public Canvas, public CanvasStateClient {
+class ANDROID_API RecordingCanvas : public Canvas, public CanvasStateClient {
enum class DeferredBarrierType {
None,
InOrder,
OutOfOrder,
};
+
public:
RecordingCanvas(size_t width, size_t height);
virtual ~RecordingCanvas();
virtual void resetRecording(int width, int height, RenderNode* node = nullptr) override;
virtual WARN_UNUSED_RESULT DisplayList* finishRecording() override;
-// ----------------------------------------------------------------------------
-// MISC HWUI OPERATIONS - TODO: CATEGORIZE
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // MISC HWUI OPERATIONS - TODO: CATEGORIZE
+ // ----------------------------------------------------------------------------
virtual void insertReorderBarrier(bool enableReorder) override;
virtual void drawLayer(DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(RenderNode* renderNode) override;
virtual void callDrawGLFunction(Functor* functor,
- GlFunctorLifecycleListener* listener) override;
+ GlFunctorLifecycleListener* listener) override;
-// ----------------------------------------------------------------------------
-// CanvasStateClient interface
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // CanvasStateClient interface
+ // ----------------------------------------------------------------------------
virtual void onViewportInitialized() override;
virtual void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) override;
virtual GLuint getTargetFbo() const override { return -1; }
-// ----------------------------------------------------------------------------
-// HWUI Canvas draw operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // HWUI Canvas draw operations
+ // ----------------------------------------------------------------------------
virtual void drawRoundRect(CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
- CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
- CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
- CanvasPropertyPaint* paint) override;
+ CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
+ CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
+ CanvasPropertyPaint* paint) override;
virtual void drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
- CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override;
+ CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) override;
-// ----------------------------------------------------------------------------
-// android/graphics/Canvas interface
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // android/graphics/Canvas interface
+ // ----------------------------------------------------------------------------
virtual SkCanvas* asSkCanvas() override;
virtual void setBitmap(const SkBitmap& bitmap) override {
@@ -93,9 +94,9 @@
virtual int width() override { return mState.getWidth(); }
virtual int height() override { return mState.getHeight(); }
-// ----------------------------------------------------------------------------
-// android/graphics/Canvas state operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // android/graphics/Canvas state operations
+ // ----------------------------------------------------------------------------
// Save (layer)
virtual int getSaveCount() const override { return mState.getSaveCount(); }
virtual int save(SaveFlags::Flags flags) override;
@@ -103,9 +104,9 @@
virtual void restoreToCount(int saveCount) override;
virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
- SaveFlags::Flags flags) override;
- virtual int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) override {
+ SaveFlags::Flags flags) override;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) override {
SkPaint paint;
paint.setAlpha(alpha);
return saveLayer(left, top, right, bottom, &paint, flags);
@@ -126,8 +127,7 @@
virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
virtual bool quickRejectPath(const SkPath& path) const override;
- virtual bool clipRect(float left, float top, float right, float bottom,
- SkClipOp op) override;
+ virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override;
virtual bool clipPath(const SkPath* path, SkClipOp op) override;
// Misc
@@ -136,59 +136,64 @@
mDrawFilter.reset(SkSafeRef(filter));
}
-// ----------------------------------------------------------------------------
-// android/graphics/Canvas draw operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // android/graphics/Canvas draw operations
+ // ----------------------------------------------------------------------------
virtual void drawColor(int color, SkBlendMode mode) override;
virtual void drawPaint(const SkPaint& paint) override;
// Geometry
virtual void drawPoint(float x, float y, const SkPaint& paint) override {
- float points[2] = { x, y };
+ float points[2] = {x, y};
drawPoints(points, 2, paint);
}
virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) override;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) override {
- float points[4] = { startX, startY, stopX, stopY };
+ const SkPaint& paint) override {
+ float points[4] = {startX, startY, stopX, stopY};
drawLines(points, 4, paint);
}
virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) override;
- virtual void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
+ virtual void drawRect(float left, float top, float right, float bottom,
+ const SkPaint& paint) override;
virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
- virtual void drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) override;
+ virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) override;
virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
- virtual void drawOval(float left, float top, float right, float bottom, const SkPaint& paint) override;
- virtual void drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+ virtual void drawOval(float left, float top, float right, float bottom,
+ const SkPaint& paint) override;
+ virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) override;
virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
- virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override
- { /* RecordingCanvas does not support drawVertices(); ignore */ }
+ virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint)
+ override { /* RecordingCanvas does not support drawVertices(); ignore */
+ }
virtual void drawVectorDrawable(VectorDrawableRoot* tree) override;
// Bitmap-based
virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) override;
- virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ const float* vertices, const int* colors,
+ const SkPaint* paint) override;
+ virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
// Text
virtual bool drawTextAbsolutePos() const override { return false; }
protected:
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) override;
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) override;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) override;
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) override;
private:
const ClipBase* getRecordedClip() {
@@ -198,20 +203,19 @@
void drawBitmap(Bitmap& bitmap, const SkPaint* paint);
void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
-
int addOp(RecordedOp* op);
-// ----------------------------------------------------------------------------
-// lazy object copy
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // lazy object copy
+ // ----------------------------------------------------------------------------
LinearAllocator& alloc() { return mDisplayList->allocator; }
void refBitmapsInShader(const SkShader* shader);
- template<class T>
+ template <class T>
inline const T* refBuffer(const T* srcBuffer, int32_t count) {
if (!srcBuffer) return nullptr;
- T* dstBuffer = (T*) mDisplayList->allocator.alloc<T>(count * sizeof(T));
+ T* dstBuffer = (T*)mDisplayList->allocator.alloc<T>(count * sizeof(T));
memcpy(dstBuffer, srcBuffer, count * sizeof(T));
return dstBuffer;
}
@@ -307,9 +311,9 @@
const ClipBase* mDeferredBarrierClip = nullptr;
DisplayList* mDisplayList = nullptr;
sk_sp<SkDrawFilter> mDrawFilter;
-}; // class RecordingCanvas
+}; // class RecordingCanvas
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RECORDING_CANVAS_H
+#endif // ANDROID_HWUI_RECORDING_CANVAS_H
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index eb05e91..0715187 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -20,20 +20,18 @@
#include <utils/Log.h>
+#include <SkRect.h>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <ostream>
-#include <SkRect.h>
namespace android {
namespace uirenderer {
#define RECT_STRING "%5.2f %5.2f %5.2f %5.2f"
-#define RECT_ARGS(r) \
- (r).left, (r).top, (r).right, (r).bottom
-#define SK_RECT_ARGS(r) \
- (r).left(), (r).top(), (r).right(), (r).bottom()
+#define RECT_ARGS(r) (r).left, (r).top, (r).right, (r).bottom
+#define SK_RECT_ARGS(r) (r).left(), (r).top(), (r).right(), (r).bottom()
///////////////////////////////////////////////////////////////////////////////
// Structs
@@ -52,52 +50,32 @@
// we don't provide copy-ctor and operator= on purpose
// because we want the compiler generated versions
- inline Rect():
- left(0),
- top(0),
- right(0),
- bottom(0) {
- }
+ inline Rect() : left(0), top(0), right(0), bottom(0) {}
- inline Rect(float left, float top, float right, float bottom):
- left(left),
- top(top),
- right(right),
- bottom(bottom) {
- }
+ inline Rect(float left, float top, float right, float bottom)
+ : left(left), top(top), right(right), bottom(bottom) {}
- inline Rect(float width, float height):
- left(0.0f),
- top(0.0f),
- right(width),
- bottom(height) {
- }
+ inline Rect(float width, float height) : left(0.0f), top(0.0f), right(width), bottom(height) {}
- inline Rect(const SkIRect& rect): // NOLINT, implicit
- left(rect.fLeft),
- top(rect.fTop),
- right(rect.fRight),
- bottom(rect.fBottom) {
- }
+ inline Rect(const SkIRect& rect)
+ : // NOLINT, implicit
+ left(rect.fLeft)
+ , top(rect.fTop)
+ , right(rect.fRight)
+ , bottom(rect.fBottom) {}
- inline Rect(const SkRect& rect): // NOLINT, implicit
- left(rect.fLeft),
- top(rect.fTop),
- right(rect.fRight),
- bottom(rect.fBottom) {
- }
+ inline Rect(const SkRect& rect)
+ : // NOLINT, implicit
+ left(rect.fLeft)
+ , top(rect.fTop)
+ , right(rect.fRight)
+ , bottom(rect.fBottom) {}
- friend int operator==(const Rect& a, const Rect& b) {
- return !memcmp(&a, &b, sizeof(a));
- }
+ friend int operator==(const Rect& a, const Rect& b) { return !memcmp(&a, &b, sizeof(a)); }
- friend int operator!=(const Rect& a, const Rect& b) {
- return memcmp(&a, &b, sizeof(a));
- }
+ friend int operator!=(const Rect& a, const Rect& b) { return memcmp(&a, &b, sizeof(a)); }
- inline void clear() {
- left = top = right = bottom = 0.0f;
- }
+ inline void clear() { left = top = right = bottom = 0.0f; }
inline bool isEmpty() const {
// this is written in such way this it'll handle NANs to return
@@ -105,9 +83,7 @@
return !((left < right) && (top < bottom));
}
- inline void setEmpty() {
- left = top = right = bottom = 0.0f;
- }
+ inline void setEmpty() { left = top = right = bottom = 0.0f; }
inline void set(float left, float top, float right, float bottom) {
this->left = left;
@@ -116,21 +92,13 @@
this->bottom = bottom;
}
- inline void set(const Rect& r) {
- set(r.left, r.top, r.right, r.bottom);
- }
+ inline void set(const Rect& r) { set(r.left, r.top, r.right, r.bottom); }
- inline void set(const SkIRect& r) {
- set(r.left(), r.top(), r.right(), r.bottom());
- }
+ inline void set(const SkIRect& r) { set(r.left(), r.top(), r.right(), r.bottom()); }
- inline float getWidth() const {
- return right - left;
- }
+ inline float getWidth() const { return right - left; }
- inline float getHeight() const {
- return bottom - top;
- }
+ inline float getHeight() const { return bottom - top; }
bool intersects(float l, float t, float r, float b) const {
float tempLeft = std::max(left, l);
@@ -138,12 +106,10 @@
float tempRight = std::min(right, r);
float tempBottom = std::min(bottom, b);
- return ((tempLeft < tempRight) && (tempTop < tempBottom)); // !isEmpty
+ return ((tempLeft < tempRight) && (tempTop < tempBottom)); // !isEmpty
}
- bool intersects(const Rect& r) const {
- return intersects(r.left, r.top, r.right, r.bottom);
- }
+ bool intersects(const Rect& r) const { return intersects(r.left, r.top, r.right, r.bottom); }
/**
* This method is named 'doIntersect' instead of 'intersect' so as not to be confused with
@@ -157,17 +123,13 @@
bottom = std::min(bottom, b);
}
- void doIntersect(const Rect& r) {
- doIntersect(r.left, r.top, r.right, r.bottom);
- }
+ void doIntersect(const Rect& r) { doIntersect(r.left, r.top, r.right, r.bottom); }
inline bool contains(float l, float t, float r, float b) const {
return l >= left && t >= top && r <= right && b <= bottom;
}
- inline bool contains(const Rect& r) const {
- return contains(r.left, r.top, r.right, r.bottom);
- }
+ inline bool contains(const Rect& r) const { return contains(r.left, r.top, r.right, r.bottom); }
bool unionWith(const Rect& r) {
if (r.left < r.right && r.top < r.bottom) {
@@ -195,9 +157,7 @@
bottom += dy;
}
- void inset(float delta) {
- outset(-delta);
- }
+ void inset(float delta) { outset(-delta); }
void outset(float delta) {
left -= delta;
@@ -279,13 +239,9 @@
bottom = std::max(bottom, y);
}
- SkRect toSkRect() const {
- return SkRect::MakeLTRB(left, top, right, bottom);
- }
+ SkRect toSkRect() const { return SkRect::MakeLTRB(left, top, right, bottom); }
- SkIRect toSkIRect() const {
- return SkIRect::MakeLTRB(left, top, right, bottom);
- }
+ SkIRect toSkIRect() const { return SkIRect::MakeLTRB(left, top, right, bottom); }
void dump(const char* label = nullptr) const {
ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
@@ -301,13 +257,10 @@
return os << "[" << rect.right << " x " << rect.bottom << "]";
}
- return os << "[" << rect.left
- << " " << rect.top
- << " " << rect.right
- << " " << rect.bottom << "]";
+ return os << "[" << rect.left << " " << rect.top << " " << rect.right << " " << rect.bottom
+ << "]";
}
-}; // class Rect
+}; // class Rect
-}; // namespace uirenderer
-}; // namespace android
-
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RenderBuffer.h b/libs/hwui/RenderBuffer.h
index 35a516a..191a66a 100644
--- a/libs/hwui/RenderBuffer.h
+++ b/libs/hwui/RenderBuffer.h
@@ -32,9 +32,8 @@
* Creates a new render buffer in the specified format and dimensions.
* The format must be one of the formats allowed by glRenderbufferStorage().
*/
- RenderBuffer(GLenum format, uint32_t width, uint32_t height):
- mFormat(format), mWidth(width), mHeight(height), mAllocated(false) {
-
+ RenderBuffer(GLenum format, uint32_t width, uint32_t height)
+ : mFormat(format), mWidth(width), mHeight(height), mAllocated(false) {
glGenRenderbuffers(1, &mName);
}
@@ -47,31 +46,23 @@
/**
* Returns the GL name of this render buffer.
*/
- GLuint getName() const {
- return mName;
- }
+ GLuint getName() const { return mName; }
/**
* Returns the format of this render buffer.
*/
- GLenum getFormat() const {
- return mFormat;
- }
+ GLenum getFormat() const { return mFormat; }
/**
* Binds this render buffer to the current GL context.
*/
- void bind() const {
- glBindRenderbuffer(GL_RENDERBUFFER, mName);
- }
+ void bind() const { glBindRenderbuffer(GL_RENDERBUFFER, mName); }
/**
* Indicates whether this render buffer has allocated its
* storage. See allocate() and resize().
*/
- bool isAllocated() const {
- return mAllocated;
- }
+ bool isAllocated() const { return mAllocated; }
/**
* Allocates this render buffer's storage if needed.
@@ -101,23 +92,19 @@
/**
* Returns the width of the render buffer in pixels.
*/
- uint32_t getWidth() const {
- return mWidth;
- }
+ uint32_t getWidth() const { return mWidth; }
/**
* Returns the height of the render buffer in pixels.
*/
- uint32_t getHeight() const {
- return mHeight;
- }
+ uint32_t getHeight() const { return mHeight; }
/**
* Returns the size of this render buffer in bytes.
*/
uint32_t getSize() const {
// Round to the nearest byte
- return (uint32_t) ((mWidth * mHeight * formatSize(mFormat)) / 8.0f + 0.5f);
+ return (uint32_t)((mWidth * mHeight * formatSize(mFormat)) / 8.0f + 0.5f);
}
/**
@@ -186,9 +173,9 @@
bool mAllocated;
GLuint mName;
-}; // struct RenderBuffer
+}; // struct RenderBuffer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RENDER_BUFFER_H
+#endif // ANDROID_HWUI_RENDER_BUFFER_H
diff --git a/libs/hwui/RenderBufferCache.cpp b/libs/hwui/RenderBufferCache.cpp
index 2f8ddfe..98010d8 100644
--- a/libs/hwui/RenderBufferCache.cpp
+++ b/libs/hwui/RenderBufferCache.cpp
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-#include "Debug.h"
-#include "Properties.h"
#include "RenderBufferCache.h"
+#include "Debug.h"
#include "DeviceInfo.h"
+#include "Properties.h"
#include <utils/Log.h>
@@ -32,9 +32,9 @@
// Debug
#if DEBUG_RENDER_BUFFERS
- #define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
+#define RENDER_BUFFER_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define RENDER_BUFFER_LOGD(...)
+#define RENDER_BUFFER_LOGD(...)
#endif
static uint32_t calculateRboCacheSize() {
@@ -48,9 +48,7 @@
// Constructors/destructor
///////////////////////////////////////////////////////////////////////////////
-RenderBufferCache::RenderBufferCache()
- : mSize(0)
- , mMaxSize(calculateRboCacheSize()) {}
+RenderBufferCache::RenderBufferCache() : mSize(0), mMaxSize(calculateRboCacheSize()) {}
RenderBufferCache::~RenderBufferCache() {
clear();
@@ -72,9 +70,8 @@
// Caching
///////////////////////////////////////////////////////////////////////////////
-int RenderBufferCache::RenderBufferEntry::compare(
- const RenderBufferCache::RenderBufferEntry& lhs,
- const RenderBufferCache::RenderBufferEntry& rhs) {
+int RenderBufferCache::RenderBufferEntry::compare(const RenderBufferCache::RenderBufferEntry& lhs,
+ const RenderBufferCache::RenderBufferEntry& rhs) {
int deltaInt = int(lhs.mWidth) - int(rhs.mWidth);
if (deltaInt != 0) return deltaInt;
@@ -87,8 +84,8 @@
void RenderBufferCache::deleteBuffer(RenderBuffer* buffer) {
if (buffer) {
RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d)",
- RenderBuffer::formatName(buffer->getFormat()),
- buffer->getWidth(), buffer->getHeight());
+ RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
+ buffer->getHeight());
mSize -= buffer->getSize();
delete buffer;
@@ -115,13 +112,13 @@
buffer = entry.mBuffer;
mSize -= buffer->getSize();
- RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)",
- RenderBuffer::formatName(format), width, height);
+ RENDER_BUFFER_LOGD("Found %s render buffer (%dx%d)", RenderBuffer::formatName(format),
+ width, height);
} else {
buffer = new RenderBuffer(format, width, height);
- RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)",
- RenderBuffer::formatName(format), width, height);
+ RENDER_BUFFER_LOGD("Created new %s render buffer (%dx%d)", RenderBuffer::formatName(format),
+ width, height);
}
buffer->bind();
@@ -147,18 +144,18 @@
mSize += size;
RENDER_BUFFER_LOGD("Added %s render buffer (%dx%d)",
- RenderBuffer::formatName(buffer->getFormat()),
- buffer->getWidth(), buffer->getHeight());
+ RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
+ buffer->getHeight());
return true;
} else {
RENDER_BUFFER_LOGD("Deleted %s render buffer (%dx%d) Size=%d, MaxSize=%d",
- RenderBuffer::formatName(buffer->getFormat()),
- buffer->getWidth(), buffer->getHeight(), size, mMaxSize);
+ RenderBuffer::formatName(buffer->getFormat()), buffer->getWidth(),
+ buffer->getHeight(), size, mMaxSize);
delete buffer;
}
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/RenderBufferCache.h b/libs/hwui/RenderBufferCache.h
index 6444331..c936a52 100644
--- a/libs/hwui/RenderBufferCache.h
+++ b/libs/hwui/RenderBufferCache.h
@@ -74,28 +74,22 @@
private:
struct RenderBufferEntry {
- RenderBufferEntry():
- mBuffer(nullptr), mWidth(0), mHeight(0) {
- }
+ RenderBufferEntry() : mBuffer(nullptr), mWidth(0), mHeight(0) {}
- RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height):
- mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {
- }
+ RenderBufferEntry(GLenum format, const uint32_t width, const uint32_t height)
+ : mBuffer(nullptr), mFormat(format), mWidth(width), mHeight(height) {}
- explicit RenderBufferEntry(RenderBuffer* buffer):
- mBuffer(buffer), mFormat(buffer->getFormat()),
- mWidth(buffer->getWidth()), mHeight(buffer->getHeight()) {
- }
+ explicit RenderBufferEntry(RenderBuffer* buffer)
+ : mBuffer(buffer)
+ , mFormat(buffer->getFormat())
+ , mWidth(buffer->getWidth())
+ , mHeight(buffer->getHeight()) {}
static int compare(const RenderBufferEntry& lhs, const RenderBufferEntry& rhs);
- bool operator==(const RenderBufferEntry& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const RenderBufferEntry& other) const { return compare(*this, other) == 0; }
- bool operator!=(const RenderBufferEntry& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const RenderBufferEntry& other) const { return compare(*this, other) != 0; }
bool operator<(const RenderBufferEntry& other) const {
return RenderBufferEntry::compare(*this, other) < 0;
@@ -105,7 +99,7 @@
GLenum mFormat;
uint32_t mWidth;
uint32_t mHeight;
- }; // struct RenderBufferEntry
+ }; // struct RenderBufferEntry
void deleteBuffer(RenderBuffer* buffer);
@@ -113,9 +107,9 @@
uint32_t mSize;
uint32_t mMaxSize;
-}; // class RenderBufferCache
+}; // class RenderBufferCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H
+#endif // ANDROID_HWUI_RENDER_BUFFER_CACHE_H
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 36a7475..fedcc10 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -21,16 +21,16 @@
#include "Debug.h"
#include "RecordedOp.h"
#include "TreeInfo.h"
+#include "VectorDrawable.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/CanvasContext.h"
#include "utils/FatVector.h"
#include "utils/MathUtils.h"
#include "utils/StringUtils.h"
#include "utils/TraceUtils.h"
-#include "VectorDrawable.h"
-#include "renderstate/RenderState.h"
-#include "renderthread/CanvasContext.h"
-#include "protos/hwui.pb.h"
#include "protos/ProtoHelpers.h"
+#include "protos/hwui.pb.h"
#include <SkPathOps.h>
#include <algorithm>
@@ -46,9 +46,7 @@
public:
explicit ImmediateRemoved(TreeInfo* info) : mTreeInfo(info) {}
- void onMaybeRemovedFromTree(RenderNode* node) override {
- node->onRemovedFromTree(mTreeInfo);
- }
+ void onMaybeRemovedFromTree(RenderNode* node) override { node->onRemovedFromTree(mTreeInfo); }
private:
TreeInfo* mTreeInfo;
@@ -60,8 +58,7 @@
, mDisplayList(nullptr)
, mStagingDisplayList(nullptr)
, mAnimatorManager(*this)
- , mParentCount(0) {
-}
+ , mParentCount(0) {}
RenderNode::~RenderNode() {
ImmediateRemoved observer(nullptr);
@@ -89,12 +86,11 @@
void RenderNode::output(std::ostream& output, uint32_t level) {
output << " (" << getName() << " " << this
- << (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : "")
- << (properties().hasShadow() ? ", casting shadow" : "")
- << (isRenderable() ? "" : ", empty")
- << (properties().getProjectBackwards() ? ", projected" : "")
- << (hasLayer() ? ", on HW Layer" : "")
- << ")" << std::endl;
+ << (MathUtils::isZero(properties().getAlpha()) ? ", zero alpha" : "")
+ << (properties().hasShadow() ? ", casting shadow" : "")
+ << (isRenderable() ? "" : ", empty")
+ << (properties().getProjectBackwards() ? ", projected" : "")
+ << (hasLayer() ? ", on HW Layer" : "") << ")" << std::endl;
properties().debugOutputProperties(output, level + 1);
@@ -105,9 +101,8 @@
output << std::endl;
}
-void RenderNode::copyTo(proto::RenderNode *pnode) {
- pnode->set_id(static_cast<uint64_t>(
- reinterpret_cast<uintptr_t>(this)));
+void RenderNode::copyTo(proto::RenderNode* pnode) {
+ pnode->set_id(static_cast<uint64_t>(reinterpret_cast<uintptr_t>(this)));
pnode->set_name(mName.string(), mName.length());
proto::RenderProperties* pprops = pnode->mutable_properties();
@@ -239,18 +234,16 @@
LayerType layerType = properties().effectiveLayerType();
// If we are not a layer OR we cannot be rendered (eg, view was detached)
// we need to destroy any Layers we may have had previously
- if (CC_LIKELY(layerType != LayerType::RenderLayer)
- || CC_UNLIKELY(!isRenderable())
- || CC_UNLIKELY(properties().getWidth() == 0)
- || CC_UNLIKELY(properties().getHeight() == 0)
- || CC_UNLIKELY(!properties().fitsOnLayer())) {
+ if (CC_LIKELY(layerType != LayerType::RenderLayer) || CC_UNLIKELY(!isRenderable()) ||
+ CC_UNLIKELY(properties().getWidth() == 0) || CC_UNLIKELY(properties().getHeight() == 0) ||
+ CC_UNLIKELY(!properties().fitsOnLayer())) {
if (CC_UNLIKELY(hasLayer())) {
renderthread::CanvasContext::destroyLayer(this);
}
return;
}
- if(info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
+ if (info.canvasContext.createOrUpdateLayer(this, *info.damageAccumulator)) {
damageSelf(info);
}
@@ -261,8 +254,8 @@
err << "Unable to create layer for " << getName();
const int maxTextureSize = Caches::getInstance().maxTextureSize;
if (getWidth() > maxTextureSize || getHeight() > maxTextureSize) {
- err << ", size " << getWidth() << "x" << getHeight()
- << " exceeds max size " << maxTextureSize;
+ err << ", size " << getWidth() << "x" << getHeight() << " exceeds max size "
+ << maxTextureSize;
} else {
err << ", see logcat for more info";
}
@@ -306,8 +299,8 @@
} else if (mDisplayList) {
willHaveFunctor = mDisplayList->hasFunctor();
}
- bool childFunctorsNeedLayer = mProperties.prepareForFunctorPresence(
- willHaveFunctor, functorsNeedLayer);
+ bool childFunctorsNeedLayer =
+ mProperties.prepareForFunctorPresence(willHaveFunctor, functorsNeedLayer);
if (CC_UNLIKELY(mPositionListener.get())) {
mPositionListener->onPositionUpdated(*this, info);
@@ -320,10 +313,12 @@
if (mDisplayList) {
info.out.hasFunctors |= mDisplayList->hasFunctor();
- bool isDirty = mDisplayList->prepareListAndChildren(observer, info, childFunctorsNeedLayer,
- [](RenderNode* child, TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer) {
- child->prepareTreeImpl(observer, info, functorsNeedLayer);
- });
+ bool isDirty = mDisplayList->prepareListAndChildren(
+ observer, info, childFunctorsNeedLayer,
+ [](RenderNode* child, TreeObserver& observer, TreeInfo& info,
+ bool functorsNeedLayer) {
+ child->prepareTreeImpl(observer, info, functorsNeedLayer);
+ });
if (isDirty) {
damageSelf(info);
}
@@ -363,9 +358,7 @@
// Make sure we inc first so that we don't fluctuate between 0 and 1,
// which would thrash the layer cache
if (mStagingDisplayList) {
- mStagingDisplayList->updateChildren([](RenderNode* child) {
- child->incParentRefCount();
- });
+ mStagingDisplayList->updateChildren([](RenderNode* child) { child->incParentRefCount(); });
}
deleteDisplayList(observer, info);
mDisplayList = mStagingDisplayList;
@@ -388,9 +381,8 @@
void RenderNode::deleteDisplayList(TreeObserver& observer, TreeInfo* info) {
if (mDisplayList) {
- mDisplayList->updateChildren([&observer, info](RenderNode* child) {
- child->decParentRefCount(observer, info);
- });
+ mDisplayList->updateChildren(
+ [&observer, info](RenderNode* child) { child->decParentRefCount(observer, info); });
if (!mDisplayList->reuseDisplayList(this, info ? &info->canvasContext : nullptr)) {
delete mDisplayList;
}
@@ -413,9 +405,7 @@
renderthread::CanvasContext::destroyLayer(this);
}
if (mDisplayList) {
- mDisplayList->updateChildren([](RenderNode* child) {
- child->destroyLayers();
- });
+ mDisplayList->updateChildren([](RenderNode* child) { child->destroyLayers(); });
}
}
@@ -461,16 +451,15 @@
if (properties().hasTransformMatrix() || applyTranslationZ) {
if (properties().isTransformTranslateOnly()) {
matrix.translate(properties().getTranslationX(), properties().getTranslationY(),
- true3dTransform ? properties().getZ() : 0.0f);
+ true3dTransform ? properties().getZ() : 0.0f);
} else {
if (!true3dTransform) {
matrix.multiply(*properties().getTransformMatrix());
} else {
mat4 true3dMat;
- true3dMat.loadTranslate(
- properties().getPivotX() + properties().getTranslationX(),
- properties().getPivotY() + properties().getTranslationY(),
- properties().getZ());
+ true3dMat.loadTranslate(properties().getPivotX() + properties().getTranslationX(),
+ properties().getPivotY() + properties().getTranslationY(),
+ properties().getZ());
true3dMat.rotate(properties().getRotationX(), 1, 0, 0);
true3dMat.rotate(properties().getRotationY(), 0, 1, 0);
true3dMat.rotate(properties().getRotation(), 0, 0, 1);
@@ -505,8 +494,7 @@
}
void RenderNode::computeOrderingImpl(
- RenderNodeOp* opState,
- std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
+ RenderNodeOp* opState, std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
const mat4* transformFromProjectionSurface) {
mProjectedNodes.clear();
if (mDisplayList == nullptr || mDisplayList->isEmpty()) return;
@@ -569,7 +557,6 @@
SkPath clipPath;
clipPath.addRect(clipRect);
Op(*outlinePath, clipPath, kIntersect_SkPathOp, &mClippedOutlineCache.clippedOutline);
-
}
return &mClippedOutlineCache.clippedOutline;
}
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index 89e022f..1469a15 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -63,7 +63,8 @@
}
/**
- * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display properties.
+ * Primary class for storing recorded canvas commands, as well as per-View/ViewGroup display
+ * properties.
*
* Recording of canvas commands is somewhat similar to SkPicture, except the canvas-recording
* functionality is split between RecordingCanvas (which manages the recording), DisplayList
@@ -74,33 +75,32 @@
* attached.
*/
class RenderNode : public VirtualLightRefBase {
-friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
-friend class FrameBuilder;
+ friend class TestUtils; // allow TestUtils to access syncDisplayList / syncProperties
+ friend class FrameBuilder;
+
public:
enum DirtyPropertyMask {
- GENERIC = 1 << 1,
- TRANSLATION_X = 1 << 2,
- TRANSLATION_Y = 1 << 3,
- TRANSLATION_Z = 1 << 4,
- SCALE_X = 1 << 5,
- SCALE_Y = 1 << 6,
- ROTATION = 1 << 7,
- ROTATION_X = 1 << 8,
- ROTATION_Y = 1 << 9,
- X = 1 << 10,
- Y = 1 << 11,
- Z = 1 << 12,
- ALPHA = 1 << 13,
- DISPLAY_LIST = 1 << 14,
+ GENERIC = 1 << 1,
+ TRANSLATION_X = 1 << 2,
+ TRANSLATION_Y = 1 << 3,
+ TRANSLATION_Z = 1 << 4,
+ SCALE_X = 1 << 5,
+ SCALE_Y = 1 << 6,
+ ROTATION = 1 << 7,
+ ROTATION_X = 1 << 8,
+ ROTATION_Y = 1 << 9,
+ X = 1 << 10,
+ Y = 1 << 11,
+ Z = 1 << 12,
+ ALPHA = 1 << 13,
+ DISPLAY_LIST = 1 << 14,
};
ANDROID_API RenderNode();
ANDROID_API virtual ~RenderNode();
// See flags defined in DisplayList.java
- enum ReplayFlag {
- kReplayFlag_ClipChildren = 0x1
- };
+ enum ReplayFlag { kReplayFlag_ClipChildren = 0x1 };
ANDROID_API void setStagingDisplayList(DisplayList* newData);
@@ -110,17 +110,13 @@
ANDROID_API int getDebugSize();
void copyTo(proto::RenderNode* node);
- bool isRenderable() const {
- return mDisplayList && !mDisplayList->isEmpty();
- }
+ bool isRenderable() const { return mDisplayList && !mDisplayList->isEmpty(); }
bool hasProjectionReceiver() const {
return mDisplayList && mDisplayList->projectionReceiveIndex >= 0;
}
- const char* getName() const {
- return mName.string();
- }
+ const char* getName() const { return mName.string(); }
void setName(const char* name) {
if (name) {
@@ -133,49 +129,29 @@
}
}
- VirtualLightRefBase* getUserContext() const {
- return mUserContext.get();
- }
+ VirtualLightRefBase* getUserContext() const { return mUserContext.get(); }
- void setUserContext(VirtualLightRefBase* context) {
- mUserContext = context;
- }
+ void setUserContext(VirtualLightRefBase* context) { mUserContext = context; }
bool isPropertyFieldDirty(DirtyPropertyMask field) const {
return mDirtyPropertyFields & field;
}
- void setPropertyFieldsDirty(uint32_t fields) {
- mDirtyPropertyFields |= fields;
- }
+ void setPropertyFieldsDirty(uint32_t fields) { mDirtyPropertyFields |= fields; }
- const RenderProperties& properties() const {
- return mProperties;
- }
+ const RenderProperties& properties() const { return mProperties; }
- RenderProperties& animatorProperties() {
- return mProperties;
- }
+ RenderProperties& animatorProperties() { return mProperties; }
- const RenderProperties& stagingProperties() {
- return mStagingProperties;
- }
+ const RenderProperties& stagingProperties() { return mStagingProperties; }
- RenderProperties& mutateStagingProperties() {
- return mStagingProperties;
- }
+ RenderProperties& mutateStagingProperties() { return mStagingProperties; }
- bool isValid() {
- return mValid;
- }
+ bool isValid() { return mValid; }
- int getWidth() const {
- return properties().getWidth();
- }
+ int getWidth() const { return properties().getWidth(); }
- int getHeight() const {
- return properties().getHeight();
- }
+ int getHeight() const { return properties().getHeight(); }
ANDROID_API virtual void prepareTree(TreeInfo& info);
void destroyHardwareResources(TreeInfo* info = nullptr);
@@ -196,18 +172,14 @@
bool nothingToDraw() const {
const Outline& outline = properties().getOutline();
- return mDisplayList == nullptr
- || properties().getAlpha() <= 0
- || (outline.getShouldClip() && outline.isEmpty())
- || properties().getScaleX() == 0
- || properties().getScaleY() == 0;
+ return mDisplayList == nullptr || properties().getAlpha() <= 0 ||
+ (outline.getShouldClip() && outline.isEmpty()) || properties().getScaleX() == 0 ||
+ properties().getScaleY() == 0;
}
- const DisplayList* getDisplayList() const {
- return mDisplayList;
- }
+ const DisplayList* getDisplayList() const { return mDisplayList; }
OffscreenBuffer* getLayer() const { return mLayer; }
- OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
+ OffscreenBuffer** getLayerHandle() { return &mLayer; } // ugh...
void setLayer(OffscreenBuffer* layer) { mLayer = layer; }
// Note: The position callbacks are relying on the listener using
@@ -234,16 +206,12 @@
// This is only modified in MODE_FULL, so it can be safely accessed
// on the UI thread.
- ANDROID_API bool hasParents() {
- return mParentCount;
- }
+ ANDROID_API bool hasParents() { return mParentCount; }
void onRemovedFromTree(TreeInfo* info);
// Called by CanvasContext to promote a RenderNode to be a root node
- void makeRoot() {
- incParentRefCount();
- }
+ void makeRoot() { incParentRefCount(); }
// Called by CanvasContext when it drops a RenderNode from being a root node
void clearRoot();
@@ -252,8 +220,8 @@
private:
void computeOrderingImpl(RenderNodeOp* opState,
- std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
- const mat4* transformFromProjectionSurface);
+ std::vector<RenderNodeOp*>* compositedChildrenOfProjectionSurface,
+ const mat4* transformFromProjectionSurface);
void syncProperties();
void syncDisplayList(TreeObserver& observer, TreeInfo* info);
@@ -309,7 +277,7 @@
sp<PositionListener> mPositionListener;
-// METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
+ // METHODS & FIELDS ONLY USED BY THE SKIA RENDERER
public:
/**
* Detach and transfer ownership of an already allocated displayList for use
@@ -361,9 +329,7 @@
return mSkiaLayer.get() ? mSkiaLayer->layerSurface.get() : nullptr;
}
- skiapipeline::SkiaLayer* getSkiaLayer() const {
- return mSkiaLayer.get();
- }
+ skiapipeline::SkiaLayer* getSkiaLayer() const { return mSkiaLayer.get(); }
/**
* Returns the path that represents the outline of RenderNode intersected with
@@ -376,6 +342,7 @@
* again or the RenderNode's outline is mutated.
*/
const SkPath* getClippedOutline(const SkRect& clipRect) const;
+
private:
/**
* If this RenderNode has been used in a previous frame then the SkiaDisplayList
@@ -401,17 +368,15 @@
SkPath clippedOutline;
};
mutable ClippedOutlineCache mClippedOutlineCache;
-}; // class RenderNode
+}; // class RenderNode
class MarkAndSweepRemoved : public TreeObserver {
-PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
+ PREVENT_COPY_AND_ASSIGN(MarkAndSweepRemoved);
public:
explicit MarkAndSweepRemoved(TreeInfo* info) : mTreeInfo(info) {}
- void onMaybeRemovedFromTree(RenderNode* node) override {
- mMarked.emplace_back(node);
- }
+ void onMaybeRemovedFromTree(RenderNode* node) override { mMarked.emplace_back(node); }
~MarkAndSweepRemoved() {
for (auto& node : mMarked) {
diff --git a/libs/hwui/RenderProperties.cpp b/libs/hwui/RenderProperties.cpp
index 146fbe7..e495744 100644
--- a/libs/hwui/RenderProperties.cpp
+++ b/libs/hwui/RenderProperties.cpp
@@ -44,9 +44,9 @@
}
bool LayerProperties::setColorFilter(SkColorFilter* filter) {
- if (mColorFilter == filter) return false;
- SkRefCnt_SafeAssign(mColorFilter, filter);
- return true;
+ if (mColorFilter == filter) return false;
+ SkRefCnt_SafeAssign(mColorFilter, filter);
+ return true;
}
bool LayerProperties::setFromPaint(const SkPaint* paint) {
@@ -66,18 +66,13 @@
return *this;
}
-RenderProperties::ComputedFields::ComputedFields()
- : mTransformMatrix(nullptr) {
-}
+RenderProperties::ComputedFields::ComputedFields() : mTransformMatrix(nullptr) {}
RenderProperties::ComputedFields::~ComputedFields() {
delete mTransformMatrix;
}
-RenderProperties::RenderProperties()
- : mStaticMatrix(nullptr)
- , mAnimationMatrix(nullptr) {
-}
+RenderProperties::RenderProperties() : mStaticMatrix(nullptr), mAnimationMatrix(nullptr) {}
RenderProperties::~RenderProperties() {
delete mStaticMatrix;
@@ -99,14 +94,14 @@
return *this;
}
-static void dumpMatrix(std::ostream& output, std::string& indent,
- const char* label, SkMatrix* matrix) {
- if (matrix) {
- output << indent << "(" << label << " " << matrix << ": ";
+static void dumpMatrix(std::ostream& output, std::string& indent, const char* label,
+ SkMatrix* matrix) {
+ if (matrix) {
+ output << indent << "(" << label << " " << matrix << ": ";
output << std::fixed << std::setprecision(2);
- output << "[" << matrix->get(0) << " "<< matrix->get(1) << " " << matrix->get(2) << "]";
- output << " [" << matrix->get(3) << " "<< matrix->get(4) << " " << matrix->get(5) << "]";
- output << " [" << matrix->get(6) << " "<< matrix->get(7) << " " << matrix->get(8) << "]";
+ output << "[" << matrix->get(0) << " " << matrix->get(1) << " " << matrix->get(2) << "]";
+ output << " [" << matrix->get(3) << " " << matrix->get(4) << " " << matrix->get(5) << "]";
+ output << " [" << matrix->get(6) << " " << matrix->get(7) << " " << matrix->get(8) << "]";
output << ")" << std::endl;
}
}
@@ -114,8 +109,8 @@
void RenderProperties::debugOutputProperties(std::ostream& output, const int level) const {
auto indent = std::string(level * 2, ' ');
if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
- output << indent << "(Translate (left, top) " << mPrimitiveFields.mLeft
- << ", " << mPrimitiveFields.mTop << ")" << std::endl;
+ output << indent << "(Translate (left, top) " << mPrimitiveFields.mLeft << ", "
+ << mPrimitiveFields.mTop << ")" << std::endl;
}
dumpMatrix(output, indent, "ConcatMatrix (static)", mStaticMatrix);
dumpMatrix(output, indent, "ConcatMatrix (animation)", mAnimationMatrix);
@@ -124,7 +119,7 @@
if (hasTransformMatrix()) {
if (isTransformTranslateOnly()) {
output << indent << "(Translate " << getTranslationX() << ", " << getTranslationY()
- << ", " << getZ() << ")" << std::endl;
+ << ", " << getZ() << ")" << std::endl;
} else {
dumpMatrix(output, indent, "ConcatMatrix ", mComputedFields.mTransformMatrix);
}
@@ -132,10 +127,9 @@
const bool isLayer = effectiveLayerType() != LayerType::None;
int clipFlags = getClippingFlags();
- if (mPrimitiveFields.mAlpha < 1
- && !MathUtils::isZero(mPrimitiveFields.mAlpha)) {
+ if (mPrimitiveFields.mAlpha < 1 && !MathUtils::isZero(mPrimitiveFields.mAlpha)) {
if (isLayer) {
- clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+ clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
@@ -146,31 +140,28 @@
Rect layerBounds(0, 0, getWidth(), getHeight());
if (clipFlags) {
getClippingRectForFlags(clipFlags, &layerBounds);
- clipFlags = 0; // all clipping done by savelayer
+ clipFlags = 0; // all clipping done by savelayer
}
- output << indent << "(SaveLayerAlpha "
- << (int)layerBounds.left << ", " << (int)layerBounds.top << ", "
- << (int)layerBounds.right << ", " << (int)layerBounds.bottom << ", "
- << (int)(mPrimitiveFields.mAlpha * 255) << ", 0x" << std::hex
- << (SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer) << ")" << std::dec
- << std::endl;
+ output << indent << "(SaveLayerAlpha " << (int)layerBounds.left << ", "
+ << (int)layerBounds.top << ", " << (int)layerBounds.right << ", "
+ << (int)layerBounds.bottom << ", " << (int)(mPrimitiveFields.mAlpha * 255)
+ << ", 0x" << std::hex << (SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer)
+ << ")" << std::dec << std::endl;
}
}
if (clipFlags) {
Rect clipRect;
getClippingRectForFlags(clipFlags, &clipRect);
- output << indent << "(ClipRect "
- << (int)clipRect.left << ", " << (int)clipRect.top << ", "
- << (int)clipRect.right << ", " << (int)clipRect.bottom << ")" << std::endl;
+ output << indent << "(ClipRect " << (int)clipRect.left << ", " << (int)clipRect.top << ", "
+ << (int)clipRect.right << ", " << (int)clipRect.bottom << ")" << std::endl;
}
if (getRevealClip().willClip()) {
Rect bounds;
getRevealClip().getBounds(&bounds);
- output << indent << "(Clip to reveal clip with bounds "
- << bounds.left << ", " << bounds.top << ", "
- << bounds.right << ", " << bounds.bottom << ")" << std::endl;
+ output << indent << "(Clip to reveal clip with bounds " << bounds.left << ", " << bounds.top
+ << ", " << bounds.right << ", " << bounds.bottom << ")" << std::endl;
}
auto& outline = mPrimitiveFields.mOutline;
@@ -179,9 +170,8 @@
output << indent << "(Clip to empty outline)";
} else if (outline.willClip()) {
const Rect& bounds = outline.getBounds();
- output << indent << "(Clip to outline with bounds "
- << bounds.left << ", " << bounds.top << ", "
- << bounds.right << ", " << bounds.bottom << ")" << std::endl;
+ output << indent << "(Clip to outline with bounds " << bounds.left << ", " << bounds.top
+ << ", " << bounds.right << ", " << bounds.bottom << ")" << std::endl;
}
}
}
@@ -212,7 +202,7 @@
mComputedFields.mTransformCamera.getMatrix(&transform3D);
transform3D.preTranslate(-getPivotX(), -getPivotY());
transform3D.postTranslate(getPivotX() + getTranslationX(),
- getPivotY() + getTranslationY());
+ getPivotY() + getTranslationY());
transform->postConcat(transform3D);
mComputedFields.mTransformCamera.restore();
}
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 9ee2f9c..837c4ef 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -18,9 +18,9 @@
#include "Caches.h"
#include "DeviceInfo.h"
+#include "Outline.h"
#include "Rect.h"
#include "RevealClip.h"
-#include "Outline.h"
#include "utils/MathUtils.h"
#include "utils/PaintUtils.h"
@@ -29,13 +29,13 @@
#include <SkMatrix.h>
#include <SkRegion.h>
-#include <algorithm>
-#include <stddef.h>
-#include <vector>
-#include <cutils/compiler.h>
#include <androidfw/ResourceTypes.h>
+#include <cutils/compiler.h>
+#include <stddef.h>
#include <utils/Log.h>
+#include <algorithm>
#include <ostream>
+#include <vector>
class SkBitmap;
class SkColorFilter;
@@ -63,7 +63,7 @@
};
enum ClippingFlags {
- CLIP_TO_BOUNDS = 0x1 << 0,
+ CLIP_TO_BOUNDS = 0x1 << 0,
CLIP_TO_CLIP_BOUNDS = 0x1 << 1,
};
@@ -77,43 +77,27 @@
return false;
}
- bool setOpaque(bool opaque) {
- return RP_SET(mOpaque, opaque);
- }
+ bool setOpaque(bool opaque) { return RP_SET(mOpaque, opaque); }
- bool opaque() const {
- return mOpaque;
- }
+ bool opaque() const { return mOpaque; }
- bool setAlpha(uint8_t alpha) {
- return RP_SET(mAlpha, alpha);
- }
+ bool setAlpha(uint8_t alpha) { return RP_SET(mAlpha, alpha); }
- uint8_t alpha() const {
- return mAlpha;
- }
+ uint8_t alpha() const { return mAlpha; }
- bool setXferMode(SkBlendMode mode) {
- return RP_SET(mMode, mode);
- }
+ bool setXferMode(SkBlendMode mode) { return RP_SET(mMode, mode); }
- SkBlendMode xferMode() const {
- return mMode;
- }
+ SkBlendMode xferMode() const { return mMode; }
bool setColorFilter(SkColorFilter* filter);
- SkColorFilter* colorFilter() const {
- return mColorFilter;
- }
+ SkColorFilter* colorFilter() const { return mColorFilter; }
// Sets alpha, xfermode, and colorfilter from an SkPaint
// paint may be NULL, in which case defaults will be set
bool setFromPaint(const SkPaint* paint);
- bool needsBlending() const {
- return !opaque() || alpha() < 255;
- }
+ bool needsBlending() const { return !opaque() || alpha() < 255; }
LayerProperties& operator=(const LayerProperties& other);
@@ -123,9 +107,7 @@
void reset();
// Private since external users should go through properties().effectiveLayerType()
- LayerType type() const {
- return mType;
- }
+ LayerType type() const { return mType; }
friend class RenderProperties;
@@ -169,16 +151,17 @@
*/
bool prepareForFunctorPresence(bool willHaveFunctor, bool ancestorDictatesFunctorsNeedLayer) {
// parent may have already dictated that a descendant layer is needed
- bool functorsNeedLayer = ancestorDictatesFunctorsNeedLayer
+ bool functorsNeedLayer =
+ ancestorDictatesFunctorsNeedLayer
// Round rect clipping forces layer for functors
- || CC_UNLIKELY(getOutline().willRoundRectClip())
- || CC_UNLIKELY(getRevealClip().willClip())
+ || CC_UNLIKELY(getOutline().willRoundRectClip()) ||
+ CC_UNLIKELY(getRevealClip().willClip())
// Complex matrices forces layer, due to stencil clipping
- || CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate())
- || CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate())
- || CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
+ || CC_UNLIKELY(getTransformMatrix() && !getTransformMatrix()->isScaleTranslate()) ||
+ CC_UNLIKELY(getAnimationMatrix() && !getAnimationMatrix()->isScaleTranslate()) ||
+ CC_UNLIKELY(getStaticMatrix() && !getStaticMatrix()->isScaleTranslate());
mComputedFields.mNeedLayerForFunctors = (willHaveFunctor && functorsNeedLayer);
@@ -210,9 +193,7 @@
return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldReceive);
}
- bool isProjectionReceiver() const {
- return mPrimitiveFields.mProjectionReceiver;
- }
+ bool isProjectionReceiver() const { return mPrimitiveFields.mProjectionReceiver; }
bool setStaticMatrix(const SkMatrix* matrix) {
delete mStaticMatrix;
@@ -225,9 +206,7 @@
}
// Can return NULL
- const SkMatrix* getStaticMatrix() const {
- return mStaticMatrix;
- }
+ const SkMatrix* getStaticMatrix() const { return mStaticMatrix; }
bool setAnimationMatrix(const SkMatrix* matrix) {
delete mAnimationMatrix;
@@ -244,124 +223,85 @@
return RP_SET(mPrimitiveFields.mAlpha, alpha);
}
- float getAlpha() const {
- return mPrimitiveFields.mAlpha;
- }
+ float getAlpha() const { return mPrimitiveFields.mAlpha; }
bool setHasOverlappingRendering(bool hasOverlappingRendering) {
return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering);
}
- bool hasOverlappingRendering() const {
- return mPrimitiveFields.mHasOverlappingRendering;
- }
+ bool hasOverlappingRendering() const { return mPrimitiveFields.mHasOverlappingRendering; }
bool setElevation(float elevation) {
return RP_SET(mPrimitiveFields.mElevation, elevation);
// Don't dirty matrix/pivot, since they don't respect Z
}
- float getElevation() const {
- return mPrimitiveFields.mElevation;
- }
+ float getElevation() const { return mPrimitiveFields.mElevation; }
bool setTranslationX(float translationX) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX);
}
- float getTranslationX() const {
- return mPrimitiveFields.mTranslationX;
- }
+ float getTranslationX() const { return mPrimitiveFields.mTranslationX; }
bool setTranslationY(float translationY) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY);
}
- float getTranslationY() const {
- return mPrimitiveFields.mTranslationY;
- }
+ float getTranslationY() const { return mPrimitiveFields.mTranslationY; }
bool setTranslationZ(float translationZ) {
return RP_SET(mPrimitiveFields.mTranslationZ, translationZ);
// mMatrixOrPivotDirty not set, since matrix doesn't respect Z
}
- float getTranslationZ() const {
- return mPrimitiveFields.mTranslationZ;
- }
+ float getTranslationZ() const { return mPrimitiveFields.mTranslationZ; }
// Animation helper
- bool setX(float value) {
- return setTranslationX(value - getLeft());
- }
+ bool setX(float value) { return setTranslationX(value - getLeft()); }
// Animation helper
- float getX() const {
- return getLeft() + getTranslationX();
- }
+ float getX() const { return getLeft() + getTranslationX(); }
// Animation helper
- bool setY(float value) {
- return setTranslationY(value - getTop());
- }
+ bool setY(float value) { return setTranslationY(value - getTop()); }
// Animation helper
- float getY() const {
- return getTop() + getTranslationY();
- }
+ float getY() const { return getTop() + getTranslationY(); }
// Animation helper
- bool setZ(float value) {
- return setTranslationZ(value - getElevation());
- }
+ bool setZ(float value) { return setTranslationZ(value - getElevation()); }
- float getZ() const {
- return getElevation() + getTranslationZ();
- }
+ float getZ() const { return getElevation() + getTranslationZ(); }
bool setRotation(float rotation) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation);
}
- float getRotation() const {
- return mPrimitiveFields.mRotation;
- }
+ float getRotation() const { return mPrimitiveFields.mRotation; }
bool setRotationX(float rotationX) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX);
}
- float getRotationX() const {
- return mPrimitiveFields.mRotationX;
- }
+ float getRotationX() const { return mPrimitiveFields.mRotationX; }
bool setRotationY(float rotationY) {
return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY);
}
- float getRotationY() const {
- return mPrimitiveFields.mRotationY;
- }
+ float getRotationY() const { return mPrimitiveFields.mRotationY; }
- bool setScaleX(float scaleX) {
- return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX);
- }
+ bool setScaleX(float scaleX) { return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX); }
- float getScaleX() const {
- return mPrimitiveFields.mScaleX;
- }
+ float getScaleX() const { return mPrimitiveFields.mScaleX; }
- bool setScaleY(float scaleY) {
- return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY);
- }
+ bool setScaleY(float scaleY) { return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY); }
- float getScaleY() const {
- return mPrimitiveFields.mScaleY;
- }
+ float getScaleY() const { return mPrimitiveFields.mScaleY; }
bool setPivotX(float pivotX) {
- if (RP_SET(mPrimitiveFields.mPivotX, pivotX)
- || !mPrimitiveFields.mPivotExplicitlySet) {
+ if (RP_SET(mPrimitiveFields.mPivotX, pivotX) || !mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
mPrimitiveFields.mPivotExplicitlySet = true;
return true;
@@ -373,13 +313,10 @@
* so the value returned may be stale if the RenderProperties has been
* modified since the last call to updateMatrix()
*/
- float getPivotX() const {
- return mPrimitiveFields.mPivotX;
- }
+ float getPivotX() const { return mPrimitiveFields.mPivotX; }
bool setPivotY(float pivotY) {
- if (RP_SET(mPrimitiveFields.mPivotY, pivotY)
- || !mPrimitiveFields.mPivotExplicitlySet) {
+ if (RP_SET(mPrimitiveFields.mPivotY, pivotY) || !mPrimitiveFields.mPivotExplicitlySet) {
mPrimitiveFields.mMatrixOrPivotDirty = true;
mPrimitiveFields.mPivotExplicitlySet = true;
return true;
@@ -387,13 +324,9 @@
return false;
}
- float getPivotY() const {
- return mPrimitiveFields.mPivotY;
- }
+ float getPivotY() const { return mPrimitiveFields.mPivotY; }
- bool isPivotExplicitlySet() const {
- return mPrimitiveFields.mPivotExplicitlySet;
- }
+ bool isPivotExplicitlySet() const { return mPrimitiveFields.mPivotExplicitlySet; }
bool setCameraDistance(float distance) {
if (distance != getCameraDistance()) {
@@ -420,9 +353,7 @@
return false;
}
- int getLeft() const {
- return mPrimitiveFields.mLeft;
- }
+ int getLeft() const { return mPrimitiveFields.mLeft; }
bool setTop(int top) {
if (RP_SET(mPrimitiveFields.mTop, top)) {
@@ -435,9 +366,7 @@
return false;
}
- int getTop() const {
- return mPrimitiveFields.mTop;
- }
+ int getTop() const { return mPrimitiveFields.mTop; }
bool setRight(int right) {
if (RP_SET(mPrimitiveFields.mRight, right)) {
@@ -450,9 +379,7 @@
return false;
}
- int getRight() const {
- return mPrimitiveFields.mRight;
- }
+ int getRight() const { return mPrimitiveFields.mRight; }
bool setBottom(int bottom) {
if (RP_SET(mPrimitiveFields.mBottom, bottom)) {
@@ -465,9 +392,7 @@
return false;
}
- int getBottom() const {
- return mPrimitiveFields.mBottom;
- }
+ int getBottom() const { return mPrimitiveFields.mBottom; }
bool setLeftTop(int left, int top) {
bool leftResult = setLeft(left);
@@ -476,8 +401,8 @@
}
bool setLeftTopRightBottom(int left, int top, int right, int bottom) {
- if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop
- || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
+ if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop ||
+ right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) {
mPrimitiveFields.mLeft = left;
mPrimitiveFields.mTop = top;
mPrimitiveFields.mRight = right;
@@ -510,17 +435,11 @@
return false;
}
- int getWidth() const {
- return mPrimitiveFields.mWidth;
- }
+ int getWidth() const { return mPrimitiveFields.mWidth; }
- int getHeight() const {
- return mPrimitiveFields.mHeight;
- }
+ int getHeight() const { return mPrimitiveFields.mHeight; }
- const SkMatrix* getAnimationMatrix() const {
- return mAnimationMatrix;
- }
+ const SkMatrix* getAnimationMatrix() const { return mAnimationMatrix; }
bool hasTransformMatrix() const {
return getTransformMatrix() && !getTransformMatrix()->isIdentity();
@@ -536,17 +455,11 @@
return mComputedFields.mTransformMatrix;
}
- int getClippingFlags() const {
- return mPrimitiveFields.mClippingFlags;
- }
+ int getClippingFlags() const { return mPrimitiveFields.mClippingFlags; }
- bool getClipToBounds() const {
- return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS;
- }
+ bool getClipToBounds() const { return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS; }
- const Rect& getClipBounds() const {
- return mPrimitiveFields.mClipBounds;
- }
+ const Rect& getClipBounds() const { return mPrimitiveFields.mClipBounds; }
void getClippingRectForFlags(uint32_t flags, Rect* outRect) const {
if (flags & CLIP_TO_BOUNDS) {
@@ -559,41 +472,25 @@
}
}
- bool getHasOverlappingRendering() const {
- return mPrimitiveFields.mHasOverlappingRendering;
- }
+ bool getHasOverlappingRendering() const { return mPrimitiveFields.mHasOverlappingRendering; }
- const Outline& getOutline() const {
- return mPrimitiveFields.mOutline;
- }
+ const Outline& getOutline() const { return mPrimitiveFields.mOutline; }
- const RevealClip& getRevealClip() const {
- return mPrimitiveFields.mRevealClip;
- }
+ const RevealClip& getRevealClip() const { return mPrimitiveFields.mRevealClip; }
- bool getProjectBackwards() const {
- return mPrimitiveFields.mProjectBackwards;
- }
+ bool getProjectBackwards() const { return mPrimitiveFields.mProjectBackwards; }
void debugOutputProperties(std::ostream& output, const int level) const;
void updateMatrix();
- Outline& mutableOutline() {
- return mPrimitiveFields.mOutline;
- }
+ Outline& mutableOutline() { return mPrimitiveFields.mOutline; }
- RevealClip& mutableRevealClip() {
- return mPrimitiveFields.mRevealClip;
- }
+ RevealClip& mutableRevealClip() { return mPrimitiveFields.mRevealClip; }
- const LayerProperties& layerProperties() const {
- return mLayerProperties;
- }
+ const LayerProperties& layerProperties() const { return mLayerProperties; }
- LayerProperties& mutateLayerProperties() {
- return mLayerProperties;
- }
+ LayerProperties& mutateLayerProperties() { return mLayerProperties; }
// Returns true if damage calculations should be clipped to bounds
// TODO: Figure out something better for getZ(), as children should still be
@@ -605,24 +502,21 @@
}
bool hasShadow() const {
- return getZ() > 0.0f
- && getOutline().getPath() != nullptr
- && getOutline().getAlpha() != 0.0f;
+ return getZ() > 0.0f && getOutline().getPath() != nullptr &&
+ getOutline().getAlpha() != 0.0f;
}
bool fitsOnLayer() const {
const DeviceInfo* deviceInfo = DeviceInfo::get();
- return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
- && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
+ return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize() &&
+ mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
}
bool promotedToLayer() const {
- return mLayerProperties.mType == LayerType::None
- && fitsOnLayer()
- && (mComputedFields.mNeedLayerForFunctors
- || (!MathUtils::isZero(mPrimitiveFields.mAlpha)
- && mPrimitiveFields.mAlpha < 1
- && mPrimitiveFields.mHasOverlappingRendering));
+ return mLayerProperties.mType == LayerType::None && fitsOnLayer() &&
+ (mComputedFields.mNeedLayerForFunctors ||
+ (!MathUtils::isZero(mPrimitiveFields.mAlpha) && mPrimitiveFields.mAlpha < 1 &&
+ mPrimitiveFields.mHasOverlappingRendering));
}
LayerType effectiveLayerType() const {
diff --git a/libs/hwui/ResourceCache.cpp b/libs/hwui/ResourceCache.cpp
index b26e433..d60b994 100644
--- a/libs/hwui/ResourceCache.cpp
+++ b/libs/hwui/ResourceCache.cpp
@@ -32,10 +32,10 @@
ALOGD("ResourceCache: cacheReport:");
for (size_t i = 0; i < mCache->size(); ++i) {
ResourceReference* ref = mCache->valueAt(i);
- ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p",
- i, mCache->keyAt(i), mCache->valueAt(i));
- ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d",
- i, ref->refCount, ref->destroyed, ref->resourceType);
+ ALOGD(" ResourceCache: mCache(%zu): resource, ref = 0x%p, 0x%p", i, mCache->keyAt(i),
+ mCache->valueAt(i));
+ ALOGD(" ResourceCache: mCache(%zu): refCount, destroyed, type = %d, %d, %d", i,
+ ref->refCount, ref->destroyed, ref->resourceType);
}
}
@@ -63,7 +63,7 @@
}
void ResourceCache::incrementRefcount(const Res_png_9patch* patchResource) {
- incrementRefcount((void*) patchResource, kNinePatch);
+ incrementRefcount((void*)patchResource, kNinePatch);
}
void ResourceCache::incrementRefcountLocked(void* resource, ResourceType resourceType) {
@@ -82,7 +82,7 @@
}
void ResourceCache::decrementRefcount(const Res_png_9patch* patchResource) {
- decrementRefcount((void*) patchResource);
+ decrementRefcount((void*)patchResource);
}
void ResourceCache::decrementRefcountLocked(void* resource) {
@@ -99,7 +99,7 @@
}
void ResourceCache::decrementRefcountLocked(const Res_png_9patch* patchResource) {
- decrementRefcountLocked((void*) patchResource);
+ decrementRefcountLocked((void*)patchResource);
}
void ResourceCache::destructor(Res_png_9patch* resource) {
@@ -117,7 +117,7 @@
} else {
// A Res_png_9patch is actually an array of byte that's larger
// than sizeof(Res_png_9patch). It must be freed as an array.
- delete[] (int8_t*) resource;
+ delete[](int8_t*) resource;
}
return;
}
@@ -136,20 +136,19 @@
switch (ref->resourceType) {
case kNinePatch: {
if (Caches::hasInstance()) {
- Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*) resource);
+ Caches::getInstance().patchCache.removeDeferred((Res_png_9patch*)resource);
} else {
// A Res_png_9patch is actually an array of byte that's larger
// than sizeof(Res_png_9patch). It must be freed as an array.
- int8_t* patch = (int8_t*) resource;
+ int8_t* patch = (int8_t*)resource;
delete[] patch;
}
- }
- break;
+ } break;
}
}
mCache->removeItem(resource);
delete ref;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ResourceCache.h b/libs/hwui/ResourceCache.h
index 3ac7864..fd3f9fd 100644
--- a/libs/hwui/ResourceCache.h
+++ b/libs/hwui/ResourceCache.h
@@ -41,9 +41,10 @@
class ResourceReference {
public:
-
explicit ResourceReference(ResourceType type) {
- refCount = 0; destroyed = false; resourceType = type;
+ refCount = 0;
+ destroyed = false;
+ resourceType = type;
}
int refCount;
@@ -51,14 +52,13 @@
ResourceType resourceType;
};
-class ANDROID_API ResourceCache: public Singleton<ResourceCache> {
+class ANDROID_API ResourceCache : public Singleton<ResourceCache> {
ResourceCache();
~ResourceCache();
friend class Singleton<ResourceCache>;
public:
-
/**
* When using these two methods, make sure to only invoke the *Locked()
* variants of increment/decrementRefcount(), recyle() and destructor()
@@ -97,7 +97,7 @@
KeyedVector<const void*, ResourceReference*>* mCache;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_RESOURCE_CACHE_H
+#endif // ANDROID_HWUI_RESOURCE_CACHE_H
diff --git a/libs/hwui/RevealClip.h b/libs/hwui/RevealClip.h
index 63821dd..a5678d4 100644
--- a/libs/hwui/RevealClip.h
+++ b/libs/hwui/RevealClip.h
@@ -25,11 +25,7 @@
class RevealClip {
public:
- RevealClip()
- : mShouldClip(false)
- , mX(0)
- , mY(0)
- , mRadius(0) {}
+ RevealClip() : mShouldClip(false), mX(0), mY(0), mRadius(0) {}
void set(bool shouldClip, float x, float y, float radius) {
mShouldClip = shouldClip;
@@ -43,13 +39,10 @@
}
}
- bool willClip() const {
- return mShouldClip;
- }
+ bool willClip() const { return mShouldClip; }
void getBounds(Rect* outBounds) const {
- outBounds->set(mX - mRadius, mY - mRadius,
- mX + mRadius, mY + mRadius);
+ outBounds->set(mX - mRadius, mY - mRadius, mX + mRadius, mY + mRadius);
}
float getRadius() const { return mRadius; }
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index e94a70a..d0155ee 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -16,8 +16,8 @@
#include <math.h>
#include <utils/Log.h>
-#include <utils/Trace.h>
#include <utils/MathUtils.h>
+#include <utils/Trace.h>
#include "AmbientShadow.h"
#include "Properties.h"
@@ -28,10 +28,10 @@
namespace android {
namespace uirenderer {
-void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount,
- const Vector3& centroid3d, const Rect& casterBounds,
- const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer) {
+void ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& centroid3d,
+ const Rect& casterBounds, const Rect& localClip,
+ float maxZ, VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
// A bunch of parameters to tweak the shadow.
@@ -53,32 +53,32 @@
return;
}
- AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
- casterVertexCount, centroid3d, heightFactor, geomFactor,
- shadowVertexBuffer);
+ AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
+ heightFactor, geomFactor, shadowVertexBuffer);
}
-void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount, const Vector3& casterCentroid,
- const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
- const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
+void ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& casterCentroid,
+ const mat4& receiverTransform,
+ const Vector3& lightCenter, int lightRadius,
+ const Rect& casterBounds, const Rect& localClip,
+ VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
Vector3 adjustedLightCenter(lightCenter);
if (CC_UNLIKELY(Properties::overrideLightPosY > 0)) {
- adjustedLightCenter.y = - Properties::overrideLightPosY; // negated since this shifts up
+ adjustedLightCenter.y = -Properties::overrideLightPosY; // negated since this shifts up
}
if (CC_UNLIKELY(Properties::overrideLightPosZ > 0)) {
adjustedLightCenter.z = Properties::overrideLightPosZ;
}
#if DEBUG_SHADOW
- ALOGD("light center %f %f %f %d",
- adjustedLightCenter.x, adjustedLightCenter.y, adjustedLightCenter.z, lightRadius);
+ ALOGD("light center %f %f %f %d", adjustedLightCenter.x, adjustedLightCenter.y,
+ adjustedLightCenter.z, lightRadius);
#endif
- if (isnan(adjustedLightCenter.x)
- || isnan(adjustedLightCenter.y)
- || isnan(adjustedLightCenter.z)) {
+ if (isnan(adjustedLightCenter.x) || isnan(adjustedLightCenter.y) ||
+ isnan(adjustedLightCenter.z)) {
return;
}
@@ -95,7 +95,7 @@
// Now light and caster are both in local space, we will check whether
// the shadow is within the clip area.
Rect lightRect = Rect(adjustedLightCenter.x - lightRadius, adjustedLightCenter.y - lightRadius,
- adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
+ adjustedLightCenter.x + lightRadius, adjustedLightCenter.y + lightRadius);
lightRect.unionWith(localClip);
if (!lightRect.intersects(casterBounds)) {
#if DEBUG_SHADOW
@@ -104,13 +104,13 @@
return;
}
- SpotShadow::createSpotShadow(isCasterOpaque, adjustedLightCenter, lightRadius,
- casterPolygon, casterVertexCount, casterCentroid, shadowVertexBuffer);
+ SpotShadow::createSpotShadow(isCasterOpaque, adjustedLightCenter, lightRadius, casterPolygon,
+ casterVertexCount, casterCentroid, shadowVertexBuffer);
#if DEBUG_SHADOW
- if(shadowVertexBuffer.getVertexCount() <= 0) {
+ if (shadowVertexBuffer.getVertexCount() <= 0) {
ALOGD("Spot shadow generation failed %d", shadowVertexBuffer.getVertexCount());
- }
+ }
#endif
}
@@ -141,7 +141,7 @@
Vector2 centroid = poly[0];
if (area != 0) {
centroid = (Vector2){static_cast<float>(sumx / (3 * area)),
- static_cast<float>(sumy / (3 * area))};
+ static_cast<float>(sumy / (3 * area))};
} else {
ALOGW("Area is 0 while computing centroid!");
}
@@ -161,8 +161,8 @@
return result;
}
-int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1,
- const Vector2& vector2, float divisor) {
+int ShadowTessellator::getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
+ float divisor) {
// When there is no distance difference, there is no need for extra vertices.
if (vector1.lengthSquared() == 0 || vector2.lengthSquared() == 0) {
return 0;
@@ -179,13 +179,13 @@
// TODO: Use look up table for the dotProduct to extraVerticesNumber
// computation, if needed.
float angle = acosf(dotProduct);
- return (int) floor(angle / divisor);
+ return (int)floor(angle / divisor);
}
void ShadowTessellator::checkOverflow(int used, int total, const char* bufferName) {
- LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d",
- bufferName, used, total);
+ LOG_ALWAYS_FATAL_IF(used > total, "Error: %s overflow!!! used %d, total %d", bufferName, used,
+ total);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index 2eaf187..79f46f9 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -68,27 +68,27 @@
class ShadowTessellator {
public:
- static void tessellateAmbientShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount,
- const Vector3& centroid3d, const Rect& casterBounds,
- const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer);
+ static void tessellateAmbientShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& centroid3d,
+ const Rect& casterBounds, const Rect& localClip, float maxZ,
+ VertexBuffer& shadowVertexBuffer);
- static void tessellateSpotShadow(bool isCasterOpaque,
- const Vector3* casterPolygon, int casterVertexCount, const Vector3& casterCentroid,
- const mat4& receiverTransform, const Vector3& lightCenter, int lightRadius,
- const Rect& casterBounds, const Rect& localClip, VertexBuffer& shadowVertexBuffer);
+ static void tessellateSpotShadow(bool isCasterOpaque, const Vector3* casterPolygon,
+ int casterVertexCount, const Vector3& casterCentroid,
+ const mat4& receiverTransform, const Vector3& lightCenter,
+ int lightRadius, const Rect& casterBounds,
+ const Rect& localClip, VertexBuffer& shadowVertexBuffer);
static Vector2 centroid2d(const Vector2* poly, int polyLength);
static Vector2 calculateNormal(const Vector2& p1, const Vector2& p2);
- static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2,
- float divisor);
+ static int getExtraVertexNumber(const Vector2& vector1, const Vector2& vector2, float divisor);
static void checkOverflow(int used, int total, const char* bufferName);
-}; // ShadowTessellator
+}; // ShadowTessellator
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SHADOW_TESSELLATOR_H
+#endif // ANDROID_HWUI_SHADOW_TESSELLATOR_H
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 1f5f733..508869a 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -26,9 +26,9 @@
#include <SkCanvasStateUtils.h>
#include <SkColorFilter.h>
#include <SkColorSpaceXformCanvas.h>
-#include <SkDrawable.h>
#include <SkDeque.h>
#include <SkDrawFilter.h>
+#include <SkDrawable.h>
#include <SkGraphics.h>
#include <SkImage.h>
#include <SkImagePriv.h>
@@ -60,8 +60,9 @@
mCanvasOwned =
std::unique_ptr<SkCanvas>(new SkCanvas(bitmap, SkCanvas::ColorBehavior::kLegacy));
if (cs.get() == nullptr || cs->isSRGB()) {
- if(!uirenderer::Properties::isSkiaEnabled()) {
- mCanvasWrapper = SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB());
+ if (!uirenderer::Properties::isSkiaEnabled()) {
+ mCanvasWrapper =
+ SkCreateColorSpaceXformCanvas(mCanvasOwned.get(), SkColorSpace::MakeSRGB());
mCanvas = mCanvasWrapper.get();
} else {
mCanvas = mCanvasOwned.get();
@@ -98,8 +99,7 @@
std::unique_ptr<SkCanvas> newCanvasWrapper;
if (cs.get() != nullptr && !cs->isSRGB()) {
newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), std::move(cs));
- }
- else if(!uirenderer::Properties::isSkiaEnabled()) {
+ } else if (!uirenderer::Properties::isSkiaEnabled()) {
newCanvasWrapper = SkCreateColorSpaceXformCanvas(newCanvas.get(), SkColorSpace::MakeSRGB());
}
@@ -155,7 +155,7 @@
}
bool preserveMatrix = !(rec->saveFlags & SaveFlags::Matrix);
- bool preserveClip = !(rec->saveFlags & SaveFlags::Clip);
+ bool preserveClip = !(rec->saveFlags & SaveFlags::Clip);
SkMatrix savedMatrix;
if (preserveMatrix) {
@@ -197,16 +197,16 @@
return layerFlags;
}
-int SkiaCanvas::saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) {
+int SkiaCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+ SaveFlags::Flags flags) {
const SkRect bounds = SkRect::MakeLTRB(left, top, right, bottom);
const SkCanvas::SaveLayerRec rec(&bounds, paint, layerFlags(flags));
return mCanvas->saveLayer(rec);
}
-int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) {
+int SkiaCanvas::saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) {
if (static_cast<unsigned>(alpha) < 0xFF) {
SkPaint alphaPaint;
alphaPaint.setAlpha(alpha);
@@ -218,24 +218,24 @@
class SkiaCanvas::Clip {
public:
Clip(const SkRect& rect, SkClipOp op, const SkMatrix& m)
- : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
+ : mType(Type::Rect), mOp(op), mMatrix(m), mRRect(SkRRect::MakeRect(rect)) {}
Clip(const SkRRect& rrect, SkClipOp op, const SkMatrix& m)
- : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
+ : mType(Type::RRect), mOp(op), mMatrix(m), mRRect(rrect) {}
Clip(const SkPath& path, SkClipOp op, const SkMatrix& m)
- : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {}
+ : mType(Type::Path), mOp(op), mMatrix(m), mPath(&path) {}
void apply(SkCanvas* canvas) const {
canvas->setMatrix(mMatrix);
switch (mType) {
- case Type::Rect:
- canvas->clipRect(mRRect.rect(), mOp);
- break;
- case Type::RRect:
- canvas->clipRRect(mRRect, mOp);
- break;
- case Type::Path:
- canvas->clipPath(*mPath.get(), mOp);
- break;
+ case Type::Rect:
+ canvas->clipRect(mRRect.rect(), mOp);
+ break;
+ case Type::RRect:
+ canvas->clipRRect(mRRect, mOp);
+ break;
+ case Type::Path:
+ canvas->clipPath(*mPath.get(), mOp);
+ break;
}
}
@@ -246,19 +246,17 @@
Path,
};
- Type mType;
- SkClipOp mOp;
- SkMatrix mMatrix;
+ Type mType;
+ SkClipOp mOp;
+ SkMatrix mMatrix;
// These are logically a union (tracked separately due to non-POD path).
SkTLazy<SkPath> mPath;
- SkRRect mRRect;
+ SkRRect mRRect;
};
const SkiaCanvas::SaveRec* SkiaCanvas::currentSaveRec() const {
- const SaveRec* rec = mSaveStack
- ? static_cast<const SaveRec*>(mSaveStack->back())
- : nullptr;
+ const SaveRec* rec = mSaveStack ? static_cast<const SaveRec*>(mSaveStack->back()) : nullptr;
int currentSaveCount = mCanvas->getSaveCount();
SkASSERT(!rec || currentSaveCount >= rec->saveCount);
@@ -436,10 +434,9 @@
// translate & scale transforms, and a simple rectangular clip.
// (This also avoids significant wasted time in calling
// SkCanvasStateUtils::CaptureCanvasState when the clip is complex).
- if (!canvas->isClipRect() ||
- (canvas->getTotalMatrix().getType() &
- ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) {
- return nullptr;
+ if (!canvas->isClipRect() || (canvas->getTotalMatrix().getType() &
+ ~(SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask))) {
+ return nullptr;
}
return SkCanvasStateUtils::CaptureCanvasState(canvas);
@@ -465,7 +462,7 @@
SkCanvas::PointMode mode) {
if (CC_UNLIKELY(count < 2 || paint.nothingToDraw())) return;
// convert the floats into SkPoints
- count >>= 1; // now it is the number of points
+ count >>= 1; // now it is the number of points
std::unique_ptr<SkPoint[]> pts(new SkPoint[count]);
for (int i = 0; i < count; i++) {
pts[i].set(points[0], points[1]);
@@ -474,7 +471,6 @@
mCanvas->drawPoints(mode, count, pts.get(), paint);
}
-
void SkiaCanvas::drawPoint(float x, float y, const SkPaint& paint) {
mCanvas->drawPoint(x, y, paint);
}
@@ -493,11 +489,9 @@
this->drawPoints(points, count, paint, SkCanvas::kLines_PointMode);
}
-void SkiaCanvas::drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) {
+void SkiaCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
mCanvas->drawRect({left, top, right, bottom}, paint);
-
}
void SkiaCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
@@ -505,8 +499,8 @@
mCanvas->drawRegion(region, paint);
}
-void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) {
+void SkiaCanvas::drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
mCanvas->drawRoundRect(rect, rx, ry, paint);
@@ -523,11 +517,15 @@
mCanvas->drawOval(oval, paint);
}
-void SkiaCanvas::drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
+void SkiaCanvas::drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) {
if (CC_UNLIKELY(paint.nothingToDraw())) return;
SkRect arc = SkRect::MakeLTRB(left, top, right, bottom);
- mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
+ if (fabs(sweepAngle) >= 360.0f) {
+ mCanvas->drawOval(arc, paint);
+ } else {
+ mCanvas->drawArc(arc, startAngle, sweepAngle, useCenter, paint);
+ }
}
void SkiaCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
@@ -547,7 +545,7 @@
// ----------------------------------------------------------------------------
const SkPaint* SkiaCanvas::addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorSpaceFilter) {
+ sk_sp<SkColorFilter> colorSpaceFilter) {
/* We don't apply the colorSpace filter if this canvas is already wrapped with
* a SkColorSpaceXformCanvas since it already takes care of converting the
* contents of the bitmap into the appropriate colorspace. The mCanvasWrapper
@@ -560,8 +558,8 @@
}
if (tmpPaint->getColorFilter()) {
- tmpPaint->setColorFilter(SkColorFilter::MakeComposeFilter(
- tmpPaint->refColorFilter(), colorSpaceFilter));
+ tmpPaint->setColorFilter(
+ SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter));
LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
} else {
tmpPaint->setColorFilter(colorSpaceFilter);
@@ -590,9 +588,9 @@
mCanvas->drawImage(image, 0, 0, addFilter(paint, &tmpPaint, colorFilter));
}
-void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) {
+void SkiaCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
@@ -600,11 +598,11 @@
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mCanvas->drawImageRect(image, srcRect, dstRect, addFilter(paint, &tmpPaint, colorFilter),
- SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint);
}
void SkiaCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) {
+ const float* vertices, const int* colors, const SkPaint* paint) {
const int ptCount = (meshWidth + 1) * (meshHeight + 1);
const int indexCount = meshWidth * meshHeight * 6;
uint32_t flags = SkVertices::kHasTexCoords_BuilderFlag;
@@ -668,7 +666,7 @@
SkASSERT(indexPtr - indices == indexCount);
}
- // double-check that we have legal indices
+// double-check that we have legal indices
#ifdef SK_DEBUG
{
for (int i = 0; i < indexCount; i++) {
@@ -685,8 +683,9 @@
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
- sk_sp<SkShader> shader = image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
- if(colorFilter) {
+ sk_sp<SkShader> shader =
+ image->makeShader(SkShader::kClamp_TileMode, SkShader::kClamp_TileMode);
+ if (colorFilter) {
shader = shader->makeWithColorFilter(colorFilter);
}
tmpPaint.setShader(shader);
@@ -694,9 +693,9 @@
mCanvas->drawVertices(builder.detach(), SkBlendMode::kModulate, tmpPaint);
}
-void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
-
+void SkiaCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) {
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
@@ -731,8 +730,8 @@
// ----------------------------------------------------------------------------
void SkiaCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) {
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) {
if (count <= 0 || paint.nothingToDraw()) return;
// Set align to left for drawing, as we don't want individual
// glyphs centered or right-aligned; the offset above takes
@@ -740,8 +739,8 @@
SkPaint paintCopy(paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
- SkRect bounds = SkRect::MakeLTRB(boundsLeft + x, boundsTop + y,
- boundsRight + x, boundsBottom + y);
+ SkRect bounds =
+ SkRect::MakeLTRB(boundsLeft + x, boundsTop + y, boundsRight + x, boundsBottom + y);
SkTextBlobBuilder builder;
const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(paintCopy, count, &bounds);
@@ -753,7 +752,8 @@
}
void SkiaCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) {
const int N = end - start;
SkAutoSTMalloc<1024, uint8_t> storage(N * (sizeof(uint16_t) + sizeof(SkRSXform)));
SkRSXform* xform = (SkRSXform*)storage.get();
@@ -773,8 +773,8 @@
}
xform[i - start].fSCos = tan.x();
xform[i - start].fSSin = tan.y();
- xform[i - start].fTx = pos.x() - tan.y() * y;
- xform[i - start].fTy = pos.y() + tan.x() * y;
+ xform[i - start].fTx = pos.x() - tan.y() * y;
+ xform[i - start].fTy = pos.y() + tan.x() * y;
}
this->asSkCanvas()->drawTextRSXform(glyphs, sizeof(uint16_t) * N, xform, nullptr, paint);
@@ -785,17 +785,24 @@
// ----------------------------------------------------------------------------
void SkiaCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) {
sk_sp<uirenderer::skiapipeline::AnimatedRoundRect> drawable(
- new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry, paint));
+ new uirenderer::skiapipeline::AnimatedRoundRect(left, top, right, bottom, rx, ry,
+ paint));
mCanvas->drawDrawable(drawable.get());
}
-void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint) {
- sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
+void SkiaCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) {
+ sk_sp<uirenderer::skiapipeline::AnimatedCircle> drawable(
+ new uirenderer::skiapipeline::AnimatedCircle(x, y, radius, paint));
mCanvas->drawDrawable(drawable.get());
}
@@ -812,8 +819,8 @@
}
void SkiaCanvas::callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) {
+ uirenderer::GlFunctorLifecycleListener* listener) {
LOG_ALWAYS_FATAL("SkiaCanvas can't directly draw GL Content");
}
-} // namespace android
+} // namespace android
diff --git a/libs/hwui/SkiaCanvas.h b/libs/hwui/SkiaCanvas.h
index e17f835..99e676a 100644
--- a/libs/hwui/SkiaCanvas.h
+++ b/libs/hwui/SkiaCanvas.h
@@ -15,11 +15,11 @@
*/
#pragma once
-#include "hwui/Canvas.h"
#include "CanvasProperty.h"
#include "DeferredLayerUpdater.h"
#include "RenderNode.h"
#include "VectorDrawable.h"
+#include "hwui/Canvas.h"
#include <SkCanvas.h>
#include <SkTLazy.h>
@@ -42,12 +42,10 @@
virtual ~SkiaCanvas();
- virtual SkCanvas* asSkCanvas() override {
- return mCanvas;
- }
+ virtual SkCanvas* asSkCanvas() override { return mCanvas; }
virtual void resetRecording(int width, int height,
- uirenderer::RenderNode* renderNode) override {
+ uirenderer::RenderNode* renderNode) override {
LOG_ALWAYS_FATAL("SkiaCanvas cannot be reset as a recording canvas");
}
@@ -70,10 +68,10 @@
virtual void restore() override;
virtual void restoreToCount(int saveCount) override;
- virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) override;
- virtual int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) override;
+ virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+ SaveFlags::Flags flags) override;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) override;
virtual void getMatrix(SkMatrix* outMatrix) const override;
virtual void setMatrix(const SkMatrix& matrix) override;
@@ -86,8 +84,7 @@
virtual bool getClipBounds(SkRect* outRect) const override;
virtual bool quickRejectRect(float left, float top, float right, float bottom) const override;
virtual bool quickRejectPath(const SkPath& path) const override;
- virtual bool clipRect(float left, float top, float right, float bottom,
- SkClipOp op) override;
+ virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) override;
virtual bool clipPath(const SkPath* path, SkClipOp op) override;
virtual SkDrawFilter* getDrawFilter() override;
@@ -101,47 +98,52 @@
virtual void drawPoint(float x, float y, const SkPaint& paint) override;
virtual void drawPoints(const float* points, int count, const SkPaint& paint) override;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) override;
+ const SkPaint& paint) override;
virtual void drawLines(const float* points, int count, const SkPaint& paint) override;
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) override;
+ const SkPaint& paint) override;
virtual void drawRegion(const SkRegion& region, const SkPaint& paint) override;
- virtual void drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) override;
+ virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) override;
virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) override;
virtual void drawOval(float left, float top, float right, float bottom,
- const SkPaint& paint) override;
- virtual void drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) override;
+ const SkPaint& paint) override;
+ virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) override;
virtual void drawPath(const SkPath& path, const SkPaint& paint) override;
virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) override;
virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) override;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) override;
- virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ const float* vertices, const int* colors,
+ const SkPaint* paint) override;
+ virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
- virtual bool drawTextAbsolutePos() const override { return true; }
+ virtual bool drawTextAbsolutePos() const override { return true; }
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) override;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) override;
virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) override;
+ uirenderer::GlFunctorLifecycleListener* listener) override;
protected:
SkiaCanvas();
@@ -149,40 +151,39 @@
void drawDrawable(SkDrawable* drawable) { mCanvas->drawDrawable(drawable); }
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) override;
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) override;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) override;
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) override;
private:
struct SaveRec {
- int saveCount;
+ int saveCount;
SaveFlags::Flags saveFlags;
- size_t clipIndex;
+ size_t clipIndex;
};
const SaveRec* currentSaveRec() const;
void recordPartialSave(SaveFlags::Flags flags);
- template<typename T>
+ template <typename T>
void recordClip(const T&, SkClipOp);
void applyPersistentClips(size_t clipStartIndex);
- void drawPoints(const float* points, int count, const SkPaint& paint,
- SkCanvas::PointMode mode);
+ void drawPoints(const float* points, int count, const SkPaint& paint, SkCanvas::PointMode mode);
const SkPaint* addFilter(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorSpaceFilter);
+ sk_sp<SkColorFilter> colorSpaceFilter);
class Clip;
- std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas
- std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
- SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us
- // unless it is the same as mCanvasOwned.get()
- std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
- std::vector<Clip> mClipStack; // tracks persistent clips.
+ std::unique_ptr<SkCanvas> mCanvasWrapper; // might own a wrapper on the canvas
+ std::unique_ptr<SkCanvas> mCanvasOwned; // might own a canvas we allocated
+ SkCanvas* mCanvas; // we do NOT own this canvas, it must survive us
+ // unless it is the same as mCanvasOwned.get()
+ std::unique_ptr<SkDeque> mSaveStack; // lazily allocated, tracks partial saves.
+ std::vector<Clip> mClipStack; // tracks persistent clips.
};
-} // namespace android
-
+} // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index ddddefa..06e2d6c 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -20,18 +20,18 @@
#include <log/log.h>
-#include "hwui/Bitmap.h"
#include <SkLatticeIter.h>
-#include <SkPatchUtils.h>
#include <SkPaint.h>
+#include <SkPatchUtils.h>
#include <SkPath.h>
#include <SkPixelRef.h>
-#include <SkRect.h>
#include <SkRRect.h>
#include <SkRSXform.h>
+#include <SkRect.h>
#include <SkSurface.h>
#include <SkTextBlobRunIterator.h>
#include <SkVertices.h>
+#include "hwui/Bitmap.h"
namespace android {
namespace uirenderer {
@@ -46,13 +46,13 @@
}
void SkiaCanvasProxy::onDrawPoints(PointMode pointMode, size_t count, const SkPoint pts[],
- const SkPaint& paint) {
+ const SkPaint& paint) {
if (!pts || count == 0) {
return;
}
// convert the SkPoints into floats
- static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
+ static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
const size_t floatCount = count << 1;
const float* floatArray = &pts[0].fX;
@@ -72,7 +72,7 @@
SkPath path;
for (size_t i = 0; i < count - 1; i++) {
path.moveTo(pts[i]);
- path.lineTo(pts[i+1]);
+ path.lineTo(pts[i + 1]);
this->drawPath(path, strokedPaint);
path.rewind();
}
@@ -95,8 +95,8 @@
if (!roundRect.isComplex()) {
const SkRect& rect = roundRect.rect();
SkVector radii = roundRect.getSimpleRadii();
- mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- radii.fX, radii.fY, paint);
+ mCanvas->drawRoundRect(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, radii.fX, radii.fY,
+ paint);
} else {
SkPath path;
path.addRRect(roundRect);
@@ -106,8 +106,8 @@
void SkiaCanvasProxy::onDrawArc(const SkRect& rect, SkScalar startAngle, SkScalar sweepAngle,
bool useCenter, const SkPaint& paint) {
- mCanvas->drawArc(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom,
- startAngle, sweepAngle, useCenter, paint);
+ mCanvas->drawArc(rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, startAngle, sweepAngle,
+ useCenter, paint);
}
void SkiaCanvasProxy::onDrawPath(const SkPath& path, const SkPaint& paint) {
@@ -115,41 +115,38 @@
}
void SkiaCanvasProxy::onDrawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint) {
+ const SkPaint* paint) {
sk_sp<Bitmap> hwuiBitmap = Bitmap::createFrom(bitmap.info(), *bitmap.pixelRef());
// HWUI doesn't support extractSubset(), so convert any subsetted bitmap into
// a drawBitmapRect(); pass through an un-subsetted bitmap.
if (hwuiBitmap && bitmap.dimensions() != hwuiBitmap->info().dimensions()) {
SkIPoint origin = bitmap.pixelRefOrigin();
- mCanvas->drawBitmap(*hwuiBitmap, origin.fX, origin.fY,
- origin.fX + bitmap.dimensions().width(),
- origin.fY + bitmap.dimensions().height(),
- left, top,
- left + bitmap.dimensions().width(),
- top + bitmap.dimensions().height(),
- paint);
+ mCanvas->drawBitmap(
+ *hwuiBitmap, origin.fX, origin.fY, origin.fX + bitmap.dimensions().width(),
+ origin.fY + bitmap.dimensions().height(), left, top,
+ left + bitmap.dimensions().width(), top + bitmap.dimensions().height(), paint);
} else {
mCanvas->drawBitmap(*hwuiBitmap, left, top, paint);
}
}
void SkiaCanvasProxy::onDrawBitmapRect(const SkBitmap& skBitmap, const SkRect* srcPtr,
- const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
+ const SkRect& dst, const SkPaint* paint, SrcRectConstraint) {
SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(skBitmap.width(), skBitmap.height());
// TODO: if bitmap is a subset, do we need to add pixelRefOrigin to src?
- Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
- mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
- dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ Bitmap* bitmap = reinterpret_cast<Bitmap*>(skBitmap.pixelRef());
+ mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft, dst.fTop,
+ dst.fRight, dst.fBottom, paint);
}
void SkiaCanvasProxy::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
- const SkRect& dst, const SkPaint*) {
- //TODO make nine-patch drawing a method on Canvas.h
+ const SkRect& dst, const SkPaint*) {
+ // TODO make nine-patch drawing a method on Canvas.h
SkDEBUGFAIL("SkiaCanvasProxy::onDrawBitmapNine is not yet supported");
}
void SkiaCanvasProxy::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
- const SkPaint* paint) {
+ const SkPaint* paint) {
SkBitmap skiaBitmap;
SkPixmap pixmap;
if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
@@ -158,24 +155,24 @@
}
void SkiaCanvasProxy::onDrawImageRect(const SkImage* image, const SkRect* srcPtr, const SkRect& dst,
- const SkPaint* paint, SrcRectConstraint constraint) {
+ const SkPaint* paint, SrcRectConstraint constraint) {
SkBitmap skiaBitmap;
SkPixmap pixmap;
if (image->peekPixels(&pixmap) && skiaBitmap.installPixels(pixmap)) {
sk_sp<Bitmap> bitmap = Bitmap::createFrom(skiaBitmap.info(), *skiaBitmap.pixelRef());
SkRect src = (srcPtr) ? *srcPtr : SkRect::MakeWH(image->width(), image->height());
- mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
- dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
+ mCanvas->drawBitmap(*bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom, dst.fLeft,
+ dst.fTop, dst.fRight, dst.fBottom, paint);
}
}
void SkiaCanvasProxy::onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
SkDEBUGFAIL("SkiaCanvasProxy::onDrawImageNine is not yet supported");
}
void SkiaCanvasProxy::onDrawImageLattice(const SkImage* image, const Lattice& lattice,
- const SkRect& dst, const SkPaint* paint) {
+ const SkRect& dst, const SkPaint* paint) {
SkLatticeIter iter(lattice, dst);
SkRect srcR, dstR;
while (iter.next(&srcR, &dstR)) {
@@ -184,7 +181,7 @@
}
void SkiaCanvasProxy::onDrawVerticesObject(const SkVertices* vertices, SkBlendMode bmode,
- const SkPaint& paint) {
+ const SkPaint& paint) {
if (mFilterHwuiCalls) {
return;
}
@@ -214,7 +211,8 @@
return saveFlags;
}
-SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(const SaveLayerRec& saveLayerRec) {
+SkCanvas::SaveLayerStrategy SkiaCanvasProxy::getSaveLayerStrategy(
+ const SaveLayerRec& saveLayerRec) {
SkRect rect;
if (saveLayerRec.fBounds) {
rect = *saveLayerRec.fBounds;
@@ -239,7 +237,7 @@
}
void SkiaCanvasProxy::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
- const SkPaint& paint) {
+ const SkPaint& paint) {
SkPath path;
path.addRRect(outer);
path.addRRect(inner);
@@ -259,7 +257,7 @@
glyphIDs = (uint16_t*)text;
count = byteLength >> 1;
} else {
- // ensure space for one glyph per ID given UTF8 encoding.
+ // ensure space for one glyph per ID given UTF8 encoding.
storage.reset(new uint16_t[byteLength]);
glyphIDs = storage.get();
count = paint.textToGlyphs(text, byteLength, storage.get());
@@ -270,12 +268,13 @@
SkPaint paint;
uint16_t* glyphIDs;
int count;
+
private:
std::unique_ptr<uint16_t[]> storage;
};
void SkiaCanvasProxy::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& origPaint) {
+ const SkPaint& origPaint) {
// convert to glyphIDs if necessary
GlyphIDConverter glyphs(text, byteLength, origPaint);
@@ -309,14 +308,14 @@
int xBaseline = 0;
int yBaseline = 0;
if (mCanvas->drawTextAbsolutePos()) {
- bounds.offset(x,y);
+ bounds.offset(x, y);
xBaseline = x;
yBaseline = y;
}
- static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
- auto glyphFunc = [&] (uint16_t* text, float* positions) {
- memcpy(text, glyphs.glyphIDs, glyphs.count*sizeof(uint16_t));
+ static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
+ auto glyphFunc = [&](uint16_t* text, float* positions) {
+ memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
size_t posIndex = 0;
// setup the first glyph position
positions[posIndex++] = xBaseline;
@@ -326,24 +325,24 @@
float yPosition = yBaseline;
for (int i = 1; i < glyphs.count; i++) {
positions[posIndex++] = xBaseline;
- yPosition += glyphWidths[i-1];
+ yPosition += glyphWidths[i - 1];
positions[posIndex++] = yPosition;
}
} else {
float xPosition = xBaseline;
for (int i = 1; i < glyphs.count; i++) {
- xPosition += glyphWidths[i-1];
+ xPosition += glyphWidths[i - 1];
positions[posIndex++] = xPosition;
positions[posIndex++] = yBaseline;
}
}
};
mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
- bounds.fRight, bounds.fBottom, 0);
+ bounds.fRight, bounds.fBottom, 0);
}
void SkiaCanvasProxy::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& origPaint) {
+ const SkPaint& origPaint) {
// convert to glyphIDs if necessary
GlyphIDConverter glyphs(text, byteLength, origPaint);
@@ -369,11 +368,11 @@
bounds.join(glyphBounds);
}
- static_assert(sizeof(SkPoint) == sizeof(float)*2, "SkPoint is no longer two floats");
- auto glyphFunc = [&] (uint16_t* text, float* positions) {
- memcpy(text, glyphs.glyphIDs, glyphs.count*sizeof(uint16_t));
+ static_assert(sizeof(SkPoint) == sizeof(float) * 2, "SkPoint is no longer two floats");
+ auto glyphFunc = [&](uint16_t* text, float* positions) {
+ memcpy(text, glyphs.glyphIDs, glyphs.count * sizeof(uint16_t));
if (mCanvas->drawTextAbsolutePos()) {
- memcpy(positions, pos, 2*glyphs.count*sizeof(float));
+ memcpy(positions, pos, 2 * glyphs.count * sizeof(float));
} else {
for (int i = 0, posIndex = 0; i < glyphs.count; i++) {
positions[posIndex++] = pos[i].fX - x;
@@ -382,11 +381,11 @@
}
};
mCanvas->drawGlyphs(glyphFunc, glyphs.count, glyphs.paint, x, y, bounds.fLeft, bounds.fTop,
- bounds.fRight, bounds.fBottom, 0);
+ bounds.fRight, bounds.fBottom, 0);
}
void SkiaCanvasProxy::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
- SkScalar constY, const SkPaint& paint) {
+ SkScalar constY, const SkPaint& paint) {
const size_t pointCount = byteLength >> 1;
std::unique_ptr<SkPoint[]> pts(new SkPoint[pointCount]);
for (size_t i = 0; i < pointCount; i++) {
@@ -396,13 +395,14 @@
}
void SkiaCanvasProxy::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint& origPaint) {
+ const SkMatrix* matrix, const SkPaint& origPaint) {
SkDEBUGFAIL("SkiaCanvasProxy::onDrawTextOnPath is not supported");
}
void SkiaCanvasProxy::onDrawTextRSXform(const void* text, size_t byteLength,
- const SkRSXform xform[], const SkRect* cullRect, const SkPaint& paint) {
- GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
+ const SkRSXform xform[], const SkRect* cullRect,
+ const SkPaint& paint) {
+ GlyphIDConverter glyphs(text, byteLength, paint); // Just get count
SkMatrix localM, currM, origM;
mCanvas->getMatrix(&currM);
origM = currM;
@@ -410,55 +410,56 @@
localM.setRSXform(*xform++);
currM.setConcat(origM, localM);
mCanvas->setMatrix(currM);
- this->onDrawText((char*)text + (byteLength / glyphs.count * i),
- byteLength / glyphs.count, 0, 0, paint);
+ this->onDrawText((char*)text + (byteLength / glyphs.count * i), byteLength / glyphs.count,
+ 0, 0, paint);
}
mCanvas->setMatrix(origM);
}
-
void SkiaCanvasProxy::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
- const SkPaint& paint) {
+ const SkPaint& paint) {
SkPaint runPaint = paint;
- SkTextBlobRunIterator it(blob);
- for (;!it.done(); it.next()) {
- size_t textLen = it.glyphCount() * sizeof(uint16_t);
- const SkPoint& offset = it.offset();
- // applyFontToPaint() always overwrites the exact same attributes,
- // so it is safe to not re-seed the paint for this reason.
- it.applyFontToPaint(&runPaint);
+ SkTextBlobRunIterator it(blob);
+ for (; !it.done(); it.next()) {
+ size_t textLen = it.glyphCount() * sizeof(uint16_t);
+ const SkPoint& offset = it.offset();
+ // applyFontToPaint() always overwrites the exact same attributes,
+ // so it is safe to not re-seed the paint for this reason.
+ it.applyFontToPaint(&runPaint);
- switch (it.positioning()) {
- case SkTextBlob::kDefault_Positioning:
- this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
- break;
- case SkTextBlob::kHorizontal_Positioning: {
- std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
- for (size_t i = 0; i < it.glyphCount(); i++) {
- pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
- }
- this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
- break;
- }
- case SkTextBlob::kFull_Positioning: {
- std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
- for (size_t i = 0; i < it.glyphCount(); i++) {
- const size_t xIndex = i*2;
- const size_t yIndex = xIndex + 1;
- pts[i].set(x + offset.x() + it.pos()[xIndex], y + offset.y() + it.pos()[yIndex]);
- }
- this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
- break;
- }
- default:
- SK_ABORT("unhandled positioning mode");
- }
- }
+ switch (it.positioning()) {
+ case SkTextBlob::kDefault_Positioning:
+ this->drawText(it.glyphs(), textLen, x + offset.x(), y + offset.y(), runPaint);
+ break;
+ case SkTextBlob::kHorizontal_Positioning: {
+ std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
+ for (size_t i = 0; i < it.glyphCount(); i++) {
+ pts[i].set(x + offset.x() + it.pos()[i], y + offset.y());
+ }
+ this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
+ break;
+ }
+ case SkTextBlob::kFull_Positioning: {
+ std::unique_ptr<SkPoint[]> pts(new SkPoint[it.glyphCount()]);
+ for (size_t i = 0; i < it.glyphCount(); i++) {
+ const size_t xIndex = i * 2;
+ const size_t yIndex = xIndex + 1;
+ pts[i].set(x + offset.x() + it.pos()[xIndex],
+ y + offset.y() + it.pos()[yIndex]);
+ }
+ this->drawPosText(it.glyphs(), textLen, pts.get(), runPaint);
+ break;
+ }
+ default:
+ SK_ABORT("unhandled positioning mode");
+ }
+ }
}
void SkiaCanvasProxy::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
- const SkPoint texCoords[4], SkBlendMode bmode, const SkPaint& paint) {
+ const SkPoint texCoords[4], SkBlendMode bmode,
+ const SkPaint& paint) {
if (mFilterHwuiCalls) {
return;
}
@@ -466,9 +467,9 @@
mCanvas->getMatrix(&matrix);
SkISize lod = SkPatchUtils::GetLevelOfDetail(cubics, &matrix);
- mCanvas->drawVertices(SkPatchUtils::MakeVertices(cubics, colors, texCoords,
- lod.width(), lod.height()).get(),
- bmode, paint);
+ mCanvas->drawVertices(
+ SkPatchUtils::MakeVertices(cubics, colors, texCoords, lod.width(), lod.height()).get(),
+ bmode, paint);
}
void SkiaCanvasProxy::onClipRect(const SkRect& rect, SkClipOp op, ClipEdgeStyle) {
@@ -485,5 +486,5 @@
mCanvas->clipPath(&path, op);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaCanvasProxy.h b/libs/hwui/SkiaCanvasProxy.h
index d11a779..360d5a0 100644
--- a/libs/hwui/SkiaCanvasProxy.h
+++ b/libs/hwui/SkiaCanvasProxy.h
@@ -17,8 +17,8 @@
#ifndef SkiaCanvasProxy_DEFINED
#define SkiaCanvasProxy_DEFINED
-#include <cutils/compiler.h>
#include <SkCanvas.h>
+#include <cutils/compiler.h>
#include "hwui/Canvas.h"
@@ -43,7 +43,6 @@
virtual ~SkiaCanvasProxy() {}
protected:
-
virtual sk_sp<SkSurface> onNewSurface(const SkImageInfo&, const SkSurfaceProps&) override;
virtual void willSave() override;
@@ -66,15 +65,15 @@
const SkPaint*) override;
virtual void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst,
const SkPaint* paint, SrcRectConstraint) override;
- virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
- const SkRect& dst, const SkPaint*) override;
+ virtual void onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst,
+ const SkPaint*) override;
virtual void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*);
virtual void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint);
+ SrcRectConstraint);
virtual void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*);
+ const SkPaint*);
virtual void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*);
+ const SkPaint*);
virtual void onDrawVerticesObject(const SkVertices*, SkBlendMode, const SkPaint&) override;
virtual void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
@@ -107,7 +106,7 @@
typedef SkCanvas INHERITED;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // SkiaCanvasProxy_DEFINED
+#endif // SkiaCanvasProxy_DEFINED
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 5c5378b..df74655 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -39,11 +39,11 @@
};
static_assert(gTileModes[SkShader::kClamp_TileMode] == GL_CLAMP_TO_EDGE,
- "SkShader TileModes have changed");
+ "SkShader TileModes have changed");
static_assert(gTileModes[SkShader::kRepeat_TileMode] == GL_REPEAT,
- "SkShader TileModes have changed");
+ "SkShader TileModes have changed");
static_assert(gTileModes[SkShader::kMirror_TileMode] == GL_MIRRORED_REPEAT,
- "SkShader TileModes have changed");
+ "SkShader TileModes have changed");
/**
* This function does not work for n == 0.
@@ -70,7 +70,7 @@
* @param modelViewMatrix Model view matrix, as supplied by the OpenGLRenderer.
*/
static void computeScreenSpaceMatrix(mat4& screenSpace, const SkMatrix& unitMatrix,
- const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
+ const SkMatrix& localMatrix, const mat4& modelViewMatrix) {
mat4 shaderMatrix;
// uses implicit construction
shaderMatrix.loadInverse(localMatrix);
@@ -95,7 +95,7 @@
}
static void toCircularUnitMatrix(const float x, const float y, const float radius,
- SkMatrix* matrix) {
+ SkMatrix* matrix) {
const float inv = 1.0f / radius;
matrix->setTranslate(-x, -y);
matrix->postScale(inv, inv);
@@ -118,8 +118,8 @@
///////////////////////////////////////////////////////////////////////////////
bool tryStoreGradient(Caches& caches, const SkShader& shader, const Matrix4 modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData::GradientShaderData* outData) {
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData::GradientShaderData* outData) {
SkShader::GradientInfo gradInfo;
gradInfo.fColorCount = 0;
gradInfo.fColors = nullptr;
@@ -135,8 +135,8 @@
case SkShader::kRadial_GradientType:
description->gradientType = ProgramDescription::kGradientCircular;
- toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY,
- gradInfo.fRadius[0], &unitMatrix);
+ toCircularUnitMatrix(gradInfo.fPoint[0].fX, gradInfo.fPoint[0].fY, gradInfo.fRadius[0],
+ &unitMatrix);
break;
case SkShader::kSweep_GradientType:
description->gradientType = ProgramDescription::kGradientSweep;
@@ -150,8 +150,8 @@
description->hasGradient = true;
description->isSimpleGradient = isSimpleGradient(gradInfo);
- computeScreenSpaceMatrix(outData->screenSpace, unitMatrix,
- shader.getLocalMatrix(), modelViewMatrix);
+ computeScreenSpaceMatrix(outData->screenSpace, unitMatrix, shader.getLocalMatrix(),
+ modelViewMatrix);
// re-query shader to get full color / offset data
std::unique_ptr<SkColor[]> colorStorage(new SkColor[gradInfo.fColorCount]);
@@ -164,7 +164,7 @@
outData->gradientSampler = (*textureUnit)++;
#ifndef SK_SCALAR_IS_FLOAT
- #error Need to convert gradInfo.fColorOffsets to float!
+#error Need to convert gradInfo.fColorOffsets to float!
#endif
outData->gradientTexture = caches.gradientCache.get(
gradInfo.fColors, gradInfo.fColorOffsets, gradInfo.fColorCount);
@@ -181,8 +181,7 @@
}
void applyGradient(Caches& caches, const SkiaShaderData::GradientShaderData& data,
- const GLsizei width, const GLsizei height) {
-
+ const GLsizei width, const GLsizei height) {
if (CC_UNLIKELY(data.gradientTexture)) {
caches.textureState().activateTexture(data.gradientSampler);
bindTexture(&caches, data.gradientTexture, data.wrapST, data.wrapST);
@@ -193,13 +192,13 @@
}
glUniform2f(caches.program().getUniform("screenSize"), 1.0f / width, 1.0f / height);
- glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1,
- GL_FALSE, &data.screenSpace.data[0]);
+ glUniformMatrix4fv(caches.program().getUniform("screenSpace"), 1, GL_FALSE,
+ &data.screenSpace.data[0]);
}
bool tryStoreBitmap(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData::BitmapShaderData* outData) {
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData::BitmapShaderData* outData) {
SkBitmap bitmap;
SkShader::TileMode xy[2];
if (!shader.isABitmap(&bitmap, nullptr, xy)) {
@@ -225,9 +224,9 @@
description->hasTranslucentConversion = texture->blend;
description->isShaderBitmapExternal = hwuiBitmap->isHardware();
// gralloc doesn't support non-clamp modes
- if (hwuiBitmap->isHardware() || (!caches.extensions().hasNPot()
- && (!isPowerOfTwo(width) || !isPowerOfTwo(height))
- && (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) {
+ if (hwuiBitmap->isHardware() ||
+ (!caches.extensions().hasNPot() && (!isPowerOfTwo(width) || !isPowerOfTwo(height)) &&
+ (xy[0] != SkShader::kClamp_TileMode || xy[1] != SkShader::kClamp_TileMode))) {
// need non-clamp mode, but it's not supported for this draw,
// so enable custom shader logic to mimic
description->useShaderBasedWrap = true;
@@ -242,7 +241,7 @@
}
computeScreenSpaceMatrix(outData->textureTransform, SkMatrix::I(), shader.getLocalMatrix(),
- modelViewMatrix);
+ modelViewMatrix);
outData->textureDimension[0] = 1.0f / width;
outData->textureDimension[1] = 1.0f / height;
@@ -256,7 +255,7 @@
glUniform1i(caches.program().getUniform("bitmapSampler"), data.bitmapSampler);
glUniformMatrix4fv(caches.program().getUniform("textureTransform"), 1, GL_FALSE,
- &data.textureTransform.data[0]);
+ &data.textureTransform.data[0]);
glUniform2fv(caches.program().getUniform("textureDimension"), 1, &data.textureDimension[0]);
}
@@ -283,20 +282,19 @@
}
void storeCompose(Caches& caches, const SkShader& bitmapShader, const SkShader& gradientShader,
- const Matrix4& modelViewMatrix, GLuint* textureUnit,
- ProgramDescription* description, SkiaShaderData* outData) {
- LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix,
- textureUnit, description, &outData->bitmapData),
- "failed storing bitmap shader data");
- LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix,
- textureUnit, description, &outData->gradientData),
- "failing storing gradient shader data");
+ const Matrix4& modelViewMatrix, GLuint* textureUnit,
+ ProgramDescription* description, SkiaShaderData* outData) {
+ LOG_ALWAYS_FATAL_IF(!tryStoreBitmap(caches, bitmapShader, modelViewMatrix, textureUnit,
+ description, &outData->bitmapData),
+ "failed storing bitmap shader data");
+ LOG_ALWAYS_FATAL_IF(!tryStoreGradient(caches, gradientShader, modelViewMatrix, textureUnit,
+ description, &outData->gradientData),
+ "failing storing gradient shader data");
}
bool tryStoreCompose(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData* outData) {
-
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData* outData) {
SkShader::ComposeRec rec;
if (!shader.asACompose(&rec)) return false;
@@ -311,34 +309,33 @@
computeScreenSpaceMatrix(transform, SkMatrix::I(), shader.getLocalMatrix(), modelViewMatrix);
if (shaderAType == kBitmap_SkiaShaderType) {
description->isBitmapFirst = true;
- storeCompose(caches, *rec.fShaderA, *rec.fShaderB,
- transform, textureUnit, description, outData);
+ storeCompose(caches, *rec.fShaderA, *rec.fShaderB, transform, textureUnit, description,
+ outData);
} else {
description->isBitmapFirst = false;
- storeCompose(caches, *rec.fShaderB, *rec.fShaderA,
- transform, textureUnit, description, outData);
+ storeCompose(caches, *rec.fShaderB, *rec.fShaderA, transform, textureUnit, description,
+ outData);
}
description->shadersMode = rec.fBlendMode;
return true;
}
void SkiaShader::store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData* outData) {
- if (tryStoreGradient(caches, shader, modelViewMatrix,
- textureUnit, description, &outData->gradientData)) {
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData* outData) {
+ if (tryStoreGradient(caches, shader, modelViewMatrix, textureUnit, description,
+ &outData->gradientData)) {
outData->skiaShaderType = kGradient_SkiaShaderType;
return;
}
- if (tryStoreBitmap(caches, shader, modelViewMatrix,
- textureUnit, description, &outData->bitmapData)) {
+ if (tryStoreBitmap(caches, shader, modelViewMatrix, textureUnit, description,
+ &outData->bitmapData)) {
outData->skiaShaderType = kBitmap_SkiaShaderType;
return;
}
- if (tryStoreCompose(caches, shader, modelViewMatrix,
- textureUnit, description, outData)) {
+ if (tryStoreCompose(caches, shader, modelViewMatrix, textureUnit, description, outData)) {
outData->skiaShaderType = kCompose_SkiaShaderType;
return;
}
@@ -347,8 +344,8 @@
outData->skiaShaderType = kNone_SkiaShaderType;
}
-void SkiaShader::apply(Caches& caches, const SkiaShaderData& data,
- const GLsizei width, const GLsizei height) {
+void SkiaShader::apply(Caches& caches, const SkiaShaderData& data, const GLsizei width,
+ const GLsizei height) {
if (!data.skiaShaderType) return;
if (data.skiaShaderType & kGradient_SkiaShaderType) {
@@ -359,5 +356,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index ab578d5..e8e92bd 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -74,13 +74,13 @@
class SkiaShader {
public:
static void store(Caches& caches, const SkShader& shader, const Matrix4& modelViewMatrix,
- GLuint* textureUnit, ProgramDescription* description,
- SkiaShaderData* outData);
- static void apply(Caches& caches, const SkiaShaderData& data,
- const GLsizei width, const GLsizei height);
+ GLuint* textureUnit, ProgramDescription* description,
+ SkiaShaderData* outData);
+ static void apply(Caches& caches, const SkiaShaderData& data, const GLsizei width,
+ const GLsizei height);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SKIA_SHADER_H
+#endif // ANDROID_HWUI_SKIA_SHADER_H
diff --git a/libs/hwui/Snapshot.cpp b/libs/hwui/Snapshot.cpp
index 9d719bd..f1a1bef 100644
--- a/libs/hwui/Snapshot.cpp
+++ b/libs/hwui/Snapshot.cpp
@@ -113,8 +113,8 @@
// Clipping round rect
///////////////////////////////////////////////////////////////////////////////
-void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
- float radius, bool highPriority) {
+void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
+ bool highPriority) {
if (bounds.isEmpty()) {
mClipArea->setEmpty();
return;
@@ -135,7 +135,7 @@
state->matrix.loadInverse(roundRectDrawingMatrix);
// compute area under rounded corners - only draws overlapping these rects need to be clipped
- for (int i = 0 ; i < 4; i++) {
+ for (int i = 0; i < 4; i++) {
state->dangerRects[i] = bounds;
}
state->dangerRects[0].bottom = state->dangerRects[1].bottom = bounds.top + radius;
@@ -170,15 +170,16 @@
}
const ClipBase* Snapshot::serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+ const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform) {
auto target = this;
if (CC_UNLIKELY(recordedClip && recordedClip->intersectWithRoot)) {
// Clip must be intersected with root, instead of current clip.
target = getClipRoot(this);
}
- return target->mClipArea->serializeIntersectedClip(allocator,
- recordedClip, recordedClipTransform);
+ return target->mClipArea->serializeIntersectedClip(allocator, recordedClip,
+ recordedClipTransform);
}
void Snapshot::applyClip(const ClipBase* recordedClip, const Matrix4& transform) {
@@ -194,15 +195,15 @@
///////////////////////////////////////////////////////////////////////////////
void Snapshot::dump() const {
- ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d",
- this, flags, previous, getViewportHeight(), !mClipArea->isSimple());
+ ALOGD("Snapshot %p, flags %x, prev %p, height %d, hasComplexClip %d", this, flags, previous,
+ getViewportHeight(), !mClipArea->isSimple());
const Rect& clipRect(mClipArea->getClipRect());
- ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d",
- clipRect.left, clipRect.top, clipRect.right, clipRect.bottom, mClipArea->isSimple());
+ ALOGD(" ClipRect %.1f %.1f %.1f %.1f, clip simple %d", clipRect.left, clipRect.top,
+ clipRect.right, clipRect.bottom, mClipArea->isSimple());
ALOGD(" Transform (at %p):", transform);
transform->dump();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 8cd90a6..655f819 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -19,9 +19,9 @@
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
+#include <ui/Region.h>
#include <utils/LinearAllocator.h>
#include <utils/RefBase.h>
-#include <ui/Region.h>
#include <SkClipOp.h>
#include <SkRegion.h>
@@ -50,10 +50,8 @@
}
bool areaRequiresRoundRectClip(const Rect& rect) const {
- return rect.intersects(dangerRects[0])
- || rect.intersects(dangerRects[1])
- || rect.intersects(dangerRects[2])
- || rect.intersects(dangerRects[3]);
+ return rect.intersects(dangerRects[0]) || rect.intersects(dangerRects[1]) ||
+ rect.intersects(dangerRects[2]) || rect.intersects(dangerRects[3]);
}
bool highPriority;
@@ -74,7 +72,6 @@
*/
class Snapshot {
public:
-
Snapshot();
Snapshot(Snapshot* s, int saveFlags);
@@ -147,8 +144,9 @@
const ClipArea& getClipArea() const { return *mClipArea; }
ClipArea& mutateClipArea() { return *mClipArea; }
- WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
- const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+ WARN_UNUSED_RESULT const ClipBase* serializeIntersectedClip(
+ LinearAllocator& allocator, const ClipBase* recordedClip,
+ const Matrix4& recordedClipTransform);
void applyClip(const ClipBase* clip, const Matrix4& transform);
/**
@@ -173,8 +171,8 @@
*
* If the current round rect clip is high priority, the incoming clip is ignored.
*/
- void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds,
- float radius, bool highPriority);
+ void setClippingRoundRect(LinearAllocator& allocator, const Rect& bounds, float radius,
+ bool highPriority);
/**
* Sets (and replaces) the current projection mask
@@ -275,7 +273,7 @@
ViewportData mViewportData;
Vector3 mRelativeLightCenter;
-}; // class Snapshot
+}; // class Snapshot
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index 7b0a1bc..e371ac8 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -37,7 +37,7 @@
// For the whole polygon, the sum of all the deltas b/t normals is 2 * M_PI,
// therefore, the maximum number of extra vertices will be twice bigger.
-#define SPOT_MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * SPOT_EXTRA_CORNER_VERTEX_PER_PI)
+#define SPOT_MAX_EXTRA_CORNER_VERTEX_NUMBER (2 * SPOT_EXTRA_CORNER_VERTEX_PER_PI)
// For each RADIANS_DIVISOR, we would allocate one more vertex b/t the normals.
#define SPOT_CORNER_RADIANS_DIVISOR (M_PI / SPOT_EXTRA_CORNER_VERTEX_PER_PI)
@@ -52,10 +52,10 @@
#include "VertexBuffer.h"
#include "utils/MathUtils.h"
-#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <utils/Log.h>
+#include <algorithm>
// TODO: After we settle down the new algorithm, we can remove the old one and
// its utility functions.
@@ -115,14 +115,14 @@
* @param p2 The second point defining the line segment
* @return The distance along the ray if it intersects with the line segment, negative if otherwise
*/
-static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy,
- const Vector2& p1, const Vector2& p2) {
+static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy, const Vector2& p1,
+ const Vector2& p2) {
// The math below is derived from solving this formula, basically the
// intersection point should stay on both the ray and the edge of (p1, p2).
// solve([p1x+t*(p2x-p1x)=dx*t2+px,p1y+t*(p2y-p1y)=dy*t2+py],[t,t2]);
float divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x);
- if (divisor == 0) return -1.0f; // error, invalid divisor
+ if (divisor == 0) return -1.0f; // error, invalid divisor
#if DEBUG_SHADOW
float interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor;
@@ -132,9 +132,10 @@
#endif
float distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) +
- rayOrigin.x * (p2.y - p1.y)) / divisor;
+ rayOrigin.x * (p2.y - p1.y)) /
+ divisor;
- return distance; // may be negative in error cases
+ return distance; // may be negative in error cases
}
/**
@@ -144,9 +145,7 @@
* @param pointsLength the number of vertices of the polygon.
*/
void SpotShadow::xsort(Vector2* points, int pointsLength) {
- auto cmp = [](const Vector2& a, const Vector2& b) -> bool {
- return a.x < b.x;
- };
+ auto cmp = [](const Vector2& a, const Vector2& b) -> bool { return a.x < b.x; };
std::sort(points, points + pointsLength, cmp);
}
@@ -171,10 +170,9 @@
lUpper[lUpperSize] = points[i];
lUpperSize++;
- while (lUpperSize > 2 && !ccw(
- lUpper[lUpperSize - 3].x, lUpper[lUpperSize - 3].y,
- lUpper[lUpperSize - 2].x, lUpper[lUpperSize - 2].y,
- lUpper[lUpperSize - 1].x, lUpper[lUpperSize - 1].y)) {
+ while (lUpperSize > 2 &&
+ !ccw(lUpper[lUpperSize - 3].x, lUpper[lUpperSize - 3].y, lUpper[lUpperSize - 2].x,
+ lUpper[lUpperSize - 2].y, lUpper[lUpperSize - 1].x, lUpper[lUpperSize - 1].y)) {
// Remove the middle point of the three last
lUpper[lUpperSize - 2].x = lUpper[lUpperSize - 1].x;
lUpper[lUpperSize - 2].y = lUpper[lUpperSize - 1].y;
@@ -192,10 +190,9 @@
lLower[lLowerSize] = points[i];
lLowerSize++;
- while (lLowerSize > 2 && !ccw(
- lLower[lLowerSize - 3].x, lLower[lLowerSize - 3].y,
- lLower[lLowerSize - 2].x, lLower[lLowerSize - 2].y,
- lLower[lLowerSize - 1].x, lLower[lLowerSize - 1].y)) {
+ while (lLowerSize > 2 &&
+ !ccw(lLower[lLowerSize - 3].x, lLower[lLowerSize - 3].y, lLower[lLowerSize - 2].x,
+ lLower[lLowerSize - 2].y, lLower[lLowerSize - 1].x, lLower[lLowerSize - 1].y)) {
// Remove the middle point of the three last
lLower[lLowerSize - 2] = lLower[lLowerSize - 1];
lLowerSize--;
@@ -223,8 +220,7 @@
*
* @return true if a right hand turn
*/
-bool SpotShadow::ccw(float ax, float ay, float bx, float by,
- float cx, float cy) {
+bool SpotShadow::ccw(float ax, float ay, float bx, float by, float cx, float cy) {
return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax) > EPSILON;
}
@@ -251,8 +247,7 @@
/**
* quick sort implementation about the center.
*/
-void SpotShadow::quicksortCirc(Vector2* points, int low, int high,
- const Vector2& center) {
+void SpotShadow::quicksortCirc(Vector2* points, int low, int high, const Vector2& center) {
int i = low, j = high;
int p = low + (high - low) / 2;
float pivot = angle(points[p], center);
@@ -281,8 +276,7 @@
* @param poly the polygon
* @return true if the testPoint is inside the poly.
*/
-bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint,
- const Vector2* poly, int len) {
+bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len) {
bool c = false;
float testx = testPoint.x;
float testy = testPoint.y;
@@ -292,9 +286,8 @@
float endX = poly[i].x;
float endY = poly[i].y;
- if (((endY > testy) != (startY > testy))
- && (testx < (startX - endX) * (testy - endY)
- / (startY - endY) + endX)) {
+ if (((endY > testy) != (startY > testy)) &&
+ (testx < (startX - endX) * (testy - endY) / (startY - endY) + endX)) {
c = !c;
}
}
@@ -326,8 +319,8 @@
* @param size the light size.
* @param ret result polygon.
*/
-void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter,
- float size, Vector3* ret) {
+void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter, float size,
+ Vector3* ret) {
// TODO: Caching all the sin / cos values and store them in a look up table.
for (int i = 0; i < points; i++) {
float angle = 2 * i * M_PI / points;
@@ -346,8 +339,8 @@
*
* @return float The ratio of (polygon.z / light.z - polygon.z)
*/
-float SpotShadow::projectCasterToOutline(Vector2& outline,
- const Vector3& lightCenter, const Vector3& polyVertex) {
+float SpotShadow::projectCasterToOutline(Vector2& outline, const Vector3& lightCenter,
+ const Vector3& polyVertex) {
float lightToPolyZ = lightCenter.z - polyVertex.z;
float ratioZ = CASTER_Z_CAP_RATIO;
if (lightToPolyZ != 0) {
@@ -372,9 +365,9 @@
* @param shadowTriangleStrip return an (x,y,alpha) triangle strip representing the shadow. Return
* empty strip if error.
*/
-void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
- float lightSize, const Vector3* poly, int polyLength, const Vector3& polyCentroid,
- VertexBuffer& shadowTriangleStrip) {
+void SpotShadow::createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter, float lightSize,
+ const Vector3* poly, int polyLength, const Vector3& polyCentroid,
+ VertexBuffer& shadowTriangleStrip) {
if (CC_UNLIKELY(lightCenter.z <= 0)) {
ALOGW("Relative Light Z is not positive. No spot shadow!");
return;
@@ -403,21 +396,18 @@
// Compute the last outline vertex to make sure we can get the normal and outline
// in one single loop.
- projectCasterToOutline(outlineData[polyLength - 1].position, lightCenter,
- poly[polyLength - 1]);
+ projectCasterToOutline(outlineData[polyLength - 1].position, lightCenter, poly[polyLength - 1]);
// Take the outline's polygon, calculate the normal for each outline edge.
int currentNormalIndex = polyLength - 1;
int nextNormalIndex = 0;
for (int i = 0; i < polyLength; i++) {
- float ratioZ = projectCasterToOutline(outlineData[i].position,
- lightCenter, poly[i]);
+ float ratioZ = projectCasterToOutline(outlineData[i].position, lightCenter, poly[i]);
outlineData[i].radius = ratioZ * lightSize;
outlineData[currentNormalIndex].normal = ShadowTessellator::calculateNormal(
- outlineData[currentNormalIndex].position,
- outlineData[nextNormalIndex].position);
+ outlineData[currentNormalIndex].position, outlineData[nextNormalIndex].position);
currentNormalIndex = (currentNormalIndex + 1) % polyLength;
nextNormalIndex++;
}
@@ -489,11 +479,9 @@
(previousNormal * (currentCornerSliceNumber - k) + currentNormal * k) /
currentCornerSliceNumber;
avgNormal.normalize();
- penumbra[penumbraIndex++] = outlineData[i].position +
- avgNormal * outlineData[i].radius;
+ penumbra[penumbraIndex++] = outlineData[i].position + avgNormal * outlineData[i].radius;
}
-
// Compute the umbra by the intersection from the outline's centroid!
//
// (V) ------------------------------------
@@ -547,7 +535,7 @@
#endif
for (int i = 0; i < polyLength; i++) {
umbra[i] = outlineData[i].position * FAKE_UMBRA_SIZE_RATIO +
- outlineCentroid * (1 - FAKE_UMBRA_SIZE_RATIO);
+ outlineCentroid * (1 - FAKE_UMBRA_SIZE_RATIO);
}
shadowStrengthScale = 1.0 / minRaitoVI;
}
@@ -556,7 +544,8 @@
int umbraLength = polyLength;
#if DEBUG_SHADOW
- ALOGD("penumbraLength is %d , allocatedPenumbraLength %d", penumbraLength, allocatedPenumbraLength);
+ ALOGD("penumbraLength is %d , allocatedPenumbraLength %d", penumbraLength,
+ allocatedPenumbraLength);
dumpPolygon(poly, polyLength, "input poly");
dumpPolygon(penumbra, penumbraLength, "penumbra");
dumpPolygon(umbra, umbraLength, "umbra");
@@ -573,10 +562,9 @@
int finalUmbraLength = hull(umbra, umbraLength, finalUmbra);
int finalPenumbraLength = hull(penumbra, penumbraLength, finalPenumbra);
- generateTriangleStrip(isCasterOpaque, shadowStrengthScale, finalPenumbra,
- finalPenumbraLength, finalUmbra, finalUmbraLength, poly, polyLength,
- shadowTriangleStrip, outlineCentroid);
-
+ generateTriangleStrip(isCasterOpaque, shadowStrengthScale, finalPenumbra, finalPenumbraLength,
+ finalUmbra, finalUmbraLength, poly, polyLength, shadowTriangleStrip,
+ outlineCentroid);
}
/**
@@ -632,7 +620,7 @@
break;
}
}
- if(resultIndex == -1) {
+ if (resultIndex == -1) {
ALOGE("resultIndex is -1, the polygon must be invalid!");
resultIndex = 0;
}
@@ -651,7 +639,7 @@
// Find the right polygon edge to shoot the ray at.
inline int findPolyIndex(bool isPositiveCross, int startPolyIndex, const Vector2& umbraDir,
- const Vector2* polyToCentroid, int polyLength) {
+ const Vector2* polyToCentroid, int polyLength) {
// Make sure we loop with a bound.
for (int i = 0; i < polyLength; i++) {
int currentIndex = (i + startPolyIndex) % polyLength;
@@ -662,7 +650,7 @@
float umbraCrossNext = umbraDir.cross(nextToCentroid);
if (sameDirections(isPositiveCross, currentCrossUmbra, umbraCrossNext)) {
#if DEBUG_SHADOW
- ALOGD("findPolyIndex loop %d times , index %d", i, currentIndex );
+ ALOGD("findPolyIndex loop %d times , index %d", i, currentIndex);
#endif
return currentIndex;
}
@@ -674,12 +662,13 @@
// Generate the index pair for penumbra / umbra vertices, and more penumbra vertices
// if needed.
inline void genNewPenumbraAndPairWithUmbra(const Vector2* penumbra, int penumbraLength,
- const Vector2* umbra, int umbraLength, Vector2* newPenumbra, int& newPenumbraIndex,
- IndexPair* verticesPair, int& verticesPairIndex) {
+ const Vector2* umbra, int umbraLength,
+ Vector2* newPenumbra, int& newPenumbraIndex,
+ IndexPair* verticesPair, int& verticesPairIndex) {
// In order to keep everything in just one loop, we need to pre-compute the
// closest umbra vertex for the last penumbra vertex.
- int previousClosestUmbraIndex = getClosestUmbraIndex(penumbra[penumbraLength - 1],
- umbra, umbraLength);
+ int previousClosestUmbraIndex =
+ getClosestUmbraIndex(penumbra[penumbraLength - 1], umbra, umbraLength);
for (int i = 0; i < penumbraLength; i++) {
const Vector2& currentPenumbraVertex = penumbra[i];
// For current penumbra vertex, starting from previousClosestUmbraIndex,
@@ -704,7 +693,8 @@
}
if (indexDelta > 1) {
- // For those umbra don't have penumbra, generate new penumbra vertices by interpolation.
+ // For those umbra don't have penumbra, generate new penumbra vertices by
+ // interpolation.
//
// Assuming Pi for penumbra vertices, and Ui for umbra vertices.
// In the case like below P1 paired with U1 and P2 paired with U5.
@@ -756,7 +746,7 @@
float weightForPreviousPenumbra = 1.0f - weightForCurrentPenumbra;
Vector2 interpolatedPenumbra = currentPenumbraVertex * weightForCurrentPenumbra +
- previousPenumbra * weightForPreviousPenumbra;
+ previousPenumbra * weightForPreviousPenumbra;
int skippedUmbraIndex = (previousClosestUmbraIndex + k + 1) % umbraLength;
verticesPair[verticesPairIndex].outerIndex = newPenumbraIndex;
@@ -775,8 +765,8 @@
}
// Precompute all the polygon's vector, return true if the reference cross product is positive.
-inline bool genPolyToCentroid(const Vector2* poly2d, int polyLength,
- const Vector2& centroid, Vector2* polyToCentroid) {
+inline bool genPolyToCentroid(const Vector2* poly2d, int polyLength, const Vector2& centroid,
+ Vector2* polyToCentroid) {
for (int j = 0; j < polyLength; j++) {
polyToCentroid[j] = poly2d[j] - centroid;
// Normalize these vectors such that we can use epsilon comparison after
@@ -798,21 +788,22 @@
// If the ray hit the polygon first, then return the intersection point as the
// closer vertex.
inline Vector2 getCloserVertex(const Vector2& umbraVertex, const Vector2& centroid,
- const Vector2* poly2d, int polyLength, const Vector2* polyToCentroid,
- bool isPositiveCross, int& previousPolyIndex) {
+ const Vector2* poly2d, int polyLength, const Vector2* polyToCentroid,
+ bool isPositiveCross, int& previousPolyIndex) {
Vector2 umbraToCentroid = umbraVertex - centroid;
float distanceToUmbra = umbraToCentroid.length();
umbraToCentroid = umbraToCentroid / distanceToUmbra;
// previousPolyIndex is updated for each item such that we can minimize the
// looping inside findPolyIndex();
- previousPolyIndex = findPolyIndex(isPositiveCross, previousPolyIndex,
- umbraToCentroid, polyToCentroid, polyLength);
+ previousPolyIndex = findPolyIndex(isPositiveCross, previousPolyIndex, umbraToCentroid,
+ polyToCentroid, polyLength);
float dx = umbraToCentroid.x;
float dy = umbraToCentroid.y;
- float distanceToIntersectPoly = rayIntersectPoints(centroid, dx, dy,
- poly2d[previousPolyIndex], poly2d[(previousPolyIndex + 1) % polyLength]);
+ float distanceToIntersectPoly =
+ rayIntersectPoints(centroid, dx, dy, poly2d[previousPolyIndex],
+ poly2d[(previousPolyIndex + 1) % polyLength]);
if (distanceToIntersectPoly < 0) {
distanceToIntersectPoly = 0;
}
@@ -833,9 +824,9 @@
* Generate a triangle strip given two convex polygon
**/
void SpotShadow::generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
- Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
- const Vector3* poly, int polyLength, VertexBuffer& shadowTriangleStrip,
- const Vector2& centroid) {
+ Vector2* penumbra, int penumbraLength, Vector2* umbra,
+ int umbraLength, const Vector3* poly, int polyLength,
+ VertexBuffer& shadowTriangleStrip, const Vector2& centroid) {
bool hasOccludedUmbraArea = false;
Vector2 poly2d[polyLength];
@@ -891,7 +882,7 @@
// For each penumbra vertex, find its closet umbra vertex by comparing the
// neighbor umbra vertices.
genNewPenumbraAndPairWithUmbra(penumbra, penumbraLength, umbra, umbraLength, newPenumbra,
- newPenumbraIndex, verticesPair, verticesPairIndex);
+ newPenumbraIndex, verticesPair, verticesPairIndex);
ShadowTessellator::checkOverflow(verticesPairIndex, maxNewPenumbraLength, "Spot pair");
ShadowTessellator::checkOverflow(newPenumbraIndex, maxNewPenumbraLength, "Spot new penumbra");
#if DEBUG_SHADOW
@@ -915,17 +906,15 @@
const int newPenumbraLength = newPenumbraIndex;
const int totalVertexCount = newPenumbraLength + umbraLength * 2;
const int totalIndexCount = 2 * umbraLength + 2 * verticesPairIndex + 6;
- AlphaVertex* shadowVertices =
- shadowTriangleStrip.alloc<AlphaVertex>(totalVertexCount);
- uint16_t* indexBuffer =
- shadowTriangleStrip.allocIndices<uint16_t>(totalIndexCount);
+ AlphaVertex* shadowVertices = shadowTriangleStrip.alloc<AlphaVertex>(totalVertexCount);
+ uint16_t* indexBuffer = shadowTriangleStrip.allocIndices<uint16_t>(totalIndexCount);
int vertexBufferIndex = 0;
int indexBufferIndex = 0;
// Fill the IB and VB for the penumbra area.
for (int i = 0; i < newPenumbraLength; i++) {
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
- newPenumbra[i].y, PENUMBRA_ALPHA);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x, newPenumbra[i].y,
+ PENUMBRA_ALPHA);
}
// Since the umbra can be a faked one when the occluder is too high, the umbra should be lighter
// in this case.
@@ -933,7 +922,7 @@
for (int i = 0; i < umbraLength; i++) {
AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
- scaledUmbraAlpha);
+ scaledUmbraAlpha);
}
for (int i = 0; i < verticesPairIndex; i++) {
@@ -966,21 +955,22 @@
for (int i = 0; i < umbraLength; i++) {
// Shoot a ray from centroid to each umbra vertices and pick the one with
// shorter distance to the centroid, b/t the umbra vertex or the intersection point.
- Vector2 closerVertex = getCloserVertex(umbra[i], centroid, poly2d, polyLength,
- polyToCentroid, isPositiveCross, previousPolyIndex);
+ Vector2 closerVertex =
+ getCloserVertex(umbra[i], centroid, poly2d, polyLength, polyToCentroid,
+ isPositiveCross, previousPolyIndex);
// We already stored the umbra vertices, just need to add the occlued umbra's ones.
indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
- closerVertex.x, closerVertex.y, scaledUmbraAlpha);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], closerVertex.x, closerVertex.y,
+ scaledUmbraAlpha);
}
} else {
// If there is no occluded umbra at all, then draw the triangle fan
// starting from the centroid to all umbra vertices.
int lastCentroidIndex = vertexBufferIndex;
- AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
- centroid.y, scaledUmbraAlpha);
+ AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x, centroid.y,
+ scaledUmbraAlpha);
for (int i = 0; i < umbraLength; i++) {
indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
indexBuffer[indexBufferIndex++] = lastCentroidIndex;
@@ -1006,8 +996,7 @@
/**
* Calculate the bounds for generating random test points.
*/
-void SpotShadow::updateBound(const Vector2 inVector, Vector2& lowerBound,
- Vector2& upperBound) {
+void SpotShadow::updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound) {
if (inVector.x < lowerBound.x) {
lowerBound.x = inVector.x;
}
@@ -1046,8 +1035,7 @@
/**
* Test whether the polygon is convex.
*/
-bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength,
- const char* name) {
+bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength, const char* name) {
bool isConvex = true;
for (int i = 0; i < polygonLength; i++) {
Vector2 start = polygon[i];
@@ -1055,13 +1043,13 @@
Vector2 end = polygon[(i + 2) % polygonLength];
float delta = (float(middle.x) - start.x) * (float(end.y) - start.y) -
- (float(middle.y) - start.y) * (float(end.x) - start.x);
+ (float(middle.y) - start.y) * (float(end.x) - start.x);
bool isCCWOrCoLinear = (delta >= EPSILON);
if (isCCWOrCoLinear) {
ALOGW("(Error Type 2): polygon (%s) is not a convex b/c start (x %f, y %f),"
- "middle (x %f, y %f) and end (x %f, y %f) , delta is %f !!!",
- name, start.x, start.y, middle.x, middle.y, end.x, end.y, delta);
+ "middle (x %f, y %f) and end (x %f, y %f) , delta is %f !!!",
+ name, start.x, start.y, middle.x, middle.y, end.x, end.y, delta);
isConvex = false;
break;
}
@@ -1074,9 +1062,9 @@
* Using Marte Carlo method, we generate a random point, and if it is inside the
* intersection, then it must be inside both source polygons.
*/
-void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length,
- const Vector2* poly2, int poly2Length,
- const Vector2* intersection, int intersectionLength) {
+void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length, const Vector2* poly2,
+ int poly2Length, const Vector2* intersection,
+ int intersectionLength) {
// Find the min and max of x and y.
Vector2 lowerBound = {FLT_MAX, FLT_MAX};
Vector2 upperBound = {-FLT_MAX, -FLT_MAX};
@@ -1102,15 +1090,15 @@
if (!testPointInsidePolygon(testPoint, poly1, poly1Length)) {
dumpPoly = true;
ALOGW("(Error Type 1): one point (%f, %f) in the intersection is"
- " not in the poly1",
- testPoint.x, testPoint.y);
+ " not in the poly1",
+ testPoint.x, testPoint.y);
}
if (!testPointInsidePolygon(testPoint, poly2, poly2Length)) {
dumpPoly = true;
ALOGW("(Error Type 1): one point (%f, %f) in the intersection is"
- " not in the poly2",
- testPoint.x, testPoint.y);
+ " not in the poly2",
+ testPoint.x, testPoint.y);
}
}
}
@@ -1128,5 +1116,5 @@
}
#endif
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h
index 6108bb6..8476be7 100644
--- a/libs/hwui/SpotShadow.h
+++ b/libs/hwui/SpotShadow.h
@@ -27,22 +27,22 @@
class SpotShadow {
public:
- static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter,
- float lightSize, const Vector3* poly, int polyLength,
- const Vector3& polyCentroid, VertexBuffer& retstrips);
+ static void createSpotShadow(bool isCasterOpaque, const Vector3& lightCenter, float lightSize,
+ const Vector3* poly, int polyLength, const Vector3& polyCentroid,
+ VertexBuffer& retstrips);
private:
struct VertexAngleData;
- static float projectCasterToOutline(Vector2& outline,
- const Vector3& lightCenter, const Vector3& polyVertex);
+ static float projectCasterToOutline(Vector2& outline, const Vector3& lightCenter,
+ const Vector3& polyVertex);
- static void computeLightPolygon(int points, const Vector3& lightCenter,
- float size, Vector3* ret);
+ static void computeLightPolygon(int points, const Vector3& lightCenter, float size,
+ Vector3* ret);
static void smoothPolygon(int level, int rays, float* rayDist);
- static float rayIntersectPoly(const Vector2* poly, int polyLength,
- const Vector2& point, float dx, float dy);
+ static float rayIntersectPoly(const Vector2* poly, int polyLength, const Vector2& point,
+ float dx, float dy);
static void xsort(Vector2* points, int pointsLength);
static int hull(Vector2* points, int pointsLength, Vector2* retPoly);
@@ -57,23 +57,23 @@
static void reverse(Vector2* polygon, int len);
static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale,
- Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength,
- const Vector3* poly, int polyLength, VertexBuffer& retstrips, const Vector2& centroid);
+ Vector2* penumbra, int penumbraLength, Vector2* umbra,
+ int umbraLength, const Vector3* poly, int polyLength,
+ VertexBuffer& retstrips, const Vector2& centroid);
#if DEBUG_SHADOW
- static bool testConvex(const Vector2* polygon, int polygonLength,
- const char* name);
- static void testIntersection(const Vector2* poly1, int poly1Length,
- const Vector2* poly2, int poly2Length,
- const Vector2* intersection, int intersectionLength);
- static void updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound );
+ static bool testConvex(const Vector2* polygon, int polygonLength, const char* name);
+ static void testIntersection(const Vector2* poly1, int poly1Length, const Vector2* poly2,
+ int poly2Length, const Vector2* intersection,
+ int intersectionLength);
+ static void updateBound(const Vector2 inVector, Vector2& lowerBound, Vector2& upperBound);
static void dumpPolygon(const Vector2* poly, int polyLength, const char* polyName);
static void dumpPolygon(const Vector3* poly, int polyLength, const char* polyName);
#endif
-}; // SpotShadow
+}; // SpotShadow
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SPOT_SHADOW_H
+#endif // ANDROID_HWUI_SPOT_SHADOW_H
diff --git a/libs/hwui/SwapBehavior.h b/libs/hwui/SwapBehavior.h
index 4091670c..3a176d7 100644
--- a/libs/hwui/SwapBehavior.h
+++ b/libs/hwui/SwapBehavior.h
@@ -26,8 +26,8 @@
kSwap_discardBuffer,
};
-} // namespace renderthread
-} //namespace uirenderer
-} // namespace android
+} // namespace renderthread
+} // namespace uirenderer
+} // namespace android
-#endif //HWUI_SWAPBEHAVIOR_H
+#endif // HWUI_SWAPBEHAVIOR_H
diff --git a/libs/hwui/TessellationCache.cpp b/libs/hwui/TessellationCache.cpp
index 63bf7bc..c7d93da 100644
--- a/libs/hwui/TessellationCache.cpp
+++ b/libs/hwui/TessellationCache.cpp
@@ -45,7 +45,8 @@
memset(&shape, 0, sizeof(Shape));
}
-TessellationCache::Description::Description(Type type, const Matrix4& transform, const SkPaint& paint)
+TessellationCache::Description::Description(Type type, const Matrix4& transform,
+ const SkPaint& paint)
: type(type)
, aa(paint.isAntiAlias())
, cap(paint.getStrokeCap())
@@ -82,7 +83,7 @@
hash = JenkinsHashMix(hash, android::hash_type(strokeWidth));
hash = JenkinsHashMix(hash, android::hash_type(scaleX));
hash = JenkinsHashMix(hash, android::hash_type(scaleY));
- hash = JenkinsHashMixBytes(hash, (uint8_t*) &shape, sizeof(Shape));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*)&shape, sizeof(Shape));
return JenkinsHashWhiten(hash);
}
@@ -94,25 +95,24 @@
paint->setStrokeWidth(strokeWidth);
}
-TessellationCache::ShadowDescription::ShadowDescription()
- : nodeKey(nullptr) {
+TessellationCache::ShadowDescription::ShadowDescription() : nodeKey(nullptr) {
memset(&matrixData, 0, sizeof(matrixData));
}
-TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey, const Matrix4* drawTransform)
+TessellationCache::ShadowDescription::ShadowDescription(const SkPath* nodeKey,
+ const Matrix4* drawTransform)
: nodeKey(nodeKey) {
memcpy(&matrixData, drawTransform->data, sizeof(matrixData));
}
bool TessellationCache::ShadowDescription::operator==(
const TessellationCache::ShadowDescription& rhs) const {
- return nodeKey == rhs.nodeKey
- && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0;
+ return nodeKey == rhs.nodeKey && memcmp(&matrixData, &rhs.matrixData, sizeof(matrixData)) == 0;
}
hash_t TessellationCache::ShadowDescription::hash() const {
- uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*) &nodeKey, sizeof(const void*));
- hash = JenkinsHashMixBytes(hash, (uint8_t*) &matrixData, sizeof(matrixData));
+ uint32_t hash = JenkinsHashMixBytes(0, (uint8_t*)&nodeKey, sizeof(const void*));
+ hash = JenkinsHashMixBytes(hash, (uint8_t*)&matrixData, sizeof(matrixData));
return JenkinsHashWhiten(hash);
}
@@ -123,9 +123,7 @@
class TessellationCache::TessellationTask : public Task<VertexBuffer*> {
public:
TessellationTask(Tessellator tessellator, const Description& description)
- : tessellator(tessellator)
- , description(description) {
- }
+ : tessellator(tessellator), description(description) {}
~TessellationTask() {}
@@ -135,8 +133,7 @@
class TessellationCache::TessellationProcessor : public TaskProcessor<VertexBuffer*> {
public:
- explicit TessellationProcessor(Caches& caches)
- : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
+ explicit TessellationProcessor(Caches& caches) : TaskProcessor<VertexBuffer*>(&caches.tasks) {}
~TessellationProcessor() {}
virtual void onProcess(const sp<Task<VertexBuffer*> >& task) override {
@@ -149,10 +146,7 @@
class TessellationCache::Buffer {
public:
- explicit Buffer(const sp<Task<VertexBuffer*> >& task)
- : mTask(task)
- , mBuffer(nullptr) {
- }
+ explicit Buffer(const sp<Task<VertexBuffer*> >& task) : mTask(task), mBuffer(nullptr) {}
~Buffer() {
mTask.clear();
@@ -203,18 +197,15 @@
}
}
-void tessellateShadows(
- const Matrix4* drawTransform, const Rect* localClip,
- bool isCasterOpaque, const SkPath* casterPerimeter,
- const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
- const Vector3& lightCenter, float lightRadius,
- VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
-
+void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque,
+ const SkPath* casterPerimeter, const Matrix4* casterTransformXY,
+ const Matrix4* casterTransformZ, const Vector3& lightCenter,
+ float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer) {
// tessellate caster outline into a 2d polygon
std::vector<Vertex> casterVertices2d;
const float casterRefinementThreshold = 2.0f;
- PathTessellator::approximatePathOutlineVertices(*casterPerimeter,
- casterRefinementThreshold, casterVertices2d);
+ PathTessellator::approximatePathOutlineVertices(*casterPerimeter, casterRefinementThreshold,
+ casterVertices2d);
// Shadow requires CCW for now. TODO: remove potential double-reverse
reverseVertexArray(&casterVertices2d.front(), casterVertices2d.size());
@@ -235,9 +226,8 @@
}
// map the centroid of the caster into 3d
- Vector2 centroid = ShadowTessellator::centroid2d(
- reinterpret_cast<const Vector2*>(&casterVertices2d.front()),
- casterVertexCount);
+ Vector2 centroid = ShadowTessellator::centroid2d(
+ reinterpret_cast<const Vector2*>(&casterVertices2d.front()), casterVertexCount);
Vector3 centroid3d = {centroid.x, centroid.y, 0};
mapPointFakeZ(centroid3d, casterTransformXY, casterTransformZ);
@@ -257,14 +247,13 @@
casterTransformXY->mapRect(casterBounds);
// actual tessellation of both shadows
- ShadowTessellator::tessellateAmbientShadow(
- isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
- casterBounds, *localClip, maxZ, ambientBuffer);
+ ShadowTessellator::tessellateAmbientShadow(isCasterOpaque, casterPolygon, casterVertexCount,
+ centroid3d, casterBounds, *localClip, maxZ,
+ ambientBuffer);
- ShadowTessellator::tessellateSpotShadow(
- isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
- *drawTransform, lightCenter, lightRadius, casterBounds, *localClip,
- spotBuffer);
+ ShadowTessellator::tessellateSpotShadow(isCasterOpaque, casterPolygon, casterVertexCount,
+ centroid3d, *drawTransform, lightCenter, lightRadius,
+ casterBounds, *localClip, spotBuffer);
}
class ShadowProcessor : public TaskProcessor<TessellationCache::vertexBuffer_pair_t> {
@@ -278,8 +267,8 @@
ATRACE_NAME("shadow tessellation");
tessellateShadows(&t->drawTransform, &t->localClip, t->opaque, &t->casterPerimeter,
- &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
- t->ambientBuffer, t->spotBuffer);
+ &t->transformXY, &t->transformZ, t->lightCenter, t->lightRadius,
+ t->ambientBuffer, t->spotBuffer);
t->setResult(TessellationCache::vertexBuffer_pair_t(&t->ambientBuffer, &t->spotBuffer));
}
@@ -292,7 +281,8 @@
TessellationCache::TessellationCache()
: mMaxSize(MB(1))
, mCache(LruCache<Description, Buffer*>::kUnlimitedCapacity)
- , mShadowCache(LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
+ , mShadowCache(
+ LruCache<ShadowDescription, Task<vertexBuffer_pair_t*>*>::kUnlimitedCapacity) {
mCache.setOnEntryRemovedListener(&mBufferRemovedListener);
mShadowCache.setOnEntryRemovedListener(&mBufferPairRemovedListener);
mDebugEnabled = Properties::debugLevel & kDebugCaches;
@@ -323,7 +313,6 @@
// Caching
///////////////////////////////////////////////////////////////////////////////
-
void TessellationCache::trim() {
uint32_t size = getSize();
while (size > mMaxSize) {
@@ -343,7 +332,7 @@
///////////////////////////////////////////////////////////////////////////////
void TessellationCache::BufferRemovedListener::operator()(Description& description,
- Buffer*& buffer) {
+ Buffer*& buffer) {
delete buffer;
}
@@ -352,32 +341,31 @@
///////////////////////////////////////////////////////////////////////////////
void TessellationCache::precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius) {
+ bool opaque, const SkPath* casterPerimeter,
+ const Matrix4* transformXY, const Matrix4* transformZ,
+ const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
if (mShadowCache.get(key)) return;
- sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque,
- casterPerimeter, transformXY, transformZ, lightCenter, lightRadius);
+ sp<ShadowTask> task = new ShadowTask(drawTransform, localClip, opaque, casterPerimeter,
+ transformXY, transformZ, lightCenter, lightRadius);
if (mShadowProcessor == nullptr) {
mShadowProcessor = new ShadowProcessor(Caches::getInstance());
}
mShadowProcessor->add(task);
- task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
+ task->incStrong(nullptr); // not using sp<>s, so manually ref while in the cache
mShadowCache.put(key, task.get());
}
sp<TessellationCache::ShadowTask> TessellationCache::getShadowTask(
- const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
+ const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
const Vector3& lightCenter, float lightRadius) {
ShadowDescription key(casterPerimeter, drawTransform);
ShadowTask* task = static_cast<ShadowTask*>(mShadowCache.get(key));
if (!task) {
- precacheShadows(drawTransform, localClip, opaque, casterPerimeter,
- transformXY, transformZ, lightCenter, lightRadius);
+ precacheShadows(drawTransform, localClip, opaque, casterPerimeter, transformXY, transformZ,
+ lightCenter, lightRadius);
task = static_cast<ShadowTask*>(mShadowCache.get(key));
}
LOG_ALWAYS_FATAL_IF(task == nullptr, "shadow not precached");
@@ -388,8 +376,8 @@
// Tessellation precaching
///////////////////////////////////////////////////////////////////////////////
-TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(
- const Description& entry, Tessellator tessellator) {
+TessellationCache::Buffer* TessellationCache::getOrCreateBuffer(const Description& entry,
+ Tessellator tessellator) {
Buffer* buffer = mCache.get(entry);
if (!buffer) {
// not cached, enqueue a task to fill the buffer
@@ -408,7 +396,7 @@
}
static VertexBuffer* tessellatePath(const TessellationCache::Description& description,
- const SkPath& path) {
+ const SkPath& path) {
Matrix4 matrix;
SkPaint paint;
description.setupMatrixAndPaint(&matrix, &paint);
@@ -422,8 +410,8 @@
///////////////////////////////////////////////////////////////////////////////
static VertexBuffer* tessellateRoundRect(const TessellationCache::Description& description) {
- SkRect rect = SkRect::MakeWH(description.shape.roundRect.width,
- description.shape.roundRect.height);
+ SkRect rect =
+ SkRect::MakeWH(description.shape.roundRect.width, description.shape.roundRect.height);
float rx = description.shape.roundRect.rx;
float ry = description.shape.roundRect.ry;
if (description.style == SkPaint::kStrokeAndFill_Style) {
@@ -437,9 +425,9 @@
return tessellatePath(description, path);
}
-TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(
- const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry) {
+TessellationCache::Buffer* TessellationCache::getRoundRectBuffer(const Matrix4& transform,
+ const SkPaint& paint, float width,
+ float height, float rx, float ry) {
Description entry(Description::Type::RoundRect, transform, paint);
entry.shape.roundRect.width = width;
entry.shape.roundRect.height = height;
@@ -448,9 +436,9 @@
return getOrCreateBuffer(entry, &tessellateRoundRect);
}
const VertexBuffer* TessellationCache::getRoundRect(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry) {
+ float width, float height, float rx, float ry) {
return getRoundRectBuffer(transform, paint, width, height, rx, ry)->getVertexBuffer();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TessellationCache.h b/libs/hwui/TessellationCache.h
index ccad1b7..a0f0ed4 100644
--- a/libs/hwui/TessellationCache.h
+++ b/libs/hwui/TessellationCache.h
@@ -90,17 +90,16 @@
class ShadowTask : public Task<vertexBuffer_pair_t> {
public:
ShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
- const SkPath* casterPerimeter, const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius)
- : drawTransform(*drawTransform)
- , localClip(localClip)
- , opaque(opaque)
- , casterPerimeter(*casterPerimeter)
- , transformXY(*transformXY)
- , transformZ(*transformZ)
- , lightCenter(lightCenter)
- , lightRadius(lightRadius) {
- }
+ const SkPath* casterPerimeter, const Matrix4* transformXY,
+ const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius)
+ : drawTransform(*drawTransform)
+ , localClip(localClip)
+ , opaque(opaque)
+ , casterPerimeter(*casterPerimeter)
+ , transformXY(*transformXY)
+ , transformZ(*transformZ)
+ , lightCenter(lightCenter)
+ , lightRadius(lightRadius) {}
/* Note - we deep copy all task parameters, because *even though* pointers into Allocator
* controlled objects (like the SkPath and Matrix4s) should be safe for the entire frame,
@@ -153,17 +152,17 @@
// TODO: precache/get for Oval, Lines, Points, etc.
- void precacheRoundRect(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry) {
+ void precacheRoundRect(const Matrix4& transform, const SkPaint& paint, float width,
+ float height, float rx, float ry) {
getRoundRectBuffer(transform, paint, width, height, rx, ry);
}
- const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry);
+ const VertexBuffer* getRoundRect(const Matrix4& transform, const SkPaint& paint, float width,
+ float height, float rx, float ry);
- sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius);
+ sp<ShadowTask> getShadowTask(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY,
+ const Matrix4* transformZ, const Vector3& lightCenter,
+ float lightRadius);
private:
class Buffer;
@@ -172,15 +171,14 @@
typedef VertexBuffer* (*Tessellator)(const Description&);
- void precacheShadows(const Matrix4* drawTransform, const Rect& localClip,
- bool opaque, const SkPath* casterPerimeter,
- const Matrix4* transformXY, const Matrix4* transformZ,
- const Vector3& lightCenter, float lightRadius);
+ void precacheShadows(const Matrix4* drawTransform, const Rect& localClip, bool opaque,
+ const SkPath* casterPerimeter, const Matrix4* transformXY,
+ const Matrix4* transformZ, const Vector3& lightCenter, float lightRadius);
- Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint,
- float width, float height);
- Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint,
- float width, float height, float rx, float ry);
+ Buffer* getRectBuffer(const Matrix4& transform, const SkPaint& paint, float width,
+ float height);
+ Buffer* getRoundRectBuffer(const Matrix4& transform, const SkPaint& paint, float width,
+ float height, float rx, float ry);
Buffer* getOrCreateBuffer(const Description& entry, Tessellator tessellator);
@@ -207,21 +205,21 @@
// holds a pointer, and implicit strong ref to each shadow task of the frame
LruCache<ShadowDescription, Task<vertexBuffer_pair_t>*> mShadowCache;
- class BufferPairRemovedListener : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> {
- void operator()(ShadowDescription& description, Task<vertexBuffer_pair_t>*& bufferPairTask) override {
+ class BufferPairRemovedListener
+ : public OnEntryRemoved<ShadowDescription, Task<vertexBuffer_pair_t>*> {
+ void operator()(ShadowDescription& description,
+ Task<vertexBuffer_pair_t>*& bufferPairTask) override {
bufferPairTask->decStrong(nullptr);
}
};
BufferPairRemovedListener mBufferPairRemovedListener;
-}; // class TessellationCache
+}; // class TessellationCache
-void tessellateShadows(
- const Matrix4* drawTransform, const Rect* localClip,
- bool isCasterOpaque, const SkPath* casterPerimeter,
- const Matrix4* casterTransformXY, const Matrix4* casterTransformZ,
- const Vector3& lightCenter, float lightRadius,
- VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer);
+void tessellateShadows(const Matrix4* drawTransform, const Rect* localClip, bool isCasterOpaque,
+ const SkPath* casterPerimeter, const Matrix4* casterTransformXY,
+ const Matrix4* casterTransformZ, const Vector3& lightCenter,
+ float lightRadius, VertexBuffer& ambientBuffer, VertexBuffer& spotBuffer);
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextDropShadowCache.cpp b/libs/hwui/TextDropShadowCache.cpp
index c521892..c892ceb 100644
--- a/libs/hwui/TextDropShadowCache.cpp
+++ b/libs/hwui/TextDropShadowCache.cpp
@@ -19,8 +19,8 @@
#include "Caches.h"
#include "Debug.h"
#include "FontRenderer.h"
-#include "TextDropShadowCache.h"
#include "Properties.h"
+#include "TextDropShadowCache.h"
namespace android {
namespace uirenderer {
@@ -38,8 +38,7 @@
hash = JenkinsHashMix(hash, android::hash_type(italicStyle));
hash = JenkinsHashMix(hash, android::hash_type(scaleX));
if (glyphs) {
- hash = JenkinsHashMixShorts(
- hash, reinterpret_cast<const uint16_t*>(glyphs), glyphCount);
+ hash = JenkinsHashMixShorts(hash, reinterpret_cast<const uint16_t*>(glyphs), glyphCount);
}
if (positions) {
for (uint32_t i = 0; i < glyphCount * 2; i++) {
@@ -146,15 +145,15 @@
}
ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
- float radius, const float* positions) {
+ float radius, const float* positions) {
ShadowText entry(paint, radius, numGlyphs, glyphs, positions);
ShadowTexture* texture = mCache.get(entry);
if (!texture) {
SkPaint paintCopy(*paint);
paintCopy.setTextAlign(SkPaint::kLeft_Align);
- FontRenderer::DropShadow shadow = mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs,
- radius, positions);
+ FontRenderer::DropShadow shadow =
+ mRenderer->renderDropShadow(&paintCopy, glyphs, numGlyphs, radius, positions);
if (!shadow.image) {
return nullptr;
@@ -174,14 +173,15 @@
if (size < mMaxSize) {
while (mSize + size > mMaxSize) {
LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
- "Failed to remove oldest from cache. mSize = %"
- PRIu32 ", mCache.size() = %zu", mSize, mCache.size());
+ "Failed to remove oldest from cache. mSize = %" PRIu32
+ ", mCache.size() = %zu",
+ mSize, mCache.size());
}
}
// Textures are Alpha8
- texture->upload(GL_ALPHA, shadow.width, shadow.height,
- GL_ALPHA, GL_UNSIGNED_BYTE, shadow.image);
+ texture->upload(GL_ALPHA, shadow.width, shadow.height, GL_ALPHA, GL_UNSIGNED_BYTE,
+ shadow.image);
texture->setFilter(GL_LINEAR);
texture->setWrap(GL_CLAMP_TO_EDGE);
@@ -205,5 +205,5 @@
return texture;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextDropShadowCache.h b/libs/hwui/TextDropShadowCache.h
index 13e8774..86a0129 100644
--- a/libs/hwui/TextDropShadowCache.h
+++ b/libs/hwui/TextDropShadowCache.h
@@ -24,8 +24,8 @@
#include <utils/LruCache.h>
#include <utils/String16.h>
-#include "font/Font.h"
#include "Texture.h"
+#include "font/Font.h"
namespace android {
namespace uirenderer {
@@ -34,13 +34,20 @@
class FontRenderer;
struct ShadowText {
- ShadowText(): glyphCount(0), radius(0.0f), textSize(0.0f), typeface(nullptr),
- flags(0), italicStyle(0.0f), scaleX(0), glyphs(nullptr), positions(nullptr) {
- }
+ ShadowText()
+ : glyphCount(0)
+ , radius(0.0f)
+ , textSize(0.0f)
+ , typeface(nullptr)
+ , flags(0)
+ , italicStyle(0.0f)
+ , scaleX(0)
+ , glyphs(nullptr)
+ , positions(nullptr) {}
// len is the number of bytes in text
ShadowText(const SkPaint* paint, float radius, uint32_t glyphCount, const glyph_t* srcGlyphs,
- const float* positions)
+ const float* positions)
: glyphCount(glyphCount)
, radius(radius)
, textSize(paint->getTextSize())
@@ -49,23 +56,17 @@
, italicStyle(paint->getTextSkewX())
, scaleX(paint->getTextScaleX())
, glyphs(srcGlyphs)
- , positions(positions) {
- }
+ , positions(positions) {}
- ~ShadowText() {
- }
+ ~ShadowText() {}
hash_t hash() const;
static int compare(const ShadowText& lhs, const ShadowText& rhs);
- bool operator==(const ShadowText& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const ShadowText& other) const { return compare(*this, other) == 0; }
- bool operator!=(const ShadowText& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const ShadowText& other) const { return compare(*this, other) != 0; }
void copyTextLocally() {
str.setTo(reinterpret_cast<const char16_t*>(glyphs), glyphCount);
@@ -91,7 +92,7 @@
String16 str;
Vector<float> positionsCopy;
-}; // struct ShadowText
+}; // struct ShadowText
// Caching support
@@ -110,15 +111,14 @@
/**
* Alpha texture used to represent a shadow.
*/
-struct ShadowTexture: public Texture {
- explicit ShadowTexture(Caches& caches): Texture(caches) {
- }
+struct ShadowTexture : public Texture {
+ explicit ShadowTexture(Caches& caches) : Texture(caches) {}
float left;
float top;
-}; // struct ShadowTexture
+}; // struct ShadowTexture
-class TextDropShadowCache: public OnEntryRemoved<ShadowText, ShadowTexture*> {
+class TextDropShadowCache : public OnEntryRemoved<ShadowText, ShadowTexture*> {
public:
TextDropShadowCache();
explicit TextDropShadowCache(uint32_t maxByteSize);
@@ -130,17 +130,15 @@
*/
void operator()(ShadowText& text, ShadowTexture*& texture) override;
- ShadowTexture* get(const SkPaint* paint, const glyph_t* text,
- int numGlyphs, float radius, const float* positions);
+ ShadowTexture* get(const SkPaint* paint, const glyph_t* text, int numGlyphs, float radius,
+ const float* positions);
/**
* Clears the cache. This causes all textures to be deleted.
*/
void clear();
- void setFontRenderer(FontRenderer& fontRenderer) {
- mRenderer = &fontRenderer;
- }
+ void setFontRenderer(FontRenderer& fontRenderer) { mRenderer = &fontRenderer; }
/**
* Returns the maximum size of the cache in bytes.
@@ -158,9 +156,9 @@
const uint32_t mMaxSize;
FontRenderer* mRenderer = nullptr;
bool mDebugEnabled;
-}; // class TextDropShadowCache
+}; // class TextDropShadowCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
+#endif // ANDROID_HWUI_TEXT_DROP_SHADOW_CACHE_H
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index b7c1e29..1e90eeb 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "Caches.h"
#include "Texture.h"
+#include "Caches.h"
#include "utils/GLUtils.h"
#include "utils/MathUtils.h"
#include "utils/TraceUtils.h"
@@ -32,22 +32,22 @@
// Number of bytes used by a texture in the given format
static int bytesPerPixel(GLint glFormat) {
switch (glFormat) {
- // The wrapped-texture case, usually means a SurfaceTexture
- case 0:
- return 0;
- case GL_LUMINANCE:
- case GL_ALPHA:
- return 1;
- case GL_SRGB8:
- case GL_RGB:
- return 3;
- case GL_SRGB8_ALPHA8:
- case GL_RGBA:
- return 4;
- case GL_RGBA16F:
- return 8;
- default:
- LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
+ // The wrapped-texture case, usually means a SurfaceTexture
+ case 0:
+ return 0;
+ case GL_LUMINANCE:
+ case GL_ALPHA:
+ return 1;
+ case GL_SRGB8:
+ case GL_RGB:
+ return 3;
+ case GL_SRGB8_ALPHA8:
+ case GL_RGBA:
+ return 4;
+ case GL_RGBA16F:
+ return 8;
+ default:
+ LOG_ALWAYS_FATAL("UNKNOWN FORMAT 0x%x", glFormat);
}
}
@@ -92,13 +92,10 @@
}
}
-bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat,
- GLint format, GLenum target) {
- if (mWidth == width
- && mHeight == height
- && mFormat == format
- && mInternalFormat == internalFormat
- && mTarget == target) {
+bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target) {
+ if (mWidth == width && mHeight == height && mFormat == format &&
+ mInternalFormat == internalFormat && mTarget == target) {
return false;
}
mWidth = width;
@@ -117,8 +114,8 @@
mMagFilter = GL_LINEAR;
}
-void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height,
- GLenum format, GLenum type, const void* pixels) {
+void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format,
+ GLenum type, const void* pixels) {
GL_CHECKPOINT(MODERATE);
// We don't have color space information, we assume the data is gamma encoded
@@ -132,11 +129,9 @@
}
mCaches.textureState().bindTexture(GL_TEXTURE_2D, mId);
if (needsAlloc) {
- glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0,
- format, type, pixels);
+ glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels);
} else if (pixels) {
- glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0,
- format, type, pixels);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, internalFormat, mWidth, mHeight, 0, format, type, pixels);
}
GL_CHECKPOINT(MODERATE);
}
@@ -148,15 +143,15 @@
mEglImageHandle = EGL_NO_IMAGE_KHR;
}
mEglImageHandle = eglCreateImageKHR(eglDisplayHandle, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
- buffer->getNativeBuffer(), 0);
+ buffer->getNativeBuffer(), 0);
glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, mEglImageHandle);
}
static void uploadToTexture(bool resize, GLint internalFormat, GLenum format, GLenum type,
- GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height, const GLvoid * data) {
-
- const bool useStride = stride != width
- && Caches::getInstance().extensions().hasUnpackRowLength();
+ GLsizei stride, GLsizei bpp, GLsizei width, GLsizei height,
+ const GLvoid* data) {
+ const bool useStride =
+ stride != width && Caches::getInstance().extensions().hasUnpackRowLength();
if ((stride == width) || useStride) {
if (useStride) {
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
@@ -175,11 +170,11 @@
// With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
// if the stride doesn't match the width
- GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+ GLvoid* temp = (GLvoid*)malloc(width * height * bpp);
if (!temp) return;
- uint8_t * pDst = (uint8_t *)temp;
- uint8_t * pSrc = (uint8_t *)data;
+ uint8_t* pDst = (uint8_t*)temp;
+ uint8_t* pSrc = (uint8_t*)data;
for (GLsizei i = 0; i < height; i++) {
memcpy(pDst, pSrc, width * bpp);
pDst += width * bpp;
@@ -196,69 +191,70 @@
}
}
-void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
- bool needSRGB, GLint* outInternalFormat, GLint* outFormat, GLint* outType) {
+void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType, bool needSRGB,
+ GLint* outInternalFormat, GLint* outFormat,
+ GLint* outType) {
switch (colorType) {
- case kAlpha_8_SkColorType:
- *outFormat = GL_ALPHA;
- *outInternalFormat = GL_ALPHA;
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kRGB_565_SkColorType:
- if (needSRGB) {
- // We would ideally use a GL_RGB/GL_SRGB8 texture but the
- // intermediate Skia bitmap needs to be ARGB_8888
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat();
+ case kAlpha_8_SkColorType:
+ *outFormat = GL_ALPHA;
+ *outInternalFormat = GL_ALPHA;
*outType = GL_UNSIGNED_BYTE;
- } else {
- *outFormat = GL_RGB;
- *outInternalFormat = GL_RGB;
- *outType = GL_UNSIGNED_SHORT_5_6_5;
- }
- break;
- // ARGB_4444 is upconverted to RGBA_8888
- case kARGB_4444_SkColorType:
- case kN32_SkColorType:
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat(needSRGB);
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kGray_8_SkColorType:
- *outFormat = GL_LUMINANCE;
- *outInternalFormat = GL_LUMINANCE;
- *outType = GL_UNSIGNED_BYTE;
- break;
- case kRGBA_F16_SkColorType:
- if (caches.extensions().getMajorGlVersion() >= 3) {
- // This format is always linear
+ break;
+ case kRGB_565_SkColorType:
+ if (needSRGB) {
+ // We would ideally use a GL_RGB/GL_SRGB8 texture but the
+ // intermediate Skia bitmap needs to be ARGB_8888
+ *outFormat = GL_RGBA;
+ *outInternalFormat = caches.rgbaInternalFormat();
+ *outType = GL_UNSIGNED_BYTE;
+ } else {
+ *outFormat = GL_RGB;
+ *outInternalFormat = GL_RGB;
+ *outType = GL_UNSIGNED_SHORT_5_6_5;
+ }
+ break;
+ // ARGB_4444 is upconverted to RGBA_8888
+ case kARGB_4444_SkColorType:
+ case kN32_SkColorType:
*outFormat = GL_RGBA;
- *outInternalFormat = GL_RGBA16F;
- *outType = GL_HALF_FLOAT;
- } else {
- *outFormat = GL_RGBA;
- *outInternalFormat = caches.rgbaInternalFormat(true);
+ *outInternalFormat = caches.rgbaInternalFormat(needSRGB);
*outType = GL_UNSIGNED_BYTE;
- }
- break;
- default:
- LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
- break;
+ break;
+ case kGray_8_SkColorType:
+ *outFormat = GL_LUMINANCE;
+ *outInternalFormat = GL_LUMINANCE;
+ *outType = GL_UNSIGNED_BYTE;
+ break;
+ case kRGBA_F16_SkColorType:
+ if (caches.extensions().getMajorGlVersion() >= 3) {
+ // This format is always linear
+ *outFormat = GL_RGBA;
+ *outInternalFormat = GL_RGBA16F;
+ *outType = GL_HALF_FLOAT;
+ } else {
+ *outFormat = GL_RGBA;
+ *outInternalFormat = caches.rgbaInternalFormat(true);
+ *outType = GL_UNSIGNED_BYTE;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", colorType);
+ break;
}
}
SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
- sk_sp<SkColorSpace> sRGB) {
+ sk_sp<SkColorSpace> sRGB) {
SkBitmap rgbaBitmap;
rgbaBitmap.allocPixels(SkImageInfo::MakeN32(bitmap.width(), bitmap.height(),
- bitmap.info().alphaType(), hasLinearBlending ? sRGB : nullptr));
+ bitmap.info().alphaType(),
+ hasLinearBlending ? sRGB : nullptr));
rgbaBitmap.eraseColor(0);
if (bitmap.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
- bitmap.readPixels(rgbaBitmap.info()
- .makeColorSpace(SkColorSpace::MakeSRGB()),
- rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0);
+ bitmap.readPixels(rgbaBitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
+ rgbaBitmap.getPixels(), rgbaBitmap.rowBytes(), 0, 0);
} else {
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(bitmap, 0.0f, 0.0f, nullptr);
@@ -268,12 +264,11 @@
}
bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending) {
- return info.colorType() == kARGB_4444_SkColorType
- || (info.colorType() == kRGB_565_SkColorType
- && hasLinearBlending
- && info.colorSpace()->isSRGB())
- || (info.colorType() == kRGBA_F16_SkColorType
- && Caches::getInstance().extensions().getMajorGlVersion() < 3);
+ return info.colorType() == kARGB_4444_SkColorType ||
+ (info.colorType() == kRGB_565_SkColorType && hasLinearBlending &&
+ info.colorSpace()->isSRGB()) ||
+ (info.colorType() == kRGBA_F16_SkColorType &&
+ Caches::getInstance().extensions().getMajorGlVersion() < 3);
}
void Texture::upload(Bitmap& bitmap) {
@@ -298,13 +293,13 @@
bool needSRGB = transferFunctionCloseToSRGB(bitmap.info().colorSpace());
GLint internalFormat, format, type;
- colorTypeToGlFormatAndType(mCaches, bitmap.colorType(),
- needSRGB && hasLinearBlending, &internalFormat, &format, &type);
+ colorTypeToGlFormatAndType(mCaches, bitmap.colorType(), needSRGB && hasLinearBlending,
+ &internalFormat, &format, &type);
// Some devices don't support GL_RGBA16F, so we need to compare the color type
// and internal GL format to decide what to do with 16 bit bitmaps
- bool rgba16fNeedsConversion = bitmap.colorType() == kRGBA_F16_SkColorType
- && internalFormat != GL_RGBA16F;
+ bool rgba16fNeedsConversion =
+ bitmap.colorType() == kRGBA_F16_SkColorType && internalFormat != GL_RGBA16F;
// RGBA16F is always linear extended sRGB
if (internalFormat == GL_RGBA16F) {
@@ -330,16 +325,16 @@
float data[16];
xyzMatrix.asColMajorf(data);
- ColorSpace::TransferParameters p =
- {fn.fG, fn.fA, fn.fB, fn.fC, fn.fD, fn.fE, fn.fF};
- ColorSpace src("Unnamed", mat4f((const float*) &data[0]).upperLeft(), p);
+ ColorSpace::TransferParameters p = {fn.fG, fn.fA, fn.fB, fn.fC,
+ fn.fD, fn.fE, fn.fF};
+ ColorSpace src("Unnamed", mat4f((const float*)&data[0]).upperLeft(), p);
mConnector.reset(new ColorSpaceConnector(src, ColorSpace::sRGB()));
// A non-sRGB color space might have a transfer function close enough to sRGB
// that we can save shader instructions by using an sRGB sampler
// This is only possible if we have hardware support for sRGB textures
- if (needSRGB && internalFormat == GL_RGBA
- && mCaches.extensions().hasSRGB() && !bitmap.isHardware()) {
+ if (needSRGB && internalFormat == GL_RGBA && mCaches.extensions().hasSRGB() &&
+ !bitmap.isHardware()) {
internalFormat = GL_SRGB8_ALPHA8;
}
}
@@ -360,13 +355,14 @@
sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
uploadToTexture(needsAlloc, internalFormat, format, type, rgbaBitmap.rowBytesAsPixels(),
- rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(),
- rgbaBitmap.height(), rgbaBitmap.getPixels());
+ rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(), rgbaBitmap.height(),
+ rgbaBitmap.getPixels());
} else if (bitmap.isHardware()) {
uploadHardwareBitmapToTexture(bitmap.graphicBuffer());
} else {
uploadToTexture(needsAlloc, internalFormat, format, type, bitmap.rowBytesAsPixels(),
- bitmap.info().bytesPerPixel(), bitmap.width(), bitmap.height(), bitmap.pixels());
+ bitmap.info().bytesPerPixel(), bitmap.width(), bitmap.height(),
+ bitmap.pixels());
}
if (canMipMap) {
@@ -382,8 +378,8 @@
}
}
-void Texture::wrap(GLuint id, uint32_t width, uint32_t height,
- GLint internalFormat, GLint format, GLenum target) {
+void Texture::wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target) {
mId = id;
mWidth = width;
mHeight = height;
@@ -399,8 +395,8 @@
if (mConnector.get() != nullptr && mInternalFormat != GL_SRGB8_ALPHA8) {
const ColorSpace::TransferParameters& p = mConnector->getSource().getTransferParameters();
if (MathUtils::isZero(p.e) && MathUtils::isZero(p.f)) {
- if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b)
- && MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) {
+ if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b) &&
+ MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) {
if (MathUtils::areEqual(p.g, 1.0f)) {
return TransferFunctionType::None;
}
@@ -413,5 +409,5 @@
return TransferFunctionType::None;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 7f742e6..5b7e4e2 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -27,10 +27,10 @@
#include <ui/ColorSpace.h>
-#include <GLES2/gl2.h>
-#include <GLES3/gl3.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
#include <SkBitmap.h>
namespace android {
@@ -48,32 +48,30 @@
*/
class Texture : public GpuMemoryTracker {
public:
- static SkBitmap uploadToN32(const SkBitmap& bitmap,
- bool hasLinearBlending, sk_sp<SkColorSpace> sRGB);
+ static SkBitmap uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
+ sk_sp<SkColorSpace> sRGB);
static bool hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending);
static void colorTypeToGlFormatAndType(const Caches& caches, SkColorType colorType,
- bool needSRGB, GLint* outInternalFormat, GLint* outFormat, GLint* outType);
+ bool needSRGB, GLint* outInternalFormat,
+ GLint* outFormat, GLint* outType);
- explicit Texture(Caches& caches)
- : GpuMemoryTracker(GpuObjectType::Texture)
- , mCaches(caches)
- { }
+ explicit Texture(Caches& caches) : GpuMemoryTracker(GpuObjectType::Texture), mCaches(caches) {}
- virtual ~Texture() { }
+ virtual ~Texture() {}
inline void setWrap(GLenum wrap, bool bindTexture = false, bool force = false) {
setWrapST(wrap, wrap, bindTexture, force);
}
virtual void setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture = false,
- bool force = false);
+ bool force = false);
inline void setFilter(GLenum filter, bool bindTexture = false, bool force = false) {
setFilterMinMag(filter, filter, bindTexture, force);
}
virtual void setFilterMinMag(GLenum min, GLenum mag, bool bindTexture = false,
- bool force = false);
+ bool force = false);
/**
* Convenience method to call glDeleteTextures() on this texture's id.
@@ -89,7 +87,7 @@
*/
void resize(uint32_t width, uint32_t height, GLint internalFormat, GLint format) {
upload(internalFormat, width, height, format,
- internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr);
+ internalFormat == GL_RGBA16F ? GL_HALF_FLOAT : GL_UNSIGNED_BYTE, nullptr);
}
/**
@@ -104,60 +102,42 @@
/**
* Basically glTexImage2D/glTexSubImage2D.
*/
- void upload(GLint internalFormat, uint32_t width, uint32_t height,
- GLenum format, GLenum type, const void* pixels);
+ void upload(GLint internalFormat, uint32_t width, uint32_t height, GLenum format, GLenum type,
+ const void* pixels);
/**
* Wraps an existing texture.
*/
- void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat,
- GLint format, GLenum target);
+ void wrap(GLuint id, uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target);
- GLuint id() const {
- return mId;
- }
+ GLuint id() const { return mId; }
- uint32_t width() const {
- return mWidth;
- }
+ uint32_t width() const { return mWidth; }
- uint32_t height() const {
- return mHeight;
- }
+ uint32_t height() const { return mHeight; }
- GLint format() const {
- return mFormat;
- }
+ GLint format() const { return mFormat; }
- GLint internalFormat() const {
- return mInternalFormat;
- }
+ GLint internalFormat() const { return mInternalFormat; }
- GLenum target() const {
- return mTarget;
- }
+ GLenum target() const { return mTarget; }
/**
* Returns nullptr if this texture does not require color space conversion
* to sRGB, or a valid pointer to a ColorSpaceConnector if a conversion
* is required.
*/
- constexpr const ColorSpaceConnector* getColorSpaceConnector() const {
- return mConnector.get();
- }
+ constexpr const ColorSpaceConnector* getColorSpaceConnector() const { return mConnector.get(); }
- constexpr bool hasColorSpaceConversion() const {
- return mConnector.get() != nullptr;
- }
+ constexpr bool hasColorSpaceConversion() const { return mConnector.get() != nullptr; }
TransferFunctionType getTransferFunctionType() const;
/**
* Returns true if this texture uses a linear encoding format.
*/
- constexpr bool isLinear() const {
- return mIsLinear;
- }
+ constexpr bool isLinear() const { return mIsLinear; }
/**
* Generation of the backing bitmap,
@@ -190,6 +170,7 @@
* the current frame. This is reset at the start of a new frame.
*/
void* isInUse = nullptr;
+
private:
// TODO: Temporarily grant private access to GlLayer, remove once
// GlLayer can be de-tangled from being a dual-purpose render target
@@ -197,8 +178,8 @@
friend class GlLayer;
// Returns true if the texture layout (size, format, etc.) changed, false if it was the same
- bool updateLayout(uint32_t width, uint32_t height, GLint internalFormat,
- GLint format, GLenum target);
+ bool updateLayout(uint32_t width, uint32_t height, GLint internalFormat, GLint format,
+ GLenum target);
void uploadHardwareBitmapToTexture(GraphicBuffer* buffer);
void resetCachedParams();
@@ -226,12 +207,11 @@
Caches& mCaches;
std::unique_ptr<ColorSpaceConnector> mConnector;
-}; // struct Texture
+}; // struct Texture
class AutoTexture {
public:
- explicit AutoTexture(Texture* texture)
- : texture(texture) {}
+ explicit AutoTexture(Texture* texture) : texture(texture) {}
~AutoTexture() {
if (texture && texture->cleanup) {
texture->deleteTexture();
@@ -240,9 +220,9 @@
}
Texture* const texture;
-}; // class AutoTexture
+}; // class AutoTexture
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TEXTURE_H
+#endif // ANDROID_HWUI_TEXTURE_H
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 6fe3606..9d365fb 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -19,12 +19,12 @@
#include <utils/Mutex.h>
#include "Caches.h"
+#include "DeviceInfo.h"
+#include "Properties.h"
#include "Texture.h"
#include "TextureCache.h"
-#include "Properties.h"
-#include "utils/TraceUtils.h"
#include "hwui/Bitmap.h"
-#include "DeviceInfo.h"
+#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
@@ -36,7 +36,7 @@
TextureCache::TextureCache()
: mCache(LruCache<uint32_t, Texture*>::kUnlimitedCapacity)
, mSize(0)
- , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps
+ , mMaxSize(DeviceInfo::multiplyByResolution(4 * 6)) // 6 screen-sized RGBA_8888 bitmaps
, mFlushRate(.4f) {
mCache.setOnEntryRemovedListener(this);
mMaxTextureSize = DeviceInfo::get()->maxTextureSize();
@@ -67,8 +67,8 @@
// This will be called already locked
if (texture) {
mSize -= texture->bitmapSize;
- TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d",
- texture->id, texture->bitmapSize, mSize);
+ TEXTURE_LOGD("TextureCache::callback: name, removed size, mSize = %d, %d, %d", texture->id,
+ texture->bitmapSize, mSize);
if (mDebugEnabled) {
ALOGD("Texture deleted, size = %d", texture->bitmapSize);
}
@@ -92,19 +92,19 @@
bool TextureCache::canMakeTextureFromBitmap(Bitmap* bitmap) {
if (bitmap->width() > mMaxTextureSize || bitmap->height() > mMaxTextureSize) {
- ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)",
- bitmap->width(), bitmap->height(), mMaxTextureSize, mMaxTextureSize);
+ ALOGW("Bitmap too large to be uploaded into a texture (%dx%d, max=%dx%d)", bitmap->width(),
+ bitmap->height(), mMaxTextureSize, mMaxTextureSize);
return false;
}
return true;
}
Texture* TextureCache::createTexture(Bitmap* bitmap) {
- Texture* texture = new Texture(Caches::getInstance());
- texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
- texture->generation = bitmap->getGenerationID();
- texture->upload(*bitmap);
- return texture;
+ Texture* texture = new Texture(Caches::getInstance());
+ texture->bitmapSize = bitmap->rowBytes() * bitmap->height();
+ texture->generation = bitmap->getGenerationID();
+ texture->upload(*bitmap);
+ return texture;
}
// Returns a prepared Texture* that either is already in the cache or can fit
@@ -113,9 +113,9 @@
if (bitmap->isHardware()) {
auto textureIterator = mHardwareTextures.find(bitmap->getStableID());
if (textureIterator == mHardwareTextures.end()) {
- Texture* texture = createTexture(bitmap);
- mHardwareTextures.insert(std::make_pair(bitmap->getStableID(),
- std::unique_ptr<Texture>(texture)));
+ Texture* texture = createTexture(bitmap);
+ mHardwareTextures.insert(
+ std::make_pair(bitmap->getStableID(), std::unique_ptr<Texture>(texture)));
if (mDebugEnabled) {
ALOGD("Texture created for hw bitmap size = %d", texture->bitmapSize);
}
@@ -147,7 +147,7 @@
texture = createTexture(bitmap);
mSize += size;
TEXTURE_LOGD("TextureCache::get: create texture(%p): name, size, mSize = %d, %d, %d",
- bitmap, texture->id, size, mSize);
+ bitmap, texture->id, size, mSize);
if (mDebugEnabled) {
ALOGD("Texture created, size = %d", size);
}
@@ -201,7 +201,7 @@
void TextureCache::clear() {
mCache.clear();
- for(auto& iter: mHardwareTextures) {
+ for (auto& iter : mHardwareTextures) {
iter.second->deleteTexture();
}
mHardwareTextures.clear();
@@ -223,5 +223,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 776ff8a..19e7bea 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -26,8 +26,8 @@
#include "Debug.h"
-#include <vector>
#include <unordered_map>
+#include <vector>
namespace android {
@@ -43,9 +43,9 @@
// Debug
#if DEBUG_TEXTURES
- #define TEXTURE_LOGD(...) ALOGD(__VA_ARGS__)
+#define TEXTURE_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define TEXTURE_LOGD(...)
+#define TEXTURE_LOGD(...)
#endif
///////////////////////////////////////////////////////////////////////////////
@@ -136,9 +136,9 @@
bool mDebugEnabled;
std::unordered_map<uint32_t, std::unique_ptr<Texture>> mHardwareTextures;
-}; // class TextureCache
+}; // class TextureCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TEXTURE_CACHE_H
+#endif // ANDROID_HWUI_TEXTURE_CACHE_H
diff --git a/libs/hwui/TreeInfo.h b/libs/hwui/TreeInfo.h
index e39614b..d701269 100644
--- a/libs/hwui/TreeInfo.h
+++ b/libs/hwui/TreeInfo.h
@@ -37,6 +37,7 @@
class ErrorHandler {
public:
virtual void onError(const std::string& message) = 0;
+
protected:
~ErrorHandler() {}
};
@@ -48,6 +49,7 @@
// is finished it is possible that the node was "resurrected" and has
// a non-zero parent count.
virtual void onMaybeRemovedFromTree(RenderNode* node) = 0;
+
protected:
virtual ~TreeObserver() {}
};
@@ -55,6 +57,7 @@
// This would be a struct, but we want to PREVENT_COPY_AND_ASSIGN
class TreeInfo {
PREVENT_COPY_AND_ASSIGN(TreeInfo);
+
public:
enum TraversalMode {
// The full monty - sync, push, run animators, etc... Used by DrawFrameTask
@@ -68,10 +71,7 @@
};
TreeInfo(TraversalMode mode, renderthread::CanvasContext& canvasContext)
- : mode(mode)
- , prepareTextures(mode == MODE_FULL)
- , canvasContext(canvasContext)
- {}
+ : mode(mode), prepareTextures(mode == MODE_FULL), canvasContext(canvasContext) {}
TraversalMode mode;
// TODO: Remove this? Currently this is used to signal to stop preparing
diff --git a/libs/hwui/UvMapper.h b/libs/hwui/UvMapper.h
index 70428d2..b495e33 100644
--- a/libs/hwui/UvMapper.h
+++ b/libs/hwui/UvMapper.h
@@ -33,15 +33,14 @@
* Using this constructor is equivalent to not using any mapping at all.
* UV coordinates in the [0..1] range remain in the [0..1] range.
*/
- UvMapper(): mIdentity(true), mMinU(0.0f), mMaxU(1.0f), mMinV(0.0f), mMaxV(1.0f) {
- }
+ UvMapper() : mIdentity(true), mMinU(0.0f), mMaxU(1.0f), mMinV(0.0f), mMaxV(1.0f) {}
/**
* Creates a new mapper with the specified ranges for U and V coordinates.
* The parameter minU must be < maxU and minV must be < maxV.
*/
- UvMapper(float minU, float maxU, float minV, float maxV):
- mMinU(minU), mMaxU(maxU), mMinV(minV), mMaxV(maxV) {
+ UvMapper(float minU, float maxU, float minV, float maxV)
+ : mMinU(minU), mMaxU(maxU), mMinV(minV), mMaxV(maxV) {
checkIdentity();
}
@@ -49,9 +48,7 @@
* Returns true if calling the map*() methods has no effect (that is,
* texture coordinates remain in the 0..1 range.)
*/
- bool isIdentity() const {
- return mIdentity;
- }
+ bool isIdentity() const { return mIdentity; }
/**
* Changes the U and V mapping ranges.
@@ -127,7 +124,7 @@
float mMaxV;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_UV_MAPPER_H
+#endif // ANDROID_HWUI_UV_MAPPER_H
diff --git a/libs/hwui/Vector.h b/libs/hwui/Vector.h
index 6367dbd..d2c15ad 100644
--- a/libs/hwui/Vector.h
+++ b/libs/hwui/Vector.h
@@ -32,13 +32,9 @@
float x;
float y;
- float lengthSquared() const {
- return x * x + y * y;
- }
+ float lengthSquared() const { return x * x + y * y; }
- float length() const {
- return sqrt(x * x + y * y);
- }
+ float length() const { return sqrt(x * x + y * y); }
void operator+=(const Vector2& v) {
x += v.x;
@@ -70,21 +66,13 @@
y *= s;
}
- Vector2 operator+(const Vector2& v) const {
- return (Vector2){x + v.x, y + v.y};
- }
+ Vector2 operator+(const Vector2& v) const { return (Vector2){x + v.x, y + v.y}; }
- Vector2 operator-(const Vector2& v) const {
- return (Vector2){x - v.x, y - v.y};
- }
+ Vector2 operator-(const Vector2& v) const { return (Vector2){x - v.x, y - v.y}; }
- Vector2 operator/(float s) const {
- return (Vector2){x / s, y / s};
- }
+ Vector2 operator/(float s) const { return (Vector2){x / s, y / s}; }
- Vector2 operator*(float s) const {
- return (Vector2){x * s, y * s};
- }
+ Vector2 operator*(float s) const { return (Vector2){x * s, y * s}; }
void normalize() {
float s = 1.0f / length();
@@ -98,18 +86,12 @@
return v;
}
- float dot(const Vector2& v) const {
- return x * v.x + y * v.y;
- }
+ float dot(const Vector2& v) const { return x * v.x + y * v.y; }
- float cross(const Vector2& v) const {
- return x * v.y - y * v.x;
- }
+ float cross(const Vector2& v) const { return x * v.y - y * v.x; }
- void dump() {
- ALOGD("Vector2[%.2f, %.2f]", x, y);
- }
-}; // class Vector2
+ void dump() { ALOGD("Vector2[%.2f, %.2f]", x, y); }
+}; // class Vector2
// MUST BE A POD - this means no ctor or dtor!
class Vector3 {
@@ -118,29 +100,20 @@
float y;
float z;
- Vector3 operator+(const Vector3& v) const {
- return (Vector3){x + v.x, y + v.y, z + v.z};
- }
+ Vector3 operator+(const Vector3& v) const { return (Vector3){x + v.x, y + v.y, z + v.z}; }
- Vector3 operator-(const Vector3& v) const {
- return (Vector3){x - v.x, y - v.y, z - v.z};
- }
+ Vector3 operator-(const Vector3& v) const { return (Vector3){x - v.x, y - v.y, z - v.z}; }
- Vector3 operator/(float s) const {
- return (Vector3){x / s, y / s, z / s};
- }
+ Vector3 operator/(float s) const { return (Vector3){x / s, y / s, z / s}; }
- Vector3 operator*(float s) const {
- return (Vector3){x * s, y * s, z * s};
- }
-
+ Vector3 operator*(float s) const { return (Vector3){x * s, y * s, z * s}; }
void dump(const char* label = "Vector3") const {
ALOGD("%s[%.2f, %.2f, %.2f]", label, x, y, z);
}
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_VECTOR_H
+#endif // ANDROID_HWUI_VECTOR_H
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 376371d..ce00488 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -16,11 +16,11 @@
#include "VectorDrawable.h"
+#include <utils/Log.h>
#include "PathParser.h"
#include "SkColorFilter.h"
#include "SkImageInfo.h"
#include "SkShader.h"
-#include <utils/Log.h>
#include "utils/Macros.h"
#include "utils/TraceUtils.h"
#include "utils/VectorDrawableUtils.h"
@@ -79,7 +79,7 @@
}
static void applyTrim(SkPath* outPath, const SkPath& inPath, float trimPathStart, float trimPathEnd,
- float trimPathOffset) {
+ float trimPathOffset) {
if (trimPathStart == 0.0f && trimPathEnd == 1.0f) {
*outPath = inPath;
return;
@@ -109,25 +109,25 @@
return mTrimmedSkPath;
}
Path::getUpdatedPath(useStagingData, tempStagingPath);
- SkPath *outPath;
+ SkPath* outPath;
if (useStagingData) {
SkPath inPath = *tempStagingPath;
applyTrim(tempStagingPath, inPath, mStagingProperties.getTrimPathStart(),
- mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
+ mStagingProperties.getTrimPathEnd(), mStagingProperties.getTrimPathOffset());
outPath = tempStagingPath;
} else {
if (mProperties.getTrimPathStart() != 0.0f || mProperties.getTrimPathEnd() != 1.0f) {
mProperties.mTrimDirty = false;
applyTrim(&mTrimmedSkPath, mSkPath, mProperties.getTrimPathStart(),
- mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
+ mProperties.getTrimPathEnd(), mProperties.getTrimPathOffset());
outPath = &mTrimmedSkPath;
} else {
outPath = &mSkPath;
}
}
const FullPathProperties& properties = useStagingData ? mStagingProperties : mProperties;
- bool setFillPath = properties.getFillGradient() != nullptr
- || properties.getFillColor() != SK_ColorTRANSPARENT;
+ bool setFillPath = properties.getFillGradient() != nullptr ||
+ properties.getFillColor() != SK_ColorTRANSPARENT;
if (setFillPath) {
SkPath::FillType ft = static_cast<SkPath::FillType>(properties.getFillType());
outPath->setFillType(ft);
@@ -138,11 +138,10 @@
void FullPath::dump() {
Path::dump();
ALOGD("stroke width, color, alpha: %f, %d, %f, fill color, alpha: %d, %f",
- mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
- mProperties.getFillColor(), mProperties.getFillAlpha());
+ mProperties.getStrokeWidth(), mProperties.getStrokeColor(), mProperties.getStrokeAlpha(),
+ mProperties.getFillColor(), mProperties.getFillAlpha());
}
-
inline SkColor applyAlpha(SkColor color, float alpha) {
int alphaBytes = SkColorGetA(color);
return SkColorSetA(color, alphaBytes * alpha);
@@ -213,7 +212,7 @@
int propertyDataSize = sizeof(FullPathProperties::PrimitiveFields);
if (length != propertyDataSize) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
- propertyDataSize, length);
+ propertyDataSize, length);
return false;
}
@@ -229,35 +228,37 @@
} else if (currentProperty == Property::fillColor) {
setFillColor(value);
} else {
- LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property"
- " with id: %d", propertyId);
+ LOG_ALWAYS_FATAL(
+ "Error setting color property on FullPath: No valid property"
+ " with id: %d",
+ propertyId);
}
}
void FullPath::FullPathProperties::setPropertyValue(int propertyId, float value) {
Property property = static_cast<Property>(propertyId);
switch (property) {
- case Property::strokeWidth:
- setStrokeWidth(value);
- break;
- case Property::strokeAlpha:
- setStrokeAlpha(value);
- break;
- case Property::fillAlpha:
- setFillAlpha(value);
- break;
- case Property::trimPathStart:
- setTrimPathStart(value);
- break;
- case Property::trimPathEnd:
- setTrimPathEnd(value);
- break;
- case Property::trimPathOffset:
- setTrimPathOffset(value);
- break;
- default:
- LOG_ALWAYS_FATAL("Invalid property id: %d for animation", propertyId);
- break;
+ case Property::strokeWidth:
+ setStrokeWidth(value);
+ break;
+ case Property::strokeAlpha:
+ setStrokeAlpha(value);
+ break;
+ case Property::fillAlpha:
+ setFillAlpha(value);
+ break;
+ case Property::trimPathStart:
+ setTrimPathStart(value);
+ break;
+ case Property::trimPathEnd:
+ setTrimPathEnd(value);
+ break;
+ case Property::trimPathOffset:
+ setTrimPathOffset(value);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid property id: %d for animation", propertyId);
+ break;
}
}
@@ -288,7 +289,7 @@
void Group::dump() {
ALOGD("Group %s has %zu children: ", mName.c_str(), mChildren.size());
ALOGD("Group translateX, Y : %f, %f, scaleX, Y: %f, %f", mProperties.getTranslateX(),
- mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
+ mProperties.getTranslateY(), mProperties.getScaleX(), mProperties.getScaleY());
for (size_t i = 0; i < mChildren.size(); i++) {
mChildren[i]->dump();
}
@@ -315,7 +316,7 @@
outMatrix->postScale(properties.getScaleX(), properties.getScaleY());
outMatrix->postRotate(properties.getRotation(), 0, 0);
outMatrix->postTranslate(properties.getTranslateX() + properties.getPivotX(),
- properties.getTranslateY() + properties.getPivotY());
+ properties.getTranslateY() + properties.getPivotY());
}
void Group::addChild(Node* child) {
@@ -329,7 +330,7 @@
int propertyCount = static_cast<int>(Property::count);
if (length != propertyCount) {
LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
- propertyCount, length);
+ propertyCount, length);
return false;
}
@@ -343,23 +344,23 @@
float Group::GroupProperties::getPropertyValue(int propertyId) const {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::rotate:
- return getRotation();
- case Property::pivotX:
- return getPivotX();
- case Property::pivotY:
- return getPivotY();
- case Property::scaleX:
- return getScaleX();
- case Property::scaleY:
- return getScaleY();
- case Property::translateX:
- return getTranslateX();
- case Property::translateY:
- return getTranslateY();
- default:
- LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
- return 0;
+ case Property::rotate:
+ return getRotation();
+ case Property::pivotX:
+ return getPivotX();
+ case Property::pivotY:
+ return getPivotY();
+ case Property::scaleX:
+ return getScaleX();
+ case Property::scaleY:
+ return getScaleY();
+ case Property::translateX:
+ return getTranslateX();
+ case Property::translateY:
+ return getTranslateY();
+ default:
+ LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
+ return 0;
}
}
@@ -367,29 +368,29 @@
void Group::GroupProperties::setPropertyValue(int propertyId, float value) {
Property currentProperty = static_cast<Property>(propertyId);
switch (currentProperty) {
- case Property::rotate:
- setRotation(value);
- break;
- case Property::pivotX:
- setPivotX(value);
- break;
- case Property::pivotY:
- setPivotY(value);
- break;
- case Property::scaleX:
- setScaleX(value);
- break;
- case Property::scaleY:
- setScaleY(value);
- break;
- case Property::translateX:
- setTranslateX(value);
- break;
- case Property::translateY:
- setTranslateY(value);
- break;
- default:
- LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
+ case Property::rotate:
+ setRotation(value);
+ break;
+ case Property::pivotX:
+ setPivotX(value);
+ break;
+ case Property::pivotY:
+ setPivotY(value);
+ break;
+ case Property::scaleX:
+ setScaleX(value);
+ break;
+ case Property::scaleY:
+ setScaleY(value);
+ break;
+ case Property::translateX:
+ setTranslateX(value);
+ break;
+ case Property::translateY:
+ setTranslateY(value);
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
}
}
@@ -401,8 +402,8 @@
return propertyId >= 0 && propertyId < static_cast<int>(Property::count);
}
-int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
- const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
+int Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds,
+ bool needsMirroring, bool canReuseCache) {
// The imageView can scale the canvas in different ways, in order to
// avoid blurry scaling, we have to draw into a bitmap with exact pixel
// size first. This bitmap size is determined by the bounds and the
@@ -417,8 +418,8 @@
canvasScaleX = fabs(canvasMatrix.getScaleX());
canvasScaleY = fabs(canvasMatrix.getScaleY());
}
- int scaledWidth = (int) (bounds.width() * canvasScaleX);
- int scaledHeight = (int) (bounds.height() * canvasScaleY);
+ int scaledWidth = (int)(bounds.width() * canvasScaleX);
+ int scaledHeight = (int)(bounds.height() * canvasScaleY);
scaledWidth = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledWidth);
scaledHeight = std::min(Tree::MAX_CACHED_BITMAP_SIZE, scaledHeight);
@@ -449,8 +450,8 @@
}
void Tree::drawStaging(Canvas* outCanvas) {
- bool redrawNeeded = allocateBitmapIfNeeded(mStagingCache,
- mStagingProperties.getScaledWidth(), mStagingProperties.getScaledHeight());
+ bool redrawNeeded = allocateBitmapIfNeeded(mStagingCache, mStagingProperties.getScaledWidth(),
+ mStagingProperties.getScaledHeight());
// draw bitmap cache
if (redrawNeeded || mStagingCache.dirty) {
updateBitmapCache(*mStagingCache.bitmap, true);
@@ -459,10 +460,11 @@
SkPaint tmpPaint;
SkPaint* paint = updatePaint(&tmpPaint, &mStagingProperties);
- outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0,
- mStagingCache.bitmap->width(), mStagingCache.bitmap->height(),
- mStagingProperties.getBounds().left(), mStagingProperties.getBounds().top(),
- mStagingProperties.getBounds().right(), mStagingProperties.getBounds().bottom(), paint);
+ outCanvas->drawBitmap(*mStagingCache.bitmap, 0, 0, mStagingCache.bitmap->width(),
+ mStagingCache.bitmap->height(), mStagingProperties.getBounds().left(),
+ mStagingProperties.getBounds().top(),
+ mStagingProperties.getBounds().right(),
+ mStagingProperties.getBounds().bottom(), paint);
}
SkPaint* Tree::getPaint() {
@@ -484,7 +486,7 @@
Bitmap& Tree::getBitmapUpdateIfDirty() {
bool redrawNeeded = allocateBitmapIfNeeded(mCache, mProperties.getScaledWidth(),
- mProperties.getScaledHeight());
+ mProperties.getScaledHeight());
if (redrawNeeded || mCache.dirty) {
updateBitmapCache(*mCache.bitmap, false);
mCache.dirty = false;
@@ -495,8 +497,8 @@
void Tree::updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context) {
SkRect dst;
sk_sp<SkSurface> surface = mCache.getSurface(&dst);
- bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth()
- && dst.height() >= mProperties.getScaledHeight();
+ bool canReuseSurface = surface && dst.width() >= mProperties.getScaledWidth() &&
+ dst.height() >= mProperties.getScaledHeight();
if (!canReuseSurface) {
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
@@ -506,7 +508,7 @@
surface = atlasEntry.surface;
mCache.setAtlas(atlas, atlasEntry.key);
} else {
- //don't draw, if we failed to allocate an offscreen buffer
+ // don't draw, if we failed to allocate an offscreen buffer
mCache.clear();
surface.reset();
}
@@ -526,7 +528,7 @@
}
void Tree::Cache::setAtlas(sp<skiapipeline::VectorDrawableAtlas> newAtlas,
- skiapipeline::AtlasKey newAtlasKey) {
+ skiapipeline::AtlasKey newAtlasKey) {
LOG_ALWAYS_FATAL_IF(newAtlasKey == INVALID_ATLAS_KEY);
clear();
mAtlas = newAtlas;
@@ -560,7 +562,8 @@
sk_sp<SkSurface> vdSurface = mCache.getSurface(&src);
if (vdSurface) {
canvas->drawImageRect(vdSurface->makeImageSnapshot().get(), src,
- mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint);
+ mutateProperties()->getBounds(), getPaint(),
+ SkCanvas::kFast_SrcRectConstraint);
} else {
// Handle the case when VectorDrawableAtlas has been destroyed, because of memory pressure.
// We render the VD into a temporary standalone buffer and mark the frame as dirty. Next
@@ -572,7 +575,8 @@
int scaledWidth = SkScalarCeilToInt(mProperties.getScaledWidth());
int scaledHeight = SkScalarCeilToInt(mProperties.getScaledHeight());
canvas->drawBitmapRect(skiaBitmap, SkRect::MakeWH(scaledWidth, scaledHeight),
- mutateProperties()->getBounds(), getPaint(), SkCanvas::kFast_SrcRectConstraint);
+ mutateProperties()->getBounds(), getPaint(),
+ SkCanvas::kFast_SrcRectConstraint);
mCache.clear();
markDirty();
}
@@ -586,10 +590,10 @@
ATRACE_FORMAT("VectorDrawable repaint %dx%d", cacheWidth, cacheHeight);
outCache.eraseColor(SK_ColorTRANSPARENT);
SkCanvas outCanvas(outCache);
- float viewportWidth = useStagingData ?
- mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
- float viewportHeight = useStagingData ?
- mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
+ float viewportWidth =
+ useStagingData ? mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
+ float viewportHeight = useStagingData ? mStagingProperties.getViewportHeight()
+ : mProperties.getViewportHeight();
float scaleX = cacheWidth / viewportWidth;
float scaleY = cacheHeight / viewportHeight;
outCanvas.scale(scaleX, scaleY);
@@ -622,7 +626,7 @@
}
}
-}; // namespace VectorDrawable
+}; // namespace VectorDrawable
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 4b80542..7f75609 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -17,15 +17,15 @@
#ifndef ANDROID_HWUI_VPATH_H
#define ANDROID_HWUI_VPATH_H
-#include "hwui/Canvas.h"
-#include "hwui/Bitmap.h"
-#include "renderthread/CacheManager.h"
#include "DisplayList.h"
+#include "hwui/Bitmap.h"
+#include "hwui/Canvas.h"
+#include "renderthread/CacheManager.h"
#include <SkBitmap.h>
+#include <SkCanvas.h>
#include <SkColor.h>
#include <SkColorFilter.h>
-#include <SkCanvas.h>
#include <SkMatrix.h>
#include <SkPaint.h>
#include <SkPath.h>
@@ -36,25 +36,35 @@
#include <cutils/compiler.h>
#include <stddef.h>
-#include <vector>
#include <string>
+#include <vector>
namespace android {
namespace uirenderer {
// Debug
#if DEBUG_VECTOR_DRAWABLE
- #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
+#define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
#else
- #define VECTOR_DRAWABLE_LOGD(...)
+#define VECTOR_DRAWABLE_LOGD(...)
#endif
namespace VectorDrawable {
-#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) \
+ (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
-#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
- onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) \
+ ({ \
+ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value)); \
+ onPropertyChanged(); \
+ retVal; \
+ })
+#define UPDATE_SKPROP(field, value) \
+ ({ \
+ bool retVal = ((field) != (value)); \
+ if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); \
+ retVal; \
+ })
/* A VectorDrawable is composed of a tree of nodes.
* Each node can be a group node, or a path.
@@ -85,12 +95,9 @@
public:
PropertyChangedListener(bool* dirty, bool* stagingDirty)
: mDirty(dirty), mStagingDirty(stagingDirty) {}
- void onPropertyChanged() {
- *mDirty = true;
- }
- void onStagingPropertyChanged() {
- *mStagingDirty = true;
- }
+ void onPropertyChanged() { *mDirty = true; }
+ void onStagingPropertyChanged() { *mStagingDirty = true; }
+
private:
bool* mDirty;
bool* mStagingDirty;
@@ -101,27 +108,23 @@
class Properties {
public:
explicit Properties(Node* node) : mNode(node) {}
- inline void onPropertyChanged() {
- mNode->onPropertyChanged(this);
- }
+ inline void onPropertyChanged() { mNode->onPropertyChanged(this); }
+
private:
Node* mNode;
};
- Node(const Node& node) {
- mName = node.mName;
- }
+ Node(const Node& node) { mName = node.mName; }
Node() {}
virtual void draw(SkCanvas* outCanvas, bool useStagingData) = 0;
virtual void dump() = 0;
- void setName(const char* name) {
- mName = name;
- }
+ void setName(const char* name) { mName = name; }
virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
mPropertyChangedListener = listener;
}
virtual void onPropertyChanged(Properties* properties) = 0;
- virtual ~Node(){}
+ virtual ~Node() {}
virtual void syncProperties() = 0;
+
protected:
std::string mName;
PropertyChangedListener* mPropertyChangedListener = nullptr;
@@ -134,8 +137,7 @@
std::vector<size_t> verbSizes;
std::vector<float> points;
bool operator==(const Data& data) const {
- return verbs == data.verbs && verbSizes == data.verbSizes
- && points == data.points;
+ return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
}
};
@@ -156,11 +158,9 @@
}
mData = data;
onPropertyChanged();
+ }
+ const Data& getData() const { return mData; }
- }
- const Data& getData() const {
- return mData;
- }
private:
Data mData;
};
@@ -177,7 +177,7 @@
if (mPropertyChangedListener) {
mPropertyChangedListener->onStagingPropertyChanged();
}
- } else if (prop == &mProperties){
+ } else if (prop == &mProperties) {
mSkPathDirty = true;
if (mPropertyChangedListener) {
mPropertyChangedListener->onPropertyChanged();
@@ -203,7 +203,7 @@
bool mStagingPropertiesDirty = true;
};
-class ANDROID_API FullPath: public Path {
+class ANDROID_API FullPath : public Path {
public:
class FullPathProperties : public Properties {
public:
@@ -234,87 +234,59 @@
onPropertyChanged();
}
void setFillGradient(SkShader* gradient) {
- if(UPDATE_SKPROP(fillGradient, gradient)) {
+ if (UPDATE_SKPROP(fillGradient, gradient)) {
onPropertyChanged();
}
}
void setStrokeGradient(SkShader* gradient) {
- if(UPDATE_SKPROP(strokeGradient, gradient)) {
+ if (UPDATE_SKPROP(strokeGradient, gradient)) {
onPropertyChanged();
}
}
- SkShader* getFillGradient() const {
- return fillGradient;
- }
- SkShader* getStrokeGradient() const {
- return strokeGradient;
- }
- float getStrokeWidth() const{
- return mPrimitiveFields.strokeWidth;
- }
+ SkShader* getFillGradient() const { return fillGradient; }
+ SkShader* getStrokeGradient() const { return strokeGradient; }
+ float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
void setStrokeWidth(float strokeWidth) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
}
- SkColor getStrokeColor() const{
- return mPrimitiveFields.strokeColor;
- }
+ SkColor getStrokeColor() const { return mPrimitiveFields.strokeColor; }
void setStrokeColor(SkColor strokeColor) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
}
- float getStrokeAlpha() const{
- return mPrimitiveFields.strokeAlpha;
- }
+ float getStrokeAlpha() const { return mPrimitiveFields.strokeAlpha; }
void setStrokeAlpha(float strokeAlpha) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
}
- SkColor getFillColor() const {
- return mPrimitiveFields.fillColor;
- }
+ SkColor getFillColor() const { return mPrimitiveFields.fillColor; }
void setFillColor(SkColor fillColor) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
}
- float getFillAlpha() const{
- return mPrimitiveFields.fillAlpha;
- }
+ float getFillAlpha() const { return mPrimitiveFields.fillAlpha; }
void setFillAlpha(float fillAlpha) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
}
- float getTrimPathStart() const{
- return mPrimitiveFields.trimPathStart;
- }
+ float getTrimPathStart() const { return mPrimitiveFields.trimPathStart; }
void setTrimPathStart(float trimPathStart) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
}
- float getTrimPathEnd() const{
- return mPrimitiveFields.trimPathEnd;
- }
+ float getTrimPathEnd() const { return mPrimitiveFields.trimPathEnd; }
void setTrimPathEnd(float trimPathEnd) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
}
- float getTrimPathOffset() const{
- return mPrimitiveFields.trimPathOffset;
- }
+ float getTrimPathOffset() const { return mPrimitiveFields.trimPathOffset; }
void setTrimPathOffset(float trimPathOffset) {
VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
}
- float getStrokeMiterLimit() const {
- return mPrimitiveFields.strokeMiterLimit;
- }
- float getStrokeLineCap() const {
- return mPrimitiveFields.strokeLineCap;
- }
- float getStrokeLineJoin() const {
- return mPrimitiveFields.strokeLineJoin;
- }
- float getFillType() const {
- return mPrimitiveFields.fillType;
- }
+ float getStrokeMiterLimit() const { return mPrimitiveFields.strokeMiterLimit; }
+ float getStrokeLineCap() const { return mPrimitiveFields.strokeLineCap; }
+ float getStrokeLineJoin() const { return mPrimitiveFields.strokeLineJoin; }
+ float getFillType() const { return mPrimitiveFields.fillType; }
bool copyProperties(int8_t* outProperties, int length) const;
void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
- SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
- float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
- int fillType) {
+ SkColor fillColor, float fillAlpha, float trimPathStart,
+ float trimPathEnd, float trimPathOffset, float strokeMiterLimit,
+ int strokeLineCap, int strokeLineJoin, int fillType) {
mPrimitiveFields.strokeWidth = strokeWidth;
mPrimitiveFields.strokeColor = strokeColor;
mPrimitiveFields.strokeAlpha = strokeAlpha;
@@ -334,6 +306,7 @@
void setColorPropertyValue(int propertyId, int32_t value);
void setPropertyValue(int propertyId, float value);
bool mTrimDirty;
+
private:
enum class Property {
strokeWidth = 0,
@@ -356,7 +329,7 @@
};
// Called from UI thread
- FullPath(const FullPath& path); // for cloning
+ FullPath(const FullPath& path); // for cloning
FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath() : Path() {}
void draw(SkCanvas* outCanvas, bool useStagingData) override;
@@ -384,18 +357,17 @@
protected:
const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
-private:
+private:
FullPathProperties mProperties = FullPathProperties(this);
FullPathProperties mStagingProperties = FullPathProperties(this);
bool mStagingPropertiesDirty = true;
// Intermediate data for drawing, render thread only
SkPath mTrimmedSkPath;
-
};
-class ANDROID_API ClipPath: public Path {
+class ANDROID_API ClipPath : public Path {
public:
ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
@@ -403,7 +375,7 @@
void draw(SkCanvas* outCanvas, bool useStagingData) override;
};
-class ANDROID_API Group: public Node {
+class ANDROID_API Group : public Node {
public:
class GroupProperties : public Properties {
public:
@@ -421,50 +393,26 @@
mPrimitiveFields = prop.mPrimitiveFields;
onPropertyChanged();
}
- float getRotation() const {
- return mPrimitiveFields.rotate;
- }
- void setRotation(float rotation) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
- }
- float getPivotX() const {
- return mPrimitiveFields.pivotX;
- }
- void setPivotX(float pivotX) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
- }
- float getPivotY() const {
- return mPrimitiveFields.pivotY;
- }
- void setPivotY(float pivotY) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
- }
- float getScaleX() const {
- return mPrimitiveFields.scaleX;
- }
- void setScaleX(float scaleX) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
- }
- float getScaleY() const {
- return mPrimitiveFields.scaleY;
- }
- void setScaleY(float scaleY) {
- VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
- }
- float getTranslateX() const {
- return mPrimitiveFields.translateX;
- }
+ float getRotation() const { return mPrimitiveFields.rotate; }
+ void setRotation(float rotation) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation); }
+ float getPivotX() const { return mPrimitiveFields.pivotX; }
+ void setPivotX(float pivotX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX); }
+ float getPivotY() const { return mPrimitiveFields.pivotY; }
+ void setPivotY(float pivotY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY); }
+ float getScaleX() const { return mPrimitiveFields.scaleX; }
+ void setScaleX(float scaleX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX); }
+ float getScaleY() const { return mPrimitiveFields.scaleY; }
+ void setScaleY(float scaleY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY); }
+ float getTranslateX() const { return mPrimitiveFields.translateX; }
void setTranslateX(float translateX) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
}
- float getTranslateY() const {
- return mPrimitiveFields.translateY;
- }
+ float getTranslateY() const { return mPrimitiveFields.translateY; }
void setTranslateY(float translateY) {
VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
}
- void updateProperties(float rotate, float pivotX, float pivotY,
- float scaleX, float scaleY, float translateX, float translateY) {
+ void updateProperties(float rotate, float pivotX, float pivotY, float scaleX, float scaleY,
+ float translateX, float translateY) {
mPrimitiveFields.rotate = rotate;
mPrimitiveFields.pivotX = pivotX;
mPrimitiveFields.pivotY = pivotY;
@@ -478,6 +426,7 @@
float getPropertyValue(int propertyId) const;
bool copyProperties(float* outProperties, int length) const;
static bool isValidProperty(int propertyId);
+
private:
enum class Property {
rotate = 0,
@@ -498,7 +447,7 @@
virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
Node::setPropertyChangedListener(listener);
for (auto& child : mChildren) {
- child->setPropertyChangedListener(listener);
+ child->setPropertyChangedListener(listener);
}
}
virtual void syncProperties() override;
@@ -531,7 +480,7 @@
GroupProperties mProperties = GroupProperties(this);
GroupProperties mStagingProperties = GroupProperties(this);
bool mStagingPropertiesDirty = true;
- std::vector< std::unique_ptr<Node> > mChildren;
+ std::vector<std::unique_ptr<Node> > mChildren;
};
class ANDROID_API Tree : public VirtualLightRefBase {
@@ -547,27 +496,25 @@
}
// Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
// canvas. Returns the number of pixels needed for the bitmap cache.
- int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
- const SkRect& bounds, bool needsMirroring, bool canReuseCache);
+ int draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds,
+ bool needsMirroring, bool canReuseCache);
void drawStaging(Canvas* canvas);
Bitmap& getBitmapUpdateIfDirty();
- void setAllowCaching(bool allowCaching) {
- mAllowCaching = allowCaching;
- }
+ void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; }
SkPaint* getPaint();
void syncProperties() {
if (mStagingProperties.mNonAnimatablePropertiesDirty) {
- mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth
- != mStagingProperties.mNonAnimatableProperties.viewportWidth)
- || (mProperties.mNonAnimatableProperties.viewportHeight
- != mStagingProperties.mNonAnimatableProperties.viewportHeight)
- || (mProperties.mNonAnimatableProperties.scaledWidth
- != mStagingProperties.mNonAnimatableProperties.scaledWidth)
- || (mProperties.mNonAnimatableProperties.scaledHeight
- != mStagingProperties.mNonAnimatableProperties.scaledHeight)
- || (mProperties.mNonAnimatableProperties.bounds
- != mStagingProperties.mNonAnimatableProperties.bounds);
+ mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth !=
+ mStagingProperties.mNonAnimatableProperties.viewportWidth) ||
+ (mProperties.mNonAnimatableProperties.viewportHeight !=
+ mStagingProperties.mNonAnimatableProperties.viewportHeight) ||
+ (mProperties.mNonAnimatableProperties.scaledWidth !=
+ mStagingProperties.mNonAnimatableProperties.scaledWidth) ||
+ (mProperties.mNonAnimatableProperties.scaledHeight !=
+ mStagingProperties.mNonAnimatableProperties.scaledHeight) ||
+ (mProperties.mNonAnimatableProperties.bounds !=
+ mStagingProperties.mNonAnimatableProperties.bounds);
mProperties.syncNonAnimatableProperties(mStagingProperties);
mStagingProperties.mNonAnimatablePropertiesDirty = false;
}
@@ -593,9 +540,7 @@
int scaledWidth = 0;
int scaledHeight = 0;
SkColorFilter* colorFilter = nullptr;
- ~NonAnimatableProperties() {
- SkSafeUnref(colorFilter);
- }
+ ~NonAnimatableProperties() { SkSafeUnref(colorFilter); }
} mNonAnimatableProperties;
bool mNonAnimatablePropertiesDirty = true;
@@ -606,14 +551,14 @@
// Copy over the data that can only be changed in UI thread
if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
- prop.mNonAnimatableProperties.colorFilter);
+ prop.mNonAnimatableProperties.colorFilter);
}
mNonAnimatableProperties = prop.mNonAnimatableProperties;
}
void setViewportSize(float width, float height) {
- if (mNonAnimatableProperties.viewportWidth != width
- || mNonAnimatableProperties.viewportHeight != height) {
+ if (mNonAnimatableProperties.viewportWidth != width ||
+ mNonAnimatableProperties.viewportHeight != height) {
mNonAnimatablePropertiesDirty = true;
mNonAnimatableProperties.viewportWidth = width;
mNonAnimatableProperties.viewportHeight = height;
@@ -632,12 +577,12 @@
// If the requested size is bigger than what the bitmap was, then
// we increase the bitmap size to match. The width and height
// are bound by MAX_CACHED_BITMAP_SIZE.
- if (mNonAnimatableProperties.scaledWidth < width
- || mNonAnimatableProperties.scaledHeight < height) {
- mNonAnimatableProperties.scaledWidth = std::max(width,
- mNonAnimatableProperties.scaledWidth);
- mNonAnimatableProperties.scaledHeight = std::max(height,
- mNonAnimatableProperties.scaledHeight);
+ if (mNonAnimatableProperties.scaledWidth < width ||
+ mNonAnimatableProperties.scaledHeight < height) {
+ mNonAnimatableProperties.scaledWidth =
+ std::max(width, mNonAnimatableProperties.scaledWidth);
+ mNonAnimatableProperties.scaledHeight =
+ std::max(height, mNonAnimatableProperties.scaledHeight);
mNonAnimatablePropertiesDirty = true;
mTree->onPropertyChanged(this);
}
@@ -648,25 +593,13 @@
mTree->onPropertyChanged(this);
}
}
- SkColorFilter* getColorFilter() const{
- return mNonAnimatableProperties.colorFilter;
- }
+ SkColorFilter* getColorFilter() const { return mNonAnimatableProperties.colorFilter; }
- float getViewportWidth() const {
- return mNonAnimatableProperties.viewportWidth;
- }
- float getViewportHeight() const {
- return mNonAnimatableProperties.viewportHeight;
- }
- float getScaledWidth() const {
- return mNonAnimatableProperties.scaledWidth;
- }
- float getScaledHeight() const {
- return mNonAnimatableProperties.scaledHeight;
- }
- void syncAnimatableProperties(const TreeProperties& prop) {
- mRootAlpha = prop.mRootAlpha;
- }
+ float getViewportWidth() const { return mNonAnimatableProperties.viewportWidth; }
+ float getViewportHeight() const { return mNonAnimatableProperties.viewportHeight; }
+ float getScaledWidth() const { return mNonAnimatableProperties.scaledWidth; }
+ float getScaledHeight() const { return mNonAnimatableProperties.scaledHeight; }
+ void syncAnimatableProperties(const TreeProperties& prop) { mRootAlpha = prop.mRootAlpha; }
bool setRootAlpha(float rootAlpha) {
if (rootAlpha != mRootAlpha) {
mAnimatablePropertiesDirty = true;
@@ -676,10 +609,8 @@
}
return false;
}
- float getRootAlpha() const { return mRootAlpha;}
- const SkRect& getBounds() const {
- return mNonAnimatableProperties.bounds;
- }
+ float getRootAlpha() const { return mRootAlpha; }
+ const SkRect& getBounds() const { return mNonAnimatableProperties.bounds; }
Tree* mTree;
};
void onPropertyChanged(TreeProperties* prop);
@@ -713,8 +644,8 @@
private:
class Cache {
public:
- sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
- //TODO: use surface instead of bitmap when drawing in software canvas
+ sk_sp<Bitmap> bitmap; // used by HWUI pipeline and software
+ // TODO: use surface instead of bitmap when drawing in software canvas
bool dirty = true;
// the rest of the code in Cache is used by Skia pipelines only
@@ -725,7 +656,7 @@
* Stores a weak pointer to the atlas and a key.
*/
void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas,
- skiapipeline::AtlasKey newAtlasKey);
+ skiapipeline::AtlasKey newAtlasKey);
/**
* Gets a surface and bounds from the atlas.
@@ -738,6 +669,7 @@
* Releases atlas key from the atlas, which makes it available for reuse.
*/
void clear();
+
private:
wp<skiapipeline::VectorDrawableAtlas> mAtlas;
skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
@@ -764,16 +696,16 @@
Cache mStagingCache;
Cache mCache;
- PropertyChangedListener mPropertyChangedListener
- = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
+ PropertyChangedListener mPropertyChangedListener =
+ PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
mutable bool mWillBeConsumed = false;
};
-} // namespace VectorDrawable
+} // namespace VectorDrawable
typedef VectorDrawable::Path::Data PathData;
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
-#endif // ANDROID_HWUI_VPATH_H
+#endif // ANDROID_HWUI_VPATH_H
diff --git a/libs/hwui/Vertex.h b/libs/hwui/Vertex.h
index db982ad..186d0a8 100644
--- a/libs/hwui/Vertex.h
+++ b/libs/hwui/Vertex.h
@@ -45,15 +45,13 @@
vertex->y = y;
}
- static inline void set(Vertex* vertex, Vector2 val) {
- set(vertex, val.x, val.y);
- }
+ static inline void set(Vertex* vertex, Vector2 val) { set(vertex, val.x, val.y); }
static inline void copyWithOffset(Vertex* vertex, const Vertex& src, float x, float y) {
set(vertex, src.x + x, src.y + y);
}
-}; // struct Vertex
+}; // struct Vertex
REQUIRE_COMPATIBLE_LAYOUT(Vertex);
@@ -65,14 +63,14 @@
float u, v;
static inline void set(TextureVertex* vertex, float x, float y, float u, float v) {
- *vertex = { x, y, u, v };
+ *vertex = {x, y, u, v};
}
static inline void setUV(TextureVertex* vertex, float u, float v) {
vertex[0].u = u;
vertex[0].v = v;
}
-}; // struct TextureVertex
+}; // struct TextureVertex
REQUIRE_COMPATIBLE_LAYOUT(TextureVertex);
@@ -83,15 +81,15 @@
struct ColorTextureVertex {
float x, y;
float u, v;
- float r, g, b, a; // pre-multiplied linear
+ float r, g, b, a; // pre-multiplied linear
- static inline void set(ColorTextureVertex* vertex, float x, float y,
- float u, float v, uint32_t color) {
+ static inline void set(ColorTextureVertex* vertex, float x, float y, float u, float v,
+ uint32_t color) {
FloatColor c;
c.set(color);
- *vertex = { x, y, u, v, c.r, c.g, c.b, c.a };
+ *vertex = {x, y, u, v, c.r, c.g, c.b, c.a};
}
-}; // struct ColorTextureVertex
+}; // struct ColorTextureVertex
REQUIRE_COMPATIBLE_LAYOUT(ColorTextureVertex);
@@ -103,22 +101,20 @@
float alpha;
static inline void set(AlphaVertex* vertex, float x, float y, float alpha) {
- *vertex = { x, y, alpha };
+ *vertex = {x, y, alpha};
}
- static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src,
- float x, float y) {
+ static inline void copyWithOffset(AlphaVertex* vertex, const AlphaVertex& src, float x,
+ float y) {
AlphaVertex::set(vertex, src.x + x, src.y + y, src.alpha);
}
- static inline void setColor(AlphaVertex* vertex, float alpha) {
- vertex[0].alpha = alpha;
- }
-}; // struct AlphaVertex
+ static inline void setColor(AlphaVertex* vertex, float alpha) { vertex[0].alpha = alpha; }
+}; // struct AlphaVertex
REQUIRE_COMPATIBLE_LAYOUT(AlphaVertex);
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_VERTEX_H
+#endif // ANDROID_HWUI_VERTEX_H
diff --git a/libs/hwui/VertexBuffer.h b/libs/hwui/VertexBuffer.h
index bdb5b7b..613cf4a 100644
--- a/libs/hwui/VertexBuffer.h
+++ b/libs/hwui/VertexBuffer.h
@@ -41,8 +41,7 @@
, mMeshFeatureFlags(kNone)
, mReallocBuffer(nullptr)
, mCleanupMethod(nullptr)
- , mCleanupIndexMethod(nullptr)
- {}
+ , mCleanupIndexMethod(nullptr) {}
~VertexBuffer() {
if (mCleanupMethod) mCleanupMethod(mBuffer);
@@ -128,10 +127,10 @@
unsigned int getVertexCount() const { return mVertexCount; }
unsigned int getSize() const { return mByteCount; }
unsigned int getIndexCount() const { return mIndexCount; }
- void updateIndexCount(unsigned int newCount) {
+ void updateIndexCount(unsigned int newCount) {
mIndexCount = std::min(newCount, mAllocatedIndexCount);
}
- void updateVertexCount(unsigned int newCount) {
+ void updateVertexCount(unsigned int newCount) {
mVertexCount = std::min(newCount, mAllocatedVertexCount);
}
MeshFeatureFlags getMeshFeatureFlags() const { return mMeshFeatureFlags; }
@@ -153,7 +152,7 @@
private:
template <class TYPE>
static void cleanup(void* buffer) {
- delete[] (TYPE*)buffer;
+ delete[](TYPE*) buffer;
}
Rect mBounds;
@@ -169,13 +168,13 @@
MeshFeatureFlags mMeshFeatureFlags;
- void* mReallocBuffer; // used for multi-allocation
+ void* mReallocBuffer; // used for multi-allocation
void (*mCleanupMethod)(void*);
void (*mCleanupIndexMethod)(void*);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_VERTEX_BUFFER_H
+#endif // ANDROID_HWUI_VERTEX_BUFFER_H
diff --git a/libs/hwui/VkLayer.cpp b/libs/hwui/VkLayer.cpp
index ef4784b..30fba7a 100644
--- a/libs/hwui/VkLayer.cpp
+++ b/libs/hwui/VkLayer.cpp
@@ -36,5 +36,5 @@
mImage = nullptr;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/VkLayer.h b/libs/hwui/VkLayer.h
index 7e41ad1..f23f472 100644
--- a/libs/hwui/VkLayer.h
+++ b/libs/hwui/VkLayer.h
@@ -36,30 +36,20 @@
virtual ~VkLayer() {}
- uint32_t getWidth() const override {
- return mWidth;
- }
+ uint32_t getWidth() const override { return mWidth; }
- uint32_t getHeight() const override {
- return mHeight;
- }
+ uint32_t getHeight() const override { return mHeight; }
void setSize(uint32_t width, uint32_t height) override {
mWidth = width;
mHeight = height;
}
- void setBlend(bool blend) override {
- mBlend = blend;
- }
+ void setBlend(bool blend) override { mBlend = blend; }
- bool isBlend() const override {
- return mBlend;
- }
+ bool isBlend() const override { return mBlend; }
- sk_sp<SkImage> getImage() {
- return mImage;
- }
+ sk_sp<SkImage> getImage() { return mImage; }
void updateTexture();
@@ -72,9 +62,9 @@
int mHeight;
bool mBlend;
- sk_sp<SkImage> mImage;
+ sk_sp<SkImage> mImage;
-}; // struct VkLayer
+}; // struct VkLayer
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/debug/DefaultGlesDriver.cpp b/libs/hwui/debug/DefaultGlesDriver.cpp
index 4515ec1..46ab200 100644
--- a/libs/hwui/debug/DefaultGlesDriver.cpp
+++ b/libs/hwui/debug/DefaultGlesDriver.cpp
@@ -35,6 +35,6 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/DefaultGlesDriver.h b/libs/hwui/debug/DefaultGlesDriver.h
index 3eab970..8027ea2 100644
--- a/libs/hwui/debug/DefaultGlesDriver.h
+++ b/libs/hwui/debug/DefaultGlesDriver.h
@@ -25,11 +25,10 @@
class DefaultGlesDriver : public GlesDriver {
public:
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
-
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/FatalBaseDriver.cpp b/libs/hwui/debug/FatalBaseDriver.cpp
index 4c38fac..ed0f831 100644
--- a/libs/hwui/debug/FatalBaseDriver.cpp
+++ b/libs/hwui/debug/FatalBaseDriver.cpp
@@ -25,9 +25,9 @@
// Generate the proxy
#define API_ENTRY(x) FatalBaseDriver::x##_
#define CALL_GL_API(x, ...) LOG_ALWAYS_FATAL("Not Implemented");
-#define CALL_GL_API_RETURN(x, ...) \
- LOG_ALWAYS_FATAL("Not Implemented"); \
- return static_cast<decltype(x(__VA_ARGS__))>(0);
+#define CALL_GL_API_RETURN(x, ...) \
+ LOG_ALWAYS_FATAL("Not Implemented"); \
+ return static_cast<decltype(x(__VA_ARGS__))>(0);
#include "gles_stubs.in"
@@ -35,6 +35,6 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/FatalBaseDriver.h b/libs/hwui/debug/FatalBaseDriver.h
index 76c30e9..45353d0 100644
--- a/libs/hwui/debug/FatalBaseDriver.h
+++ b/libs/hwui/debug/FatalBaseDriver.h
@@ -28,10 +28,10 @@
class FatalBaseDriver : public GlesDriver {
public:
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesDriver.cpp b/libs/hwui/debug/GlesDriver.cpp
index 97e8f3a..98f06b0 100644
--- a/libs/hwui/debug/GlesDriver.cpp
+++ b/libs/hwui/debug/GlesDriver.cpp
@@ -41,6 +41,6 @@
return skiaInterface;
}
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesDriver.h b/libs/hwui/debug/GlesDriver.h
index 3c36487..1c77c1a 100644
--- a/libs/hwui/debug/GlesDriver.h
+++ b/libs/hwui/debug/GlesDriver.h
@@ -43,13 +43,13 @@
virtual sk_sp<const GrGLInterface> getSkiaInterface();
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) = 0;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
static GlesDriver* get();
static std::unique_ptr<GlesDriver> replace(std::unique_ptr<GlesDriver>&& driver);
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.cpp b/libs/hwui/debug/GlesErrorCheckWrapper.cpp
index 7ededaa..8d11c19 100644
--- a/libs/hwui/debug/GlesErrorCheckWrapper.cpp
+++ b/libs/hwui/debug/GlesErrorCheckWrapper.cpp
@@ -29,38 +29,39 @@
while ((status = mBase.glGetError_()) != GL_NO_ERROR) {
lastError = status;
switch (status) {
- case GL_INVALID_ENUM:
- ALOGE("GL error: GL_INVALID_ENUM");
- lastErrorName = "GL_INVALID_ENUM";
- break;
- case GL_INVALID_VALUE:
- ALOGE("GL error: GL_INVALID_VALUE");
- lastErrorName = "GL_INVALID_VALUE";
- break;
- case GL_INVALID_OPERATION:
- ALOGE("GL error: GL_INVALID_OPERATION");
- lastErrorName = "GL_INVALID_OPERATION";
- break;
- case GL_OUT_OF_MEMORY:
- ALOGE("GL error: Out of memory!");
- lastErrorName = "GL_OUT_OF_MEMORY";
- break;
- default:
- ALOGE("GL error: 0x%x", status);
- lastErrorName = "UNKNOWN";
+ case GL_INVALID_ENUM:
+ ALOGE("GL error: GL_INVALID_ENUM");
+ lastErrorName = "GL_INVALID_ENUM";
+ break;
+ case GL_INVALID_VALUE:
+ ALOGE("GL error: GL_INVALID_VALUE");
+ lastErrorName = "GL_INVALID_VALUE";
+ break;
+ case GL_INVALID_OPERATION:
+ ALOGE("GL error: GL_INVALID_OPERATION");
+ lastErrorName = "GL_INVALID_OPERATION";
+ break;
+ case GL_OUT_OF_MEMORY:
+ ALOGE("GL error: Out of memory!");
+ lastErrorName = "GL_OUT_OF_MEMORY";
+ break;
+ default:
+ ALOGE("GL error: 0x%x", status);
+ lastErrorName = "UNKNOWN";
}
}
- LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR,
- "%s error! %s (0x%x)", apicall, lastErrorName, lastError);
+ LOG_ALWAYS_FATAL_IF(lastError != GL_NO_ERROR, "%s error! %s (0x%x)", apicall, lastErrorName,
+ lastError);
}
#define API_ENTRY(x) GlesErrorCheckWrapper::x##_
-#define CALL_GL_API(x, ...) \
- mBase.x##_(__VA_ARGS__); assertNoErrors(#x)
+#define CALL_GL_API(x, ...) \
+ mBase.x##_(__VA_ARGS__); \
+ assertNoErrors(#x)
-#define CALL_GL_API_RETURN(x, ...) \
+#define CALL_GL_API_RETURN(x, ...) \
auto ret = mBase.x##_(__VA_ARGS__); \
- assertNoErrors(#x); \
+ assertNoErrors(#x); \
return ret
#include "gles_stubs.in"
@@ -69,6 +70,6 @@
#undef CALL_GL_API
#undef CALL_GL_API_RETURN
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/GlesErrorCheckWrapper.h b/libs/hwui/debug/GlesErrorCheckWrapper.h
index fd45fc0..ee5cc1f 100644
--- a/libs/hwui/debug/GlesErrorCheckWrapper.h
+++ b/libs/hwui/debug/GlesErrorCheckWrapper.h
@@ -27,7 +27,7 @@
GlesErrorCheckWrapper(GlesDriver& base) : mBase(base) {}
#define GL_ENTRY(ret, api, ...) virtual ret api##_(__VA_ARGS__) override;
- #include "gles_decls.in"
+#include "gles_decls.in"
#undef GL_ENTRY
private:
@@ -36,6 +36,6 @@
GlesDriver& mBase;
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/MockGlesDriver.h b/libs/hwui/debug/MockGlesDriver.h
index e0bfc57..e48ca19 100644
--- a/libs/hwui/debug/MockGlesDriver.h
+++ b/libs/hwui/debug/MockGlesDriver.h
@@ -27,10 +27,11 @@
class MockGlesDriver : public FatalBaseDriver {
public:
MOCK_METHOD2(glBindBuffer_, void(GLenum target, GLuint buffer));
- MOCK_METHOD4(glBufferData_, void(GLenum target, GLsizeiptr size, const void *data, GLenum usage));
- MOCK_METHOD2(glGenBuffers_, void(GLsizei n, GLuint *buffers));
+ MOCK_METHOD4(glBufferData_,
+ void(GLenum target, GLsizeiptr size, const void* data, GLenum usage));
+ MOCK_METHOD2(glGenBuffers_, void(GLsizei n, GLuint* buffers));
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/NullGlesDriver.cpp b/libs/hwui/debug/NullGlesDriver.cpp
index 8fbe4bf..212b242 100644
--- a/libs/hwui/debug/NullGlesDriver.cpp
+++ b/libs/hwui/debug/NullGlesDriver.cpp
@@ -29,27 +29,27 @@
GLboolean scissorEnabled;
} gState;
-static void nullglGenCommon(GLsizei n, GLuint *buffers) {
+static void nullglGenCommon(GLsizei n, GLuint* buffers) {
static GLuint nextId = 0;
int i;
- for(i = 0; i < n; i++) {
+ for (i = 0; i < n; i++) {
buffers[i] = ++nextId;
}
}
-void NullGlesDriver::glGenBuffers_(GLsizei n, GLuint *buffers) {
+void NullGlesDriver::glGenBuffers_(GLsizei n, GLuint* buffers) {
nullglGenCommon(n, buffers);
}
-void NullGlesDriver::glGenFramebuffers_(GLsizei n, GLuint *framebuffers) {
+void NullGlesDriver::glGenFramebuffers_(GLsizei n, GLuint* framebuffers) {
nullglGenCommon(n, framebuffers);
}
-void NullGlesDriver::glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) {
+void NullGlesDriver::glGenRenderbuffers_(GLsizei n, GLuint* renderbuffers) {
nullglGenCommon(n, renderbuffers);
}
-void NullGlesDriver::glGenTextures_(GLsizei n, GLuint *textures) {
+void NullGlesDriver::glGenTextures_(GLsizei n, GLuint* textures) {
nullglGenCommon(n, textures);
}
@@ -63,35 +63,37 @@
return ++nextShader;
}
-void NullGlesDriver::glGetProgramiv_(GLuint program, GLenum pname, GLint *params) {
+void NullGlesDriver::glGetProgramiv_(GLuint program, GLenum pname, GLint* params) {
switch (pname) {
- case GL_DELETE_STATUS:
- case GL_LINK_STATUS:
- case GL_VALIDATE_STATUS:
- *params = GL_TRUE;
- break;
- case GL_INFO_LOG_LENGTH:
- *params = 16;
- break;
+ case GL_DELETE_STATUS:
+ case GL_LINK_STATUS:
+ case GL_VALIDATE_STATUS:
+ *params = GL_TRUE;
+ break;
+ case GL_INFO_LOG_LENGTH:
+ *params = 16;
+ break;
}
}
-void NullGlesDriver::glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+void NullGlesDriver::glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) {
*length = snprintf(infoLog, bufSize, "success");
if (*length >= bufSize) {
*length = bufSize - 1;
}
}
-void NullGlesDriver::glGetShaderiv_(GLuint shader, GLenum pname, GLint *params) {
+void NullGlesDriver::glGetShaderiv_(GLuint shader, GLenum pname, GLint* params) {
switch (pname) {
- case GL_COMPILE_STATUS:
- case GL_DELETE_STATUS:
- *params = GL_TRUE;
+ case GL_COMPILE_STATUS:
+ case GL_DELETE_STATUS:
+ *params = GL_TRUE;
}
}
-void NullGlesDriver::glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+void NullGlesDriver::glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) {
*length = snprintf(infoLog, bufSize, "success");
if (*length >= bufSize) {
*length = bufSize - 1;
@@ -100,9 +102,9 @@
void setBooleanState(GLenum cap, GLboolean value) {
switch (cap) {
- case GL_SCISSOR_TEST:
- gState.scissorEnabled = value;
- break;
+ case GL_SCISSOR_TEST:
+ gState.scissorEnabled = value;
+ break;
}
}
@@ -116,55 +118,55 @@
GLboolean NullGlesDriver::glIsEnabled_(GLenum cap) {
switch (cap) {
- case GL_SCISSOR_TEST:
- return gState.scissorEnabled;
- default:
- return GL_FALSE;
+ case GL_SCISSOR_TEST:
+ return gState.scissorEnabled;
+ default:
+ return GL_FALSE;
}
}
-void NullGlesDriver::glGetIntegerv_(GLenum pname, GLint *data) {
+void NullGlesDriver::glGetIntegerv_(GLenum pname, GLint* data) {
switch (pname) {
- case GL_MAX_TEXTURE_SIZE:
- *data = 2048;
- break;
- case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
- *data = 4;
- break;
- default:
- *data = 0;
+ case GL_MAX_TEXTURE_SIZE:
+ *data = 2048;
+ break;
+ case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
+ *data = 4;
+ break;
+ default:
+ *data = 0;
}
}
GLenum NullGlesDriver::glCheckFramebufferStatus_(GLenum target) {
switch (target) {
- case GL_FRAMEBUFFER:
- return GL_FRAMEBUFFER_COMPLETE;
- default:
- return 0; // error case
+ case GL_FRAMEBUFFER:
+ return GL_FRAMEBUFFER_COMPLETE;
+ default:
+ return 0; // error case
}
}
static const char* getString(GLenum name) {
switch (name) {
- case GL_VENDOR:
- return "android";
- case GL_RENDERER:
- return "null";
- case GL_VERSION:
- return "OpenGL ES 2.0 rev1";
- case GL_SHADING_LANGUAGE_VERSION:
- return "OpenGL ES GLSL ES 2.0 rev1";
- case GL_EXTENSIONS:
- default:
- return "";
+ case GL_VENDOR:
+ return "android";
+ case GL_RENDERER:
+ return "null";
+ case GL_VERSION:
+ return "OpenGL ES 2.0 rev1";
+ case GL_SHADING_LANGUAGE_VERSION:
+ return "OpenGL ES GLSL ES 2.0 rev1";
+ case GL_EXTENSIONS:
+ default:
+ return "";
}
}
const GLubyte* NullGlesDriver::glGetString_(GLenum name) {
- return (GLubyte*) getString(name);
+ return (GLubyte*)getString(name);
}
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/NullGlesDriver.h b/libs/hwui/debug/NullGlesDriver.h
index 37ca8f34..1a27dbc 100644
--- a/libs/hwui/debug/NullGlesDriver.h
+++ b/libs/hwui/debug/NullGlesDriver.h
@@ -26,26 +26,28 @@
public:
virtual sk_sp<const GrGLInterface> getSkiaInterface() override;
- virtual void glGenBuffers_(GLsizei n, GLuint *buffers) override;
- virtual void glGenFramebuffers_(GLsizei n, GLuint *framebuffers) override;
- virtual void glGenRenderbuffers_(GLsizei n, GLuint *renderbuffers) override;
- virtual void glGenTextures_(GLsizei n, GLuint *textures) override;
+ virtual void glGenBuffers_(GLsizei n, GLuint* buffers) override;
+ virtual void glGenFramebuffers_(GLsizei n, GLuint* framebuffers) override;
+ virtual void glGenRenderbuffers_(GLsizei n, GLuint* renderbuffers) override;
+ virtual void glGenTextures_(GLsizei n, GLuint* textures) override;
virtual GLuint glCreateProgram_(void) override;
virtual GLuint glCreateShader_(GLenum type) override;
- virtual void glGetProgramiv_(GLuint program, GLenum pname, GLint *params) override;
- virtual void glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) override;
- virtual void glGetShaderiv_(GLuint shader, GLenum pname, GLint *params) override;
- virtual void glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) override;
+ virtual void glGetProgramiv_(GLuint program, GLenum pname, GLint* params) override;
+ virtual void glGetProgramInfoLog_(GLuint program, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) override;
+ virtual void glGetShaderiv_(GLuint shader, GLenum pname, GLint* params) override;
+ virtual void glGetShaderInfoLog_(GLuint shader, GLsizei bufSize, GLsizei* length,
+ GLchar* infoLog) override;
virtual void glEnable_(GLenum cap) override;
virtual void glDisable_(GLenum cap) override;
virtual GLboolean glIsEnabled_(GLenum cap) override;
- virtual void glGetIntegerv_(GLenum pname, GLint *data) override;
+ virtual void glGetIntegerv_(GLenum pname, GLint* data) override;
virtual const GLubyte* glGetString_(GLenum name) override;
virtual GLenum glCheckFramebufferStatus_(GLenum target) override;
virtual void glActiveTexture_(GLenum texture) override {}
virtual void glAttachShader_(GLuint program, GLuint shader) override {}
- virtual void glBindAttribLocation_(GLuint program, GLuint index, const GLchar *name) override {}
+ virtual void glBindAttribLocation_(GLuint program, GLuint index, const GLchar* name) override {}
virtual void glBindBuffer_(GLenum target, GLuint buffer) override {}
virtual void glBindFramebuffer_(GLenum target, GLuint framebuffer) override {}
virtual void glBindRenderbuffer_(GLenum target, GLuint renderbuffer) override {}
@@ -54,116 +56,147 @@
virtual void glBlendEquation_(GLenum mode) override {}
virtual void glBlendEquationSeparate_(GLenum modeRGB, GLenum modeAlpha) override {}
virtual void glBlendFunc_(GLenum sfactor, GLenum dfactor) override {}
- virtual void glBlendFuncSeparate_(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha) override {}
- virtual void glBufferData_(GLenum target, GLsizeiptr size, const void *data, GLenum usage) override {}
- virtual void glBufferSubData_(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) override {}
+ virtual void glBlendFuncSeparate_(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha,
+ GLenum dfactorAlpha) override {}
+ virtual void glBufferData_(GLenum target, GLsizeiptr size, const void* data,
+ GLenum usage) override {}
+ virtual void glBufferSubData_(GLenum target, GLintptr offset, GLsizeiptr size,
+ const void* data) override {}
virtual void glClear_(GLbitfield mask) override {}
virtual void glClearColor_(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) override {}
virtual void glClearDepthf_(GLfloat d) override {}
virtual void glClearStencil_(GLint s) override {}
- virtual void glColorMask_(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) override {}
+ virtual void glColorMask_(GLboolean red, GLboolean green, GLboolean blue,
+ GLboolean alpha) override {}
virtual void glCompileShader_(GLuint shader) override {}
- virtual void glCompressedTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data) override {}
- virtual void glCompressedTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data) override {}
- virtual void glCopyTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) override {}
- virtual void glCopyTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) override {}
+ virtual void glCompressedTexImage2D_(GLenum target, GLint level, GLenum internalformat,
+ GLsizei width, GLsizei height, GLint border,
+ GLsizei imageSize, const void* data) override {}
+ virtual void glCompressedTexSubImage2D_(GLenum target, GLint level, GLint xoffset,
+ GLint yoffset, GLsizei width, GLsizei height,
+ GLenum format, GLsizei imageSize,
+ const void* data) override {}
+ virtual void glCopyTexImage2D_(GLenum target, GLint level, GLenum internalformat, GLint x,
+ GLint y, GLsizei width, GLsizei height, GLint border) override {}
+ virtual void glCopyTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLint x, GLint y, GLsizei width, GLsizei height) override {}
virtual void glCullFace_(GLenum mode) override {}
- virtual void glDeleteBuffers_(GLsizei n, const GLuint *buffers) override {}
- virtual void glDeleteFramebuffers_(GLsizei n, const GLuint *framebuffers) override {}
+ virtual void glDeleteBuffers_(GLsizei n, const GLuint* buffers) override {}
+ virtual void glDeleteFramebuffers_(GLsizei n, const GLuint* framebuffers) override {}
virtual void glDeleteProgram_(GLuint program) override {}
- virtual void glDeleteRenderbuffers_(GLsizei n, const GLuint *renderbuffers) override {}
+ virtual void glDeleteRenderbuffers_(GLsizei n, const GLuint* renderbuffers) override {}
virtual void glDeleteShader_(GLuint shader) override {}
- virtual void glDeleteTextures_(GLsizei n, const GLuint *textures) override {}
+ virtual void glDeleteTextures_(GLsizei n, const GLuint* textures) override {}
virtual void glDepthFunc_(GLenum func) override {}
virtual void glDepthMask_(GLboolean flag) override {}
virtual void glDepthRangef_(GLfloat n, GLfloat f) override {}
virtual void glDetachShader_(GLuint program, GLuint shader) override {}
virtual void glDisableVertexAttribArray_(GLuint index) override {}
virtual void glDrawArrays_(GLenum mode, GLint first, GLsizei count) override {}
- virtual void glDrawElements_(GLenum mode, GLsizei count, GLenum type, const void *indices) override {}
+ virtual void glDrawElements_(GLenum mode, GLsizei count, GLenum type,
+ const void* indices) override {}
virtual void glEnableVertexAttribArray_(GLuint index) override {}
virtual void glFinish_(void) override {}
virtual void glFlush_(void) override {}
- virtual void glFramebufferRenderbuffer_(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) override {}
- virtual void glFramebufferTexture2D_(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) override {}
+ virtual void glFramebufferRenderbuffer_(GLenum target, GLenum attachment,
+ GLenum renderbuffertarget,
+ GLuint renderbuffer) override {}
+ virtual void glFramebufferTexture2D_(GLenum target, GLenum attachment, GLenum textarget,
+ GLuint texture, GLint level) override {}
virtual void glFrontFace_(GLenum mode) override {}
virtual void glGenerateMipmap_(GLenum target) override {}
- virtual GLint glGetAttribLocation_(GLuint program, const GLchar *name) override { return 1; }
+ virtual GLint glGetAttribLocation_(GLuint program, const GLchar* name) override { return 1; }
virtual GLenum glGetError_(void) override { return GL_NO_ERROR; }
- virtual GLint glGetUniformLocation_(GLuint program, const GLchar *name) override { return 2; }
+ virtual GLint glGetUniformLocation_(GLuint program, const GLchar* name) override { return 2; }
virtual void glHint_(GLenum target, GLenum mode) override {}
virtual void glLineWidth_(GLfloat width) override {}
virtual void glLinkProgram_(GLuint program) override {}
virtual void glPixelStorei_(GLenum pname, GLint param) override {}
virtual void glPolygonOffset_(GLfloat factor, GLfloat units) override {}
- virtual void glReadPixels_(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void *pixels) override {}
+ virtual void glReadPixels_(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format,
+ GLenum type, void* pixels) override {}
virtual void glReleaseShaderCompiler_(void) override {}
- virtual void glRenderbufferStorage_(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) override {}
+ virtual void glRenderbufferStorage_(GLenum target, GLenum internalformat, GLsizei width,
+ GLsizei height) override {}
virtual void glSampleCoverage_(GLfloat value, GLboolean invert) override {}
virtual void glScissor_(GLint x, GLint y, GLsizei width, GLsizei height) override {}
- virtual void glShaderBinary_(GLsizei count, const GLuint *shaders, GLenum binaryformat, const void *binary, GLsizei length) override {}
- virtual void glShaderSource_(GLuint shader, GLsizei count, const GLchar *const*string, const GLint *length) override {}
+ virtual void glShaderBinary_(GLsizei count, const GLuint* shaders, GLenum binaryformat,
+ const void* binary, GLsizei length) override {}
+ virtual void glShaderSource_(GLuint shader, GLsizei count, const GLchar* const* string,
+ const GLint* length) override {}
virtual void glStencilFunc_(GLenum func, GLint ref, GLuint mask) override {}
- virtual void glStencilFuncSeparate_(GLenum face, GLenum func, GLint ref, GLuint mask) override {}
+ virtual void glStencilFuncSeparate_(GLenum face, GLenum func, GLint ref, GLuint mask) override {
+ }
virtual void glStencilMask_(GLuint mask) override {}
virtual void glStencilMaskSeparate_(GLenum face, GLuint mask) override {}
virtual void glStencilOp_(GLenum fail, GLenum zfail, GLenum zpass) override {}
- virtual void glStencilOpSeparate_(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass) override {}
- virtual void glTexImage2D_(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void *pixels) override {}
+ virtual void glStencilOpSeparate_(GLenum face, GLenum sfail, GLenum dpfail,
+ GLenum dppass) override {}
+ virtual void glTexImage2D_(GLenum target, GLint level, GLint internalformat, GLsizei width,
+ GLsizei height, GLint border, GLenum format, GLenum type,
+ const void* pixels) override {}
virtual void glTexParameterf_(GLenum target, GLenum pname, GLfloat param) override {}
- virtual void glTexParameterfv_(GLenum target, GLenum pname, const GLfloat *params) override {}
+ virtual void glTexParameterfv_(GLenum target, GLenum pname, const GLfloat* params) override {}
virtual void glTexParameteri_(GLenum target, GLenum pname, GLint param) override {}
- virtual void glTexParameteriv_(GLenum target, GLenum pname, const GLint *params) override {}
- virtual void glTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) override {}
+ virtual void glTexParameteriv_(GLenum target, GLenum pname, const GLint* params) override {}
+ virtual void glTexSubImage2D_(GLenum target, GLint level, GLint xoffset, GLint yoffset,
+ GLsizei width, GLsizei height, GLenum format, GLenum type,
+ const void* pixels) override {}
virtual void glUniform1f_(GLint location, GLfloat v0) override {}
- virtual void glUniform1fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform1fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform1i_(GLint location, GLint v0) override {}
- virtual void glUniform1iv_(GLint location, GLsizei count, const GLint *value) override {}
+ virtual void glUniform1iv_(GLint location, GLsizei count, const GLint* value) override {}
virtual void glUniform2f_(GLint location, GLfloat v0, GLfloat v1) override {}
- virtual void glUniform2fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform2fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform2i_(GLint location, GLint v0, GLint v1) override {}
- virtual void glUniform2iv_(GLint location, GLsizei count, const GLint *value) override {}
+ virtual void glUniform2iv_(GLint location, GLsizei count, const GLint* value) override {}
virtual void glUniform3f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) override {}
- virtual void glUniform3fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform3fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform3i_(GLint location, GLint v0, GLint v1, GLint v2) override {}
- virtual void glUniform3iv_(GLint location, GLsizei count, const GLint *value) override {}
- virtual void glUniform4f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) override {}
- virtual void glUniform4fv_(GLint location, GLsizei count, const GLfloat *value) override {}
+ virtual void glUniform3iv_(GLint location, GLsizei count, const GLint* value) override {}
+ virtual void glUniform4f_(GLint location, GLfloat v0, GLfloat v1, GLfloat v2,
+ GLfloat v3) override {}
+ virtual void glUniform4fv_(GLint location, GLsizei count, const GLfloat* value) override {}
virtual void glUniform4i_(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) override {}
- virtual void glUniform4iv_(GLint location, GLsizei count, const GLint *value) override {}
- virtual void glUniformMatrix2fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {}
- virtual void glUniformMatrix3fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {}
- virtual void glUniformMatrix4fv_(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) override {}
+ virtual void glUniform4iv_(GLint location, GLsizei count, const GLint* value) override {}
+ virtual void glUniformMatrix2fv_(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) override {}
+ virtual void glUniformMatrix3fv_(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) override {}
+ virtual void glUniformMatrix4fv_(GLint location, GLsizei count, GLboolean transpose,
+ const GLfloat* value) override {}
virtual void glUseProgram_(GLuint program) override {}
virtual void glValidateProgram_(GLuint program) override {}
virtual void glVertexAttrib1f_(GLuint index, GLfloat x) override {}
- virtual void glVertexAttrib1fv_(GLuint index, const GLfloat *v) override {}
+ virtual void glVertexAttrib1fv_(GLuint index, const GLfloat* v) override {}
virtual void glVertexAttrib2f_(GLuint index, GLfloat x, GLfloat y) override {}
- virtual void glVertexAttrib2fv_(GLuint index, const GLfloat *v) override {}
+ virtual void glVertexAttrib2fv_(GLuint index, const GLfloat* v) override {}
virtual void glVertexAttrib3f_(GLuint index, GLfloat x, GLfloat y, GLfloat z) override {}
- virtual void glVertexAttrib3fv_(GLuint index, const GLfloat *v) override {}
- virtual void glVertexAttrib4f_(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) override {}
- virtual void glVertexAttrib4fv_(GLuint index, const GLfloat *v) override {}
- virtual void glVertexAttribPointer_(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer) override {}
+ virtual void glVertexAttrib3fv_(GLuint index, const GLfloat* v) override {}
+ virtual void glVertexAttrib4f_(GLuint index, GLfloat x, GLfloat y, GLfloat z,
+ GLfloat w) override {}
+ virtual void glVertexAttrib4fv_(GLuint index, const GLfloat* v) override {}
+ virtual void glVertexAttribPointer_(GLuint index, GLint size, GLenum type, GLboolean normalized,
+ GLsizei stride, const void* pointer) override {}
virtual void glViewport_(GLint x, GLint y, GLsizei width, GLsizei height) override {}
// gles2 ext
- virtual void glInsertEventMarkerEXT_(GLsizei length, const GLchar *marker) override {}
- virtual void glPushGroupMarkerEXT_(GLsizei length, const GLchar *marker) override {}
+ virtual void glInsertEventMarkerEXT_(GLsizei length, const GLchar* marker) override {}
+ virtual void glPushGroupMarkerEXT_(GLsizei length, const GLchar* marker) override {}
virtual void glPopGroupMarkerEXT_(void) override {}
- virtual void glDiscardFramebufferEXT_(GLenum target, GLsizei numAttachments, const GLenum *attachments) override {}
+ virtual void glDiscardFramebufferEXT_(GLenum target, GLsizei numAttachments,
+ const GLenum* attachments) override {}
virtual void glEGLImageTargetTexture2DOES_(GLenum target, GLeglImageOES image) override {}
// GLES3
- virtual void* glMapBufferRange_(GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access) override {
+ virtual void* glMapBufferRange_(GLenum target, GLintptr offset, GLsizeiptr length,
+ GLbitfield access) override {
return 0;
}
- virtual GLboolean glUnmapBuffer_(GLenum target) override {
- return GL_FALSE;
- }
+ virtual GLboolean glUnmapBuffer_(GLenum target) override { return GL_FALSE; }
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/ScopedReplaceDriver.h b/libs/hwui/debug/ScopedReplaceDriver.h
index 342c9d2..110196f 100644
--- a/libs/hwui/debug/ScopedReplaceDriver.h
+++ b/libs/hwui/debug/ScopedReplaceDriver.h
@@ -33,14 +33,13 @@
Driver& get() { return *mCurrentDriver; }
- ~ScopedReplaceDriver() {
- GlesDriver::replace(std::move(mOldDriver));
- }
+ ~ScopedReplaceDriver() { GlesDriver::replace(std::move(mOldDriver)); }
+
private:
std::unique_ptr<GlesDriver> mOldDriver;
Driver* mCurrentDriver;
};
-} // namespace debug
-} // namespace uirenderer
-} // namespace android
+} // namespace debug
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/debug/gles_redefine.h b/libs/hwui/debug/gles_redefine.h
index 201f0a9..49b5069 100644
--- a/libs/hwui/debug/gles_redefine.h
+++ b/libs/hwui/debug/gles_redefine.h
@@ -212,7 +212,8 @@
#define glDrawElementsInstancedANGLE wrap_glDrawElementsInstancedANGLE
#define glDrawElementsInstancedBaseInstanceEXT wrap_glDrawElementsInstancedBaseInstanceEXT
#define glDrawElementsInstancedBaseVertex wrap_glDrawElementsInstancedBaseVertex
-#define glDrawElementsInstancedBaseVertexBaseInstanceEXT wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT
+#define glDrawElementsInstancedBaseVertexBaseInstanceEXT \
+ wrap_glDrawElementsInstancedBaseVertexBaseInstanceEXT
#define glDrawElementsInstancedBaseVertexEXT wrap_glDrawElementsInstancedBaseVertexEXT
#define glDrawElementsInstancedBaseVertexOES wrap_glDrawElementsInstancedBaseVertexOES
#define glDrawElementsInstancedEXT wrap_glDrawElementsInstancedEXT
diff --git a/libs/hwui/debug/nullegl.cpp b/libs/hwui/debug/nullegl.cpp
index 2ae71df..ca47f8f 100644
--- a/libs/hwui/debug/nullegl.cpp
+++ b/libs/hwui/debug/nullegl.cpp
@@ -21,8 +21,8 @@
#include <stdlib.h>
#include <string.h>
-static EGLDisplay gDisplay = (EGLDisplay) 1;
-static EGLSyncKHR gFence = (EGLSyncKHR) 1;
+static EGLDisplay gDisplay = (EGLDisplay)1;
+static EGLSyncKHR gFence = (EGLSyncKHR)1;
typedef struct {
EGLSurface surface;
@@ -43,8 +43,8 @@
ThreadState* getThreadState() {
ThreadState* ptr;
pthread_once(&ThreadStateSetupOnce, makeThreadState);
- if ((ptr = (ThreadState*) pthread_getspecific(ThreadStateKey)) == NULL) {
- ptr = (ThreadState*) calloc(1, sizeof(ThreadState));
+ if ((ptr = (ThreadState*)pthread_getspecific(ThreadStateKey)) == NULL) {
+ ptr = (ThreadState*)calloc(1, sizeof(ThreadState));
ptr->context = EGL_NO_CONTEXT;
ptr->surface = EGL_NO_SURFACE;
pthread_setspecific(ThreadStateKey, ptr);
@@ -60,7 +60,7 @@
return gDisplay;
}
-EGLBoolean eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) {
+EGLBoolean eglInitialize(EGLDisplay dpy, EGLint* major, EGLint* minor) {
return EGL_TRUE;
}
@@ -68,30 +68,27 @@
return EGL_TRUE;
}
-const char * eglQueryString(EGLDisplay dpy, EGLint name) {
+const char* eglQueryString(EGLDisplay dpy, EGLint name) {
if (name == EGL_EXTENSIONS) {
return "EGL_KHR_swap_buffers_with_damage";
}
return "";
}
-EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
- EGLConfig *configs, EGLint config_size,
- EGLint *num_config) {
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs,
+ EGLint config_size, EGLint* num_config) {
memset(configs, 9, sizeof(EGLConfig) * config_size);
*num_config = config_size;
return EGL_TRUE;
}
-EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
- EGLNativeWindowType win,
- const EGLint *attrib_list) {
- return (EGLSurface) malloc(sizeof(void*));
+EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
+ const EGLint* attrib_list) {
+ return (EGLSurface)malloc(sizeof(void*));
}
-EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
- const EGLint *attrib_list) {
- return (EGLSurface) malloc(sizeof(void*));
+EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list) {
+ return (EGLSurface)malloc(sizeof(void*));
}
EGLBoolean eglDestroySurface(EGLDisplay dpy, EGLSurface surface) {
@@ -99,8 +96,7 @@
return EGL_TRUE;
}
-EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint *value) {
+EGLBoolean eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value) {
*value = 1000;
return EGL_TRUE;
}
@@ -109,8 +105,7 @@
return EGL_TRUE;
}
-EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
- EGLint attribute, EGLint value) {
+EGLBoolean eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) {
return EGL_TRUE;
}
@@ -118,18 +113,16 @@
return EGL_TRUE;
}
-EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
- EGLContext share_context,
- const EGLint *attrib_list) {
- return (EGLContext) malloc(sizeof(void*));
+EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context,
+ const EGLint* attrib_list) {
+ return (EGLContext)malloc(sizeof(void*));
}
EGLBoolean eglDestroyContext(EGLDisplay dpy, EGLContext ctx) {
free(ctx);
return EGL_TRUE;
}
-EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
- EGLSurface read, EGLContext ctx) {
+EGLBoolean eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) {
ThreadState* state = getThreadState();
state->surface = draw;
state->context = ctx;
@@ -152,15 +145,17 @@
return EGL_TRUE;
}
-EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint rectCount) {
+EGLBoolean eglSwapBuffersWithDamageKHR(EGLDisplay dpy, EGLSurface surface, EGLint* rects,
+ EGLint rectCount) {
return EGL_TRUE;
}
-EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) {
- return (EGLImageKHR) malloc(sizeof(EGLImageKHR));
+EGLImageKHR eglCreateImageKHR(EGLDisplay dpy, EGLContext ctx, EGLenum target,
+ EGLClientBuffer buffer, const EGLint* attrib_list) {
+ return (EGLImageKHR)malloc(sizeof(EGLImageKHR));
}
-EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list) {
+EGLSyncKHR eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint* attrib_list) {
return gFence;
}
diff --git a/libs/hwui/font/CacheTexture.cpp b/libs/hwui/font/CacheTexture.cpp
index 73beba9..5dd8bb8 100644
--- a/libs/hwui/font/CacheTexture.cpp
+++ b/libs/hwui/font/CacheTexture.cpp
@@ -16,12 +16,12 @@
#include <SkGlyph.h>
-#include "CacheTexture.h"
-#include "FontUtil.h"
#include "../Caches.h"
#include "../Debug.h"
#include "../Extensions.h"
#include "../PixelBuffer.h"
+#include "CacheTexture.h"
+#include "FontUtil.h"
namespace android {
namespace uirenderer {
@@ -37,9 +37,8 @@
*/
CacheBlock* CacheBlock::insertBlock(CacheBlock* head, CacheBlock* newBlock) {
#if DEBUG_FONT_RENDERER
- ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
- newBlock, newBlock->mX, newBlock->mY,
- newBlock->mWidth, newBlock->mHeight);
+ ALOGD("insertBlock: this, x, y, w, h = %p, %d, %d, %d, %d", newBlock, newBlock->mX,
+ newBlock->mY, newBlock->mWidth, newBlock->mHeight);
#endif
CacheBlock* currBlock = head;
@@ -81,9 +80,8 @@
CacheBlock* CacheBlock::removeBlock(CacheBlock* head, CacheBlock* blockToRemove) {
#if DEBUG_FONT_RENDERER
- ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d",
- blockToRemove, blockToRemove->mX, blockToRemove->mY,
- blockToRemove->mWidth, blockToRemove->mHeight);
+ ALOGD("removeBlock: this, x, y, w, h = %p, %d, %d, %d, %d", blockToRemove, blockToRemove->mX,
+ blockToRemove->mY, blockToRemove->mWidth, blockToRemove->mHeight);
#endif
CacheBlock* newHead = head;
@@ -93,7 +91,7 @@
if (prevBlock) {
// If this doesn't hold, we have a use-after-free below.
LOG_ALWAYS_FATAL_IF(head == blockToRemove,
- "removeBlock: head should not have a previous block");
+ "removeBlock: head should not have a previous block");
prevBlock->mNext = nextBlock;
} else {
newHead = nextBlock;
@@ -121,8 +119,9 @@
, mCaches(Caches::getInstance()) {
mTexture.blend = true;
- mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
- getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
+ mCacheBlocks =
+ new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+ getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
// OpenGL ES 3.0+ lets us specify the row length for unpack operations such
// as glTexSubImage2D(). This allows us to upload a sub-rectangle of a texture.
@@ -150,8 +149,9 @@
void CacheTexture::init() {
// reset, then create a new remainder space to start again
reset();
- mCacheBlocks = new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
- getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
+ mCacheBlocks =
+ new CacheBlock(TEXTURE_BORDER_SIZE, TEXTURE_BORDER_SIZE,
+ getWidth() - TEXTURE_BORDER_SIZE, getHeight() - TEXTURE_BORDER_SIZE);
}
void CacheTexture::releaseMesh() {
@@ -233,7 +233,7 @@
if (mFormat != GL_ALPHA) {
#if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: texture format %x is inappropriate for monochromatic glyphs",
- mFormat);
+ mFormat);
#endif
return false;
}
@@ -272,8 +272,8 @@
// it's the remainder space (mY == 0) or there's only enough height for this one glyph
// or it's within ROUNDING_SIZE of the block width
if (roundedUpW <= cacheBlock->mWidth && glyphH <= cacheBlock->mHeight &&
- (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
- (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
+ (cacheBlock->mY == TEXTURE_BORDER_SIZE ||
+ (cacheBlock->mWidth - roundedUpW < CACHE_BLOCK_ROUNDING_SIZE))) {
if (cacheBlock->mHeight - glyphH < glyphH) {
// Only enough space for this glyph - don't bother rounding up the width
roundedUpW = glyphW;
@@ -292,12 +292,13 @@
if (getHeight() - glyphH >= glyphH) {
// There's enough height left over to create a new CacheBlock
- CacheBlock* newBlock = new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE,
- roundedUpW, getHeight() - glyphH - TEXTURE_BORDER_SIZE);
+ CacheBlock* newBlock =
+ new CacheBlock(oldX, glyphH + TEXTURE_BORDER_SIZE, roundedUpW,
+ getHeight() - glyphH - TEXTURE_BORDER_SIZE);
#if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: Created new block: this, x, y, w, h = %p, %d, %d, %d, %d",
- newBlock, newBlock->mX, newBlock->mY,
- newBlock->mWidth, newBlock->mHeight);
+ newBlock, newBlock->mX, newBlock->mY, newBlock->mWidth,
+ newBlock->mHeight);
#endif
mCacheBlocks = CacheBlock::insertBlock(mCacheBlocks, newBlock);
}
@@ -307,8 +308,8 @@
cacheBlock->mHeight -= glyphH;
#if DEBUG_FONT_RENDERER
ALOGD("fitBitmap: Added to existing block: this, x, y, w, h = %p, %d, %d, %d, %d",
- cacheBlock, cacheBlock->mX, cacheBlock->mY,
- cacheBlock->mWidth, cacheBlock->mHeight);
+ cacheBlock, cacheBlock->mX, cacheBlock->mY, cacheBlock->mWidth,
+ cacheBlock->mHeight);
#endif
}
@@ -319,7 +320,7 @@
mDirty = true;
const Rect r(*retOriginX - TEXTURE_BORDER_SIZE, *retOriginY - TEXTURE_BORDER_SIZE,
- *retOriginX + glyphW, *retOriginY + glyphH);
+ *retOriginX + glyphW, *retOriginY + glyphH);
mDirtyRect.unionWith(r);
mNumGlyphs++;
@@ -350,5 +351,5 @@
return free;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/CacheTexture.h b/libs/hwui/font/CacheTexture.h
index 6750a8a..654378e 100644
--- a/libs/hwui/font/CacheTexture.h
+++ b/libs/hwui/font/CacheTexture.h
@@ -26,7 +26,6 @@
#include <SkGlyph.h>
#include <utils/Log.h>
-
namespace android {
namespace uirenderer {
@@ -53,9 +52,8 @@
CacheBlock* mNext;
CacheBlock* mPrev;
- CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height):
- mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {
- }
+ CacheBlock(uint16_t x, uint16_t y, uint16_t width, uint16_t height)
+ : mX(x), mY(y), mWidth(width), mHeight(height), mNext(nullptr), mPrev(nullptr) {}
static CacheBlock* insertBlock(CacheBlock* head, CacheBlock* newBlock);
static CacheBlock* removeBlock(CacheBlock* head, CacheBlock* blockToRemove);
@@ -63,9 +61,8 @@
void output() {
CacheBlock* currBlock = this;
while (currBlock) {
- ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d",
- currBlock, currBlock->mX, currBlock->mY,
- currBlock->mWidth, currBlock->mHeight);
+ ALOGD("Block: this, x, y, w, h = %p, %d, %d, %d, %d", currBlock, currBlock->mX,
+ currBlock->mY, currBlock->mWidth, currBlock->mHeight);
currBlock = currBlock->mNext;
}
}
@@ -91,29 +88,19 @@
bool fitBitmap(const SkGlyph& glyph, uint32_t* retOriginX, uint32_t* retOriginY);
- inline uint16_t getWidth() const {
- return mWidth;
- }
+ inline uint16_t getWidth() const { return mWidth; }
- inline uint16_t getHeight() const {
- return mHeight;
- }
+ inline uint16_t getHeight() const { return mHeight; }
- inline GLenum getFormat() const {
- return mFormat;
- }
+ inline GLenum getFormat() const { return mFormat; }
inline uint32_t getOffset(uint16_t x, uint16_t y) const {
return (y * getWidth() + x) * PixelBuffer::formatSize(mFormat);
}
- inline const Rect* getDirtyRect() const {
- return &mDirtyRect;
- }
+ inline const Rect* getDirtyRect() const { return &mDirtyRect; }
- inline PixelBuffer* getPixelBuffer() const {
- return mPixelBuffer;
- }
+ inline PixelBuffer* getPixelBuffer() const { return mPixelBuffer; }
Texture& getTexture() {
allocatePixelBuffer();
@@ -125,43 +112,28 @@
return mTexture.id();
}
- inline bool isDirty() const {
- return mDirty;
- }
+ inline bool isDirty() const { return mDirty; }
- inline bool getLinearFiltering() const {
- return mLinearFiltering;
- }
+ inline bool getLinearFiltering() const { return mLinearFiltering; }
/**
* This method assumes that the proper texture unit is active.
*/
void setLinearFiltering(bool linearFiltering);
- inline uint16_t getGlyphCount() const {
- return mNumGlyphs;
- }
+ inline uint16_t getGlyphCount() const { return mNumGlyphs; }
- TextureVertex* mesh() const {
- return mMesh;
- }
+ TextureVertex* mesh() const { return mMesh; }
- uint32_t meshElementCount() const {
- return mCurrentQuad * 6;
- }
+ uint32_t meshElementCount() const { return mCurrentQuad * 6; }
- uint16_t* indices() const {
- return (uint16_t*) nullptr;
- }
+ uint16_t* indices() const { return (uint16_t*)nullptr; }
- void resetMesh() {
- mCurrentQuad = 0;
- }
+ void resetMesh() { mCurrentQuad = 0; }
- inline void addQuad(float x1, float y1, float u1, float v1,
- float x2, float y2, float u2, float v2,
- float x3, float y3, float u3, float v3,
- float x4, float y4, float u4, float v4) {
+ inline void addQuad(float x1, float y1, float u1, float v1, float x2, float y2, float u2,
+ float v2, float x3, float y3, float u3, float v3, float x4, float y4,
+ float u4, float v4) {
TextureVertex* mesh = mMesh + mCurrentQuad * 4;
TextureVertex::set(mesh++, x2, y2, u2, v2);
TextureVertex::set(mesh++, x3, y3, u3, v3);
@@ -170,13 +142,9 @@
mCurrentQuad++;
}
- bool canDraw() const {
- return mCurrentQuad > 0;
- }
+ bool canDraw() const { return mCurrentQuad > 0; }
- bool endOfMesh() const {
- return mCurrentQuad == mMaxQuadCount;
- }
+ bool endOfMesh() const { return mCurrentQuad == mMaxQuadCount; }
uint32_t calculateFreeMemory() const;
@@ -199,7 +167,7 @@
Rect mDirtyRect;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_CACHE_TEXTURE_H
+#endif // ANDROID_HWUI_CACHE_TEXTURE_H
diff --git a/libs/hwui/font/CachedGlyphInfo.h b/libs/hwui/font/CachedGlyphInfo.h
index 073d59b..93bb823 100644
--- a/libs/hwui/font/CachedGlyphInfo.h
+++ b/libs/hwui/font/CachedGlyphInfo.h
@@ -50,7 +50,7 @@
CacheTexture* mCacheTexture;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_CACHED_GLYPH_INFO_H
+#endif // ANDROID_HWUI_CACHED_GLYPH_INFO_H
diff --git a/libs/hwui/font/Font.cpp b/libs/hwui/font/Font.cpp
index 24d497c..41a24a8 100644
--- a/libs/hwui/font/Font.cpp
+++ b/libs/hwui/font/Font.cpp
@@ -19,17 +19,17 @@
#include <utils/JenkinsHash.h>
#include <utils/Trace.h>
-#include <SkSurfaceProps.h>
#include <SkGlyph.h>
#include <SkGlyphCache.h>
+#include <SkSurfaceProps.h>
#include <SkUtils.h>
-#include "FontUtil.h"
-#include "Font.h"
#include "../Debug.h"
#include "../FontRenderer.h"
#include "../PixelBuffer.h"
#include "../Properties.h"
+#include "Font.h"
+#include "FontUtil.h"
namespace android {
namespace uirenderer {
@@ -38,8 +38,8 @@
// Font
///////////////////////////////////////////////////////////////////////////////
-Font::Font(FontRenderer* state, const Font::FontDescription& desc) :
- mState(state), mDescription(desc) { }
+Font::Font(FontRenderer* state, const Font::FontDescription& desc)
+ : mState(state), mDescription(desc) {}
Font::FontDescription::FontDescription(const SkPaint* paint, const SkMatrix& rasterMatrix)
: mLookupTransform(rasterMatrix) {
@@ -82,7 +82,7 @@
}
int Font::FontDescription::compare(const Font::FontDescription& lhs,
- const Font::FontDescription& rhs) {
+ const Font::FontDescription& rhs) {
int deltaInt = int(lhs.mFontId) - int(rhs.mFontId);
if (deltaInt != 0) return deltaInt;
@@ -110,15 +110,15 @@
deltaInt = int(lhs.mHinting) - int(rhs.mHinting);
if (deltaInt != 0) return deltaInt;
- if (lhs.mLookupTransform[SkMatrix::kMScaleX] <
- rhs.mLookupTransform[SkMatrix::kMScaleX]) return -1;
- if (lhs.mLookupTransform[SkMatrix::kMScaleX] >
- rhs.mLookupTransform[SkMatrix::kMScaleX]) return +1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleX] < rhs.mLookupTransform[SkMatrix::kMScaleX])
+ return -1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleX] > rhs.mLookupTransform[SkMatrix::kMScaleX])
+ return +1;
- if (lhs.mLookupTransform[SkMatrix::kMScaleY] <
- rhs.mLookupTransform[SkMatrix::kMScaleY]) return -1;
- if (lhs.mLookupTransform[SkMatrix::kMScaleY] >
- rhs.mLookupTransform[SkMatrix::kMScaleY]) return +1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleY] < rhs.mLookupTransform[SkMatrix::kMScaleY])
+ return -1;
+ if (lhs.mLookupTransform[SkMatrix::kMScaleY] > rhs.mLookupTransform[SkMatrix::kMScaleY])
+ return +1;
return 0;
}
@@ -132,10 +132,10 @@
}
}
-void Font::measureCachedGlyph(CachedGlyphInfo *glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- int width = (int) glyph->mBitmapWidth;
- int height = (int) glyph->mBitmapHeight;
+void Font::measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
+ int width = (int)glyph->mBitmapWidth;
+ int height = (int)glyph->mBitmapHeight;
int nPenX = x + glyph->mBitmapLeft;
int nPenY = y + glyph->mBitmapTop;
@@ -154,10 +154,10 @@
}
}
-void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- float width = (float) glyph->mBitmapWidth;
- float height = (float) glyph->mBitmapHeight;
+void Font::drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW,
+ uint32_t bitmapH, Rect* bounds, const float* pos) {
+ float width = (float)glyph->mBitmapWidth;
+ float height = (float)glyph->mBitmapHeight;
float nPenX = x + glyph->mBitmapLeft;
float nPenY = y + glyph->mBitmapTop + height;
@@ -167,16 +167,16 @@
float v1 = glyph->mBitmapMinV;
float v2 = glyph->mBitmapMaxV;
- mState->appendMeshQuad(nPenX, nPenY, u1, v2,
- nPenX + width, nPenY, u2, v2,
- nPenX + width, nPenY - height, u2, v1,
- nPenX, nPenY - height, u1, v1, glyph->mCacheTexture);
+ mState->appendMeshQuad(nPenX, nPenY, u1, v2, nPenX + width, nPenY, u2, v2, nPenX + width,
+ nPenY - height, u2, v1, nPenX, nPenY - height, u1, v1,
+ glyph->mCacheTexture);
}
-void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
- uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos) {
- float width = (float) glyph->mBitmapWidth;
- float height = (float) glyph->mBitmapHeight;
+void Font::drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
+ const float* pos) {
+ float width = (float)glyph->mBitmapWidth;
+ float height = (float)glyph->mBitmapHeight;
SkPoint p[4];
p[0].iset(glyph->mBitmapLeft, glyph->mBitmapTop + height);
@@ -196,15 +196,14 @@
float v1 = glyph->mBitmapMinV;
float v2 = glyph->mBitmapMaxV;
- mState->appendRotatedMeshQuad(
- p[0].x(), p[0].y(), u1, v2,
- p[1].x(), p[1].y(), u2, v2,
- p[2].x(), p[2].y(), u2, v1,
- p[3].x(), p[3].y(), u1, v1, glyph->mCacheTexture);
+ mState->appendRotatedMeshQuad(p[0].x(), p[0].y(), u1, v2, p[1].x(), p[1].y(), u2, v2, p[2].x(),
+ p[2].y(), u2, v1, p[3].x(), p[3].y(), u1, v1,
+ glyph->mCacheTexture);
}
void Font::drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
- uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds, const float* pos) {
+ uint32_t bitmapWidth, uint32_t bitmapHeight, Rect* bounds,
+ const float* pos) {
int dstX = x + glyph->mBitmapLeft;
int dstY = y + glyph->mBitmapTop;
@@ -221,12 +220,11 @@
const uint8_t* cacheBuffer = pixelBuffer->map();
for (uint32_t cacheY = startY, bitmapY = dstY * bitmapWidth; cacheY < endY;
- cacheY += srcStride, bitmapY += bitmapWidth) {
-
+ cacheY += srcStride, bitmapY += bitmapWidth) {
for (uint32_t i = 0; i < glyph->mBitmapWidth; ++i) {
uint8_t* dst = &(bitmap[bitmapY + dstX + i]);
- const uint8_t& src = cacheBuffer[
- cacheY + (glyph->mStartX + i)*formatSize + alpha_channel_offset];
+ const uint8_t& src =
+ cacheBuffer[cacheY + (glyph->mStartX + i) * formatSize + alpha_channel_offset];
// Add alpha values to a max of 255, full opacity. This is done to handle
// fonts/strings where glyphs overlap.
*dst = std::min(*dst + src, 255);
@@ -235,7 +233,7 @@
}
void Font::drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
- SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
+ SkPathMeasure& measure, SkPoint* position, SkVector* tangent) {
const float halfWidth = glyph->mBitmapWidth * 0.5f;
const float height = glyph->mBitmapHeight;
@@ -249,13 +247,13 @@
// Move along the tangent and offset by the normal
destination[0].set(-tangent->fX * halfWidth - tangent->fY * vOffset,
- -tangent->fY * halfWidth + tangent->fX * vOffset);
+ -tangent->fY * halfWidth + tangent->fX * vOffset);
destination[1].set(tangent->fX * halfWidth - tangent->fY * vOffset,
- tangent->fY * halfWidth + tangent->fX * vOffset);
+ tangent->fY * halfWidth + tangent->fX * vOffset);
destination[2].set(destination[1].fX + tangent->fY * height,
- destination[1].fY - tangent->fX * height);
+ destination[1].fY - tangent->fX * height);
destination[3].set(destination[0].fX + tangent->fY * height,
- destination[0].fY - tangent->fX * height);
+ destination[0].fY - tangent->fX * height);
const float u1 = glyph->mBitmapMinU;
const float u2 = glyph->mBitmapMaxU;
@@ -263,14 +261,10 @@
const float v2 = glyph->mBitmapMaxV;
mState->appendRotatedMeshQuad(
- position->x() + destination[0].x(),
- position->y() + destination[0].y(), u1, v2,
- position->x() + destination[1].x(),
- position->y() + destination[1].y(), u2, v2,
- position->x() + destination[2].x(),
- position->y() + destination[2].y(), u2, v1,
- position->x() + destination[3].x(),
- position->y() + destination[3].y(), u1, v1,
+ position->x() + destination[0].x(), position->y() + destination[0].y(), u1, v2,
+ position->x() + destination[1].x(), position->y() + destination[1].y(), u2, v2,
+ position->x() + destination[2].x(), position->y() + destination[2].y(), u2, v1,
+ position->x() + destination[3].x(), position->y() + destination[3].y(), u1, v1,
glyph->mCacheTexture);
}
@@ -280,7 +274,8 @@
// Is the glyph still in texture cache?
if (!cachedGlyph->mIsValid) {
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
- SkAutoGlyphCacheNoGamma autoCache(*paint, &surfaceProps, &mDescription.mLookupTransform);
+ SkAutoGlyphCacheNoGamma autoCache(*paint, &surfaceProps,
+ &mDescription.mLookupTransform);
const SkGlyph& skiaGlyph = GET_METRICS(autoCache.getCache(), textUnit);
updateGlyphCache(paint, skiaGlyph, autoCache.getCache(), cachedGlyph, precaching);
}
@@ -291,14 +286,13 @@
return cachedGlyph;
}
-void Font::render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions) {
- render(paint, glyphs, numGlyphs, x, y, FRAMEBUFFER, nullptr,
- 0, 0, nullptr, positions);
+void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ const float* positions) {
+ render(paint, glyphs, numGlyphs, x, y, FRAMEBUFFER, nullptr, 0, 0, nullptr, positions);
}
-void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs,
- const SkPath* path, float hOffset, float vOffset) {
+void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkPath* path,
+ float hOffset, float vOffset) {
if (numGlyphs == 0 || glyphs == nullptr) {
return;
}
@@ -345,8 +339,8 @@
}
}
-void Font::measure(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, Rect *bounds, const float* positions) {
+void Font::measure(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, Rect* bounds,
+ const float* positions) {
if (bounds == nullptr) {
ALOGE("No return rectangle provided to measure text");
return;
@@ -374,21 +368,19 @@
}
}
-void Font::render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
- uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* positions) {
+void Font::render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ RenderMode mode, uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH,
+ Rect* bounds, const float* positions) {
if (numGlyphs == 0 || glyphs == nullptr) {
return;
}
- static RenderGlyph gRenderGlyph[] = {
- &android::uirenderer::Font::drawCachedGlyph,
- &android::uirenderer::Font::drawCachedGlyphTransformed,
- &android::uirenderer::Font::drawCachedGlyphBitmap,
- &android::uirenderer::Font::drawCachedGlyphBitmap,
- &android::uirenderer::Font::measureCachedGlyph,
- &android::uirenderer::Font::measureCachedGlyph
- };
+ static RenderGlyph gRenderGlyph[] = {&android::uirenderer::Font::drawCachedGlyph,
+ &android::uirenderer::Font::drawCachedGlyphTransformed,
+ &android::uirenderer::Font::drawCachedGlyphBitmap,
+ &android::uirenderer::Font::drawCachedGlyphBitmap,
+ &android::uirenderer::Font::measureCachedGlyph,
+ &android::uirenderer::Font::measureCachedGlyph};
RenderGlyph render = gRenderGlyph[(mode << 1) + !mIdentityTransform];
int glyphsCount = 0;
@@ -406,13 +398,12 @@
// If it's still not valid, we couldn't cache it, so we shouldn't
// draw garbage; also skip empty glyphs (spaces)
if (cachedGlyph->mIsValid && cachedGlyph->mCacheTexture) {
- int penX = x + (int) roundf(positions[(glyphsCount << 1)]);
- int penY = y + (int) roundf(positions[(glyphsCount << 1) + 1]);
+ int penX = x + (int)roundf(positions[(glyphsCount << 1)]);
+ int penY = y + (int)roundf(positions[(glyphsCount << 1) + 1]);
#ifdef BUGREPORT_FONT_CACHE_USAGE
mState->historyTracker().glyphRendered(cachedGlyph, penX, penY);
#endif
- (*this.*render)(cachedGlyph, penX, penY,
- bitmap, bitmapW, bitmapH, bounds, positions);
+ (*this.*render)(cachedGlyph, penX, penY, bitmap, bitmapW, bitmapH, bounds, positions);
} else {
#ifdef BUGREPORT_FONT_CACHE_USAGE
mState->historyTracker().glyphRendered(cachedGlyph, -1, -1);
@@ -424,7 +415,7 @@
}
void Font::updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
- SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching) {
+ SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching) {
glyph->mAdvanceX = skiaGlyph.fAdvanceX;
glyph->mAdvanceY = skiaGlyph.fAdvanceY;
glyph->mBitmapLeft = skiaGlyph.fLeft;
@@ -458,10 +449,10 @@
uint32_t cacheWidth = glyph->mCacheTexture->getWidth();
uint32_t cacheHeight = glyph->mCacheTexture->getHeight();
- glyph->mBitmapMinU = startX / (float) cacheWidth;
- glyph->mBitmapMinV = startY / (float) cacheHeight;
- glyph->mBitmapMaxU = endX / (float) cacheWidth;
- glyph->mBitmapMaxV = endY / (float) cacheHeight;
+ glyph->mBitmapMinU = startX / (float)cacheWidth;
+ glyph->mBitmapMinV = startY / (float)cacheHeight;
+ glyph->mBitmapMaxU = endX / (float)cacheWidth;
+ glyph->mBitmapMaxV = endY / (float)cacheHeight;
mState->setTextureDirty();
}
@@ -495,5 +486,5 @@
return font;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/Font.h b/libs/hwui/font/Font.h
index 504dabb..85221bc 100644
--- a/libs/hwui/font/Font.h
+++ b/libs/hwui/font/Font.h
@@ -21,14 +21,14 @@
#include <utils/KeyedVector.h>
-#include <SkScalar.h>
#include <SkPaint.h>
#include <SkPathMeasure.h>
+#include <SkScalar.h>
#include <SkTypeface.h>
-#include "FontUtil.h"
-#include "../Rect.h"
#include "../Matrix.h"
+#include "../Rect.h"
+#include "FontUtil.h"
class SkGlyphCache;
@@ -49,9 +49,7 @@
*/
class Font {
public:
- enum Style {
- kFakeBold = 1
- };
+ enum Style { kFakeBold = 1 };
struct FontDescription {
FontDescription(const SkPaint* paint, const SkMatrix& matrix);
@@ -60,13 +58,9 @@
hash_t hash() const;
- bool operator==(const FontDescription& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const FontDescription& other) const { return compare(*this, other) == 0; }
- bool operator!=(const FontDescription& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const FontDescription& other) const { return compare(*this, other) != 0; }
SkFontID mFontId;
float mFontSize;
@@ -83,15 +77,13 @@
~Font();
- void render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, const float* positions);
+ void render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ const float* positions);
- void render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, const SkPath* path, float hOffset, float vOffset);
+ void render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, const SkPath* path,
+ float hOffset, float vOffset);
- const Font::FontDescription& getDescription() const {
- return mDescription;
- }
+ const Font::FontDescription& getDescription() const { return mDescription; }
/**
* Creates a new font associated with the specified font state.
@@ -103,8 +95,8 @@
Font(FontRenderer* state, const Font::FontDescription& desc);
- typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*,
- uint32_t, uint32_t, Rect*, const float*);
+ typedef void (Font::*RenderGlyph)(CachedGlyphInfo*, int, int, uint8_t*, uint32_t, uint32_t,
+ Rect*, const float*);
enum RenderMode {
FRAMEBUFFER,
@@ -114,36 +106,33 @@
void precache(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs);
- void render(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, int x, int y, RenderMode mode, uint8_t *bitmap,
- uint32_t bitmapW, uint32_t bitmapH, Rect *bounds, const float* positions);
+ void render(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, int x, int y,
+ RenderMode mode, uint8_t* bitmap, uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
+ const float* positions);
- void measure(const SkPaint* paint, const glyph_t* glyphs,
- int numGlyphs, Rect *bounds, const float* positions);
+ void measure(const SkPaint* paint, const glyph_t* glyphs, int numGlyphs, Rect* bounds,
+ const float* positions);
void invalidateTextureCache(CacheTexture* cacheTexture = nullptr);
CachedGlyphInfo* cacheGlyph(const SkPaint* paint, glyph_t glyph, bool precaching);
void updateGlyphCache(const SkPaint* paint, const SkGlyph& skiaGlyph,
- SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching);
+ SkGlyphCache* skiaGlyphCache, CachedGlyphInfo* glyph, bool precaching);
- void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
- void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
- void drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
- void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y,
- uint8_t *bitmap, uint32_t bitmapW, uint32_t bitmapH,
- Rect* bounds, const float* pos);
+ void measureCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW,
+ uint32_t bitmapH, Rect* bounds, const float* pos);
+ void drawCachedGlyph(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap, uint32_t bitmapW,
+ uint32_t bitmapH, Rect* bounds, const float* pos);
+ void drawCachedGlyphTransformed(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds,
+ const float* pos);
+ void drawCachedGlyphBitmap(CachedGlyphInfo* glyph, int x, int y, uint8_t* bitmap,
+ uint32_t bitmapW, uint32_t bitmapH, Rect* bounds, const float* pos);
void drawCachedGlyph(CachedGlyphInfo* glyph, float x, float hOffset, float vOffset,
- SkPathMeasure& measure, SkPoint* position, SkVector* tangent);
+ SkPathMeasure& measure, SkPoint* position, SkVector* tangent);
CachedGlyphInfo* getCachedGlyph(const SkPaint* paint, glyph_t textUnit,
- bool precaching = false);
+ bool precaching = false);
FontRenderer* mState;
FontDescription mDescription;
@@ -154,8 +143,7 @@
bool mIdentityTransform;
};
-inline int strictly_order_type(const Font::FontDescription& lhs,
- const Font::FontDescription& rhs) {
+inline int strictly_order_type(const Font::FontDescription& lhs, const Font::FontDescription& rhs) {
return Font::FontDescription::compare(lhs, rhs) < 0;
}
@@ -167,7 +155,7 @@
return entry.hash();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_FONT_H
+#endif // ANDROID_HWUI_FONT_H
diff --git a/libs/hwui/font/FontCacheHistoryTracker.cpp b/libs/hwui/font/FontCacheHistoryTracker.cpp
index a2bfb27..5b61c49 100644
--- a/libs/hwui/font/FontCacheHistoryTracker.cpp
+++ b/libs/hwui/font/FontCacheHistoryTracker.cpp
@@ -16,15 +16,15 @@
#include "FontCacheHistoryTracker.h"
-#include "CachedGlyphInfo.h"
#include "CacheTexture.h"
+#include "CachedGlyphInfo.h"
namespace android {
namespace uirenderer {
void FontCacheHistoryTracker::dumpCachedGlyph(String8& log, const CachedGlyph& glyph) {
log.appendFormat("glyph (texture %p, position: (%d, %d), size: %dx%d, gen: %d)", glyph.texture,
- glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
+ glyph.startX, glyph.startY, glyph.bitmapW, glyph.bitmapH, glyph.generation);
}
void FontCacheHistoryTracker::dumpRenderEntry(String8& log, const RenderEntry& entry) {
@@ -40,7 +40,7 @@
void FontCacheHistoryTracker::dumpUploadEntry(String8& log, const CachedGlyph& glyph) {
if (glyph.bitmapW == 0 && glyph.bitmapH == 0) {
log.appendFormat(" cleared cachetexture %p in gen %d\n", glyph.texture,
- glyph.generation);
+ glyph.generation);
} else {
log.appendFormat(" uploaded ");
dumpCachedGlyph(log, glyph);
@@ -73,7 +73,7 @@
}
void FontCacheHistoryTracker::glyphUploaded(CacheTexture* texture, uint32_t x, uint32_t y,
- uint16_t glyphW, uint16_t glyphH) {
+ uint16_t glyphW, uint16_t glyphH) {
CachedGlyph& glyph = mUploadHistory.next();
glyph.generation = generation;
glyph.texture = texture;
@@ -96,5 +96,5 @@
void FontCacheHistoryTracker::frameCompleted() {
generation++;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/font/FontCacheHistoryTracker.h b/libs/hwui/font/FontCacheHistoryTracker.h
index f1d9b9f..4b9cecc 100644
--- a/libs/hwui/font/FontCacheHistoryTracker.h
+++ b/libs/hwui/font/FontCacheHistoryTracker.h
@@ -35,6 +35,7 @@
void frameCompleted();
void dump(String8& log) const;
+
private:
struct CachedGlyph {
void* texture;
@@ -60,5 +61,5 @@
uint16_t generation = 0;
};
-}; // namespace uirenderer
-}; // namespace android
\ No newline at end of file
+}; // namespace uirenderer
+}; // namespace android
\ No newline at end of file
diff --git a/libs/hwui/font/FontUtil.h b/libs/hwui/font/FontUtil.h
index d4b4ff9..596e153 100644
--- a/libs/hwui/font/FontUtil.h
+++ b/libs/hwui/font/FontUtil.h
@@ -26,11 +26,11 @@
///////////////////////////////////////////////////////////////////////////////
#ifdef TEXTURE_BORDER_SIZE
- #if TEXTURE_BORDER_SIZE != 1
- #error TEXTURE_BORDER_SIZE other than 1 is not currently supported
- #endif
+#if TEXTURE_BORDER_SIZE != 1
+#error TEXTURE_BORDER_SIZE other than 1 is not currently supported
+#endif
#else
- #define TEXTURE_BORDER_SIZE 1
+#define TEXTURE_BORDER_SIZE 1
#endif
#define CACHE_BLOCK_ROUNDING_SIZE 4
@@ -43,4 +43,4 @@
// [-1, 1]. Result is an integral float.
#define AUTO_KERN(prev, next) static_cast<float>(((next) - (prev) + 32) >> 6)
-#endif // ANDROID_HWUI_FONT_UTIL_H
+#endif // ANDROID_HWUI_FONT_UTIL_H
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 0aeb762..795ec5b 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -17,38 +17,37 @@
#include "Caches.h"
#include "renderthread/EglManager.h"
-#include "renderthread/RenderThread.h"
#include "renderthread/RenderProxy.h"
+#include "renderthread/RenderThread.h"
#include "utils/Color.h"
#include <sys/mman.h>
-#include <log/log.h>
#include <cutils/ashmem.h>
+#include <log/log.h>
-#include <private/gui/ComposerService.h>
#include <binder/IServiceManager.h>
+#include <private/gui/ComposerService.h>
#include <ui/PixelFormat.h>
#include <SkCanvas.h>
-#include <SkToSRGBColorFilter.h>
#include <SkImagePriv.h>
+#include <SkToSRGBColorFilter.h>
namespace android {
static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
int32_t rowBytes32 = SkToS32(rowBytes);
- int64_t bigSize = (int64_t) height * rowBytes32;
+ int64_t bigSize = (int64_t)height * rowBytes32;
if (rowBytes32 < 0 || !sk_64_isS32(bigSize)) {
- return false; // allocation will be too large
+ return false; // allocation will be too large
}
*size = sk_64_asS32(bigSize);
return true;
}
-typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info,
- size_t rowBytes);
+typedef sk_sp<Bitmap> (*AllocPixelRef)(size_t allocSize, const SkImageInfo& info, size_t rowBytes);
static sk_sp<Bitmap> allocateBitmap(SkBitmap* bitmap, AllocPixelRef alloc) {
const SkImageInfo& info = bitmap->info();
@@ -74,7 +73,7 @@
}
sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(SkBitmap* bitmap) {
- return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
+ return allocateBitmap(bitmap, &Bitmap::allocateAshmemBitmap);
}
static sk_sp<Bitmap> allocateHeapBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
@@ -90,7 +89,7 @@
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(SkBitmap* bitmap) {
- return allocateBitmap(bitmap, &android::allocateHeapBitmap);
+ return allocateBitmap(bitmap, &android::allocateHeapBitmap);
}
sk_sp<Bitmap> Bitmap::allocateHeapBitmap(const SkImageInfo& info) {
@@ -102,8 +101,7 @@
return android::allocateHeapBitmap(size, info, info.minRowBytes());
}
-sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info,
- size_t rowBytes) {
+sk_sp<Bitmap> Bitmap::allocateAshmemBitmap(size_t size, const SkImageInfo& info, size_t rowBytes) {
// Create new ashmem region with read/write priv
int fd = ashmem_create_region("bitmap", size);
if (fd < 0) {
@@ -125,25 +123,25 @@
}
void FreePixelRef(void* addr, void* context) {
- auto pixelRef = (SkPixelRef*) context;
+ auto pixelRef = (SkPixelRef*)context;
pixelRef->unref();
}
sk_sp<Bitmap> Bitmap::createFrom(const SkImageInfo& info, SkPixelRef& pixelRef) {
pixelRef.ref();
- return sk_sp<Bitmap>(new Bitmap((void*) pixelRef.pixels(), (void*) &pixelRef, FreePixelRef,
- info, pixelRef.rowBytes()));
+ return sk_sp<Bitmap>(new Bitmap((void*)pixelRef.pixels(), (void*)&pixelRef, FreePixelRef, info,
+ pixelRef.rowBytes()));
}
sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
PixelFormat format = graphicBuffer->getPixelFormat();
if (!graphicBuffer.get() ||
- (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
+ (format != PIXEL_FORMAT_RGBA_8888 && format != PIXEL_FORMAT_RGBA_FP16)) {
return nullptr;
}
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeSRGB());
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType,
+ SkColorSpace::MakeSRGB());
return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}
@@ -155,8 +153,8 @@
// Need to validate the alpha type to filter against the color type
// to prevent things like a non-opaque RGB565 bitmap
SkAlphaType alphaType;
- LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
- info.colorType(), info.alphaType(), &alphaType),
+ LOG_ALWAYS_FATAL_IF(
+ !SkColorTypeValidateAlphaType(info.colorType(), info.alphaType(), &alphaType),
"Failed to validate alpha type!");
return info.makeAlphaType(alphaType);
}
@@ -173,28 +171,27 @@
}
Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
- , mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::Heap) {
+ : SkPixelRef(info.width(), info.height(), address, rowBytes)
+ , mInfo(validateAlpha(info))
+ , mPixelStorageType(PixelStorageType::Heap) {
mPixelStorage.heap.address = address;
mPixelStorage.heap.size = size;
}
-Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
- , mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::External) {
+Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
+ size_t rowBytes)
+ : SkPixelRef(info.width(), info.height(), address, rowBytes)
+ , mInfo(validateAlpha(info))
+ , mPixelStorageType(PixelStorageType::External) {
mPixelStorage.external.address = address;
mPixelStorage.external.context = context;
mPixelStorage.external.freeFunc = freeFunc;
}
-Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
- const SkImageInfo& info, size_t rowBytes)
- : SkPixelRef(info.width(), info.height(), address, rowBytes)
- , mInfo(validateAlpha(info))
- , mPixelStorageType(PixelStorageType::Ashmem) {
+Bitmap::Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes)
+ : SkPixelRef(info.width(), info.height(), address, rowBytes)
+ , mInfo(validateAlpha(info))
+ , mPixelStorageType(PixelStorageType::Ashmem) {
mPixelStorage.ashmem.address = address;
mPixelStorage.ashmem.fd = fd;
mPixelStorage.ashmem.size = mappedSize;
@@ -207,32 +204,31 @@
, mPixelStorageType(PixelStorageType::Hardware) {
mPixelStorage.hardware.buffer = buffer;
buffer->incStrong(buffer);
- setImmutable(); // HW bitmaps are always immutable
+ setImmutable(); // HW bitmaps are always immutable
if (uirenderer::Properties::isSkiaEnabled()) {
mImage = SkImage::MakeFromAHardwareBuffer(reinterpret_cast<AHardwareBuffer*>(buffer),
- mInfo.alphaType(), mInfo.refColorSpace());
+ mInfo.alphaType(), mInfo.refColorSpace());
}
}
Bitmap::~Bitmap() {
switch (mPixelStorageType) {
- case PixelStorageType::External:
- mPixelStorage.external.freeFunc(mPixelStorage.external.address,
- mPixelStorage.external.context);
- break;
- case PixelStorageType::Ashmem:
- munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
- close(mPixelStorage.ashmem.fd);
- break;
- case PixelStorageType::Heap:
- free(mPixelStorage.heap.address);
- break;
- case PixelStorageType::Hardware:
- auto buffer = mPixelStorage.hardware.buffer;
- buffer->decStrong(buffer);
- mPixelStorage.hardware.buffer = nullptr;
- break;
-
+ case PixelStorageType::External:
+ mPixelStorage.external.freeFunc(mPixelStorage.external.address,
+ mPixelStorage.external.context);
+ break;
+ case PixelStorageType::Ashmem:
+ munmap(mPixelStorage.ashmem.address, mPixelStorage.ashmem.size);
+ close(mPixelStorage.ashmem.fd);
+ break;
+ case PixelStorageType::Heap:
+ free(mPixelStorage.heap.address);
+ break;
+ case PixelStorageType::Hardware:
+ auto buffer = mPixelStorage.hardware.buffer;
+ buffer->decStrong(buffer);
+ mPixelStorage.hardware.buffer = nullptr;
+ break;
}
android::uirenderer::renderthread::RenderProxy::onBitmapDestroyed(getStableID());
@@ -248,32 +244,32 @@
void* Bitmap::getStorage() const {
switch (mPixelStorageType) {
- case PixelStorageType::External:
- return mPixelStorage.external.address;
- case PixelStorageType::Ashmem:
- return mPixelStorage.ashmem.address;
- case PixelStorageType::Heap:
- return mPixelStorage.heap.address;
- case PixelStorageType::Hardware:
- return nullptr;
+ case PixelStorageType::External:
+ return mPixelStorage.external.address;
+ case PixelStorageType::Ashmem:
+ return mPixelStorage.ashmem.address;
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.address;
+ case PixelStorageType::Hardware:
+ return nullptr;
}
}
int Bitmap::getAshmemFd() const {
switch (mPixelStorageType) {
- case PixelStorageType::Ashmem:
- return mPixelStorage.ashmem.fd;
- default:
- return -1;
+ case PixelStorageType::Ashmem:
+ return mPixelStorage.ashmem.fd;
+ default:
+ return -1;
}
}
size_t Bitmap::getAllocationByteCount() const {
switch (mPixelStorageType) {
- case PixelStorageType::Heap:
- return mPixelStorage.heap.size;
- default:
- return rowBytes() * height();
+ case PixelStorageType::Heap:
+ return mPixelStorage.heap.size;
+ default:
+ return rowBytes() * height();
}
}
@@ -294,7 +290,8 @@
if (isHardware()) {
if (uirenderer::Properties::isSkiaEnabled()) {
outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
- info().colorType(), info().alphaType(), nullptr));
+ info().colorType(), info().alphaType(),
+ nullptr));
} else {
outBitmap->allocPixels(info());
}
@@ -330,11 +327,11 @@
// TODO: refactor Bitmap to not derive from SkPixelRef, which would allow caching here.
image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
}
- if(uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr
- && !image->colorSpace()->isSRGB()) {
+ if (uirenderer::Properties::isSkiaEnabled() && image->colorSpace() != nullptr &&
+ !image->colorSpace()->isSRGB()) {
*outputColorFilter = SkToSRGBColorFilter::Make(image->refColorSpace());
}
return image;
}
-} // namespace android
+} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index fc27af9f..a75276f 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -19,11 +19,11 @@
#include <SkColorFilter.h>
#include <SkColorSpace.h>
#include <SkImage.h>
+#include <SkImage.h>
#include <SkImageInfo.h>
#include <SkPixelRef.h>
#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
-#include <SkImage.h>
namespace android {
@@ -36,7 +36,7 @@
namespace uirenderer {
namespace renderthread {
- class RenderThread;
+class RenderThread;
}
}
@@ -53,17 +53,16 @@
static sk_sp<Bitmap> allocateAshmemBitmap(SkBitmap* bitmap);
static sk_sp<Bitmap> allocateAshmemBitmap(size_t allocSize, const SkImageInfo& info,
- size_t rowBytes);
+ size_t rowBytes);
static sk_sp<Bitmap> createFrom(sp<GraphicBuffer> graphicBuffer);
static sk_sp<Bitmap> createFrom(const SkImageInfo&, SkPixelRef&);
Bitmap(void* address, size_t allocSize, const SkImageInfo& info, size_t rowBytes);
- Bitmap(void* address, void* context, FreeFunc freeFunc,
- const SkImageInfo& info, size_t rowBytes);
- Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
- size_t rowBytes);
+ Bitmap(void* address, void* context, FreeFunc freeFunc, const SkImageInfo& info,
+ size_t rowBytes);
+ Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info, size_t rowBytes);
Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
int rowBytesAsPixels() const {
@@ -85,15 +84,11 @@
bool isOpaque() const { return mInfo.isOpaque(); }
SkColorType colorType() const { return mInfo.colorType(); }
- const SkImageInfo& info() const {
- return mInfo;
- }
+ const SkImageInfo& info() const { return mInfo; }
void getBounds(SkRect* bounds) const;
- bool isHardware() const {
- return mPixelStorageType == PixelStorageType::Hardware;
- }
+ bool isHardware() const { return mPixelStorageType == PixelStorageType::Hardware; }
GraphicBuffer* graphicBuffer();
@@ -109,6 +104,7 @@
* buffer that has no colorspace defined).
*/
sk_sp<SkImage> makeImage(sk_sp<SkColorFilter>* outputColorFilter);
+
private:
virtual ~Bitmap();
void* getStorage() const;
@@ -139,7 +135,7 @@
} hardware;
} mPixelStorage;
- sk_sp<SkImage> mImage; // Cache is used only for HW Bitmaps with Skia pipeline.
+ sk_sp<SkImage> mImage; // Cache is used only for HW Bitmaps with Skia pipeline.
};
-} //namespace android
+} // namespace android
diff --git a/libs/hwui/hwui/Canvas.cpp b/libs/hwui/hwui/Canvas.cpp
index 6f05799..75e414e 100644
--- a/libs/hwui/hwui/Canvas.cpp
+++ b/libs/hwui/hwui/Canvas.cpp
@@ -16,13 +16,13 @@
#include "Canvas.h"
-#include "RecordingCanvas.h"
-#include "RenderNode.h"
#include "MinikinUtils.h"
#include "Paint.h"
#include "Properties.h"
-#include "pipeline/skia/SkiaRecordingCanvas.h"
+#include "RecordingCanvas.h"
+#include "RenderNode.h"
#include "Typeface.h"
+#include "pipeline/skia/SkiaRecordingCanvas.h"
#include <SkDrawFilter.h>
@@ -36,7 +36,7 @@
}
static inline void drawStroke(SkScalar left, SkScalar right, SkScalar top, SkScalar thickness,
- const SkPaint& paint, Canvas* canvas) {
+ const SkPaint& paint, Canvas* canvas) {
const SkScalar strokeWidth = fmax(thickness, 1.0f);
const SkScalar bottom = top + strokeWidth;
canvas->drawRect(left, top, right, bottom, paint);
@@ -91,20 +91,18 @@
class DrawTextFunctor {
public:
- DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas,
- const SkPaint& paint, float x, float y, minikin::MinikinRect& bounds,
- float totalAdvance)
- : layout(layout)
- , canvas(canvas)
- , paint(paint)
- , x(x)
- , y(y)
- , bounds(bounds)
- , totalAdvance(totalAdvance) {
- }
+ DrawTextFunctor(const minikin::Layout& layout, Canvas* canvas, const SkPaint& paint, float x,
+ float y, minikin::MinikinRect& bounds, float totalAdvance)
+ : layout(layout)
+ , canvas(canvas)
+ , paint(paint)
+ , x(x)
+ , y(y)
+ , bounds(bounds)
+ , totalAdvance(totalAdvance) {}
void operator()(size_t start, size_t end) {
- auto glyphFunc = [&] (uint16_t* text, float* positions) {
+ auto glyphFunc = [&](uint16_t* text, float* positions) {
if (canvas->drawTextAbsolutePos()) {
for (size_t i = start, textIndex = 0, posIndex = 0; i < end; i++) {
text[textIndex++] = layout.getGlyphId(i);
@@ -133,20 +131,21 @@
simplifyPaint(darken ? SK_ColorWHITE : SK_ColorBLACK, &outlinePaint);
outlinePaint.setStyle(SkPaint::kStrokeAndFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, outlinePaint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ bounds.mRight, bounds.mBottom, totalAdvance);
// inner
SkPaint innerPaint(paint);
simplifyPaint(darken ? SK_ColorBLACK : SK_ColorWHITE, &innerPaint);
innerPaint.setStyle(SkPaint::kFill_Style);
canvas->drawGlyphs(glyphFunc, glyphCount, innerPaint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ bounds.mRight, bounds.mBottom, totalAdvance);
} else {
// standard draw path
canvas->drawGlyphs(glyphFunc, glyphCount, paint, x, y, bounds.mLeft, bounds.mTop,
- bounds.mRight, bounds.mBottom, totalAdvance);
+ bounds.mRight, bounds.mBottom, totalAdvance);
}
}
+
private:
const minikin::Layout& layout;
Canvas* canvas;
@@ -157,14 +156,14 @@
float totalAdvance;
};
-void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount,
- float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint,
- const Typeface* typeface) {
+void Canvas::drawText(const uint16_t* text, int start, int count, int contextCount, float x,
+ float y, minikin::Bidi bidiFlags, const Paint& origPaint,
+ const Typeface* typeface) {
// minikin may modify the original paint
Paint paint(origPaint);
- minikin::Layout layout = MinikinUtils::doLayout(
- &paint, bidiFlags, typeface, text, start, count, contextCount);
+ minikin::Layout layout =
+ MinikinUtils::doLayout(&paint, bidiFlags, typeface, text, start, count, contextCount);
x += MinikinUtils::xOffsetForTextAlign(&paint, layout);
@@ -186,18 +185,18 @@
class DrawTextOnPathFunctor {
public:
DrawTextOnPathFunctor(const minikin::Layout& layout, Canvas* canvas, float hOffset,
- float vOffset, const Paint& paint, const SkPath& path)
- : layout(layout)
- , canvas(canvas)
- , hOffset(hOffset)
- , vOffset(vOffset)
- , paint(paint)
- , path(path) {
- }
+ float vOffset, const Paint& paint, const SkPath& path)
+ : layout(layout)
+ , canvas(canvas)
+ , hOffset(hOffset)
+ , vOffset(vOffset)
+ , paint(paint)
+ , path(path) {}
void operator()(size_t start, size_t end) {
canvas->drawLayoutOnPath(layout, hOffset, vOffset, paint, path, start, end);
}
+
private:
const minikin::Layout& layout;
Canvas* canvas;
@@ -208,11 +207,11 @@
};
void Canvas::drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags,
- const SkPath& path, float hOffset, float vOffset, const Paint& paint,
- const Typeface* typeface) {
+ const SkPath& path, float hOffset, float vOffset, const Paint& paint,
+ const Typeface* typeface) {
Paint paintCopy(paint);
- minikin::Layout layout = MinikinUtils::doLayout(
- &paintCopy, bidiFlags, typeface, text, 0, count, count);
+ minikin::Layout layout =
+ MinikinUtils::doLayout(&paintCopy, bidiFlags, typeface, text, 0, count, count);
hOffset += MinikinUtils::hOffsetForTextAlign(&paintCopy, layout, path);
// Set align to left for drawing, as we don't want individual
@@ -224,4 +223,4 @@
MinikinUtils::forFontRun(layout, &paintCopy, f);
}
-} // namespace android
+} // namespace android
diff --git a/libs/hwui/hwui/Canvas.h b/libs/hwui/hwui/Canvas.h
index 0a1bae7..e682a2e 100644
--- a/libs/hwui/hwui/Canvas.h
+++ b/libs/hwui/hwui/Canvas.h
@@ -19,10 +19,10 @@
#include <cutils/compiler.h>
#include <utils/Functor.h>
+#include <androidfw/ResourceTypes.h>
#include "GlFunctorLifecycleListener.h"
#include "Properties.h"
#include "utils/Macros.h"
-#include <androidfw/ResourceTypes.h>
#include <SkBitmap.h>
#include <SkCanvas.h>
@@ -32,35 +32,35 @@
class SkVertices;
namespace minikin {
- class Layout;
- enum class Bidi : uint8_t;
+class Layout;
+enum class Bidi : uint8_t;
}
namespace android {
namespace uirenderer {
- class CanvasPropertyPaint;
- class CanvasPropertyPrimitive;
- class DeferredLayerUpdater;
- class DisplayList;
- class RenderNode;
+class CanvasPropertyPaint;
+class CanvasPropertyPrimitive;
+class DeferredLayerUpdater;
+class DisplayList;
+class RenderNode;
}
namespace SaveFlags {
// These must match the corresponding Canvas API constants.
enum {
- Matrix = 0x01,
- Clip = 0x02,
+ Matrix = 0x01,
+ Clip = 0x02,
HasAlphaLayer = 0x04,
- ClipToLayer = 0x10,
+ ClipToLayer = 0x10,
// Helper constant
- MatrixClip = Matrix | Clip,
+ MatrixClip = Matrix | Clip,
};
typedef uint32_t Flags;
-} // namespace SaveFlags
+} // namespace SaveFlags
namespace uirenderer {
class SkiaCanvasProxy;
@@ -78,7 +78,7 @@
class ANDROID_API Canvas {
public:
- virtual ~Canvas() {};
+ virtual ~Canvas(){};
static Canvas* create_canvas(const SkBitmap& bitmap);
@@ -97,8 +97,8 @@
determined based on Properties::getRenderPipelineType().
*
*/
- static WARN_UNUSED_RESULT Canvas* create_recording_canvas(int width, int height,
- uirenderer::RenderNode* renderNode = nullptr);
+ static WARN_UNUSED_RESULT Canvas* create_recording_canvas(
+ int width, int height, uirenderer::RenderNode* renderNode = nullptr);
/**
* Create a new Canvas object which delegates to an SkCanvas.
@@ -126,40 +126,43 @@
*/
virtual SkCanvas* asSkCanvas() = 0;
-
virtual void setBitmap(const SkBitmap& bitmap) = 0;
virtual bool isOpaque() = 0;
virtual int width() = 0;
virtual int height() = 0;
-// ----------------------------------------------------------------------------
-// View System operations (not exposed in public Canvas API)
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // View System operations (not exposed in public Canvas API)
+ // ----------------------------------------------------------------------------
virtual void resetRecording(int width, int height,
- uirenderer::RenderNode* renderNode = nullptr) = 0;
+ uirenderer::RenderNode* renderNode = nullptr) = 0;
virtual uirenderer::DisplayList* finishRecording() = 0;
virtual void insertReorderBarrier(bool enableReorder) = 0;
bool isHighContrastText() const { return uirenderer::Properties::enableHighContrastText; }
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) = 0;
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) = 0;
virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) = 0;
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) = 0;
virtual void drawLayer(uirenderer::DeferredLayerUpdater* layerHandle) = 0;
virtual void drawRenderNode(uirenderer::RenderNode* renderNode) = 0;
virtual void callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) = 0;
+ uirenderer::GlFunctorLifecycleListener* listener) = 0;
-// ----------------------------------------------------------------------------
-// Canvas state operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // Canvas state operations
+ // ----------------------------------------------------------------------------
// Save (layer)
virtual int getSaveCount() const = 0;
@@ -167,10 +170,10 @@
virtual void restore() = 0;
virtual void restoreToCount(int saveCount) = 0;
- virtual int saveLayer(float left, float top, float right, float bottom,
- const SkPaint* paint, SaveFlags::Flags flags) = 0;
- virtual int saveLayerAlpha(float left, float top, float right, float bottom,
- int alpha, SaveFlags::Flags flags) = 0;
+ virtual int saveLayer(float left, float top, float right, float bottom, const SkPaint* paint,
+ SaveFlags::Flags flags) = 0;
+ virtual int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
+ SaveFlags::Flags flags) = 0;
// Matrix
virtual void getMatrix(SkMatrix* outMatrix) const = 0;
@@ -187,8 +190,7 @@
virtual bool quickRejectRect(float left, float top, float right, float bottom) const = 0;
virtual bool quickRejectPath(const SkPath& path) const = 0;
- virtual bool clipRect(float left, float top, float right, float bottom,
- SkClipOp op) = 0;
+ virtual bool clipRect(float left, float top, float right, float bottom, SkClipOp op) = 0;
virtual bool clipPath(const SkPath* path, SkClipOp op) = 0;
// filters
@@ -198,9 +200,9 @@
// WebView only
virtual SkCanvasState* captureCanvasState() const { return nullptr; }
-// ----------------------------------------------------------------------------
-// Canvas draw operations
-// ----------------------------------------------------------------------------
+ // ----------------------------------------------------------------------------
+ // Canvas draw operations
+ // ----------------------------------------------------------------------------
virtual void drawColor(int color, SkBlendMode mode) = 0;
virtual void drawPaint(const SkPaint& paint) = 0;
@@ -208,34 +210,32 @@
virtual void drawPoint(float x, float y, const SkPaint& paint) = 0;
virtual void drawPoints(const float* points, int floatCount, const SkPaint& paint) = 0;
virtual void drawLine(float startX, float startY, float stopX, float stopY,
- const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
virtual void drawLines(const float* points, int floatCount, const SkPaint& paint) = 0;
virtual void drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
virtual void drawRegion(const SkRegion& region, const SkPaint& paint) = 0;
- virtual void drawRoundRect(float left, float top, float right, float bottom,
- float rx, float ry, const SkPaint& paint) = 0;
+ virtual void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
+ const SkPaint& paint) = 0;
virtual void drawCircle(float x, float y, float radius, const SkPaint& paint) = 0;
virtual void drawOval(float left, float top, float right, float bottom,
- const SkPaint& paint) = 0;
- virtual void drawArc(float left, float top, float right, float bottom,
- float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
+ const SkPaint& paint) = 0;
+ virtual void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, bool useCenter, const SkPaint& paint) = 0;
virtual void drawPath(const SkPath& path, const SkPaint& paint) = 0;
virtual void drawVertices(const SkVertices*, SkBlendMode, const SkPaint& paint) = 0;
// Bitmap-based
- virtual void drawBitmap(Bitmap& bitmap, float left, float top,
- const SkPaint* paint) = 0;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) = 0;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) = 0;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) = 0;
virtual void drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
- const float* vertices, const int* colors, const SkPaint* paint) = 0;
- virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) = 0;
+ const float* vertices, const int* colors, const SkPaint* paint) = 0;
+ virtual void drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) = 0;
/**
* Specifies if the positions passed to ::drawText are absolute or relative
@@ -255,13 +255,12 @@
* Converts utf16 text to glyphs, calculating position and boundary,
* and delegating the final draw to virtual drawGlyphs method.
*/
- void drawText(const uint16_t* text, int start, int count, int contextCount,
- float x, float y, minikin::Bidi bidiFlags, const Paint& origPaint,
- const Typeface* typeface);
+ void drawText(const uint16_t* text, int start, int count, int contextCount, float x, float y,
+ minikin::Bidi bidiFlags, const Paint& origPaint, const Typeface* typeface);
void drawTextOnPath(const uint16_t* text, int count, minikin::Bidi bidiFlags,
- const SkPath& path, float hOffset, float vOffset, const Paint& paint,
- const Typeface* typeface);
+ const SkPath& path, float hOffset, float vOffset, const Paint& paint,
+ const Typeface* typeface);
protected:
void drawTextDecorations(float x, float y, float length, const SkPaint& paint);
@@ -272,13 +271,14 @@
* totalAdvance: used to define width of text decorations (underlines, strikethroughs).
*/
virtual void drawGlyphs(ReadGlyphFunc glyphFunc, int count, const SkPaint& paint, float x,
- float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
- float totalAdvance) = 0;
+ float y, float boundsLeft, float boundsTop, float boundsRight,
+ float boundsBottom, float totalAdvance) = 0;
virtual void drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
- const SkPaint& paint, const SkPath& path, size_t start, size_t end) = 0;
+ const SkPaint& paint, const SkPath& path, size_t start,
+ size_t end) = 0;
friend class DrawTextFunctor;
friend class DrawTextOnPathFunctor;
friend class uirenderer::SkiaCanvasProxy;
};
-}; // namespace android
+}; // namespace android
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a5b4c42..5d33860 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -16,37 +16,41 @@
#include "MinikinSkia.h"
-#include <log/log.h>
#include <SkFontDescriptor.h>
#include <SkFontMgr.h>
#include <SkPaint.h>
#include <SkTypeface.h>
+#include <log/log.h>
namespace android {
MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
- int ttcIndex, const std::vector<minikin::FontVariation>& axes) :
- minikin::MinikinFont(typeface->uniqueID()), mTypeface(std::move(typeface)), mFontData(fontData),
- mFontSize(fontSize), mTtcIndex(ttcIndex), mAxes(axes) {
-}
+ int ttcIndex, const std::vector<minikin::FontVariation>& axes)
+ : minikin::MinikinFont(typeface->uniqueID())
+ , mTypeface(std::move(typeface))
+ , mFontData(fontData)
+ , mFontSize(fontSize)
+ , mTtcIndex(ttcIndex)
+ , mAxes(axes) {}
static void MinikinFontSkia_SetSkiaPaint(const minikin::MinikinFont* font, SkPaint* skPaint,
- const minikin::MinikinPaint& paint) {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) {
skPaint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
skPaint->setTextSize(paint.size);
skPaint->setTextScaleX(paint.scaleX);
skPaint->setTextSkewX(paint.skewX);
MinikinFontSkia::unpackPaintFlags(skPaint, paint.paintFlags);
// Apply font fakery on top of user-supplied flags.
- MinikinFontSkia::populateSkPaint(skPaint, font, paint.fakery);
+ MinikinFontSkia::populateSkPaint(skPaint, font, fakery);
}
-float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const {
+float MinikinFontSkia::GetHorizontalAdvance(uint32_t glyph_id, const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkScalar skWidth;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), &skWidth, NULL);
#ifdef VERBOSE
ALOGD("width for typeface %d glyph %d = %f", mTypeface->uniqueID(), glyph_id, skWidth);
@@ -55,11 +59,12 @@
}
void MinikinFontSkia::GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
- const minikin::MinikinPaint& paint) const {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
uint16_t glyph16 = glyph_id;
SkRect skBounds;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
skPaint.getTextWidths(&glyph16, sizeof(glyph16), NULL, &skBounds);
bounds->mLeft = skBounds.fLeft;
bounds->mTop = skBounds.fTop;
@@ -68,9 +73,10 @@
}
void MinikinFontSkia::GetFontExtent(minikin::MinikinExtent* extent,
- const minikin::MinikinPaint& paint) const {
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const {
SkPaint skPaint;
- MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint);
+ MinikinFontSkia_SetSkiaPaint(this, &skPaint, paint, fakery);
SkPaint::FontMetrics metrics;
skPaint.getFontMetrics(&metrics);
extent->ascent = metrics.fAscent;
@@ -78,7 +84,7 @@
extent->line_gap = metrics.fLeading;
}
-SkTypeface *MinikinFontSkia::GetSkTypeface() const {
+SkTypeface* MinikinFontSkia::GetSkTypeface() const {
return mTypeface.get();
}
@@ -122,7 +128,7 @@
sk_sp<SkTypeface> face(fm->makeFromStream(std::move(stream), params));
return std::make_shared<MinikinFontSkia>(std::move(face), mFontData, mFontSize, ttcIndex,
- variations);
+ variations);
}
uint32_t MinikinFontSkia::packPaintFlags(const SkPaint* paint) {
@@ -130,9 +136,9 @@
SkPaint::Hinting hinting = paint->getHinting();
// select only flags that might affect text layout
flags &= (SkPaint::kAntiAlias_Flag | SkPaint::kFakeBoldText_Flag | SkPaint::kLinearText_Flag |
- SkPaint::kSubpixelText_Flag | SkPaint::kDevKernText_Flag |
- SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag |
- SkPaint::kVerticalText_Flag);
+ SkPaint::kSubpixelText_Flag | SkPaint::kDevKernText_Flag |
+ SkPaint::kEmbeddedBitmapText_Flag | SkPaint::kAutoHinting_Flag |
+ SkPaint::kVerticalText_Flag);
flags |= (hinting << 16);
return flags;
}
@@ -143,12 +149,11 @@
}
void MinikinFontSkia::populateSkPaint(SkPaint* paint, const MinikinFont* font,
- minikin::FontFakery fakery) {
+ minikin::FontFakery fakery) {
paint->setTypeface(reinterpret_cast<const MinikinFontSkia*>(font)->RefSkTypeface());
paint->setFakeBoldText(paint->isFakeBoldText() || fakery.isFakeBold());
if (fakery.isFakeItalic()) {
paint->setTextSkewX(paint->getTextSkewX() - 0.25f);
}
}
-
}
diff --git a/libs/hwui/hwui/MinikinSkia.h b/libs/hwui/hwui/MinikinSkia.h
index a19f4a7..d156598 100644
--- a/libs/hwui/hwui/MinikinSkia.h
+++ b/libs/hwui/hwui/MinikinSkia.h
@@ -17,9 +17,9 @@
#ifndef _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
#define _ANDROID_GRAPHICS_MINIKIN_SKIA_H_
+#include <SkRefCnt.h>
#include <cutils/compiler.h>
#include <minikin/MinikinFont.h>
-#include <SkRefCnt.h>
class SkPaint;
class SkTypeface;
@@ -29,16 +29,17 @@
class ANDROID_API MinikinFontSkia : public minikin::MinikinFont {
public:
explicit MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
- int ttcIndex, const std::vector<minikin::FontVariation>& axes);
+ int ttcIndex, const std::vector<minikin::FontVariation>& axes);
- float GetHorizontalAdvance(uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const;
+ float GetHorizontalAdvance(uint32_t glyph_id, const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
void GetBounds(minikin::MinikinRect* bounds, uint32_t glyph_id,
- const minikin::MinikinPaint &paint) const;
+ const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
- void GetFontExtent(minikin::MinikinExtent* extent,
- const minikin::MinikinPaint &paint) const;
+ void GetFontExtent(minikin::MinikinExtent* extent, const minikin::MinikinPaint& paint,
+ const minikin::FontFakery& fakery) const override;
SkTypeface* GetSkTypeface() const;
sk_sp<SkTypeface> RefSkTypeface() const;
@@ -56,7 +57,8 @@
// set typeface and fake bold/italic parameters
static void populateSkPaint(SkPaint* paint, const minikin::MinikinFont* font,
- minikin::FontFakery fakery);
+ minikin::FontFakery fakery);
+
private:
sk_sp<SkTypeface> mTypeface;
diff --git a/libs/hwui/hwui/MinikinUtils.cpp b/libs/hwui/hwui/MinikinUtils.cpp
index 814d2cf..90fe0b7 100644
--- a/libs/hwui/hwui/MinikinUtils.cpp
+++ b/libs/hwui/hwui/MinikinUtils.cpp
@@ -26,50 +26,50 @@
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 = 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.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.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);
+ const Typeface* typeface, const uint16_t* buf, size_t start,
+ size_t count, size_t bufSize) {
+ minikin::MinikinPaint minikinPaint = prepareMinikinPaint(paint, typeface);
minikin::Layout layout;
- layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinStyle, minikinPaint,
- Typeface::resolveDefault(typeface)->fFontCollection);
+ layout.doLayout(buf, start, count, bufSize, bidiFlags, minikinPaint,
+ Typeface::resolveDefault(typeface)->fFontCollection);
return layout;
}
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);
+ const Typeface* typeface, const uint16_t* buf, size_t start,
+ size_t count, size_t bufSize, float* advances) {
+ 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, nullptr /* extent */,
- nullptr /* overhangs */);
+ return minikin::Layout::measureText(buf, start, count, bufSize, bidiFlags, minikinPaint,
+ resolvedTypeface->fFontCollection, advances,
+ nullptr /* extent */, nullptr /* overhangs */);
}
bool MinikinUtils::hasVariationSelector(const Typeface* typeface, uint32_t codepoint, uint32_t vs) {
@@ -92,7 +92,7 @@
}
float MinikinUtils::hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
- const SkPath& path) {
+ const SkPath& path) {
float align = 0;
switch (paint->getTextAlign()) {
case Paint::kCenter_Align:
@@ -107,5 +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 2e8aa58..7036cbe 100644
--- a/libs/hwui/hwui/MinikinUtils.h
+++ b/libs/hwui/hwui/MinikinUtils.h
@@ -19,39 +19,40 @@
* Paint and so on.
**/
- // TODO: does this really need to be separate from MinikinSkia?
+// TODO: does this really need to be separate from MinikinSkia?
#ifndef _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
#define _ANDROID_GRAPHICS_MINIKIN_UTILS_H_
#include <cutils/compiler.h>
#include <minikin/Layout.h>
-#include "Paint.h"
#include "MinikinSkia.h"
+#include "Paint.h"
#include "Typeface.h"
namespace android {
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, size_t start, size_t count,
- size_t bufSize);
+ const Typeface* typeface, const uint16_t* buf,
+ size_t start, size_t count, size_t bufSize);
ANDROID_API static float 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);
+ const Typeface* typeface, const uint16_t* buf,
+ size_t start, size_t count, size_t bufSize,
+ float* advances);
ANDROID_API static bool hasVariationSelector(const Typeface* typeface, uint32_t codepoint,
- uint32_t vs);
+ uint32_t vs);
ANDROID_API static float xOffsetForTextAlign(Paint* paint, const minikin::Layout& layout);
ANDROID_API static float hOffsetForTextAlign(Paint* paint, const minikin::Layout& layout,
- const SkPath& path);
+ const SkPath& path);
// f is a functor of type void f(size_t start, size_t end);
template <typename F>
ANDROID_API static void forFontRun(const minikin::Layout& layout, Paint* paint, F& f) {
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index f3779fd..76beb11 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -32,8 +32,8 @@
public:
// Default values for underlined and strikethrough text,
// as defined by Skia in SkTextFormatParams.h.
- constexpr static float kStdStrikeThru_Offset = (-6.0f / 21.0f);
- constexpr static float kStdUnderline_Offset = (1.0f / 9.0f);
+ constexpr static float kStdStrikeThru_Offset = (-6.0f / 21.0f);
+ constexpr static float kStdUnderline_Offset = (1.0f / 9.0f);
constexpr static float kStdUnderline_Thickness = (1.0f / 18.0f);
constexpr static float kStdUnderline_Top =
@@ -51,79 +51,54 @@
Paint& operator=(const Paint& other);
friend bool operator==(const Paint& a, const Paint& b);
- friend bool operator!=(const Paint& a, const Paint& b) {
- return !(a == b);
- }
+ friend bool operator!=(const Paint& a, const Paint& b) { return !(a == b); }
- void setLetterSpacing(float letterSpacing) {
- mLetterSpacing = letterSpacing;
- }
+ void setLetterSpacing(float letterSpacing) { mLetterSpacing = letterSpacing; }
- float getLetterSpacing() const {
- return mLetterSpacing;
- }
+ float getLetterSpacing() const { return mLetterSpacing; }
- void setWordSpacing(float wordSpacing) {
- mWordSpacing = wordSpacing;
- }
+ void setWordSpacing(float wordSpacing) { mWordSpacing = wordSpacing; }
- float getWordSpacing() const {
- return mWordSpacing;
- }
+ float getWordSpacing() const { return mWordSpacing; }
void setFontFeatureSettings(const std::string& fontFeatureSettings) {
mFontFeatureSettings = fontFeatureSettings;
}
- std::string getFontFeatureSettings() const {
- return mFontFeatureSettings;
+ std::string getFontFeatureSettings() const { return mFontFeatureSettings; }
+
+ void setMinikinLocaleListId(uint32_t minikinLocaleListId) {
+ mMinikinLocaleListId = minikinLocaleListId;
}
- void setMinikinLangListId(uint32_t minikinLangListId) {
- mMinikinLangListId = minikinLangListId;
- }
+ uint32_t getMinikinLocaleListId() const { return mMinikinLocaleListId; }
- uint32_t getMinikinLangListId() const {
- return mMinikinLangListId;
- }
+ void setFontVariant(minikin::FontVariant variant) { mFontVariant = variant; }
- void setFontVariant(minikin::FontVariant variant) {
- mFontVariant = variant;
- }
+ minikin::FontVariant getFontVariant() const { return mFontVariant; }
- minikin::FontVariant getFontVariant() const {
- return mFontVariant;
- }
+ void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; }
- void setHyphenEdit(uint32_t hyphen) {
- mHyphenEdit = hyphen;
- }
+ uint32_t getHyphenEdit() const { return mHyphenEdit; }
- uint32_t getHyphenEdit() const {
- return mHyphenEdit;
- }
+ void setAndroidTypeface(Typeface* typeface) { mTypeface = typeface; }
- void setAndroidTypeface(Typeface* typeface) {
- mTypeface = typeface;
- }
-
- const Typeface* getAndroidTypeface() const {
- return mTypeface;
- }
+ const Typeface* getAndroidTypeface() const { return mTypeface; }
private:
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;
};
} // namespace android
-#endif // ANDROID_GRAPHICS_PAINT_H_
+#endif // ANDROID_GRAPHICS_PAINT_H_
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index a5c2087..94492c5 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -18,33 +18,40 @@
namespace android {
-Paint::Paint() :
- SkPaint(), mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(),
- mMinikinLangListId(0), mFontVariant(minikin::VARIANT_DEFAULT) {
-}
+Paint::Paint()
+ : SkPaint()
+ , mLetterSpacing(0)
+ , mWordSpacing(0)
+ , mFontFeatureSettings()
+ , 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), mFontVariant(paint.mFontVariant),
- mHyphenEdit(paint.mHyphenEdit),
- mTypeface(paint.mTypeface) {
-}
+Paint::Paint(const Paint& paint)
+ : SkPaint(paint)
+ , mLetterSpacing(paint.mLetterSpacing)
+ , mWordSpacing(paint.mWordSpacing)
+ , mFontFeatureSettings(paint.mFontFeatureSettings)
+ , mMinikinLocaleListId(paint.mMinikinLocaleListId)
+ , mFontVariant(paint.mFontVariant)
+ , mHyphenEdit(paint.mHyphenEdit)
+ , mTypeface(paint.mTypeface) {}
-Paint::Paint(const SkPaint& paint) : SkPaint(paint),
- mLetterSpacing(0), mWordSpacing(0), mFontFeatureSettings(), mMinikinLangListId(0),
- mFontVariant(minikin::VARIANT_DEFAULT) {
-}
+Paint::Paint(const SkPaint& paint)
+ : SkPaint(paint)
+ , mLetterSpacing(0)
+ , mWordSpacing(0)
+ , mFontFeatureSettings()
+ , mMinikinLocaleListId(0)
+ , mFontVariant(minikin::FontVariant::DEFAULT) {}
-Paint::~Paint() {
-}
+Paint::~Paint() {}
Paint& Paint::operator=(const Paint& other) {
SkPaint::operator=(other);
mLetterSpacing = other.mLetterSpacing;
mWordSpacing = other.mWordSpacing;
mFontFeatureSettings = other.mFontFeatureSettings;
- mMinikinLangListId = other.mMinikinLangListId;
+ mMinikinLocaleListId = other.mMinikinLocaleListId;
mFontVariant = other.mFontVariant;
mHyphenEdit = other.mHyphenEdit;
mTypeface = other.mTypeface;
@@ -52,14 +59,10 @@
}
bool operator==(const Paint& a, const Paint& b) {
- 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.mHyphenEdit == b.mHyphenEdit
- && a.mTypeface == b.mTypeface;
+ return static_cast<const SkPaint&>(a) == static_cast<const SkPaint&>(b) &&
+ a.mLetterSpacing == b.mLetterSpacing && a.mWordSpacing == b.mWordSpacing &&
+ a.mFontFeatureSettings == b.mFontFeatureSettings &&
+ 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 7cc0871..e527adc 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -16,15 +16,15 @@
#include "Typeface.h"
-#include <pthread.h>
#include <fcntl.h> // For tests.
-#include <sys/stat.h> // For tests.
+#include <pthread.h>
#include <sys/mman.h> // For tests.
+#include <sys/stat.h> // For tests.
#include "MinikinSkia.h"
-#include "SkTypeface.h"
#include "SkPaint.h"
#include "SkStream.h" // Fot tests.
+#include "SkTypeface.h"
#include <minikin/FontCollection.h>
#include <minikin/FontFamily.h>
@@ -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.
@@ -90,8 +89,8 @@
return result;
}
-Typeface* Typeface::createFromTypefaceWithVariation(Typeface* src,
- const std::vector<minikin::FontVariation>& variations) {
+Typeface* Typeface::createFromTypefaceWithVariation(
+ Typeface* src, const std::vector<minikin::FontVariation>& variations) {
const Typeface* resolvedFace = Typeface::resolveDefault(src);
Typeface* result = new Typeface();
if (result != nullptr) {
@@ -123,9 +122,8 @@
return result;
}
-Typeface* Typeface::createFromFamilies(
- std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
- int weight, int italic) {
+Typeface* Typeface::createFromFamilies(std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
+ int weight, int italic) {
Typeface* result = new Typeface;
result->fFontCollection.reset(new minikin::FontCollection(families));
@@ -135,7 +133,7 @@
const minikin::FontStyle defaultStyle;
const minikin::MinikinFont* mf =
- families.empty() ? nullptr : families[0]->getClosestMatch(defaultStyle).font;
+ families.empty() ? nullptr : families[0]->getClosestMatch(defaultStyle).font;
if (mf != nullptr) {
SkTypeface* skTypeface = reinterpret_cast<const MinikinFontSkia*>(mf)->GetSkTypeface();
const SkFontStyle& style = skTypeface->fontStyle();
@@ -151,7 +149,7 @@
weight = weightFromFont;
}
if (italic == RESOLVE_BY_FONT_TABLE) {
- italic = italicFromFont? 1 : 0;
+ italic = italicFromFont ? 1 : 0;
}
}
@@ -185,7 +183,7 @@
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
std::shared_ptr<minikin::FontFamily> family = std::make_shared<minikin::FontFamily>(
- std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+ std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
std::shared_ptr<minikin::FontCollection> collection =
std::make_shared<minikin::FontCollection>(std::move(family));
@@ -193,9 +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/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index d90114d..ef8d8f4 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#ifndef _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
#define _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
@@ -22,8 +21,8 @@
#include <cutils/compiler.h>
#include <minikin/FontCollection.h>
-#include <vector>
#include <memory>
+#include <vector>
namespace android {
@@ -32,19 +31,14 @@
constexpr int RESOLVE_BY_FONT_TABLE = -1;
struct ANDROID_API Typeface {
- public:
+public:
std::shared_ptr<minikin::FontCollection> fFontCollection;
// resolved style actually used for rendering
minikin::FontStyle fStyle;
// style used in the API
- enum Style : uint8_t {
- kNormal = 0,
- kBold = 0x01,
- kItalic = 0x02,
- kBoldItalic = 0x03
- };
+ enum Style : uint8_t { kNormal = 0, kBold = 0x01, kItalic = 0x02, kBoldItalic = 0x03 };
Style fAPIStyle;
static const Typeface* resolveDefault(const Typeface* src);
@@ -77,23 +71,21 @@
static Typeface* createRelative(Typeface* src, Style desiredStyle);
static Typeface* createAbsolute(Typeface* base, int weight, bool italic);
- static Typeface* createFromTypefaceWithVariation(Typeface* src,
- const std::vector<minikin::FontVariation>& variations);
+ static Typeface* createFromTypefaceWithVariation(
+ Typeface* src, const std::vector<minikin::FontVariation>& variations);
static Typeface* createFromFamilies(
- std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
- int weight, int italic);
+ std::vector<std::shared_ptr<minikin::FontFamily>>&& families, int weight, int italic);
static void setDefault(const Typeface* face);
// Sets roboto font as the default typeface for testing purpose.
static void setRobotoTypefaceForTest();
- private:
+
+private:
// base weight in CSS-style units, 1..1000
int fBaseWeight;
-
};
-
}
#endif // _ANDROID_GRAPHICS_TYPEFACE_IMPL_H_
diff --git a/libs/hwui/pipeline/skia/AnimatedDrawables.h b/libs/hwui/pipeline/skia/AnimatedDrawables.h
index 44c494f..efef6de 100644
--- a/libs/hwui/pipeline/skia/AnimatedDrawables.h
+++ b/libs/hwui/pipeline/skia/AnimatedDrawables.h
@@ -16,10 +16,10 @@
#pragma once
-#include "CanvasProperty.h"
-#include <utils/RefBase.h>
#include <SkCanvas.h>
#include <SkDrawable.h>
+#include <utils/RefBase.h>
+#include "CanvasProperty.h"
namespace android {
namespace uirenderer {
@@ -28,16 +28,12 @@
class AnimatedRoundRect : public SkDrawable {
public:
AnimatedRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p)
- : mLeft(left)
- , mTop(top)
- , mRight(right)
- , mBottom(bottom)
- , mRx(rx)
- , mRy(ry)
- , mPaint(p) {}
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* p)
+ : mLeft(left), mTop(top), mRight(right), mBottom(bottom), mRx(rx), mRy(ry), mPaint(p) {}
protected:
virtual SkRect onGetBounds() override {
@@ -61,11 +57,9 @@
class AnimatedCircle : public SkDrawable {
public:
AnimatedCircle(uirenderer::CanvasPropertyPrimitive* x, uirenderer::CanvasPropertyPrimitive* y,
- uirenderer::CanvasPropertyPrimitive* radius, uirenderer::CanvasPropertyPaint* paint)
- : mX(x)
- , mY(y)
- , mRadius(radius)
- , mPaint(paint) {}
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint)
+ : mX(x), mY(y), mRadius(radius), mPaint(paint) {}
protected:
virtual SkRect onGetBounds() override {
@@ -85,6 +79,6 @@
sp<uirenderer::CanvasPropertyPaint> mPaint;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/DumpOpsCanvas.h b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
index 34fb04c..1f83d1a 100644
--- a/libs/hwui/pipeline/skia/DumpOpsCanvas.h
+++ b/libs/hwui/pipeline/skia/DumpOpsCanvas.h
@@ -16,6 +16,7 @@
#pragma once
+#include "RenderNode.h"
#include "SkiaDisplayList.h"
namespace android {
@@ -32,8 +33,7 @@
: mOutput(output)
, mLevel(level)
, mDisplayList(displayList)
- , mIdent((level + 1) * 2, ' ') {
- }
+ , mIdent((level + 1) * 2, ' ') {}
protected:
void onClipRect(const SkRect& rect, SkClipOp, ClipEdgeStyle) override {
@@ -52,9 +52,7 @@
mOutput << mIdent << "clipRegion" << std::endl;
}
- void onDrawPaint(const SkPaint&) override {
- mOutput << mIdent << "drawPaint" << std::endl;
- }
+ void onDrawPaint(const SkPaint&) override { mOutput << mIdent << "drawPaint" << std::endl; }
void onDrawPath(const SkPath&, const SkPaint&) override {
mOutput << mIdent << "drawPath" << std::endl;
@@ -92,22 +90,21 @@
mOutput << mIdent << "drawPosText" << std::endl;
}
- void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar,
- const SkPaint&) override {
+ void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar, const SkPaint&) override {
mOutput << mIdent << "drawPosTextH" << std::endl;
}
void onDrawTextOnPath(const void*, size_t, const SkPath&, const SkMatrix*,
- const SkPaint&) override {
+ const SkPaint&) override {
mOutput << mIdent << "drawTextOnPath" << std::endl;
}
void onDrawTextRSXform(const void*, size_t, const SkRSXform[], const SkRect*,
- const SkPaint&) override {
+ const SkPaint&) override {
mOutput << mIdent << "drawTextRSXform" << std::endl;
}
- void onDrawTextBlob(const SkTextBlob*, SkScalar,SkScalar, const SkPaint&) override {
+ void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint&) override {
mOutput << mIdent << "drawTextBlob" << std::endl;
}
@@ -116,17 +113,17 @@
}
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst,
- const SkPaint*) override {
+ const SkPaint*) override {
mOutput << mIdent << "drawImageNine" << std::endl;
}
void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) override {
+ SrcRectConstraint) override {
mOutput << mIdent << "drawImageRect" << std::endl;
}
void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) override {
+ const SkPaint*) override {
mOutput << mIdent << "drawImageLattice" << std::endl;
}
@@ -157,21 +154,21 @@
private:
RenderNodeDrawable* getRenderNodeDrawable(SkDrawable* drawable) {
- for (auto& child : mDisplayList.mChildNodes) {
+ for (auto& child : mDisplayList.mChildNodes) {
if (drawable == &child) {
return &child;
}
- }
- return nullptr;
+ }
+ return nullptr;
}
GLFunctorDrawable* getGLFunctorDrawable(SkDrawable* drawable) {
- for (auto& child : mDisplayList.mChildFunctors) {
+ for (auto& child : mDisplayList.mChildFunctors) {
if (drawable == &child) {
return &child;
}
- }
- return nullptr;
+ }
+ return nullptr;
}
std::ostream& mOutput;
@@ -180,6 +177,6 @@
std::string mIdent;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index fcd72af..145e3c4 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -15,19 +15,19 @@
*/
#include "GLFunctorDrawable.h"
+#include <GrContext.h>
+#include <private/hwui/DrawGlInfo.h>
#include "GlFunctorLifecycleListener.h"
#include "RenderNode.h"
#include "SkAndroidFrameworkUtils.h"
#include "SkClipStack.h"
-#include <private/hwui/DrawGlInfo.h>
-#include <GrContext.h>
namespace android {
namespace uirenderer {
namespace skiapipeline {
GLFunctorDrawable::~GLFunctorDrawable() {
- if(mListener.get() != nullptr) {
+ if (mListener.get() != nullptr) {
mListener->onGlFunctorReleased(mFunctor);
}
}
@@ -73,7 +73,7 @@
bool clearStencilAfterFunctor = false;
- //apply a simple clip with a scissor or a complex clip with a stencil
+ // apply a simple clip with a scissor or a complex clip with a stencil
SkRegion clipRegion;
canvas->temporary_internal_getRgnClip(&clipRegion);
if (CC_UNLIKELY(clipRegion.isComplex())) {
@@ -106,7 +106,7 @@
(*mFunctor)(DrawGlInfo::kModeDraw, &info);
if (clearStencilAfterFunctor) {
- //clear stencil buffer as it may be used by Skia
+ // clear stencil buffer as it may be used by Skia
glDisable(GL_SCISSOR_TEST);
glDisable(GL_STENCIL_TEST);
glStencilMask(0x1);
@@ -115,8 +115,8 @@
}
canvas->getGrContext()->resetContext();
- }
+}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.h b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
index 012c948..af57d7d 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.h
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.h
@@ -19,8 +19,8 @@
#include <SkCanvas.h>
#include <SkDrawable.h>
-#include <utils/RefBase.h>
#include <utils/Functor.h>
+#include <utils/RefBase.h>
namespace android {
namespace uirenderer {
@@ -36,24 +36,21 @@
class GLFunctorDrawable : public SkDrawable {
public:
GLFunctorDrawable(Functor* functor, GlFunctorLifecycleListener* listener, SkCanvas* canvas)
- : mFunctor(functor)
- , mListener(listener)
- , mBounds(canvas->getLocalClipBounds())
- {}
+ : mFunctor(functor), mListener(listener), mBounds(canvas->getLocalClipBounds()) {}
virtual ~GLFunctorDrawable();
void syncFunctor() const;
- protected:
+protected:
virtual SkRect onGetBounds() override { return mBounds; }
virtual void onDraw(SkCanvas* canvas) override;
- private:
- Functor* mFunctor;
- sp<GlFunctorLifecycleListener> mListener;
- const SkRect mBounds;
+private:
+ Functor* mFunctor;
+ sp<GlFunctorLifecycleListener> mListener;
+ const SkRect mBounds;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index def04e1..d9584db 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "GlLayer.h"
#include "LayerDrawable.h"
+#include "GlLayer.h"
#include "VkLayer.h"
#include "GrBackendSurface.h"
@@ -51,9 +51,9 @@
externalTexture.fTarget = glLayer->getRenderTarget();
externalTexture.fID = glLayer->getTextureId();
GrBackendTexture backendTexture(layerWidth, layerHeight, kRGBA_8888_GrPixelConfig,
- externalTexture);
+ externalTexture);
layerImage = SkImage::MakeFromTexture(context, backendTexture, kTopLeft_GrSurfaceOrigin,
- kPremul_SkAlphaType, nullptr);
+ kPremul_SkAlphaType, nullptr);
} else {
SkASSERT(layer->getApi() == Layer::Api::Vulkan);
VkLayer* vkLayer = static_cast<VkLayer*>(layer);
@@ -64,12 +64,12 @@
if (layerImage) {
SkMatrix textureMatrix;
layer->getTexTransform().copyTo(textureMatrix);
- //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
// use bottom left origin and remove flipV and invert transformations.
SkMatrix flipV;
flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
textureMatrix.preConcat(flipV);
- textureMatrix.preScale(1.0f/layerWidth, 1.0f/layerHeight);
+ textureMatrix.preScale(1.0f / layerWidth, 1.0f / layerHeight);
textureMatrix.postScale(layerWidth, layerHeight);
SkMatrix textureMatrixInv;
if (!textureMatrix.invert(&textureMatrixInv)) {
@@ -98,6 +98,6 @@
return layerImage;
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.h b/libs/hwui/pipeline/skia/LayerDrawable.h
index d34d8e0..3450387 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.h
+++ b/libs/hwui/pipeline/skia/LayerDrawable.h
@@ -29,21 +29,21 @@
* Draws a layer backed by an OpenGL texture into a SkCanvas.
*/
class LayerDrawable : public SkDrawable {
- public:
- explicit LayerDrawable(DeferredLayerUpdater* layerUpdater)
- : mLayerUpdater(layerUpdater) {}
+public:
+ explicit LayerDrawable(DeferredLayerUpdater* layerUpdater) : mLayerUpdater(layerUpdater) {}
static bool DrawLayer(GrContext* context, SkCanvas* canvas, Layer* layer);
- protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight());
- }
- virtual void onDraw(SkCanvas* canvas) override;
+
+protected:
+ virtual SkRect onGetBounds() override {
+ return SkRect::MakeWH(mLayerUpdater->getWidth(), mLayerUpdater->getHeight());
+ }
+ virtual void onDraw(SkCanvas* canvas) override;
private:
sp<DeferredLayerUpdater> mLayerUpdater;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index ca93925..46d4ae7 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -15,33 +15,34 @@
*/
#include "RenderNodeDrawable.h"
+#include <SkPaintFilterCanvas.h>
#include "RenderNode.h"
#include "SkiaDisplayList.h"
#include "SkiaPipeline.h"
#include "utils/TraceUtils.h"
-#include <SkPaintFilterCanvas.h>
namespace android {
namespace uirenderer {
namespace skiapipeline {
-void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList,
- int nestLevel) {
+void RenderNodeDrawable::drawBackwardsProjectedNodes(SkCanvas* canvas,
+ const SkiaDisplayList& displayList,
+ int nestLevel) {
LOG_ALWAYS_FATAL_IF(0 == nestLevel && !displayList.mProjectionReceiver);
for (auto& child : displayList.mChildNodes) {
const RenderProperties& childProperties = child.getNodeProperties();
- //immediate children cannot be projected on their parent
+ // immediate children cannot be projected on their parent
if (childProperties.getProjectBackwards() && nestLevel > 0) {
SkAutoCanvasRestore acr2(canvas, true);
- //Apply recorded matrix, which is a total matrix saved at recording time to avoid
- //replaying all DL commands.
+ // Apply recorded matrix, which is a total matrix saved at recording time to avoid
+ // replaying all DL commands.
canvas->concat(child.getRecordedMatrix());
child.drawContent(canvas);
}
- //skip walking sub-nodes if current display list contains a receiver with exception of
- //level 0, which is a known receiver
+ // skip walking sub-nodes if current display list contains a receiver with exception of
+ // level 0, which is a known receiver
if (0 == nestLevel || !displayList.containsProjectionReceiver()) {
SkAutoCanvasRestore acr(canvas, true);
SkMatrix nodeMatrix;
@@ -51,9 +52,9 @@
hwuiMatrix.copyTo(nodeMatrix);
canvas->concat(nodeMatrix);
SkiaDisplayList* childDisplayList = static_cast<SkiaDisplayList*>(
- (const_cast<DisplayList*>(childNode->getDisplayList())));
+ (const_cast<DisplayList*>(childNode->getDisplayList())));
if (childDisplayList) {
- drawBackwardsProjectedNodes(canvas, *childDisplayList, nestLevel+1);
+ drawBackwardsProjectedNodes(canvas, *childDisplayList, nestLevel + 1);
}
}
}
@@ -92,8 +93,8 @@
}
void RenderNodeDrawable::onDraw(SkCanvas* canvas) {
- //negative and positive Z order are drawn out of order, if this render node drawable is in
- //a reordering section
+ // negative and positive Z order are drawn out of order, if this render node drawable is in
+ // a reordering section
if ((!mInReorderingSection) || MathUtils::isZero(mRenderNode->properties().getZ())) {
this->forceDraw(canvas);
}
@@ -118,13 +119,13 @@
SkAutoCanvasRestore acr(canvas, true);
const RenderProperties& properties = this->getNodeProperties();
- //pass this outline to the children that may clip backward projected nodes
- displayList->mProjectedOutline = displayList->containsProjectionReceiver()
- ? &properties.getOutline() : nullptr;
+ // pass this outline to the children that may clip backward projected nodes
+ displayList->mProjectedOutline =
+ displayList->containsProjectionReceiver() ? &properties.getOutline() : nullptr;
if (!properties.getProjectBackwards()) {
drawContent(canvas);
if (mProjectedDisplayList) {
- acr.restore(); //draw projected children using parent matrix
+ acr.restore(); // draw projected children using parent matrix
LOG_ALWAYS_FATAL_IF(!mProjectedDisplayList->mProjectedOutline);
const bool shouldClip = mProjectedDisplayList->mProjectedOutline->getPath();
SkAutoCanvasRestore acr2(canvas, shouldClip);
@@ -138,12 +139,10 @@
displayList->mProjectedOutline = nullptr;
}
-static bool layerNeedsPaint(const LayerProperties& properties,
- float alphaMultiplier, SkPaint* paint) {
- if (alphaMultiplier < 1.0f
- || properties.alpha() < 255
- || properties.xferMode() != SkBlendMode::kSrcOver
- || properties.colorFilter() != nullptr) {
+static bool layerNeedsPaint(const LayerProperties& properties, float alphaMultiplier,
+ SkPaint* paint) {
+ if (alphaMultiplier < 1.0f || properties.alpha() < 255 ||
+ properties.xferMode() != SkBlendMode::kSrcOver || properties.colorFilter() != nullptr) {
paint->setAlpha(properties.alpha() * alphaMultiplier);
paint->setBlendMode(properties.xferMode());
paint->setColorFilter(sk_ref_sp(properties.colorFilter()));
@@ -155,13 +154,14 @@
class AlphaFilterCanvas : public SkPaintFilterCanvas {
public:
AlphaFilterCanvas(SkCanvas* canvas, float alpha) : SkPaintFilterCanvas(canvas), mAlpha(alpha) {}
+
protected:
bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type t) const override {
SkTLazy<SkPaint> defaultPaint;
if (!*paint) {
paint->init(*defaultPaint.init());
}
- paint->writable()->setAlpha((uint8_t)(*paint)->getAlpha()*mAlpha);
+ paint->writable()->setAlpha((uint8_t)(*paint)->getAlpha() * mAlpha);
return true;
}
void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
@@ -169,6 +169,7 @@
// get their alpha applied. THe default SkPaintFilterCanvas::onDrawDrawable does not unroll.
drawable->draw(this, matrix);
}
+
private:
float mAlpha;
};
@@ -189,7 +190,7 @@
displayList->mProjectedReceiverParentMatrix = canvas->getTotalMatrix();
}
- //TODO should we let the bound of the drawable do this for us?
+ // TODO should we let the bound of the drawable do this for us?
const SkRect bounds = SkRect::MakeWH(properties.getWidth(), properties.getHeight());
bool quickRejected = properties.getClipToBounds() && canvas->quickReject(bounds);
if (!quickRejected) {
@@ -221,7 +222,7 @@
}
}
- // composing a software layer with alpha
+ // composing a software layer with alpha
} else if (properties.effectiveLayerType() == LayerType::Software) {
SkPaint paint;
bool needsLayer = layerNeedsPaint(layerProperties, alphaMultiplier, &paint);
@@ -246,7 +247,7 @@
}
void RenderNodeDrawable::setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier) {
+ float* alphaMultiplier) {
if (properties.getLeft() != 0 || properties.getTop() != 0) {
canvas->translate(properties.getLeft(), properties.getTop());
}
@@ -266,7 +267,7 @@
int clipFlags = properties.getClippingFlags();
if (properties.getAlpha() < 1) {
if (isLayer) {
- clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+ clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
}
if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
*alphaMultiplier = properties.getAlpha();
@@ -275,18 +276,18 @@
Rect layerBounds(0, 0, properties.getWidth(), properties.getHeight());
if (clipFlags) {
properties.getClippingRectForFlags(clipFlags, &layerBounds);
- clipFlags = 0; // all clipping done by savelayer
+ clipFlags = 0; // all clipping done by savelayer
}
- SkRect bounds = SkRect::MakeLTRB(layerBounds.left, layerBounds.top,
- layerBounds.right, layerBounds.bottom);
- canvas->saveLayerAlpha(&bounds, (int) (properties.getAlpha() * 255));
+ SkRect bounds = SkRect::MakeLTRB(layerBounds.left, layerBounds.top, layerBounds.right,
+ layerBounds.bottom);
+ canvas->saveLayerAlpha(&bounds, (int)(properties.getAlpha() * 255));
}
if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) {
// pretend alpha always causes savelayer to warn about
// performance problem affecting old versions
ATRACE_FORMAT("alpha caused saveLayer %dx%d", properties.getWidth(),
- properties.getHeight());
+ properties.getHeight());
}
}
@@ -312,6 +313,6 @@
}
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.h b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
index 3eed647..ef21cd8 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.h
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.h
@@ -47,7 +47,7 @@
* layer into the canvas.
*/
explicit RenderNodeDrawable(RenderNode* node, SkCanvas* canvas, bool composeLayer = true,
- bool inReorderingSection = false)
+ bool inReorderingSection = false)
: mRenderNode(node)
, mRecordedTransform(canvas->getTotalMatrix())
, mComposeLayer(composeLayer)
@@ -113,13 +113,13 @@
* @param nestLevel should be always 0. Used to track how far we are from the receiver.
*/
void drawBackwardsProjectedNodes(SkCanvas* canvas, const SkiaDisplayList& displayList,
- int nestLevel = 0);
+ int nestLevel = 0);
/**
* Applies the rendering properties of a view onto a SkCanvas.
*/
static void setViewProperties(const RenderProperties& properties, SkCanvas* canvas,
- float* alphaMultiplier);
+ float* alphaMultiplier);
/**
* Stores transform on the canvas at time of recording and is used for
@@ -150,6 +150,6 @@
SkiaDisplayList* mProjectedDisplayList = nullptr;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
index c8207bc..67e0602 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.cpp
@@ -30,26 +30,24 @@
namespace skiapipeline {
StartReorderBarrierDrawable::StartReorderBarrierDrawable(SkiaDisplayList* data)
- : mEndChildIndex(0)
- , mBeginChildIndex(data->mChildNodes.size())
- , mDisplayList(data) {
-}
+ : mEndChildIndex(0), mBeginChildIndex(data->mChildNodes.size()), mDisplayList(data) {}
void StartReorderBarrierDrawable::onDraw(SkCanvas* canvas) {
if (mChildren.empty()) {
- //mChildren is allocated and initialized only the first time onDraw is called and cached for
- //subsequent calls
+ // mChildren is allocated and initialized only the first time onDraw is called and cached
+ // for
+ // subsequent calls
mChildren.reserve(mEndChildIndex - mBeginChildIndex + 1);
for (int i = mBeginChildIndex; i <= mEndChildIndex; i++) {
mChildren.push_back(const_cast<RenderNodeDrawable*>(&mDisplayList->mChildNodes[i]));
}
}
std::stable_sort(mChildren.begin(), mChildren.end(),
- [](RenderNodeDrawable* a, RenderNodeDrawable* b) {
- const float aZValue = a->getNodeProperties().getZ();
- const float bZValue = b->getNodeProperties().getZ();
- return aZValue < bZValue;
- });
+ [](RenderNodeDrawable* a, RenderNodeDrawable* b) {
+ const float aZValue = a->getNodeProperties().getZ();
+ const float bZValue = b->getNodeProperties().getZ();
+ return aZValue < bZValue;
+ });
size_t drawIndex = 0;
const size_t endIndex = mChildren.size();
@@ -57,7 +55,7 @@
RenderNodeDrawable* childNode = mChildren[drawIndex];
SkASSERT(childNode);
const float casterZ = childNode->getNodeProperties().getZ();
- if (casterZ >= -NON_ZERO_EPSILON) { //draw only children with negative Z
+ if (casterZ >= -NON_ZERO_EPSILON) { // draw only children with negative Z
return;
}
childNode->forceDraw(canvas);
@@ -85,8 +83,9 @@
size_t drawIndex = 0;
const size_t endIndex = zChildren.size();
- while (drawIndex < endIndex //draw only children with positive Z
- && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON) drawIndex++;
+ while (drawIndex < endIndex // draw only children with positive Z
+ && zChildren[drawIndex]->getNodeProperties().getZ() <= NON_ZERO_EPSILON)
+ drawIndex++;
size_t shadowIndex = drawIndex;
float lastCasterZ = 0.0f;
@@ -98,7 +97,7 @@
// OR if its caster's Z value is similar to the previous potential caster
if (shadowIndex == drawIndex || casterZ - lastCasterZ < SHADOW_DELTA) {
this->drawShadow(canvas, zChildren[shadowIndex]);
- lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
+ lastCasterZ = casterZ; // must do this even if current caster not casting a shadow
shadowIndex++;
continue;
}
@@ -116,23 +115,21 @@
void EndReorderBarrierDrawable::drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster) {
const RenderProperties& casterProperties = caster->getNodeProperties();
- if (casterProperties.getAlpha() <= 0.0f
- || casterProperties.getOutline().getAlpha() <= 0.0f
- || !casterProperties.getOutline().getPath()
- || casterProperties.getScaleX() == 0
- || casterProperties.getScaleY() == 0) {
+ if (casterProperties.getAlpha() <= 0.0f || casterProperties.getOutline().getAlpha() <= 0.0f ||
+ !casterProperties.getOutline().getPath() || casterProperties.getScaleX() == 0 ||
+ casterProperties.getScaleY() == 0) {
// no shadow to draw
return;
}
- const SkScalar casterAlpha = casterProperties.getAlpha()
- * casterProperties.getOutline().getAlpha();
+ const SkScalar casterAlpha =
+ casterProperties.getAlpha() * casterProperties.getOutline().getAlpha();
if (casterAlpha <= 0.0f) {
return;
}
- float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha()/255.f)*casterAlpha;
- float spotAlpha = (SkiaPipeline::getSpotShadowAlpha()/255.f)*casterAlpha;
+ float ambientAlpha = (SkiaPipeline::getAmbientShadowAlpha() / 255.f) * casterAlpha;
+ float spotAlpha = (SkiaPipeline::getSpotShadowAlpha() / 255.f) * casterAlpha;
const RevealClip& revealClip = casterProperties.getRevealClip();
const SkPath* revealClipPath = revealClip.getPath();
@@ -172,7 +169,7 @@
}
// intersect the shadow-casting path with the reveal, if present
- SkPath tmpPath; // holds temporary SkPath to store the result of intersections
+ SkPath tmpPath; // holds temporary SkPath to store the result of intersections
if (revealClipPath) {
Op(*casterPath, *revealClipPath, kIntersect_SkPathOp, &tmpPath);
tmpPath.setIsVolatile(true);
@@ -190,11 +187,12 @@
} else {
zParams = SkPoint3::Make(0, 0, casterProperties.getZ());
}
- SkShadowUtils::DrawShadow(canvas, *casterPath, zParams, skiaLightPos,
- SkiaPipeline::getLightRadius(), ambientAlpha, spotAlpha, SK_ColorBLACK,
- casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
+ SkShadowUtils::DrawShadow(
+ canvas, *casterPath, zParams, skiaLightPos, SkiaPipeline::getLightRadius(),
+ ambientAlpha, spotAlpha, SK_ColorBLACK,
+ casterAlpha < 1.0f ? SkShadowFlags::kTransparentOccluder_ShadowFlag : 0);
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
index 9f00d23..3c48d36 100644
--- a/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
+++ b/libs/hwui/pipeline/skia/ReorderBarrierDrawables.h
@@ -41,9 +41,7 @@
explicit StartReorderBarrierDrawable(SkiaDisplayList* data);
protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeLargest();
- }
+ virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
virtual void onDraw(SkCanvas* canvas) override;
private:
@@ -65,16 +63,16 @@
class EndReorderBarrierDrawable : public SkDrawable {
public:
explicit EndReorderBarrierDrawable(StartReorderBarrierDrawable* startBarrier);
+
protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeLargest();
- }
+ virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
virtual void onDraw(SkCanvas* canvas) override;
+
private:
void drawShadow(SkCanvas* canvas, RenderNodeDrawable* caster);
StartReorderBarrierDrawable* mStartBarrier;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // 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/pipeline/skia/SkiaDisplayList.cpp b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
index 3ddc09f..cb10901 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.cpp
@@ -16,14 +16,13 @@
#include "SkiaDisplayList.h"
-#include "renderthread/CanvasContext.h"
-#include "VectorDrawable.h"
#include "DumpOpsCanvas.h"
#include "SkiaPipeline.h"
+#include "VectorDrawable.h"
+#include "renderthread/CanvasContext.h"
#include <SkImagePriv.h>
-
namespace android {
namespace uirenderer {
namespace skiapipeline {
@@ -49,8 +48,8 @@
}
}
-bool SkiaDisplayList::prepareListAndChildren(TreeObserver& observer, TreeInfo& info,
- bool functorsNeedLayer,
+bool SkiaDisplayList::prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) {
// If the prepare tree is triggered by the UI thread and no previous call to
// pinImages has failed then we must pin all mutable images in the GPU cache
@@ -64,7 +63,7 @@
}
bool hasBackwardProjectedNodesHere = false;
- bool hasBackwardProjectedNodesSubtree= false;
+ bool hasBackwardProjectedNodesSubtree = false;
for (auto& child : mChildNodes) {
hasBackwardProjectedNodesHere |= child.getNodeProperties().getProjectBackwards();
@@ -78,14 +77,15 @@
info.damageAccumulator->popTransform();
}
- //The purpose of next block of code is to reset projected display list if there are no
- //backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
+ // The purpose of next block of code is to reset projected display list if there are no
+ // backward projected nodes. This speeds up drawing, by avoiding an extra walk of the tree
if (mProjectionReceiver) {
- mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this : nullptr);
+ mProjectionReceiver->setProjectedDisplayList(hasBackwardProjectedNodesSubtree ? this
+ : nullptr);
info.hasBackwardProjectedNodes = hasBackwardProjectedNodesHere;
} else {
- info.hasBackwardProjectedNodes = hasBackwardProjectedNodesSubtree
- || hasBackwardProjectedNodesHere;
+ info.hasBackwardProjectedNodes =
+ hasBackwardProjectedNodesSubtree || hasBackwardProjectedNodesHere;
}
bool isDirty = false;
@@ -94,7 +94,8 @@
if (vectorDrawable->isDirty()) {
isDirty = true;
static_cast<SkiaPipeline*>(info.canvasContext.getRenderPipeline())
- ->getVectorDrawables()->push_back(vectorDrawable);
+ ->getVectorDrawables()
+ ->push_back(vectorDrawable);
}
vectorDrawable->setPropertyChangeWillBeConsumed(true);
}
@@ -121,6 +122,6 @@
mDisplayList.draw(&canvas);
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaDisplayList.h b/libs/hwui/pipeline/skia/SkiaDisplayList.h
index 66375d1..6883d33 100644
--- a/libs/hwui/pipeline/skia/SkiaDisplayList.h
+++ b/libs/hwui/pipeline/skia/SkiaDisplayList.h
@@ -20,9 +20,9 @@
#include "GLFunctorDrawable.h"
#include "RenderNodeDrawable.h"
-#include <deque>
#include <SkLiteDL.h>
#include <SkLiteRecorder.h>
+#include <deque>
namespace android {
namespace uirenderer {
@@ -62,7 +62,7 @@
* need to monitor that they don't extend beyond the lifetime of the class
* that creates them. Allocator dtor invokes all SkDrawable dtors.
*/
- template<class T, typename... Params>
+ template <class T, typename... Params>
SkDrawable* allocateDrawable(Params&&... params) {
return allocator.create<T>(std::forward<Params>(params)...);
}
@@ -113,7 +113,8 @@
* to subclass from DisplayList
*/
- bool prepareListAndChildren(TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
+ bool prepareListAndChildren(
+ TreeObserver& observer, TreeInfo& info, bool functorsNeedLayer,
std::function<void(RenderNode*, TreeObserver&, TreeInfo&, bool)> childFn) override;
/**
@@ -145,24 +146,25 @@
std::vector<VectorDrawableRoot*> mVectorDrawables;
SkLiteDL mDisplayList;
- //mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection
- //receiver. It is set at record time and used at both prepare and draw tree traversals to
- //make sure backward projected nodes are found and drawn immediately after mProjectionReceiver.
+ // mProjectionReceiver points to a child node (stored in mChildNodes) that is as a projection
+ // receiver. It is set at record time and used at both prepare and draw tree traversals to
+ // make sure backward projected nodes are found and drawn immediately after mProjectionReceiver.
RenderNodeDrawable* mProjectionReceiver = nullptr;
- //mProjectedOutline is valid only when render node tree is traversed during the draw pass.
- //Render nodes that have a child receiver node, will store a pointer to their outline in
- //mProjectedOutline. Child receiver node will apply the clip before any backward projected
- //node is drawn.
+ // mProjectedOutline is valid only when render node tree is traversed during the draw pass.
+ // Render nodes that have a child receiver node, will store a pointer to their outline in
+ // mProjectedOutline. Child receiver node will apply the clip before any backward projected
+ // node is drawn.
const Outline* mProjectedOutline = nullptr;
- //mProjectedReceiverParentMatrix is valid when render node tree is traversed during the draw
- //pass. Render nodes that have a child receiver node, will store their matrix in
- //mProjectedReceiverParentMatrix. Child receiver node will set the matrix and then clip with the
- //outline of their parent.
+ // mProjectedReceiverParentMatrix is valid when render node tree is traversed during the draw
+ // pass. Render nodes that have a child receiver node, will store their matrix in
+ // mProjectedReceiverParentMatrix. Child receiver node will set the matrix and then clip with
+ // the
+ // outline of their parent.
SkMatrix mProjectedReceiverParentMatrix;
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaLayer.h b/libs/hwui/pipeline/skia/SkiaLayer.h
index 904d57e0..82e6914 100644
--- a/libs/hwui/pipeline/skia/SkiaLayer.h
+++ b/libs/hwui/pipeline/skia/SkiaLayer.h
@@ -26,14 +26,12 @@
/**
* An offscreen rendering target used to contain the contents a RenderNode.
*/
-struct SkiaLayer
-{
+struct SkiaLayer {
sk_sp<SkSurface> layerSurface;
Matrix4 inverseTransformInWindow;
bool hasRenderedSinceRepaint = false;
};
-
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index abba70e..365d740 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,15 +16,15 @@
#include "SkiaOpenGLPipeline.h"
-#include "hwui/Bitmap.h"
#include "DeferredLayerUpdater.h"
#include "GlLayer.h"
#include "LayerDrawable.h"
-#include "renderthread/EglManager.h"
-#include "renderthread/Frame.h"
-#include "renderstate/RenderState.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
+#include "hwui/Bitmap.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/EglManager.h"
+#include "renderthread/Frame.h"
#include "utils/TraceUtils.h"
#include <GrBackendSurface.h>
@@ -39,9 +39,7 @@
namespace skiapipeline {
SkiaOpenGLPipeline::SkiaOpenGLPipeline(RenderThread& thread)
- : SkiaPipeline(thread)
- , mEglManager(thread.eglManager()) {
-}
+ : SkiaPipeline(thread), mEglManager(thread.eglManager()) {}
MakeCurrentResult SkiaOpenGLPipeline::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
@@ -55,19 +53,17 @@
Frame SkiaOpenGLPipeline::getFrame() {
LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "drawRenderNode called on a context with no surface!");
+ "drawRenderNode called on a context with no surface!");
return mEglManager.beginFrame(mEglSurface);
}
-bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty,
- const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
-
+bool SkiaOpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) {
mEglManager.damageFrame(frame, dirty);
// setup surface for fbo0
@@ -77,7 +73,7 @@
wideColorGamut ? kRGBA_half_GrPixelConfig : kRGBA_8888_GrPixelConfig;
GrBackendRenderTarget backendRT(frame.width(), frame.height(), 0, STENCIL_BUFFER_SIZE,
- pixelConfig, fboInfo);
+ pixelConfig, fboInfo);
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
@@ -86,13 +82,13 @@
mRenderThread.getGrContext(), backendRT, kBottomLeft_GrSurfaceOrigin, nullptr, &props));
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
- contentDrawBounds, surface);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
+ surface);
layerUpdateQueue->clear();
// Draw visual debugging features
- if (CC_UNLIKELY(Properties::showDirtyRegions
- || ProfileType::None != Properties::getProfileType())) {
+ if (CC_UNLIKELY(Properties::showDirtyRegions ||
+ ProfileType::None != Properties::getProfileType())) {
SkCanvas* profileCanvas = surface->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
@@ -107,9 +103,8 @@
return true;
}
-bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew,
- const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
-
+bool SkiaOpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
GL_CHECKPOINT(LOW);
// Even if we decided to cancel the frame, from the perspective of jank
@@ -140,7 +135,7 @@
* then reading from the intermediate buffer into the bitmap.
*/
sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
- SkBudgeted::kYes, bitmap->info());
+ SkBudgeted::kYes, bitmap->info());
Layer* layer = deferredLayer->backingLayer();
if (LayerDrawable::DrawLayer(mRenderThread.getGrContext(), tmpSurface->getCanvas(), layer)) {
@@ -155,9 +150,9 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
- GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
- mode, blend);
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ GlLayer* layer =
+ new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
layer->generateTexture();
return layer;
}
@@ -174,8 +169,7 @@
}
bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
- ColorMode colorMode) {
-
+ ColorMode colorMode) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
@@ -221,8 +215,7 @@
class AutoEglFence {
public:
- AutoEglFence(EGLDisplay display)
- : mDisplay(display) {
+ AutoEglFence(EGLDisplay display) : mDisplay(display) {
fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
}
@@ -233,17 +226,17 @@
}
EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoEglImage {
public:
- AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
- : mDisplay(display) {
- EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
+ AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
+ EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ imageAttrs);
}
~AutoEglImage() {
@@ -253,6 +246,7 @@
}
EGLImageKHR image = EGL_NO_IMAGE_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
@@ -264,16 +258,14 @@
glBindTexture(GL_TEXTURE_2D, mTexture);
}
- ~AutoSkiaGlTexture() {
- glDeleteTextures(1, &mTexture);
- }
+ ~AutoSkiaGlTexture() { glDeleteTextures(1, &mTexture); }
private:
GLuint mTexture = 0;
};
sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
- SkBitmap& skBitmap) {
+ SkBitmap& skBitmap) {
renderThread.eglManager().initialize();
sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
@@ -282,67 +274,67 @@
GLint format, type;
bool isSupported = false;
- //TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
+ // TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
switch (info.colorType()) {
- case kRGBA_8888_SkColorType:
- isSupported = true;
- // ARGB_4444 is upconverted to RGBA_8888
- case kARGB_4444_SkColorType:
- pixelFormat = PIXEL_FORMAT_RGBA_8888;
- format = GL_RGBA;
- type = GL_UNSIGNED_BYTE;
- break;
- case kRGBA_F16_SkColorType:
- isSupported = grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig);
- if (isSupported) {
- type = GL_HALF_FLOAT;
- pixelFormat = PIXEL_FORMAT_RGBA_FP16;
- } else {
- type = GL_UNSIGNED_BYTE;
+ case kRGBA_8888_SkColorType:
+ isSupported = true;
+ // ARGB_4444 is upconverted to RGBA_8888
+ case kARGB_4444_SkColorType:
pixelFormat = PIXEL_FORMAT_RGBA_8888;
- }
- format = GL_RGBA;
- break;
- case kRGB_565_SkColorType:
- isSupported = true;
- pixelFormat = PIXEL_FORMAT_RGB_565;
- format = GL_RGB;
- type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- case kGray_8_SkColorType:
- isSupported = true;
- pixelFormat = PIXEL_FORMAT_RGBA_8888;
- format = GL_LUMINANCE;
- type = GL_UNSIGNED_BYTE;
- break;
- default:
- ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
- return nullptr;
+ format = GL_RGBA;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ case kRGBA_F16_SkColorType:
+ isSupported = grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig);
+ if (isSupported) {
+ type = GL_HALF_FLOAT;
+ pixelFormat = PIXEL_FORMAT_RGBA_FP16;
+ } else {
+ type = GL_UNSIGNED_BYTE;
+ pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ }
+ format = GL_RGBA;
+ break;
+ case kRGB_565_SkColorType:
+ isSupported = true;
+ pixelFormat = PIXEL_FORMAT_RGB_565;
+ format = GL_RGB;
+ type = GL_UNSIGNED_SHORT_5_6_5;
+ break;
+ case kGray_8_SkColorType:
+ isSupported = true;
+ pixelFormat = PIXEL_FORMAT_RGBA_8888;
+ format = GL_LUMINANCE;
+ type = GL_UNSIGNED_BYTE;
+ break;
+ default:
+ ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
+ return nullptr;
}
-
SkBitmap bitmap;
if (isSupported) {
bitmap = skBitmap;
} else {
- bitmap.allocPixels(SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(),
- nullptr));
+ bitmap.allocPixels(
+ SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
bitmap.eraseColor(0);
if (info.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
- bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
+ bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
} else {
SkCanvas canvas(bitmap);
canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
}
}
- sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) + "]");
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ info.width(), info.height(), pixelFormat,
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER,
+ std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
+ "]");
status_t error = buffer->initCheck();
if (error < 0) {
@@ -350,18 +342,17 @@
return nullptr;
}
- //upload the bitmap into a texture
+ // upload the bitmap into a texture
EGLDisplay display = eglGetCurrentDisplay();
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer->getNativeBuffer();
AutoEglImage autoImage(display, clientBuffer);
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ uirenderer::renderthread::EglManager::eglErrorString());
return nullptr;
}
AutoSkiaGlTexture glTexture;
@@ -372,7 +363,7 @@
// But asynchronous in sense that driver may upload texture onto hardware buffer when we first
// use it in drawing
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
- bitmap.getPixels());
+ bitmap.getPixels());
GL_CHECKPOINT(MODERATE);
// The fence is used to wait for the texture upload to finish
@@ -386,7 +377,7 @@
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
// pipeline flush (similar to what a glFlush() would do.)
EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
return nullptr;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index aa29c8e..5e013b6 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -33,25 +33,24 @@
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode) override;
+ renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
- SkBitmap& skBitmap);
+ SkBitmap& skBitmap);
private:
renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index b286392..6db57ca 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -16,16 +16,16 @@
#include "SkiaOpenGLReadback.h"
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GrBackendSurface.h>
+#include <SkCanvas.h>
+#include <SkSurface.h>
+#include <gl/GrGLInterface.h>
+#include <gl/GrGLTypes.h>
#include "DeviceInfo.h"
#include "Matrix.h"
#include "Properties.h"
-#include <SkCanvas.h>
-#include <SkSurface.h>
-#include <GrBackendSurface.h>
-#include <gl/GrGLInterface.h>
-#include <gl/GrGLTypes.h>
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
using namespace android::uirenderer::renderthread;
@@ -34,8 +34,8 @@
namespace skiapipeline {
CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) {
-
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) {
GLuint sourceTexId;
glGenTextures(1, &sourceTexId);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, sourceTexId);
@@ -46,7 +46,7 @@
sk_sp<const GrGLInterface> glInterface(GrGLCreateNativeInterface());
LOG_ALWAYS_FATAL_IF(!glInterface.get());
grContext.reset(GrContext::Create(GrBackend::kOpenGL_GrBackend,
- (GrBackendContext)glInterface.get()));
+ (GrBackendContext)glInterface.get()));
} else {
grContext->resetContext();
}
@@ -57,13 +57,13 @@
GrPixelConfig pixelConfig;
switch (bitmap->colorType()) {
- case kRGBA_F16_SkColorType:
- pixelConfig = kRGBA_half_GrPixelConfig;
- break;
- case kN32_SkColorType:
- default:
- pixelConfig = kRGBA_8888_GrPixelConfig;
- break;
+ case kRGBA_F16_SkColorType:
+ pixelConfig = kRGBA_half_GrPixelConfig;
+ break;
+ case kN32_SkColorType:
+ default:
+ pixelConfig = kRGBA_8888_GrPixelConfig;
+ break;
}
/* Ideally, we would call grContext->caps()->isConfigRenderable(...). We
@@ -73,7 +73,7 @@
* for reading back float buffers (skbug.com/6945).
*/
if (pixelConfig == kRGBA_half_GrPixelConfig &&
- !grContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
+ !DeviceInfo::get()->extensions().hasRenderableFloatTextures()) {
ALOGW("Can't copy surface into bitmap, RGBA_F16 config is not supported");
return CopyResult::DestinationInvalid;
}
@@ -82,7 +82,7 @@
CopyResult copyResult = CopyResult::UnknownError;
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), backendTexture,
- kTopLeft_GrSurfaceOrigin));
+ kTopLeft_GrSurfaceOrigin));
if (image) {
int displayedWidth = imgWidth, displayedHeight = imgHeight;
// If this is a 90 or 270 degree rotation we need to swap width/height to get the device
@@ -100,12 +100,12 @@
if (srcNotEmpty) {
SkMatrix textureMatrixInv;
imgTransform.copyTo(textureMatrixInv);
- //TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
+ // TODO: after skia bug https://bugs.chromium.org/p/skia/issues/detail?id=7075 is fixed
// use bottom left origin and remove flipV and invert transformations.
SkMatrix flipV;
flipV.setAll(1, 0, 0, 0, -1, 1, 0, 0, 1);
textureMatrixInv.preConcat(flipV);
- textureMatrixInv.preScale(1.0f/displayedWidth, 1.0f/displayedHeight);
+ textureMatrixInv.preScale(1.0f / displayedWidth, 1.0f / displayedHeight);
textureMatrixInv.postScale(imgWidth, imgHeight);
SkMatrix textureMatrix;
if (!textureMatrixInv.invert(&textureMatrix)) {
@@ -117,20 +117,20 @@
// we render in an offscreen buffer to scale and to avoid an issue b/62262733
// with reading incorrect data from EGLImage backed SkImage (likely a driver bug)
- sk_sp<SkSurface> scaledSurface = SkSurface::MakeRenderTarget(
- grContext.get(), SkBudgeted::kYes, bitmap->info());
+ sk_sp<SkSurface> scaledSurface =
+ SkSurface::MakeRenderTarget(grContext.get(), SkBudgeted::kYes, bitmap->info());
SkPaint paint;
paint.setBlendMode(SkBlendMode::kSrc);
// Apply a filter, which is matching OpenGL pipeline readback behaviour. Filter usage
// is codified by tests using golden images like DecodeAccuracyTest.
- if (skiaSrcRect.width() != bitmap->width()
- || skiaSrcRect.height() != bitmap->height()) {
- //TODO: apply filter always, but check if tests will be fine
+ if (skiaSrcRect.width() != bitmap->width() ||
+ skiaSrcRect.height() != bitmap->height()) {
+ // TODO: apply filter always, but check if tests will be fine
paint.setFilterQuality(kLow_SkFilterQuality);
}
scaledSurface->getCanvas()->concat(textureMatrix);
scaledSurface->getCanvas()->drawImageRect(image, skiaSrcRect, skiaDestRect, &paint,
- SkCanvas::kFast_SrcRectConstraint);
+ SkCanvas::kFast_SrcRectConstraint);
image = scaledSurface->makeImageSnapshot();
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
index d914409..cc9fb3b 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.h
@@ -25,9 +25,11 @@
class SkiaOpenGLReadback : public OpenGLReadback {
public:
SkiaOpenGLReadback(renderthread::RenderThread& thread) : OpenGLReadback(thread) {}
+
protected:
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
- int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) override;
+ int imgWidth, int imgHeight, const Rect& srcRect,
+ SkBitmap* bitmap) override;
};
} /* namespace skiapipeline */
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index a092cd5..d5fe7f4 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -16,7 +16,6 @@
#include "SkiaPipeline.h"
-#include "utils/TraceUtils.h"
#include <SkImageEncoder.h>
#include <SkImagePriv.h>
#include <SkOverdrawCanvas.h>
@@ -26,6 +25,7 @@
#include <SkPixelSerializer.h>
#include <SkStream.h>
#include "VectorDrawable.h"
+#include "utils/TraceUtils.h"
#include <unistd.h>
@@ -35,13 +35,13 @@
namespace uirenderer {
namespace skiapipeline {
-float SkiaPipeline::mLightRadius = 0;
+float SkiaPipeline::mLightRadius = 0;
uint8_t SkiaPipeline::mAmbientShadowAlpha = 0;
uint8_t SkiaPipeline::mSpotShadowAlpha = 0;
Vector3 SkiaPipeline::mLightCenter = {FLT_MIN, FLT_MIN, FLT_MIN};
-SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
+SkiaPipeline::SkiaPipeline(RenderThread& thread) : mRenderThread(thread) {
mVectorDrawables.reserve(30);
}
@@ -82,8 +82,8 @@
}
void SkiaPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) {
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo) {
updateLighting(lightGeometry, lightInfo);
ATRACE_NAME("draw layers");
renderVectorDrawableCache();
@@ -91,8 +91,8 @@
layerUpdateQueue->clear();
}
-void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers,
- bool opaque, bool wideColorGamut) {
+void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque,
+ bool wideColorGamut) {
sk_sp<GrContext> cachedContext;
// Render all layers that need to be updated, in order.
@@ -129,7 +129,8 @@
return;
}
- ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(), bounds.height());
+ ATRACE_FORMAT("drawLayer [%s] %.1f x %.1f", layerNode->getName(), bounds.width(),
+ bounds.height());
layerNode->getSkiaLayer()->hasRenderedSinceRepaint = false;
layerCanvas->clear(SK_ColorTRANSPARENT);
@@ -158,22 +159,21 @@
}
}
-bool SkiaPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
+bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) {
SkSurface* layer = node->getLayerSurface();
if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) {
SkImageInfo info;
if (wideColorGamut) {
info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType,
- kPremul_SkAlphaType);
+ kPremul_SkAlphaType);
} else {
info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight());
}
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
SkASSERT(mRenderThread.getGrContext() != nullptr);
- node->setLayerSurface(
- SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
- info, 0, &props));
+ node->setLayerSurface(SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
+ SkBudgeted::kYes, info, 0, &props));
if (node->getLayerSurface()) {
// update the transform in window of the layer to reset its origin wrt light source
// position
@@ -211,8 +211,8 @@
SkData* onEncode(const SkPixmap& pixmap) override {
SkDynamicMemoryWStream buf;
return SkEncodeImage(&buf, pixmap, SkEncodedImageFormat::kPNG, 100)
- ? buf.detachAsData().release()
- : nullptr;
+ ? buf.detachAsData().release()
+ : nullptr;
}
};
@@ -245,7 +245,7 @@
TaskProcessor<bool>::add(task);
}
- virtual void onProcess(const sp<Task<bool> >& task) override {
+ virtual void onProcess(const sp<Task<bool>>& task) override {
SavePictureTask* t = static_cast<SavePictureTask*>(task.get());
if (0 == access(t->filename.c_str(), F_OK)) {
@@ -257,8 +257,8 @@
if (stream.isValid()) {
stream.write(t->data->data(), t->data->size());
stream.flush();
- SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s",
- stream.bytesWritten(), t->filename.c_str());
+ SkDebugf("SKP Captured Drawing Output (%d bytes) for frame. %s", stream.bytesWritten(),
+ t->filename.c_str());
}
task->setResult(true);
@@ -271,8 +271,8 @@
char prop[PROPERTY_VALUE_MAX] = {'\0'};
if (!recordingPicture) {
property_get(PROPERTY_CAPTURE_SKP_FILENAME, prop, "0");
- recordingPicture = prop[0] != '0'
- && mCapturedFile != prop; //ensure we capture only once per filename
+ recordingPicture = prop[0] != '0' &&
+ mCapturedFile != prop; // ensure we capture only once per filename
if (recordingPicture) {
mCapturedFile = prop;
mCaptureSequence = property_get_int32(PROPERTY_CAPTURE_SKP_FRAMES, 1);
@@ -281,7 +281,7 @@
if (recordingPicture) {
mRecorder.reset(new SkPictureRecorder());
return mRecorder->beginRecording(surface->width(), surface->height(), nullptr,
- SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
+ SkPictureRecorder::kPlaybackDrawPicture_RecordFlag);
}
}
return surface->getCanvas();
@@ -296,7 +296,7 @@
PngPixelSerializer serializer;
picture->serialize(&stream, &serializer);
- //offload saving to file in a different thread
+ // offload saving to file in a different thread
if (!mSavePictureProcessor.get()) {
TaskManager* taskManager = getTaskManager();
mSavePictureProcessor = new SavePictureProcessor(
@@ -305,8 +305,9 @@
if (1 == mCaptureSequence) {
mSavePictureProcessor->savePicture(stream.detachAsData(), mCapturedFile);
} else {
- mSavePictureProcessor->savePicture(stream.detachAsData(),
- mCapturedFile + "_" + std::to_string(mCaptureSequence));
+ mSavePictureProcessor->savePicture(
+ stream.detachAsData(),
+ mCapturedFile + "_" + std::to_string(mCaptureSequence));
}
mCaptureSequence--;
}
@@ -315,9 +316,9 @@
}
void SkiaPipeline::renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, sk_sp<SkSurface> surface) {
-
+ const std::vector<sp<RenderNode>>& nodes, bool opaque,
+ bool wideColorGamut, const Rect& contentDrawBounds,
+ sk_sp<SkSurface> surface) {
renderVectorDrawableCache();
// draw all layers up front
@@ -343,14 +344,14 @@
namespace {
static Rect nodeBounds(RenderNode& node) {
auto& props = node.properties();
- return Rect(props.getLeft(), props.getTop(),
- props.getRight(), props.getBottom());
+ return Rect(props.getLeft(), props.getTop(), props.getRight(), props.getBottom());
}
}
void SkiaPipeline::renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, SkCanvas* canvas) {
+ const std::vector<sp<RenderNode>>& nodes, bool opaque,
+ bool wideColorGamut, const Rect& contentDrawBounds,
+ SkCanvas* canvas) {
SkAutoCanvasRestore saver(canvas, true);
canvas->androidFramework_setDeviceClipRestriction(clip.roundOut());
@@ -364,15 +365,18 @@
root.draw(canvas);
}
} else if (0 == nodes.size()) {
- //nothing to draw
+ // nothing to draw
} else {
// It there are multiple render nodes, they are laid out as follows:
// #0 - backdrop (content + caption)
// #1 - content (local bounds are at (0,0), will be translated and clipped to backdrop)
// #2 - additional overlay nodes
- // Usually the backdrop cannot be seen since it will be entirely covered by the content. While
- // resizing however it might become partially visible. The following render loop will crop the
- // backdrop against the content and draw the remaining part of it. It will then draw the content
+ // Usually the backdrop cannot be seen since it will be entirely covered by the content.
+ // While
+ // resizing however it might become partially visible. The following render loop will crop
+ // the
+ // backdrop against the content and draw the remaining part of it. It will then draw the
+ // content
// cropped to the backdrop (since that indicates a shrinking of the window).
//
// Additional nodes will be drawn on top with no particular clipping semantics.
@@ -384,29 +388,31 @@
// Backdrop bounds in render target space
const Rect backdrop = nodeBounds(*nodes[0]);
- // Bounds that content will fill in render target space (note content node bounds may be bigger)
+ // Bounds that content will fill in render target space (note content node bounds may be
+ // bigger)
Rect content(contentDrawBounds.getWidth(), contentDrawBounds.getHeight());
content.translate(backdrop.left, backdrop.top);
if (!content.contains(backdrop) && !nodes[0]->nothingToDraw()) {
// Content doesn't entirely overlap backdrop, so fill around content (right/bottom)
// Note: in the future, if content doesn't snap to backdrop's left/top, this may need to
- // also fill left/top. Currently, both 2up and freeform position content at the top/left of
+ // also fill left/top. Currently, both 2up and freeform position content at the top/left
+ // of
// the backdrop, so this isn't necessary.
RenderNodeDrawable backdropNode(nodes[0].get(), canvas);
if (content.right < backdrop.right) {
// draw backdrop to right side of content
SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top,
- backdrop.right, backdrop.bottom));
+ canvas->clipRect(SkRect::MakeLTRB(content.right, backdrop.top, backdrop.right,
+ backdrop.bottom));
backdropNode.draw(canvas);
}
if (content.bottom < backdrop.bottom) {
// draw backdrop to bottom of content
// Note: bottom fill uses content left/right, to avoid overdrawing left/right fill
SkAutoCanvasRestore acr(canvas, true);
- canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom,
- content.right, backdrop.bottom));
+ canvas->clipRect(SkRect::MakeLTRB(content.left, content.bottom, content.right,
+ backdrop.bottom));
backdropNode.draw(canvas);
}
}
@@ -419,8 +425,9 @@
SkAutoCanvasRestore acr(canvas, true);
canvas->translate(dx, dy);
- const SkRect contentLocalClip = SkRect::MakeXYWH(contentDrawBounds.left,
- contentDrawBounds.top, backdrop.getWidth(), backdrop.getHeight());
+ const SkRect contentLocalClip =
+ SkRect::MakeXYWH(contentDrawBounds.left, contentDrawBounds.top,
+ backdrop.getWidth(), backdrop.getHeight());
canvas->clipRect(contentLocalClip);
contentNode.draw(canvas);
} else {
@@ -447,8 +454,8 @@
SkString log("Resource Cache Usage:\n");
log.appendf("%8d items out of %d maximum items\n", resources, maxResources);
- log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n",
- bytes, bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
+ log.appendf("%8zu bytes (%.2f MB) out of %.2f MB maximum\n", bytes,
+ bytes * (1.0f / (1024.0f * 1024.0f)), maxBytes * (1.0f / (1024.0f * 1024.0f)));
ALOGD("%s", log.c_str());
}
@@ -461,13 +468,17 @@
// (2) Requires premul colors (instead of unpremul).
// (3) Requires RGBA colors (instead of BGRA).
static const uint32_t kOverdrawColors[2][6] = {
- { 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f, },
- { 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f, },
+ {
+ 0x00000000, 0x00000000, 0x2f2f0000, 0x2f002f00, 0x3f00003f, 0x7f00007f,
+ },
+ {
+ 0x00000000, 0x00000000, 0x2f2f0000, 0x4f004f4f, 0x5f50335f, 0x7f00007f,
+ },
};
void SkiaPipeline::renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector<sp<RenderNode>>& nodes, const Rect &contentDrawBounds,
- sk_sp<SkSurface> surface) {
+ const std::vector<sp<RenderNode>>& nodes,
+ const Rect& contentDrawBounds, sk_sp<SkSurface> surface) {
// Set up the overdraw canvas.
SkImageInfo offscreenInfo = SkImageInfo::MakeA8(surface->width(), surface->height());
sk_sp<SkSurface> offscreen = surface->makeSurface(offscreenInfo);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.h b/libs/hwui/pipeline/skia/SkiaPipeline.h
index 67b1878..2709227 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.h
@@ -16,10 +16,10 @@
#pragma once
-#include "renderthread/CanvasContext.h"
-#include "FrameBuilder.h"
-#include "renderthread/IRenderPipeline.h"
#include <SkSurface.h>
+#include "FrameBuilder.h"
+#include "renderthread/CanvasContext.h"
+#include "renderthread/IRenderPipeline.h"
class SkPictureRecorder;
@@ -42,15 +42,15 @@
void onPrepareTree() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) override;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) override;
- bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) override;
+ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) override;
void renderFrame(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, sk_sp<SkSurface> surface);
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+ const Rect& contentDrawBounds, sk_sp<SkSurface> surface);
std::vector<VectorDrawableRoot*>* getVectorDrawables() { return &mVectorDrawables; }
@@ -86,7 +86,7 @@
Vector3 adjustedLightCenter = mLightCenter;
if (CC_UNLIKELY(Properties::overrideLightPosY > 0)) {
// negated since this shifts up
- adjustedLightCenter.y = - Properties::overrideLightPosY;
+ adjustedLightCenter.y = -Properties::overrideLightPosY;
}
if (CC_UNLIKELY(Properties::overrideLightPosZ > 0)) {
adjustedLightCenter.z = Properties::overrideLightPosZ;
@@ -97,7 +97,7 @@
}
static void updateLighting(const FrameBuilder::LightGeometry& lightGeometry,
- const BakedOpRenderer::LightInfo& lightInfo) {
+ const BakedOpRenderer::LightInfo& lightInfo) {
mLightRadius = lightGeometry.radius;
mAmbientShadowAlpha = lightInfo.ambientShadowAlpha;
mSpotShadowAlpha = lightInfo.spotShadowAlpha;
@@ -111,16 +111,16 @@
private:
void renderFrameImpl(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, bool opaque, bool wideColorGamut,
- const Rect &contentDrawBounds, SkCanvas* canvas);
+ const std::vector<sp<RenderNode>>& nodes, bool opaque, bool wideColorGamut,
+ const Rect& contentDrawBounds, SkCanvas* canvas);
/**
* Debugging feature. Draws a semi-transparent overlay on each pixel, indicating
* how many times it has been drawn.
*/
void renderOverdraw(const LayerUpdateQueue& layers, const SkRect& clip,
- const std::vector< sp<RenderNode> >& nodes, const Rect &contentDrawBounds,
- sk_sp<SkSurface>);
+ const std::vector<sp<RenderNode>>& nodes, const Rect& contentDrawBounds,
+ sk_sp<SkSurface>);
/**
* Render mVectorDrawables into offscreen buffers.
@@ -137,7 +137,6 @@
*/
std::vector<VectorDrawableRoot*> mVectorDrawables;
-
// Block of properties used only for debugging to record a SkPicture and save it in a file.
/**
* mCapturedFile is used to enforce we don't capture more than once for a given name (cause
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp b/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
index d97fb37..492c39f 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.cpp
@@ -20,7 +20,7 @@
namespace uirenderer {
void SkiaProfileRenderer::drawRect(float left, float top, float right, float bottom,
- const SkPaint& paint) {
+ const SkPaint& paint) {
SkRect rect = SkRect::MakeLTRB(left, top, right, bottom);
mCanvas->drawRect(rect, paint);
}
@@ -28,7 +28,7 @@
void SkiaProfileRenderer::drawRects(const float* rects, int count, const SkPaint& paint) {
for (int index = 0; index + 4 <= count; index += 4) {
SkRect rect = SkRect::MakeLTRB(rects[index + 0], rects[index + 1], rects[index + 2],
- rects[index + 3]);
+ rects[index + 3]);
mCanvas->drawRect(rect, paint);
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
index e6b7f83..5ae7d6b 100644
--- a/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
+++ b/libs/hwui/pipeline/skia/SkiaProfileRenderer.h
@@ -23,8 +23,7 @@
class SkiaProfileRenderer : public IProfileRenderer {
public:
- SkiaProfileRenderer(SkCanvas* canvas)
- : mCanvas(canvas) {}
+ SkiaProfileRenderer(SkCanvas* canvas) : mCanvas(canvas) {}
void drawRect(float left, float top, float right, float bottom, const SkPaint& paint) override;
void drawRects(const float* rects, int count, const SkPaint& paint) override;
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 0bdf153..6657fe8 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -16,12 +16,12 @@
#include "SkiaRecordingCanvas.h"
+#include <SkImagePriv.h>
#include "Layer.h"
-#include "RenderNode.h"
#include "LayerDrawable.h"
#include "NinePatchUtils.h"
+#include "RenderNode.h"
#include "pipeline/skia/AnimatedDrawables.h"
-#include <SkImagePriv.h>
namespace android {
namespace uirenderer {
@@ -32,7 +32,7 @@
// ----------------------------------------------------------------------------
void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
- int height) {
+ int height) {
mCurrentBarrier = nullptr;
SkASSERT(mDisplayList.get() == nullptr);
@@ -59,17 +59,21 @@
// ----------------------------------------------------------------------------
void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) {
// Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator.
- drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom,
- rx, ry, paint));
+ drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, rx, ry,
+ paint));
}
void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) {
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) {
drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
}
@@ -77,15 +81,14 @@
if (nullptr != mCurrentBarrier) {
// finish off the existing chunk
SkDrawable* drawable =
- mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(
- mCurrentBarrier);
+ mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(mCurrentBarrier);
mCurrentBarrier = nullptr;
drawDrawable(drawable);
}
if (enableReorder) {
mCurrentBarrier = (StartReorderBarrierDrawable*)
- mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
- mDisplayList.get());
+ mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
+ mDisplayList.get());
drawDrawable(mCurrentBarrier);
}
}
@@ -113,25 +116,21 @@
}
void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
- uirenderer::GlFunctorLifecycleListener* listener) {
+ uirenderer::GlFunctorLifecycleListener* listener) {
// Drawable dtor will be invoked when mChildFunctors deque is cleared.
mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
drawDrawable(&mDisplayList->mChildFunctors.back());
}
class VectorDrawable : public SkDrawable {
- public:
+public:
VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {}
- protected:
- virtual SkRect onGetBounds() override {
- return SkRect::MakeLargest();
- }
- virtual void onDraw(SkCanvas* canvas) override {
- mRoot->draw(canvas);
- }
+protected:
+ virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
+ virtual void onDraw(SkCanvas* canvas) override { mRoot->draw(canvas); }
- private:
+private:
sp<VectorDrawableRoot> mRoot;
};
@@ -145,7 +144,7 @@
// ----------------------------------------------------------------------------
inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
- sk_sp<SkColorFilter> colorFilter) {
+ sk_sp<SkColorFilter> colorFilter) {
if ((origPaint && origPaint->isAntiAlias()) || colorFilter) {
if (origPaint) {
*tmpPaint = *origPaint;
@@ -180,8 +179,7 @@
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
@@ -194,9 +192,9 @@
}
}
-void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
- float dstBottom, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) {
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
@@ -204,15 +202,16 @@
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter),
- SkCanvas::kFast_SrcRectConstraint);
- if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty()
- && !dstRect.isEmpty()) {
+ SkCanvas::kFast_SrcRectConstraint);
+ if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
+ !dstRect.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
+void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
+ float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) {
SkCanvas::Lattice lattice;
NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
@@ -236,12 +235,12 @@
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
mRecorder.drawImageLattice(image.get(), lattice, dst,
- bitmapPaint(paint, &tmpPaint, colorFilter));
+ bitmapPaint(paint, &tmpPaint, colorFilter));
if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
mDisplayList->mMutableImages.push_back(image.get());
}
}
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
index 10829f8..d35bbab 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.h
@@ -15,10 +15,10 @@
*/
#pragma once
+#include <SkLiteRecorder.h>
+#include "ReorderBarrierDrawables.h"
#include "SkiaCanvas.h"
#include "SkiaDisplayList.h"
-#include "ReorderBarrierDrawables.h"
-#include <SkLiteRecorder.h>
namespace android {
namespace uirenderer {
@@ -29,7 +29,7 @@
* SkLiteRecorder and a SkiaDisplayList.
*/
class SkiaRecordingCanvas : public SkiaCanvas {
- public:
+public:
explicit SkiaRecordingCanvas(uirenderer::RenderNode* renderNode, int width, int height) {
initDisplayList(renderNode, width, height);
}
@@ -39,31 +39,32 @@
}
virtual void resetRecording(int width, int height,
- uirenderer::RenderNode* renderNode) override {
+ uirenderer::RenderNode* renderNode) override {
initDisplayList(renderNode, width, height);
}
virtual uirenderer::DisplayList* finishRecording() override;
- virtual void drawBitmap(Bitmap& bitmap, float left, float top,
- const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
- const SkPaint* paint) override;
- virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
- float srcRight, float srcBottom, float dstLeft, float dstTop,
- float dstRight, float dstBottom, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) override;
+ virtual void drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
+ float srcBottom, float dstLeft, float dstTop, float dstRight,
+ float dstBottom, const SkPaint* paint) override;
virtual void drawNinePatch(Bitmap& hwuiBitmap, const android::Res_png_9patch& chunk,
- float dstLeft, float dstTop, float dstRight, float dstBottom,
- const SkPaint* paint) override;
+ float dstLeft, float dstTop, float dstRight, float dstBottom,
+ const SkPaint* paint) override;
virtual void drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
- uirenderer::CanvasPropertyPrimitive* top, uirenderer::CanvasPropertyPrimitive* right,
- uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
- uirenderer::CanvasPropertyPrimitive* ry,
- uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* top,
+ uirenderer::CanvasPropertyPrimitive* right,
+ uirenderer::CanvasPropertyPrimitive* bottom,
+ uirenderer::CanvasPropertyPrimitive* rx,
+ uirenderer::CanvasPropertyPrimitive* ry,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawCircle(uirenderer::CanvasPropertyPrimitive* x,
- uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
- uirenderer::CanvasPropertyPaint* paint) override;
+ uirenderer::CanvasPropertyPrimitive* y,
+ uirenderer::CanvasPropertyPrimitive* radius,
+ uirenderer::CanvasPropertyPaint* paint) override;
virtual void drawVectorDrawable(VectorDrawableRoot* vectorDrawable) override;
@@ -88,6 +89,6 @@
void initDisplayList(uirenderer::RenderNode* renderNode, int width, int height);
};
-}; // namespace skiapipeline
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace skiapipeline
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index e1ef71f7..6530074 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -17,12 +17,12 @@
#include "SkiaVulkanPipeline.h"
#include "DeferredLayerUpdater.h"
-#include "renderthread/Frame.h"
#include "Readback.h"
-#include "renderstate/RenderState.h"
#include "SkiaPipeline.h"
#include "SkiaProfileRenderer.h"
#include "VkLayer.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/Frame.h"
#include <SkSurface.h>
#include <SkTypes.h>
@@ -41,8 +41,7 @@
namespace skiapipeline {
SkiaVulkanPipeline::SkiaVulkanPipeline(renderthread::RenderThread& thread)
- : SkiaPipeline(thread)
- , mVkManager(thread.vulkanManager()) {}
+ : SkiaPipeline(thread), mVkManager(thread.vulkanManager()) {}
MakeCurrentResult SkiaVulkanPipeline::makeCurrent() {
return MakeCurrentResult::AlreadyCurrent;
@@ -50,7 +49,7 @@
Frame SkiaVulkanPipeline::getFrame() {
LOG_ALWAYS_FATAL_IF(mVkSurface == nullptr,
- "drawRenderNode called on a context with no surface!");
+ "drawRenderNode called on a context with no surface!");
SkSurface* backBuffer = mVkManager.getBackbufferSurface(mVkSurface);
if (backBuffer == nullptr) {
@@ -62,27 +61,25 @@
return frame;
}
-bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty,
- const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector<sp<RenderNode>>& renderNodes,
- FrameInfoVisualizer* profiler) {
-
+bool SkiaVulkanPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) {
sk_sp<SkSurface> backBuffer = mVkSurface->getBackBufferSurface();
if (backBuffer.get() == nullptr) {
return false;
}
SkiaPipeline::updateLighting(lightGeometry, lightInfo);
- renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut,
- contentDrawBounds, backBuffer);
+ renderFrame(*layerUpdateQueue, dirty, renderNodes, opaque, wideColorGamut, contentDrawBounds,
+ backBuffer);
layerUpdateQueue->clear();
// Draw visual debugging features
- if (CC_UNLIKELY(Properties::showDirtyRegions
- || ProfileType::None != Properties::getProfileType())) {
+ if (CC_UNLIKELY(Properties::showDirtyRegions ||
+ ProfileType::None != Properties::getProfileType())) {
SkCanvas* profileCanvas = backBuffer->getCanvas();
SkiaProfileRenderer profileRenderer(profileCanvas);
profiler->draw(profileRenderer);
@@ -97,9 +94,8 @@
return true;
}
-bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew,
- const SkRect& screenDirty, FrameInfo* currentFrameInfo, bool* requireSwap) {
-
+bool SkiaVulkanPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
*requireSwap = drew;
// Even if we decided to cancel the frame, from the perspective of jank
@@ -119,7 +115,7 @@
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
return new VkLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
}
@@ -129,11 +125,10 @@
return new DeferredLayerUpdater(mRenderThread.renderState(), createLayer, Layer::Api::Vulkan);
}
-void SkiaVulkanPipeline::onStop() {
-}
+void SkiaVulkanPipeline::onStop() {}
bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
- ColorMode colorMode) {
+ ColorMode colorMode) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
@@ -162,16 +157,15 @@
}
sk_sp<Bitmap> SkiaVulkanPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
- SkBitmap& skBitmap) {
- //TODO: implement this function for Vulkan pipeline
- //code below is a hack to avoid crashing because of missing HW Bitmap support
- sp<GraphicBuffer> buffer = new GraphicBuffer(skBitmap.info().width(), skBitmap.info().height(),
- PIXEL_FORMAT_RGBA_8888,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
- std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [")
- + std::to_string(getpid()) + "]");
+ SkBitmap& skBitmap) {
+ // TODO: implement this function for Vulkan pipeline
+ // code below is a hack to avoid crashing because of missing HW Bitmap support
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ skBitmap.info().width(), skBitmap.info().height(), PIXEL_FORMAT_RGBA_8888,
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER,
+ std::string("SkiaVulkanPipeline::allocateHardwareBitmap pid [") +
+ std::to_string(getpid()) + "]");
status_t error = buffer->initCheck();
if (error < 0) {
ALOGW("SkiaVulkanPipeline::allocateHardwareBitmap() failed in GraphicBuffer.create()");
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
index 263206d..03b4c79 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.h
@@ -31,25 +31,24 @@
renderthread::MakeCurrentResult makeCurrent() override;
renderthread::Frame getFrame() override;
bool draw(const renderthread::Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode> >& renderNodes,
+ FrameInfoVisualizer* profiler) override;
bool swapBuffers(const renderthread::Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
- renderthread::ColorMode colorMode) override;
+ renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
- SkBitmap& skBitmap);
+ SkBitmap& skBitmap);
private:
renderthread::VulkanManager& mVkManager;
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
index 9c9e17d..8fb621d 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.cpp
@@ -19,9 +19,9 @@
#include <GrRectanizer_pow2.h>
#include <SkCanvas.h>
#include <cmath>
-#include "utils/TraceUtils.h"
#include "renderthread/RenderProxy.h"
#include "renderthread/RenderThread.h"
+#include "utils/TraceUtils.h"
namespace android {
namespace uirenderer {
@@ -30,8 +30,7 @@
VectorDrawableAtlas::VectorDrawableAtlas(size_t surfaceArea, StorageMode storageMode)
: mWidth((int)std::sqrt(surfaceArea))
, mHeight((int)std::sqrt(surfaceArea))
- , mStorageMode(storageMode) {
-}
+ , mStorageMode(storageMode) {}
void VectorDrawableAtlas::prepareForDraw(GrContext* context) {
if (StorageMode::allowSharedSurface == mStorageMode) {
@@ -55,8 +54,8 @@
#define MAX_UNUSED_RATIO 2.0f
bool VectorDrawableAtlas::isFragmented() {
- return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES
- && mPixelUsedByVDs*MAX_UNUSED_RATIO < mPixelAllocated;
+ return mConsecutiveFailures > MAX_CONSECUTIVE_FAILURES &&
+ mPixelUsedByVDs * MAX_UNUSED_RATIO < mPixelAllocated;
}
void VectorDrawableAtlas::repackIfNeeded(GrContext* context) {
@@ -69,9 +68,9 @@
}
// compare to CacheEntry objects based on VD area.
-bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second)
-{
- return first.VDrect.width()*first.VDrect.height() < second.VDrect.width()*second.VDrect.height();
+bool VectorDrawableAtlas::compareCacheEntry(const CacheEntry& first, const CacheEntry& second) {
+ return first.VDrect.width() * first.VDrect.height() <
+ second.VDrect.width() * second.VDrect.height();
}
void VectorDrawableAtlas::repack(GrContext* context) {
@@ -88,7 +87,7 @@
mRectanizer = std::make_unique<GrRectanizerPow2>(mWidth, mHeight);
} else {
if (!mSurface) {
- return; //nothing to repack
+ return; // nothing to repack
}
mRectanizer.reset();
}
@@ -106,20 +105,20 @@
for (CacheEntry& entry : mRects) {
SkRect currentVDRect = entry.VDrect;
- SkImage* sourceImage; //copy either from the atlas or from a standalone surface
+ SkImage* sourceImage; // copy either from the atlas or from a standalone surface
if (entry.surface) {
if (!fitInAtlas(currentVDRect.width(), currentVDRect.height())) {
- continue; //don't even try to repack huge VD
+ continue; // don't even try to repack huge VD
}
sourceImage = entry.surface->makeImageSnapshot().get();
} else {
sourceImage = sourceImageAtlas;
}
- size_t VDRectArea = currentVDRect.width()*currentVDRect.height();
+ size_t VDRectArea = currentVDRect.width() * currentVDRect.height();
SkIPoint16 pos;
if (canvas && mRectanizer->addRect(currentVDRect.width(), currentVDRect.height(), &pos)) {
- SkRect newRect = SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(),
- currentVDRect.height());
+ SkRect newRect =
+ SkRect::MakeXYWH(pos.fX, pos.fY, currentVDRect.width(), currentVDRect.height());
canvas->drawImageRect(sourceImage, currentVDRect, newRect, nullptr);
entry.VDrect = newRect;
entry.rect = newRect;
@@ -134,8 +133,7 @@
if (!entry.surface) {
// A rectangle moved from an atlas to a standalone surface.
mPixelUsedByVDs -= VDRectArea;
- SkRect newRect = SkRect::MakeWH(currentVDRect.width(),
- currentVDRect.height());
+ SkRect newRect = SkRect::MakeWH(currentVDRect.width(), currentVDRect.height());
entry.surface = createSurface(newRect.width(), newRect.height(), context);
auto tempCanvas = entry.surface->getCanvas();
tempCanvas->clear(SK_ColorTRANSPARENT);
@@ -158,7 +156,7 @@
}
if (mSurface) {
- const size_t area = width*height;
+ const size_t area = width * height;
// Use a rectanizer to allocate unused space from the atlas surface.
bool notTooBig = fitInAtlas(width, height);
@@ -243,10 +241,10 @@
// Store freed atlas rectangles in "mFreeRects" and try to reuse them later, when atlas
// is full.
SkRect& removedRect = entry->rect;
- size_t rectArea = removedRect.width()*removedRect.height();
+ size_t rectArea = removedRect.width() * removedRect.height();
mFreeRects.emplace(rectArea, removedRect);
SkRect& removedVDRect = entry->VDrect;
- size_t VDRectArea = removedVDRect.width()*removedVDRect.height();
+ size_t VDRectArea = removedVDRect.width() * removedVDRect.height();
mPixelUsedByVDs -= VDRectArea;
mConsecutiveFailures = 0;
}
@@ -272,8 +270,8 @@
SkImageInfo info = SkImageInfo::MakeN32(width, height, kPremul_SkAlphaType, colorSpace);
// This must have a top-left origin so that calls to surface->canvas->writePixels
// performs a basic texture upload instead of a more complex drawing operation
- return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0,
- kTopLeft_GrSurfaceOrigin, nullptr);
+ return SkSurface::MakeRenderTarget(context, SkBudgeted::kYes, info, 0, kTopLeft_GrSurfaceOrigin,
+ nullptr);
}
void VectorDrawableAtlas::setStorageMode(StorageMode mode) {
diff --git a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
index 0683b39..74e48ce 100644
--- a/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
+++ b/libs/hwui/pipeline/skia/VectorDrawableAtlas.h
@@ -16,12 +16,12 @@
#pragma once
-#include <map>
#include <SkSurface.h>
#include <utils/FatVector.h>
#include <utils/RefBase.h>
#include <utils/Thread.h>
#include <list>
+#include <map>
class GrRectanizer;
@@ -55,18 +55,15 @@
* When a VectorDrawable is deleted, it invokes VectorDrawableAtlas::releaseEntry, which is keeping
* track of free spaces and allow to reuse the surface for another VD.
*/
- //TODO: Check if not using atlas for AnimatedVD is more efficient.
- //TODO: For low memory situations, when there are no paint effects in VD, we may render without an
- //TODO: offscreen surface.
+// TODO: Check if not using atlas for AnimatedVD is more efficient.
+// TODO: For low memory situations, when there are no paint effects in VD, we may render without an
+// TODO: offscreen surface.
class VectorDrawableAtlas : public virtual RefBase {
public:
- enum class StorageMode {
- allowSharedSurface,
- disallowSharedSurface
- };
+ enum class StorageMode { allowSharedSurface, disallowSharedSurface };
VectorDrawableAtlas(size_t surfaceArea,
- StorageMode storageMode = StorageMode::allowSharedSurface);
+ StorageMode storageMode = StorageMode::allowSharedSurface);
/**
* "prepareForDraw" may allocate a new surface if needed. It may schedule to repack the
@@ -120,10 +117,8 @@
private:
struct CacheEntry {
CacheEntry(const SkRect& newVDrect, const SkRect& newRect,
- const sk_sp<SkSurface>& newSurface)
- : VDrect(newVDrect)
- , rect(newRect)
- , surface(newSurface) { }
+ const sk_sp<SkSurface>& newSurface)
+ : VDrect(newVDrect), rect(newRect), surface(newSurface) {}
/**
* size and position of VectorDrawable into the atlas or in "this.surface"
@@ -204,7 +199,7 @@
sk_sp<SkSurface> createSurface(int width, int height, GrContext* context);
inline bool fitInAtlas(int width, int height) {
- return 2*width < mWidth && 2*height < mHeight;
+ return 2 * width < mWidth && 2 * height < mHeight;
}
void repack(GrContext* context);
diff --git a/libs/hwui/private/hwui/DrawGlInfo.h b/libs/hwui/private/hwui/DrawGlInfo.h
index f578513..efa9da2 100644
--- a/libs/hwui/private/hwui/DrawGlInfo.h
+++ b/libs/hwui/private/hwui/DrawGlInfo.h
@@ -81,9 +81,9 @@
// commands are issued.
kStatusDrew = 0x4
};
-}; // struct DrawGlInfo
+}; // struct DrawGlInfo
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_DRAW_GL_INFO_H
+#endif // ANDROID_HWUI_DRAW_GL_INFO_H
diff --git a/libs/hwui/protos/ProtoHelpers.h b/libs/hwui/protos/ProtoHelpers.h
index 832e312..833c77f 100644
--- a/libs/hwui/protos/ProtoHelpers.h
+++ b/libs/hwui/protos/ProtoHelpers.h
@@ -35,7 +35,7 @@
src.writeToMemory(&*dest->begin());
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
-#endif // PROTOHELPERS_H
+#endif // PROTOHELPERS_H
diff --git a/libs/hwui/renderstate/Blend.cpp b/libs/hwui/renderstate/Blend.cpp
index b1ca4a2..5bef01c 100644
--- a/libs/hwui/renderstate/Blend.cpp
+++ b/libs/hwui/renderstate/Blend.cpp
@@ -52,49 +52,42 @@
// In this array, the index of each Blender equals the value of the first
// entry. For instance, gBlends[1] == gBlends[SkBlendMode::kSrc]
-const Blender kBlends[] = {
- { SkBlendMode::kClear, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kSrc, GL_ONE, GL_ZERO },
- { SkBlendMode::kDst, GL_ZERO, GL_ONE },
- { SkBlendMode::kSrcOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kDstOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkBlendMode::kSrcIn, GL_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kDstIn, GL_ZERO, GL_SRC_ALPHA },
- { SkBlendMode::kSrcOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kDstOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kSrcATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kDstATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kPlus, GL_ONE, GL_ONE },
- { SkBlendMode::kModulate, GL_ZERO, GL_SRC_COLOR },
- { SkBlendMode::kScreen, GL_ONE, GL_ONE_MINUS_SRC_COLOR }
-};
+const Blender kBlends[] = {{SkBlendMode::kClear, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kSrc, GL_ONE, GL_ZERO},
+ {SkBlendMode::kDst, GL_ZERO, GL_ONE},
+ {SkBlendMode::kSrcOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kDstOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+ {SkBlendMode::kSrcIn, GL_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kDstIn, GL_ZERO, GL_SRC_ALPHA},
+ {SkBlendMode::kSrcOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kDstOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kSrcATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kDstATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+ {SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kPlus, GL_ONE, GL_ONE},
+ {SkBlendMode::kModulate, GL_ZERO, GL_SRC_COLOR},
+ {SkBlendMode::kScreen, GL_ONE, GL_ONE_MINUS_SRC_COLOR}};
// This array contains the swapped version of each SkBlendMode. For instance
// this array's SrcOver blending mode is actually DstOver. You can refer to
// createLayer() for more information on the purpose of this array.
-const Blender kBlendsSwap[] = {
- { SkBlendMode::kClear, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kSrc, GL_ZERO, GL_ONE },
- { SkBlendMode::kDst, GL_ONE, GL_ZERO },
- { SkBlendMode::kSrcOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
- { SkBlendMode::kDstOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kSrcIn, GL_ZERO, GL_SRC_ALPHA },
- { SkBlendMode::kDstIn, GL_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kSrcOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kDstOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
- { SkBlendMode::kSrcATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
- { SkBlendMode::kDstATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
- { SkBlendMode::kPlus, GL_ONE, GL_ONE },
- { SkBlendMode::kModulate, GL_DST_COLOR, GL_ZERO },
- { SkBlendMode::kScreen, GL_ONE_MINUS_DST_COLOR, GL_ONE }
-};
+const Blender kBlendsSwap[] = {{SkBlendMode::kClear, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kSrc, GL_ZERO, GL_ONE},
+ {SkBlendMode::kDst, GL_ONE, GL_ZERO},
+ {SkBlendMode::kSrcOver, GL_ONE_MINUS_DST_ALPHA, GL_ONE},
+ {SkBlendMode::kDstOver, GL_ONE, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kSrcIn, GL_ZERO, GL_SRC_ALPHA},
+ {SkBlendMode::kDstIn, GL_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kSrcOut, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kDstOut, GL_ONE_MINUS_DST_ALPHA, GL_ZERO},
+ {SkBlendMode::kSrcATop, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA},
+ {SkBlendMode::kDstATop, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kXor, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA},
+ {SkBlendMode::kPlus, GL_ONE, GL_ONE},
+ {SkBlendMode::kModulate, GL_DST_COLOR, GL_ZERO},
+ {SkBlendMode::kScreen, GL_ONE_MINUS_DST_COLOR, GL_ONE}};
-Blend::Blend()
- : mEnabled(false)
- , mSrcMode(GL_ZERO)
- , mDstMode(GL_ZERO) {
+Blend::Blend() : mEnabled(false), mSrcMode(GL_ZERO), mDstMode(GL_ZERO) {
// gl blending off by default
}
@@ -145,4 +138,3 @@
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/Blend.h b/libs/hwui/renderstate/Blend.h
index a9de246..7e559ba 100644
--- a/libs/hwui/renderstate/Blend.h
+++ b/libs/hwui/renderstate/Blend.h
@@ -28,6 +28,7 @@
class Blend {
friend class RenderState;
+
public:
// dictates whether to swap src/dst
enum class ModeOrderSwap {
@@ -36,19 +37,18 @@
};
void syncEnabled();
- static void getFactors(SkBlendMode mode, ModeOrderSwap modeUsage,
- GLenum* outSrc, GLenum* outDst);
+ static void getFactors(SkBlendMode mode, ModeOrderSwap modeUsage, GLenum* outSrc,
+ GLenum* outDst);
void setFactors(GLenum src, GLenum dst);
- bool getEnabled() {
- return mEnabled;
- }
+ bool getEnabled() { return mEnabled; }
void getFactors(GLenum* src, GLenum* dst) {
*src = mSrcMode;
*dst = mDstMode;
}
void dump();
+
private:
Blend();
void invalidate();
@@ -60,4 +60,4 @@
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_BLEND_H
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderstate/MeshState.cpp b/libs/hwui/renderstate/MeshState.cpp
index 6d02936..4f6c49e 100644
--- a/libs/hwui/renderstate/MeshState.cpp
+++ b/libs/hwui/renderstate/MeshState.cpp
@@ -38,12 +38,12 @@
for (uint32_t i = 0; i < kMaxNumberOfQuads; i++) {
uint16_t quad = i * 4;
int index = i * 6;
- regionIndices[index ] = quad; // top-left
- regionIndices[index + 1] = quad + 1; // top-right
- regionIndices[index + 2] = quad + 2; // bottom-left
- regionIndices[index + 3] = quad + 2; // bottom-left
- regionIndices[index + 4] = quad + 1; // top-right
- regionIndices[index + 5] = quad + 3; // bottom-right
+ regionIndices[index] = quad; // top-left
+ regionIndices[index + 1] = quad + 1; // top-right
+ regionIndices[index + 2] = quad + 2; // bottom-left
+ regionIndices[index + 3] = quad + 2; // bottom-left
+ regionIndices[index + 4] = quad + 1; // top-right
+ regionIndices[index + 5] = quad + 3; // bottom-right
}
glGenBuffers(1, &mQuadListIndices);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mQuadListIndices);
@@ -65,10 +65,10 @@
void MeshState::dump() {
ALOGD("MeshState VBOs: unitQuad %d, current %d", mUnitQuadBuffer, mCurrentBuffer);
ALOGD("MeshState IBOs: quadList %d, current %d", mQuadListIndices, mCurrentIndicesBuffer);
- ALOGD("MeshState vertices: vertex data %p, stride %d",
- mCurrentPositionPointer, mCurrentPositionStride);
- ALOGD("MeshState texCoord: data %p, stride %d",
- mCurrentTexCoordsPointer, mCurrentTexCoordsStride);
+ ALOGD("MeshState vertices: vertex data %p, stride %d", mCurrentPositionPointer,
+ mCurrentPositionStride);
+ ALOGD("MeshState texCoord: data %p, stride %d", mCurrentTexCoordsPointer,
+ mCurrentTexCoordsStride);
}
///////////////////////////////////////////////////////////////////////////////
@@ -89,8 +89,8 @@
return bindMeshBuffer(0);
}
-void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size,
- const void* data, GLenum usage) {
+void MeshState::genOrUpdateMeshBuffer(GLuint* buffer, GLsizeiptr size, const void* data,
+ GLenum usage) {
if (!*buffer) {
glGenBuffers(1, buffer);
}
@@ -98,8 +98,8 @@
glBufferData(GL_ARRAY_BUFFER, size, data, usage);
}
-void MeshState::updateMeshBufferSubData(GLuint buffer, GLintptr offset,
- GLsizeiptr size, const void* data) {
+void MeshState::updateMeshBufferSubData(GLuint buffer, GLintptr offset, GLsizeiptr size,
+ const void* data) {
bindMeshBuffer(buffer);
glBufferSubData(GL_ARRAY_BUFFER, offset, size, data);
}
@@ -119,9 +119,8 @@
void MeshState::bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride) {
// update pos coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
- if (mCurrentBuffer == 0
- || vertices != mCurrentPositionPointer
- || stride != mCurrentPositionStride) {
+ if (mCurrentBuffer == 0 || vertices != mCurrentPositionPointer ||
+ stride != mCurrentPositionStride) {
glVertexAttribPointer(Program::kBindingPosition, 2, GL_FLOAT, GL_FALSE, stride, vertices);
mCurrentPositionPointer = vertices;
mCurrentPositionStride = stride;
@@ -130,9 +129,8 @@
void MeshState::bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride) {
// update tex coords if !current vbo, since vertices may point into mutable memory (e.g. stack)
- if (mCurrentBuffer == 0
- || vertices != mCurrentTexCoordsPointer
- || stride != mCurrentTexCoordsStride) {
+ if (mCurrentBuffer == 0 || vertices != mCurrentTexCoordsPointer ||
+ stride != mCurrentTexCoordsStride) {
glVertexAttribPointer(Program::kBindingTexCoords, 2, GL_FLOAT, GL_FALSE, stride, vertices);
mCurrentTexCoordsPointer = vertices;
mCurrentTexCoordsStride = stride;
@@ -179,4 +177,3 @@
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/MeshState.h b/libs/hwui/renderstate/MeshState.h
index 17ad462..95faf1e 100644
--- a/libs/hwui/renderstate/MeshState.h
+++ b/libs/hwui/renderstate/MeshState.h
@@ -33,10 +33,7 @@
// This array is never used directly but used as a memcpy source in the
// OpenGLRenderer constructor
const TextureVertex kUnitQuadVertices[] = {
- { 0, 0, 0, 0 },
- { 1, 0, 1, 0 },
- { 0, 1, 0, 1 },
- { 1, 1, 1, 1 },
+ {0, 0, 0, 0}, {1, 0, 1, 0}, {0, 1, 0, 1}, {1, 1, 1, 1},
};
const GLsizei kVertexStride = sizeof(Vertex);
@@ -82,15 +79,13 @@
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gTextureVertexStride and a size of 2.
*/
- void bindPositionVertexPointer(const GLvoid* vertices,
- GLsizei stride = kTextureVertexStride);
+ void bindPositionVertexPointer(const GLvoid* vertices, GLsizei stride = kTextureVertexStride);
/**
* Binds an attrib to the specified float vertex pointer.
* Assumes a stride of gTextureVertexStride and a size of 2.
*/
- void bindTexCoordsVertexPointer(const GLvoid* vertices,
- GLsizei stride = kTextureVertexStride);
+ void bindTexCoordsVertexPointer(const GLvoid* vertices, GLsizei stride = kTextureVertexStride);
/**
* Resets the vertex pointers.
@@ -111,6 +106,7 @@
///////////////////////////////////////////////////////////////////////////////
GLuint getUnitQuadVBO() { return mUnitQuadBuffer; }
GLuint getQuadListIBO() { return mQuadListIndices; }
+
private:
MeshState();
@@ -134,4 +130,4 @@
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_MESHSTATE_H
+#endif // RENDERSTATE_MESHSTATE_H
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp
index ea292d6..a0f5cb9 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.cpp
+++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp
@@ -33,8 +33,8 @@
// OffscreenBuffer
////////////////////////////////////////////////////////////////////////////////
-OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t viewportWidth, uint32_t viewportHeight, bool wideColorGamut)
+OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth,
+ uint32_t viewportHeight, bool wideColorGamut)
: GpuMemoryTracker(GpuObjectType::OffscreenBuffer)
, renderState(renderState)
, viewportWidth(viewportWidth)
@@ -45,8 +45,8 @@
uint32_t height = computeIdealDimension(viewportHeight);
ATRACE_FORMAT("Allocate %ux%u HW Layer", width, height);
caches.textureState().activateTexture(0);
- texture.resize(width, height,
- wideColorGamut ? GL_RGBA16F : caches.rgbaInternalFormat(), GL_RGBA);
+ texture.resize(width, height, wideColorGamut ? GL_RGBA16F : caches.rgbaInternalFormat(),
+ GL_RGBA);
texture.blend = true;
texture.setWrap(GL_CLAMP_TO_EDGE);
// not setting filter on texture, since it's set when drawing, based on transform
@@ -61,8 +61,8 @@
void OffscreenBuffer::dirty(Rect dirtyArea) {
dirtyArea.doIntersect(0, 0, viewportWidth, viewportHeight);
if (!dirtyArea.isEmpty()) {
- region.orSelf(android::Rect(dirtyArea.left, dirtyArea.top,
- dirtyArea.right, dirtyArea.bottom));
+ region.orSelf(
+ android::Rect(dirtyArea.left, dirtyArea.top, dirtyArea.right, dirtyArea.bottom));
}
}
@@ -78,7 +78,8 @@
const float texX = 1.0f / float(texture.width());
const float texY = 1.0f / float(texture.height());
- FatVector<TextureVertex, 64> meshVector(count * 4); // uses heap if more than 64 vertices needed
+ FatVector<TextureVertex, 64> meshVector(count *
+ 4); // uses heap if more than 64 vertices needed
TextureVertex* mesh = &meshVector[0];
for (size_t i = 0; i < count; i++) {
const android::Rect* r = &rects[i];
@@ -94,10 +95,9 @@
TextureVertex::set(mesh++, r->right, r->bottom, u2, v2);
}
elementCount = count * 6;
- renderState.meshState().genOrUpdateMeshBuffer(&vbo,
- sizeof(TextureVertex) * count * 4,
- &meshVector[0],
- GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
+ renderState.meshState().genOrUpdateMeshBuffer(
+ &vbo, sizeof(TextureVertex) * count * 4, &meshVector[0],
+ GL_DYNAMIC_DRAW); // TODO: GL_STATIC_DRAW if savelayer
}
uint32_t OffscreenBuffer::computeIdealDimension(uint32_t dimension) {
@@ -117,12 +117,11 @@
///////////////////////////////////////////////////////////////////////////////
OffscreenBufferPool::OffscreenBufferPool()
- // 4 screen-sized RGBA_8888 textures
- : mMaxSize(DeviceInfo::multiplyByResolution(4 * 4)) {
-}
+ // 4 screen-sized RGBA_8888 textures
+ : mMaxSize(DeviceInfo::multiplyByResolution(4 * 4)) {}
OffscreenBufferPool::~OffscreenBufferPool() {
- clear(); // TODO: unique_ptr?
+ clear(); // TODO: unique_ptr?
}
int OffscreenBufferPool::Entry::compare(const Entry& lhs, const Entry& rhs) {
@@ -143,8 +142,8 @@
mSize = 0;
}
-OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState,
- const uint32_t width, const uint32_t height, bool wideColorGamut) {
+OffscreenBuffer* OffscreenBufferPool::get(RenderState& renderState, const uint32_t width,
+ const uint32_t height, bool wideColorGamut) {
OffscreenBuffer* layer = nullptr;
Entry entry(width, height, wideColorGamut);
@@ -159,18 +158,18 @@
layer->viewportHeight = height;
mSize -= layer->getSizeInBytes();
} else {
- layer = new OffscreenBuffer(renderState, Caches::getInstance(),
- width, height, wideColorGamut);
+ layer = new OffscreenBuffer(renderState, Caches::getInstance(), width, height,
+ wideColorGamut);
}
return layer;
}
-OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer,
- const uint32_t width, const uint32_t height) {
+OffscreenBuffer* OffscreenBufferPool::resize(OffscreenBuffer* layer, const uint32_t width,
+ const uint32_t height) {
RenderState& renderState = layer->renderState;
- if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width)
- && layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) {
+ if (layer->texture.width() == OffscreenBuffer::computeIdealDimension(width) &&
+ layer->texture.height() == OffscreenBuffer::computeIdealDimension(height)) {
// resize in place
layer->viewportWidth = width;
layer->viewportHeight = height;
@@ -214,5 +213,5 @@
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h
index d9422c9..08ae052 100644
--- a/libs/hwui/renderstate/OffscreenBufferPool.h
+++ b/libs/hwui/renderstate/OffscreenBufferPool.h
@@ -18,10 +18,10 @@
#define ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
#include <GpuMemoryTracker.h>
+#include <ui/Region.h>
#include "Caches.h"
#include "Texture.h"
#include "utils/Macros.h"
-#include <ui/Region.h>
#include <set>
@@ -42,8 +42,8 @@
*/
class OffscreenBuffer : GpuMemoryTracker {
public:
- OffscreenBuffer(RenderState& renderState, Caches& caches,
- uint32_t viewportWidth, uint32_t viewportHeight, bool wideColorGamut = false);
+ OffscreenBuffer(RenderState& renderState, Caches& caches, uint32_t viewportWidth,
+ uint32_t viewportHeight, bool wideColorGamut = false);
~OffscreenBuffer();
Rect getTextureCoordinates();
@@ -91,11 +91,11 @@
OffscreenBufferPool();
~OffscreenBufferPool();
- WARN_UNUSED_RESULT OffscreenBuffer* get(RenderState& renderState,
- const uint32_t width, const uint32_t height, bool wideColorGamut = false);
+ WARN_UNUSED_RESULT OffscreenBuffer* get(RenderState& renderState, const uint32_t width,
+ const uint32_t height, bool wideColorGamut = false);
- WARN_UNUSED_RESULT OffscreenBuffer* resize(OffscreenBuffer* layer,
- const uint32_t width, const uint32_t height);
+ WARN_UNUSED_RESULT OffscreenBuffer* resize(OffscreenBuffer* layer, const uint32_t width,
+ const uint32_t height);
void putOrDelete(OffscreenBuffer* layer);
@@ -120,6 +120,7 @@
* Prints out the content of the pool.
*/
void dump();
+
private:
struct Entry {
Entry() {}
@@ -133,36 +134,29 @@
: layer(layer)
, width(layer->texture.width())
, height(layer->texture.height())
- , wideColorGamut(layer->wideColorGamut) {
- }
+ , wideColorGamut(layer->wideColorGamut) {}
static int compare(const Entry& lhs, const Entry& rhs);
- bool operator==(const Entry& other) const {
- return compare(*this, other) == 0;
- }
+ bool operator==(const Entry& other) const { return compare(*this, other) == 0; }
- bool operator!=(const Entry& other) const {
- return compare(*this, other) != 0;
- }
+ bool operator!=(const Entry& other) const { return compare(*this, other) != 0; }
- bool operator<(const Entry& other) const {
- return Entry::compare(*this, other) < 0;
- }
+ bool operator<(const Entry& other) const { return Entry::compare(*this, other) < 0; }
OffscreenBuffer* layer = nullptr;
uint32_t width = 0;
uint32_t height = 0;
bool wideColorGamut = false;
- }; // struct Entry
+ }; // struct Entry
std::multiset<Entry> mPool;
uint32_t mSize = 0;
uint32_t mMaxSize;
-}; // class OffscreenBufferCache
+}; // class OffscreenBufferCache
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
+#endif // ANDROID_HWUI_OFFSCREEN_BUFFER_POOL_H
diff --git a/libs/hwui/renderstate/PixelBufferState.cpp b/libs/hwui/renderstate/PixelBufferState.cpp
index c23af52..3a6efb8 100644
--- a/libs/hwui/renderstate/PixelBufferState.cpp
+++ b/libs/hwui/renderstate/PixelBufferState.cpp
@@ -18,9 +18,7 @@
namespace android {
namespace uirenderer {
-PixelBufferState::PixelBufferState()
- : mCurrentPixelBuffer(0) {
-}
+PixelBufferState::PixelBufferState() : mCurrentPixelBuffer(0) {}
bool PixelBufferState::bind(GLuint buffer) {
if (mCurrentPixelBuffer != buffer) {
@@ -42,4 +40,3 @@
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/PixelBufferState.h b/libs/hwui/renderstate/PixelBufferState.h
index 8dab21d..f7ae6c5 100644
--- a/libs/hwui/renderstate/PixelBufferState.h
+++ b/libs/hwui/renderstate/PixelBufferState.h
@@ -22,10 +22,11 @@
namespace uirenderer {
class PixelBufferState {
- friend class Caches; // TODO: move to RenderState
+ friend class Caches; // TODO: move to RenderState
public:
bool bind(GLuint buffer);
bool unbind();
+
private:
PixelBufferState();
GLuint mCurrentPixelBuffer;
@@ -34,4 +35,4 @@
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_PIXELBUFFERSTATE_H
+#endif // RENDERSTATE_PIXELBUFFERSTATE_H
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index 0ceca33..5e33353 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -13,11 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "renderstate/RenderState.h"
+#include <GpuMemoryTracker.h>
#include "DeferredLayerUpdater.h"
#include "GlLayer.h"
#include "VkLayer.h"
-#include <GpuMemoryTracker.h>
-#include "renderstate/RenderState.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/EglManager.h"
@@ -31,21 +31,18 @@
namespace uirenderer {
RenderState::RenderState(renderthread::RenderThread& thread)
- : mRenderThread(thread)
- , mViewportWidth(0)
- , mViewportHeight(0)
- , mFramebuffer(0) {
+ : mRenderThread(thread), mViewportWidth(0), mViewportHeight(0), mFramebuffer(0) {
mThreadId = pthread_self();
}
RenderState::~RenderState() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
- "State object lifecycle not managed correctly");
+ "State object lifecycle not managed correctly");
}
void RenderState::onGLContextCreated() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
- "State object lifecycle not managed correctly");
+ "State object lifecycle not managed correctly");
GpuMemoryTracker::onGpuContextCreated();
mBlend = new Blend();
@@ -67,7 +64,7 @@
static void layerLostGlContext(Layer* layer) {
LOG_ALWAYS_FATAL_IF(layer->getApi() != Layer::Api::OpenGL,
- "layerLostGlContext on non GL layer");
+ "layerLostGlContext on non GL layer");
static_cast<GlLayer*>(layer)->onGlContextLost();
}
@@ -94,7 +91,7 @@
void RenderState::onVkContextCreated() {
LOG_ALWAYS_FATAL_IF(mBlend || mMeshState || mScissor || mStencil,
- "State object lifecycle not managed correctly");
+ "State object lifecycle not managed correctly");
GpuMemoryTracker::onGpuContextCreated();
}
@@ -117,9 +114,9 @@
void RenderState::flush(Caches::FlushMode mode) {
switch (mode) {
case Caches::FlushMode::Full:
- // fall through
+ // fall through
case Caches::FlushMode::Moderate:
- // fall through
+ // fall through
case Caches::FlushMode::Layers:
if (mLayerPool) mLayerPool->clear();
break;
@@ -140,7 +137,6 @@
glViewport(0, 0, mViewportWidth, mViewportHeight);
}
-
void RenderState::getViewport(GLsizei* outWidth, GLsizei* outHeight) {
*outWidth = mViewportWidth;
*outHeight = mViewportHeight;
@@ -189,15 +185,13 @@
meshState().disableTexCoordsVertexArray();
debugOverdraw(false, false);
// TODO: We need a way to know whether the functor is sRGB aware (b/32072673)
- if (mCaches->extensions().hasLinearBlending() &&
- mCaches->extensions().hasSRGBWriteControl()) {
+ if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
glDisable(GL_FRAMEBUFFER_SRGB_EXT);
}
}
void RenderState::resumeFromFunctorInvoke() {
- if (mCaches->extensions().hasLinearBlending() &&
- mCaches->extensions().hasSRGBWriteControl()) {
+ if (mCaches->extensions().hasLinearBlending() && mCaches->extensions().hasSRGBWriteControl()) {
glEnable(GL_FRAMEBUFFER_SRGB_EXT);
}
@@ -249,7 +243,7 @@
///////////////////////////////////////////////////////////////////////////////
void RenderState::render(const Glop& glop, const Matrix4& orthoMatrix,
- bool overrideDisableBlending) {
+ bool overrideDisableBlending) {
const Glop::Mesh& mesh = glop.mesh;
const Glop::Mesh::Vertices& vertices = mesh.vertices;
const Glop::Mesh::Indices& indices = mesh.indices;
@@ -266,21 +260,19 @@
fill.program->setColor(fill.color);
}
- fill.program->set(orthoMatrix,
- glop.transform.modelView,
- glop.transform.meshTransform(),
- glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
+ fill.program->set(orthoMatrix, glop.transform.modelView, glop.transform.meshTransform(),
+ glop.transform.transformFlags & TransformFlags::OffsetByFudgeFactor);
// Color filter uniforms
if (fill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
const FloatColor& color = fill.filter.color;
- glUniform4f(mCaches->program().getUniform("colorBlend"),
- color.r, color.g, color.b, color.a);
+ glUniform4f(mCaches->program().getUniform("colorBlend"), color.r, color.g, color.b,
+ color.a);
} else if (fill.filterMode == ProgramDescription::ColorFilterMode::Matrix) {
glUniformMatrix4fv(mCaches->program().getUniform("colorMatrix"), 1, GL_FALSE,
- fill.filter.matrix.matrix);
+ fill.filter.matrix.matrix);
glUniform4fv(mCaches->program().getUniform("colorMatrixVector"), 1,
- fill.filter.matrix.vector);
+ fill.filter.matrix.vector);
}
// Round rect clipping uniforms
@@ -295,15 +287,14 @@
// Divide by the radius to simplify the calculations in the fragment shader
// roundRectPos is also passed from vertex shader relative to top/left & radius
glUniform4f(fill.program->getUniform("roundRectInnerRectLTWH"),
- innerRect.left / roundedOutRadius, innerRect.top / roundedOutRadius,
- (innerRect.right - innerRect.left) / roundedOutRadius,
- (innerRect.bottom - innerRect.top) / roundedOutRadius);
+ innerRect.left / roundedOutRadius, innerRect.top / roundedOutRadius,
+ (innerRect.right - innerRect.left) / roundedOutRadius,
+ (innerRect.bottom - innerRect.top) / roundedOutRadius);
- glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"),
- 1, GL_FALSE, &state->matrix.data[0]);
+ glUniformMatrix4fv(fill.program->getUniform("roundRectInvTransform"), 1, GL_FALSE,
+ &state->matrix.data[0]);
- glUniform1f(fill.program->getUniform("roundRectRadius"),
- roundedOutRadius);
+ glUniform1f(fill.program->getUniform("roundRectRadius"), roundedOutRadius);
}
GL_CHECKPOINT(MODERATE);
@@ -333,8 +324,8 @@
}
if (texture.textureTransform) {
- glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1,
- GL_FALSE, &texture.textureTransform->data[0]);
+ glUniformMatrix4fv(fill.program->getUniform("mainTextureTransform"), 1, GL_FALSE,
+ &texture.textureTransform->data[0]);
}
}
@@ -349,12 +340,13 @@
if (vertices.attribFlags & VertexAttribFlags::Color) {
colorLocation = fill.program->getAttrib("colors");
glEnableVertexAttribArray(colorLocation);
- glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride, vertices.color);
+ glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, vertices.stride,
+ vertices.color);
}
int alphaLocation = -1;
if (vertices.attribFlags & VertexAttribFlags::Alpha) {
// NOTE: alpha vertex position is computed assuming no VBO
- const void* alphaCoords = ((const GLbyte*) vertices.position) + kVertexAlphaOffset;
+ const void* alphaCoords = ((const GLbyte*)vertices.position) + kVertexAlphaOffset;
alphaLocation = fill.program->getAttrib("vtxAlpha");
glEnableVertexAttribArray(alphaLocation);
glVertexAttribPointer(alphaLocation, 1, GL_FLOAT, GL_FALSE, vertices.stride, alphaCoords);
@@ -363,8 +355,9 @@
SkiaShader::apply(*mCaches, fill.skiaShaderData, mViewportWidth, mViewportHeight);
GL_CHECKPOINT(MODERATE);
- Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType) ?
- fill.skiaShaderData.bitmapData.bitmapTexture : nullptr;
+ Texture* texture = (fill.skiaShaderData.skiaShaderType & kBitmap_SkiaShaderType)
+ ? fill.skiaShaderData.bitmapData.bitmapTexture
+ : nullptr;
const AutoTexture autoCleanup(texture);
// If we have a shader and a base texture, the base texture is assumed to be an alpha mask
@@ -373,8 +366,8 @@
if (colorSpaceTexture != nullptr) {
if (colorSpaceTexture->hasColorSpaceConversion()) {
const ColorSpaceConnector* connector = colorSpaceTexture->getColorSpaceConnector();
- glUniformMatrix3fv(fill.program->getUniform("colorSpaceMatrix"), 1,
- GL_FALSE, connector->getTransform().asArray());
+ glUniformMatrix3fv(fill.program->getUniform("colorSpaceMatrix"), 1, GL_FALSE,
+ connector->getTransform().asArray());
}
TransferFunctionType transferFunction = colorSpaceTexture->getTransferFunctionType();
@@ -387,15 +380,15 @@
break;
case TransferFunctionType::Full:
glUniform1fv(fill.program->getUniform("transferFunction"), 7,
- reinterpret_cast<const float*>(&source.getTransferParameters().g));
+ reinterpret_cast<const float*>(&source.getTransferParameters().g));
break;
case TransferFunctionType::Limited:
glUniform1fv(fill.program->getUniform("transferFunction"), 5,
- reinterpret_cast<const float*>(&source.getTransferParameters().g));
+ reinterpret_cast<const float*>(&source.getTransferParameters().g));
break;
case TransferFunctionType::Gamma:
glUniform1f(fill.program->getUniform("transferFunctionGamma"),
- source.getTransferParameters().g);
+ source.getTransferParameters().g);
break;
}
}
@@ -421,16 +414,17 @@
GLsizei elementsCount = mesh.elementCount;
const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
while (elementsCount > 0) {
- GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+ GLsizei drawCount = std::min(elementsCount, (GLsizei)kMaxNumberOfQuads * 6);
GLsizei vertexCount = (drawCount / 6) * 4;
meshState().bindPositionVertexPointer(vertexData, vertices.stride);
if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
- meshState().bindTexCoordsVertexPointer(
- vertexData + kMeshTextureOffset, vertices.stride);
+ meshState().bindTexCoordsVertexPointer(vertexData + kMeshTextureOffset,
+ vertices.stride);
}
if (mCaches->extensions().getMajorGlVersion() >= 3) {
- glDrawRangeElements(mesh.primitiveMode, 0, vertexCount-1, drawCount, GL_UNSIGNED_SHORT, nullptr);
+ glDrawRangeElements(mesh.primitiveMode, 0, vertexCount - 1, drawCount,
+ GL_UNSIGNED_SHORT, nullptr);
} else {
glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
}
@@ -439,10 +433,13 @@
}
} else if (indices.bufferObject || indices.indices) {
if (mCaches->extensions().getMajorGlVersion() >= 3) {
- // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine the min/max index values)
- glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount-1, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+ // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine
+ // the min/max index values)
+ glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount - 1, mesh.elementCount,
+ GL_UNSIGNED_SHORT, indices.indices);
} else {
- glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+ glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT,
+ indices.indices);
}
} else {
glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
diff --git a/libs/hwui/renderstate/RenderState.h b/libs/hwui/renderstate/RenderState.h
index 315fa2d..e033cf2 100644
--- a/libs/hwui/renderstate/RenderState.h
+++ b/libs/hwui/renderstate/RenderState.h
@@ -26,14 +26,14 @@
#include "renderstate/Stencil.h"
#include "utils/Macros.h"
-#include <set>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
-#include <ui/Region.h>
-#include <utils/Mutex.h>
-#include <utils/Functor.h>
-#include <utils/RefBase.h>
#include <private/hwui/DrawGlInfo.h>
+#include <ui/Region.h>
+#include <utils/Functor.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <set>
class GrContext;
@@ -57,6 +57,7 @@
friend class renderthread::RenderThread;
friend class Caches;
friend class renderthread::CacheManager;
+
public:
void onGLContextCreated();
void onGLContextDestroyed();
@@ -79,12 +80,8 @@
void debugOverdraw(bool enable, bool clear);
- void registerLayer(Layer* layer) {
- mActiveLayers.insert(layer);
- }
- void unregisterLayer(Layer* layer) {
- mActiveLayers.erase(layer);
- }
+ void registerLayer(Layer* layer) { mActiveLayers.insert(layer); }
+ void unregisterLayer(Layer* layer) { mActiveLayers.erase(layer); }
void registerCanvasContext(renderthread::CanvasContext* context) {
mRegisteredContexts.insert(context);
@@ -127,7 +124,6 @@
explicit RenderState(renderthread::RenderThread& thread);
~RenderState();
-
renderthread::RenderThread& mRenderThread;
Caches* mCaches = nullptr;
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index 61dd8c3..e37ed02 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -23,12 +23,7 @@
namespace uirenderer {
Scissor::Scissor()
- : mEnabled(false)
- , mScissorX(0)
- , mScissorY(0)
- , mScissorWidth(0)
- , mScissorHeight(0) {
-}
+ : mEnabled(false), mScissorX(0), mScissorY(0), mScissorWidth(0), mScissorHeight(0) {}
bool Scissor::setEnabled(bool enabled) {
if (mEnabled != enabled) {
@@ -44,9 +39,8 @@
}
bool Scissor::set(GLint x, GLint y, GLint width, GLint height) {
- if (mEnabled && (x != mScissorX || y != mScissorY
- || width != mScissorWidth || height != mScissorHeight)) {
-
+ if (mEnabled &&
+ (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight)) {
if (x < 0) {
width += x;
x = 0;
@@ -80,10 +74,7 @@
GLint width = std::max(0, ((int)clip.right) - x);
GLint height = std::max(0, (viewportHeight - (int)clip.top) - y);
- if (x != mScissorX
- || y != mScissorY
- || width != mScissorWidth
- || height != mScissorHeight) {
+ if (x != mScissorX || y != mScissorY || width != mScissorWidth || height != mScissorHeight) {
glScissor(x, y, width, height);
mScissorX = x;
@@ -104,10 +95,9 @@
}
void Scissor::dump() {
- ALOGD("Scissor: enabled %d, %d %d %d %d",
- mEnabled, mScissorX, mScissorY, mScissorWidth, mScissorHeight);
+ ALOGD("Scissor: enabled %d, %d %d %d %d", mEnabled, mScissorX, mScissorY, mScissorWidth,
+ mScissorHeight);
}
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index f302244..2b04f4e 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -26,6 +26,7 @@
class Scissor {
friend class RenderState;
+
public:
bool setEnabled(bool enabled);
bool set(GLint x, GLint y, GLint width, GLint height);
@@ -33,6 +34,7 @@
void reset();
bool isEnabled() { return mEnabled; }
void dump();
+
private:
Scissor();
void invalidate();
@@ -46,4 +48,4 @@
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_SCISSOR_H
+#endif // RENDERSTATE_SCISSOR_H
diff --git a/libs/hwui/renderstate/Stencil.cpp b/libs/hwui/renderstate/Stencil.cpp
index f594421..dc465fc 100644
--- a/libs/hwui/renderstate/Stencil.cpp
+++ b/libs/hwui/renderstate/Stencil.cpp
@@ -136,5 +136,5 @@
ALOGD("Stencil: state %d", mState);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/renderstate/Stencil.h b/libs/hwui/renderstate/Stencil.h
index 5f7d405..95f3723 100644
--- a/libs/hwui/renderstate/Stencil.h
+++ b/libs/hwui/renderstate/Stencil.h
@@ -78,36 +78,26 @@
/**
* Indicates whether either test or write is enabled.
*/
- bool isEnabled() {
- return mState != StencilState::Disabled;
- }
+ bool isEnabled() { return mState != StencilState::Disabled; }
/**
* Indicates whether testing only is enabled.
*/
- bool isTestEnabled() {
- return mState == StencilState::Test;
- }
+ bool isTestEnabled() { return mState == StencilState::Test; }
- bool isWriteEnabled() {
- return mState == StencilState::Write;
- }
+ bool isWriteEnabled() { return mState == StencilState::Write; }
void dump();
private:
- enum class StencilState {
- Disabled,
- Test,
- Write
- };
+ enum class StencilState { Disabled, Test, Write };
void enable();
StencilState mState = StencilState::Disabled;
-}; // class Stencil
+}; // class Stencil
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_STENCIL_H
+#endif // ANDROID_HWUI_STENCIL_H
diff --git a/libs/hwui/renderstate/TextureState.cpp b/libs/hwui/renderstate/TextureState.cpp
index f9a1f8c..470b4f5 100644
--- a/libs/hwui/renderstate/TextureState.cpp
+++ b/libs/hwui/renderstate/TextureState.cpp
@@ -19,9 +19,9 @@
#include "utils/TraceUtils.h"
#include <GLES3/gl3.h>
-#include <memory>
-#include <SkCanvas.h>
#include <SkBitmap.h>
+#include <SkCanvas.h>
+#include <memory>
namespace android {
namespace uirenderer {
@@ -30,22 +30,16 @@
static const int SHADOW_LUT_SIZE = 128;
// Must define as many texture units as specified by kTextureUnitsCount
-const GLenum kTextureUnits[] = {
- GL_TEXTURE0,
- GL_TEXTURE1,
- GL_TEXTURE2,
- GL_TEXTURE3
-};
+const GLenum kTextureUnits[] = {GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2, GL_TEXTURE3};
-TextureState::TextureState()
- : mTextureUnit(0) {
+TextureState::TextureState() : mTextureUnit(0) {
glActiveTexture(kTextureUnits[0]);
resetBoundTextures();
GLint maxTextureUnits;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
LOG_ALWAYS_FATAL_IF(maxTextureUnits < kTextureUnitsCount,
- "At least %d texture units are required!", kTextureUnitsCount);
+ "At least %d texture units are required!", kTextureUnitsCount);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
}
@@ -86,8 +80,8 @@
void TextureState::activateTexture(GLuint textureUnit) {
LOG_ALWAYS_FATAL_IF(textureUnit >= kTextureUnitsCount,
- "Tried to use texture unit index %d, only %d exist",
- textureUnit, kTextureUnitsCount);
+ "Tried to use texture unit index %d, only %d exist", textureUnit,
+ kTextureUnitsCount);
if (mTextureUnit != textureUnit) {
glActiveTexture(kTextureUnits[textureUnit]);
mTextureUnit = textureUnit;
@@ -151,4 +145,3 @@
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderstate/TextureState.h b/libs/hwui/renderstate/TextureState.h
index 7296fd3..f1996d4 100644
--- a/libs/hwui/renderstate/TextureState.h
+++ b/libs/hwui/renderstate/TextureState.h
@@ -16,8 +16,8 @@
#ifndef RENDERSTATE_TEXTURESTATE_H
#define RENDERSTATE_TEXTURESTATE_H
-#include "Vertex.h"
#include "Texture.h"
+#include "Vertex.h"
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -29,9 +29,8 @@
class Texture;
class TextureState {
- friend class Caches; // TODO: move to RenderState
+ friend class Caches; // TODO: move to RenderState
public:
-
void constructTexture(Caches& caches);
/**
@@ -96,4 +95,4 @@
} /* namespace uirenderer */
} /* namespace android */
-#endif // RENDERSTATE_BLEND_H
+#endif // RENDERSTATE_BLEND_H
diff --git a/libs/hwui/renderthread/CacheManager.cpp b/libs/hwui/renderthread/CacheManager.cpp
index 0572a8d..c22364b 100644
--- a/libs/hwui/renderthread/CacheManager.cpp
+++ b/libs/hwui/renderthread/CacheManager.cpp
@@ -18,11 +18,12 @@
#include "Layer.h"
#include "RenderThread.h"
+#include "pipeline/skia/ShaderCache.h"
#include "renderstate/RenderState.h"
-#include <gui/Surface.h>
#include <GrContextOptions.h>
#include <SkExecutor.h>
+#include <gui/Surface.h>
#include <math.h>
#include <set>
@@ -42,9 +43,9 @@
#define FONT_CACHE_MIN_MB (0.5f)
#define FONT_CACHE_MAX_MB (4.0f)
-CacheManager::CacheManager(const DisplayInfo& display)
- : mMaxSurfaceArea(display.w * display.h) {
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2,
+CacheManager::CacheManager(const DisplayInfo& display) : mMaxSurfaceArea(display.w * display.h) {
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
+ mMaxSurfaceArea / 2,
skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
}
@@ -63,8 +64,9 @@
void CacheManager::destroy() {
// cleanup any caches here as the GrContext is about to go away...
mGrContext.reset(nullptr);
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2,
- skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(
+ mMaxSurfaceArea / 2,
+ skiapipeline::VectorDrawableAtlas::StorageMode::disallowSharedSurface);
}
void CacheManager::updateContextCacheSizes() {
@@ -126,6 +128,8 @@
}
contextOptions->fExecutor = mTaskProcessor.get();
}
+
+ contextOptions->fPersistentCache = &skiapipeline::ShaderCache::get();
}
void CacheManager::trimMemory(TrimMemoryMode mode) {
@@ -137,7 +141,7 @@
switch (mode) {
case TrimMemoryMode::Complete:
- mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea/2);
+ mVectorDrawableAtlas = new skiapipeline::VectorDrawableAtlas(mMaxSurfaceArea / 2);
mGrContext->freeGpuResources();
break;
case TrimMemoryMode::UiHidden:
@@ -175,8 +179,8 @@
log.appendFormat("Caches:\n");
log.appendFormat(" Current / Maximum\n");
- log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n",
- 0.0f, 0.0f, (size_t)0);
+ log.appendFormat(" VectorDrawableAtlas %6.2f kB / %6.2f kB (entries = %zu)\n", 0.0f, 0.0f,
+ (size_t)0);
if (renderState) {
if (renderState->mActiveLayers.size() > 0) {
@@ -185,24 +189,21 @@
size_t layerMemoryTotal = 0;
for (std::set<Layer*>::iterator it = renderState->mActiveLayers.begin();
- it != renderState->mActiveLayers.end(); it++) {
+ it != renderState->mActiveLayers.end(); it++) {
const Layer* layer = *it;
const char* layerType = layer->getApi() == Layer::Api::OpenGL ? "GlLayer" : "VkLayer";
- log.appendFormat(" %s size %dx%d\n", layerType,
- layer->getWidth(), layer->getHeight());
+ log.appendFormat(" %s size %dx%d\n", layerType, layer->getWidth(),
+ layer->getHeight());
layerMemoryTotal += layer->getWidth() * layer->getHeight() * 4;
}
log.appendFormat(" Layers Total %6.2f kB (numLayers = %zu)\n",
layerMemoryTotal / 1024.0f, renderState->mActiveLayers.size());
}
-
log.appendFormat("Total memory usage:\n");
- log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n",
- bytesCached, bytesCached / 1024.0f / 1024.0f,
+ log.appendFormat(" %zu bytes, %.2f MB (%.2f MB is purgeable)\n", bytesCached,
+ bytesCached / 1024.0f / 1024.0f,
mGrContext->getResourceCachePurgeableBytes() / 1024.0f / 1024.0f);
-
-
}
} /* namespace renderthread */
diff --git a/libs/hwui/renderthread/CacheManager.h b/libs/hwui/renderthread/CacheManager.h
index 3ba2690..d037045 100644
--- a/libs/hwui/renderthread/CacheManager.h
+++ b/libs/hwui/renderthread/CacheManager.h
@@ -42,10 +42,7 @@
class CacheManager {
public:
- enum class TrimMemoryMode {
- Complete,
- UiHidden
- };
+ enum class TrimMemoryMode { Complete, UiHidden };
void configureContext(GrContextOptions* context);
void trimMemory(TrimMemoryMode mode);
@@ -58,12 +55,12 @@
size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
TaskManager* getTaskManager() { return &mTaskManager; }
+
private:
friend class RenderThread;
CacheManager(const DisplayInfo& display);
-
void reset(GrContext* grContext);
void destroy();
void updateContextCacheSizes();
@@ -92,4 +89,3 @@
} /* namespace android */
#endif /* CACHEMANAGER_H */
-
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 36a0da1..b7bb2d15 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -14,24 +14,24 @@
* limitations under the License.
*/
-#include <GpuMemoryTracker.h>
#include "CanvasContext.h"
+#include <GpuMemoryTracker.h>
#include "AnimationContext.h"
#include "Caches.h"
#include "EglManager.h"
#include "Frame.h"
#include "LayerUpdateQueue.h"
+#include "OpenGLPipeline.h"
#include "Properties.h"
#include "RenderThread.h"
#include "hwui/Canvas.h"
-#include "renderstate/RenderState.h"
-#include "renderstate/Stencil.h"
-#include "protos/hwui.pb.h"
-#include "OpenGLPipeline.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "protos/hwui.pb.h"
+#include "renderstate/RenderState.h"
+#include "renderstate/Stencil.h"
#include "utils/GLUtils.h"
#include "utils/TimeUtils.h"
@@ -40,9 +40,9 @@
#include <private/hwui/DrawGlInfo.h>
#include <strings.h>
-#include <algorithm>
#include <fcntl.h>
#include <sys/stat.h>
+#include <algorithm>
#include <cstdlib>
@@ -63,23 +63,22 @@
namespace uirenderer {
namespace renderthread {
-CanvasContext* CanvasContext::create(RenderThread& thread,
- bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory) {
-
+CanvasContext* CanvasContext::create(RenderThread& thread, bool translucent,
+ RenderNode* rootRenderNode, IContextFactory* contextFactory) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
case RenderPipelineType::OpenGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
- std::make_unique<OpenGLPipeline>(thread));
+ std::make_unique<OpenGLPipeline>(thread));
case RenderPipelineType::SkiaGL:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
- std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
+ std::make_unique<skiapipeline::SkiaOpenGLPipeline>(thread));
case RenderPipelineType::SkiaVulkan:
return new CanvasContext(thread, translucent, rootRenderNode, contextFactory,
- std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
+ std::make_unique<skiapipeline::SkiaVulkanPipeline>(thread));
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
return nullptr;
@@ -96,7 +95,7 @@
skiapipeline::SkiaPipeline::destroyLayer(node);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -115,7 +114,7 @@
skiapipeline::SkiaVulkanPipeline::invokeFunctor(thread, functor);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -131,14 +130,14 @@
skiapipeline::SkiaPipeline::prepareToDraw(thread, bitmap);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
-CanvasContext::CanvasContext(RenderThread& thread, bool translucent,
- RenderNode* rootRenderNode, IContextFactory* contextFactory,
- std::unique_ptr<IRenderPipeline> renderPipeline)
+CanvasContext::CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory,
+ std::unique_ptr<IRenderPipeline> renderPipeline)
: mRenderThread(thread)
, mOpaque(!translucent)
, mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
@@ -170,7 +169,7 @@
void CanvasContext::removeRenderNode(RenderNode* node) {
node->clearRoot();
mRenderNodes.erase(std::remove(mRenderNodes.begin(), mRenderNodes.end(), node),
- mRenderNodes.end());
+ mRenderNodes.end());
}
void CanvasContext::destroy() {
@@ -192,10 +191,10 @@
mFrameNumber = -1;
if (hasSurface) {
- mHaveNewSurface = true;
- mSwapHistory.clear();
+ mHaveNewSurface = true;
+ mSwapHistory.clear();
} else {
- mRenderThread.removeFrameCallback(this);
+ mRenderThread.removeFrameCallback(this);
}
}
@@ -219,8 +218,7 @@
}
}
-void CanvasContext::setup(float lightRadius,
- uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+void CanvasContext::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
mLightGeometry.radius = lightRadius;
mLightInfo.ambientShadowAlpha = ambientShadowAlpha;
mLightInfo.spotShadowAlpha = spotShadowAlpha;
@@ -254,7 +252,7 @@
return true;
default:
LOG_ALWAYS_FATAL("unexpected result %d from IRenderPipeline::makeCurrent",
- (int32_t) result);
+ (int32_t)result);
}
return true;
@@ -277,8 +275,7 @@
// Was there a happy queue & dequeue time? If so, don't
// consider it stuffed
- if (swapA.dequeueDuration < SLOW_THRESHOLD
- && swapA.queueDuration < SLOW_THRESHOLD) {
+ if (swapA.dequeueDuration < SLOW_THRESHOLD && swapA.queueDuration < SLOW_THRESHOLD) {
return false;
}
@@ -293,8 +290,7 @@
// Was there a happy queue & dequeue time? If so, don't
// consider it stuffed
- if (swapB.dequeueDuration < SLOW_THRESHOLD
- && swapB.queueDuration < SLOW_THRESHOLD) {
+ if (swapB.dequeueDuration < SLOW_THRESHOLD && swapB.queueDuration < SLOW_THRESHOLD) {
return false;
}
@@ -306,8 +302,8 @@
return true;
}
-void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
- int64_t syncQueued, RenderNode* target) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued,
+ RenderNode* target) {
mRenderThread.removeFrameCallback(this);
// If the previous frame was dropped we don't need to hold onto it, so
@@ -358,8 +354,8 @@
// Already drew for this vsync pulse, UI draw request missed
// the deadline for RT animations
info.out.canDrawThisFrame = false;
- } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3
- || (latestVsync - mLastDropVsync) < 500_ms) {
+ } else if (vsyncDelta >= mRenderThread.timeLord().frameIntervalNanos() * 3 ||
+ (latestVsync - mLastDropVsync) < 500_ms) {
// It's been several frame intervals, assume the buffer queue is fine
// or the last drop was too recent
info.out.canDrawThisFrame = true;
@@ -402,10 +398,10 @@
mDamageAccumulator.finish(&dirty);
// TODO: Re-enable after figuring out cause of b/22592975
-// if (dirty.isEmpty() && Properties::skipEmptyFrames) {
-// mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
-// return;
-// }
+ // if (dirty.isEmpty() && Properties::skipEmptyFrames) {
+ // mCurrentFrameInfo->addFlag(FrameInfoFlags::SkippedFrame);
+ // return;
+ // }
mCurrentFrameInfo->markIssueDrawCommandsStart();
@@ -414,18 +410,19 @@
SkRect windowDirty = computeDirtyRect(frame, &dirty);
bool drew = mRenderPipeline->draw(frame, windowDirty, dirty, mLightGeometry, &mLayerUpdateQueue,
- mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo, mRenderNodes, &(profiler()));
+ mContentDrawBounds, mOpaque, mWideColorGamut, mLightInfo,
+ mRenderNodes, &(profiler()));
waitOnFences();
bool requireSwap = false;
- bool didSwap = mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo,
- &requireSwap);
+ bool didSwap =
+ mRenderPipeline->swapBuffers(frame, drew, windowDirty, mCurrentFrameInfo, &requireSwap);
mIsDirty = false;
if (requireSwap) {
- if (!didSwap) { //some error happened
+ if (!didSwap) { // some error happened
setSurface(nullptr);
}
SwapHistory& swap = mSwapHistory.next();
@@ -449,10 +446,8 @@
swap.dequeueDuration = 0;
swap.queueDuration = 0;
}
- mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration)
- = swap.dequeueDuration;
- mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration)
- = swap.queueDuration;
+ mCurrentFrameInfo->set(FrameInfoIndex::DequeueBufferDuration) = swap.dequeueDuration;
+ mCurrentFrameInfo->set(FrameInfoIndex::QueueBufferDuration) = swap.queueDuration;
mHaveNewSurface = false;
mFrameNumber = -1;
} else {
@@ -464,9 +459,9 @@
mCurrentFrameInfo->markFrameCompleted();
#if LOG_FRAMETIME_MMA
- float thisFrame = mCurrentFrameInfo->duration(
- FrameInfoIndex::IssueDrawCommandsStart,
- FrameInfoIndex::FrameCompleted) / NANOS_PER_MILLIS_F;
+ float thisFrame = mCurrentFrameInfo->duration(FrameInfoIndex::IssueDrawCommandsStart,
+ FrameInfoIndex::FrameCompleted) /
+ NANOS_PER_MILLIS_F;
if (sFrameCount) {
sBenchMma = ((9 * sBenchMma) + thisFrame) / 10;
} else {
@@ -491,7 +486,6 @@
caches.fontRenderer.getFontRenderer().historyTracker().frameCompleted();
}
#endif
-
}
// Called by choreographer to do an RT-driven animation
@@ -505,9 +499,7 @@
nsecs_t vsync = mRenderThread.timeLord().computeFrameTimeNanos();
int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
- UiFrameInfoBuilder(frameInfo)
- .addFlag(FrameInfoFlags::RTAnimation)
- .setVsync(vsync, vsync);
+ UiFrameInfoBuilder(frameInfo).addFlag(FrameInfoFlags::RTAnimation).setVsync(vsync, vsync);
TreeInfo info(TreeInfo::MODE_RT_ONLY, *this);
prepareTree(info, frameInfo, systemTime(CLOCK_MONOTONIC), node);
@@ -529,7 +521,7 @@
if (mPrefetchedLayers.size()) {
for (auto& node : mPrefetchedLayers) {
ALOGW("Incorrectly called buildLayer on View: %s, destroying layer...",
- node->getName());
+ node->getName());
node->destroyLayers();
node->decStrong(nullptr);
}
@@ -555,8 +547,8 @@
// purposes when the frame is actually drawn
node->setPropertyFieldsDirty(RenderNode::GENERIC);
- mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue,
- mOpaque, mWideColorGamut, mLightInfo);
+ mRenderPipeline->renderLayers(mLightGeometry, &mLayerUpdateQueue, mOpaque, mWideColorGamut,
+ mLightInfo);
node->incStrong(nullptr);
mPrefetchedLayers.insert(node);
@@ -607,7 +599,7 @@
break;
}
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -634,7 +626,7 @@
using namespace google::protobuf::io;
char package[128];
// Check whether tracing is enabled for this process.
- FILE * file = fopen("/proc/self/cmdline", "r");
+ FILE* file = fopen("/proc/self/cmdline", "r");
if (file) {
if (!fgets(package, 128, file)) {
ALOGE("Error reading cmdline: %s (%d)", strerror(errno), errno);
@@ -643,8 +635,7 @@
}
fclose(file);
} else {
- ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno),
- errno);
+ ALOGE("Error opening /proc/self/cmdline: %s (%d)", strerror(errno), errno);
return;
}
char path[1024];
@@ -675,8 +666,7 @@
class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
public:
- explicit FuncTaskProcessor(TaskManager* taskManager)
- : TaskProcessor<bool>(taskManager) {}
+ explicit FuncTaskProcessor(TaskManager* taskManager) : TaskProcessor<bool>(taskManager) {}
virtual void onProcess(const sp<Task<bool> >& task) override {
FuncTask* t = static_cast<FuncTask*>(task.get());
@@ -714,8 +704,8 @@
dirty->setEmpty();
} else {
if (!dirty->isEmpty() && !dirty->intersect(0, 0, frame.width(), frame.height())) {
- ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?",
- SK_RECT_ARGS(*dirty), frame.width(), frame.height());
+ ALOGW("Dirty " RECT_STRING " doesn't intersect with 0 0 %d %d ?", SK_RECT_ARGS(*dirty),
+ frame.width(), frame.height());
dirty->setEmpty();
}
profiler().unionDirty(dirty);
@@ -735,7 +725,7 @@
// last frame so there's nothing to union() against
// Therefore we only care about the > 1 case.
if (frame.bufferAge() > 1) {
- if (frame.bufferAge() > (int) mSwapHistory.size()) {
+ if (frame.bufferAge() > (int)mSwapHistory.size()) {
// We don't have enough history to handle this old of a buffer
// Just do a full-draw
dirty->set(0, 0, frame.width(), frame.height());
@@ -744,7 +734,7 @@
// to the damage history (happens below)
// So we need to damage
for (int i = mSwapHistory.size() - 1;
- i > ((int) mSwapHistory.size()) - frame.bufferAge(); i--) {
+ i > ((int)mSwapHistory.size()) - frame.bufferAge(); i--) {
dirty->join(mSwapHistory[i].damage);
}
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index f8a8775..d80a247 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -27,17 +27,17 @@
#include "IRenderPipeline.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
-#include "thread/Task.h"
-#include "thread/TaskProcessor.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
-#include <cutils/compiler.h>
#include <EGL/egl.h>
#include <SkBitmap.h>
#include <SkRect.h>
-#include <utils/Functor.h>
+#include <cutils/compiler.h>
#include <gui/Surface.h>
+#include <utils/Functor.h>
#include <functional>
#include <set>
@@ -63,8 +63,8 @@
// TODO: Rename to Renderer or some other per-window, top-level manager
class CanvasContext : public IFrameCallback {
public:
- static CanvasContext* create(RenderThread& thread, bool translucent,
- RenderNode* rootRenderNode, IContextFactory* contextFactory);
+ static CanvasContext* create(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory);
virtual ~CanvasContext();
/**
@@ -89,9 +89,7 @@
bool pinImages(std::vector<SkImage*>& mutableImages) {
return mRenderPipeline->pinImages(mutableImages);
}
- bool pinImages(LsaVector<sk_sp<Bitmap>>& images) {
- return mRenderPipeline->pinImages(images);
- }
+ bool pinImages(LsaVector<sk_sp<Bitmap>>& images) { return mRenderPipeline->pinImages(images); }
/**
* Unpin any image that had be previously pinned to the GPU cache
@@ -122,14 +120,12 @@
void setStopped(bool stopped);
bool hasSurface() { return mNativeSurface.get(); }
- void setup(float lightRadius,
- uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
void setWideGamut(bool wideGamut);
bool makeCurrent();
- void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
- int64_t syncQueued, RenderNode* target);
+ void prepareTree(TreeInfo& info, int64_t* uiFrameInfo, int64_t syncQueued, RenderNode* target);
void draw();
void destroy();
@@ -161,13 +157,9 @@
void addRenderNode(RenderNode* node, bool placeFront);
void removeRenderNode(RenderNode* node);
- void setContentDrawBounds(const Rect& bounds) {
- mContentDrawBounds = bounds;
- }
+ void setContentDrawBounds(const Rect& bounds) { mContentDrawBounds = bounds; }
- RenderState& getRenderState() {
- return mRenderThread.renderState();
- }
+ RenderState& getRenderState() { return mRenderThread.renderState(); }
void addFrameMetricsObserver(FrameMetricsObserver* observer) {
if (mFrameMetricsReporter.get() == nullptr) {
@@ -197,7 +189,7 @@
private:
CanvasContext(RenderThread& thread, bool translucent, RenderNode* rootRenderNode,
- IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
+ IContextFactory* contextFactory, std::unique_ptr<IRenderPipeline> renderPipeline);
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -239,14 +231,14 @@
bool mOpaque;
bool mWideColorGamut = false;
BakedOpRenderer::LightInfo mLightInfo;
- FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };
+ FrameBuilder::LightGeometry mLightGeometry = {{0, 0, 0}, 0};
bool mHaveNewSurface = false;
DamageAccumulator mDamageAccumulator;
LayerUpdateQueue mLayerUpdateQueue;
std::unique_ptr<AnimationContext> mAnimationContext;
- std::vector< sp<RenderNode> > mRenderNodes;
+ std::vector<sp<RenderNode>> mRenderNodes;
FrameInfo* mCurrentFrameInfo = nullptr;
std::string mName;
@@ -266,8 +258,8 @@
};
class FuncTaskProcessor;
- std::vector< sp<FuncTask> > mFrameFences;
- sp<TaskProcessor<bool> > mFrameWorkProcessor;
+ std::vector<sp<FuncTask>> mFrameFences;
+ sp<TaskProcessor<bool>> mFrameWorkProcessor;
std::unique_ptr<IRenderPipeline> mRenderPipeline;
};
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 0a94678..8372331 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -33,21 +33,20 @@
: mRenderThread(nullptr)
, mContext(nullptr)
, mContentDrawBounds(0, 0, 0, 0)
- , mSyncResult(SyncResult::OK) {
-}
+ , mSyncResult(SyncResult::OK) {}
-DrawFrameTask::~DrawFrameTask() {
-}
+DrawFrameTask::~DrawFrameTask() {}
void DrawFrameTask::setContext(RenderThread* thread, CanvasContext* context,
- RenderNode* targetNode) {
+ RenderNode* targetNode) {
mRenderThread = thread;
mContext = context;
mTargetNode = targetNode;
}
void DrawFrameTask::pushLayerUpdate(DeferredLayerUpdater* layer) {
- LOG_ALWAYS_FATAL_IF(!mContext, "Lifecycle violation, there's no context to pushLayerUpdate with!");
+ LOG_ALWAYS_FATAL_IF(!mContext,
+ "Lifecycle violation, there's no context to pushLayerUpdate with!");
for (size_t i = 0; i < mLayers.size(); i++) {
if (mLayers[i].get() == layer) {
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 4e4b6da..ea51ae4 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -24,8 +24,8 @@
#include "RenderTask.h"
-#include "../Rect.h"
#include "../FrameInfo.h"
+#include "../Rect.h"
#include "../TreeInfo.h"
namespace android {
@@ -90,7 +90,7 @@
/*********************************************
* Single frame data
*********************************************/
- std::vector< sp<DeferredLayerUpdater> > mLayers;
+ std::vector<sp<DeferredLayerUpdater> > mLayers;
int mSyncResult;
int64_t mSyncQueued;
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 87e5bfd..4df7caf 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -18,17 +18,17 @@
#include <string>
-#include "utils/StringUtils.h"
#include <cutils/properties.h>
#include <log/log.h>
+#include "utils/StringUtils.h"
#include "Caches.h"
#include "DeviceInfo.h"
#include "Frame.h"
#include "Properties.h"
#include "RenderThread.h"
-#include "renderstate/RenderState.h"
#include "Texture.h"
+#include "renderstate/RenderState.h"
#include <EGL/eglext.h>
#include <GrContextOptions.h>
@@ -47,7 +47,9 @@
namespace uirenderer {
namespace renderthread {
-#define ERROR_CASE(x) case x: return #x;
+#define ERROR_CASE(x) \
+ case x: \
+ return #x;
static const char* egl_error_str(EGLint error) {
switch (error) {
ERROR_CASE(EGL_SUCCESS)
@@ -65,8 +67,8 @@
ERROR_CASE(EGL_BAD_PARAMETER)
ERROR_CASE(EGL_BAD_SURFACE)
ERROR_CASE(EGL_CONTEXT_LOST)
- default:
- return "Unknown error";
+ default:
+ return "Unknown error";
}
}
const char* EglManager::eglErrorString() {
@@ -89,8 +91,7 @@
, mEglConfigWideGamut(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
- , mCurrentSurface(EGL_NO_SURFACE) {
-}
+ , mCurrentSurface(EGL_NO_SURFACE) {}
void EglManager::initialize() {
if (hasEglContext()) return;
@@ -98,12 +99,12 @@
ATRACE_NAME("Creating EGLContext");
mEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
- LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s", eglErrorString());
+ LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ eglErrorString());
EGLint major, minor;
LOG_ALWAYS_FATAL_IF(eglInitialize(mEglDisplay, &major, &minor) == EGL_FALSE,
- "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
+ "Failed to initialize display %p! err=%s", mEglDisplay, eglErrorString());
ALOGI("Initialized EGL, version %d.%d", (int)major, (int)minor);
@@ -141,23 +142,22 @@
options.fDisableDistanceFieldPaths = true;
mRenderThread.cacheManager().configureContext(&options);
mRenderThread.setGrContext(GrContext::Create(GrBackend::kOpenGL_GrBackend,
- (GrBackendContext)glInterface.get(), options));
+ (GrBackendContext)glInterface.get(), options));
}
}
void EglManager::initExtensions() {
- auto extensions = StringUtils::split(
- eglQueryString(mEglDisplay, EGL_EXTENSIONS));
+ auto extensions = StringUtils::split(eglQueryString(mEglDisplay, EGL_EXTENSIONS));
// For our purposes we don't care if EGL_BUFFER_AGE is a result of
// EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
// under EGL_KHR_partial_update and we don't need the expanded scope
// that EGL_EXT_buffer_age provides.
- EglExtensions.bufferAge = extensions.has("EGL_EXT_buffer_age")
- || extensions.has("EGL_KHR_partial_update");
+ EglExtensions.bufferAge =
+ extensions.has("EGL_EXT_buffer_age") || extensions.has("EGL_KHR_partial_update");
EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
- "Missing required extension EGL_KHR_swap_buffers_with_damage");
+ "Missing required extension EGL_KHR_swap_buffers_with_damage");
EglExtensions.glColorSpace = extensions.has("EGL_KHR_gl_colorspace");
EglExtensions.noConfigContext = extensions.has("EGL_KHR_no_config_context");
@@ -175,30 +175,37 @@
void EglManager::loadConfigs() {
ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
- EGLint swapBehavior = (mSwapBehavior == SwapBehavior::Preserved)
- ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
- EGLint attribs[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_ALPHA_SIZE, 8,
- EGL_DEPTH_SIZE, 0,
- EGL_CONFIG_CAVEAT, EGL_NONE,
- EGL_STENCIL_SIZE, Stencil::getStencilSize(),
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE
- };
+ EGLint swapBehavior =
+ (mSwapBehavior == SwapBehavior::Preserved) ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
+ EGLint attribs[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_BLUE_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_CONFIG_CAVEAT,
+ EGL_NONE,
+ EGL_STENCIL_SIZE,
+ Stencil::getStencilSize(),
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | swapBehavior,
+ EGL_NONE};
EGLint numConfigs = 1;
- if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs)
- || numConfigs != 1) {
+ if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs) ||
+ numConfigs != 1) {
if (mSwapBehavior == SwapBehavior::Preserved) {
// Try again without dirty regions enabled
ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
mSwapBehavior = SwapBehavior::Discard;
loadConfigs();
- return; // the call to loadConfigs() we just made picks the wide gamut config
+ return; // the call to loadConfigs() we just made picks the wide gamut config
} else {
// Failed to get a valid config
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
@@ -207,22 +214,30 @@
if (EglExtensions.pixelFormatFloat) {
// If we reached this point, we have a valid swap behavior
- EGLint attribs16F[] = {
- EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
- EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
- EGL_RED_SIZE, 16,
- EGL_GREEN_SIZE, 16,
- EGL_BLUE_SIZE, 16,
- EGL_ALPHA_SIZE, 16,
- EGL_DEPTH_SIZE, 0,
- EGL_STENCIL_SIZE, Stencil::getStencilSize(),
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
- EGL_NONE
- };
+ EGLint attribs16F[] = {EGL_RENDERABLE_TYPE,
+ EGL_OPENGL_ES2_BIT,
+ EGL_COLOR_COMPONENT_TYPE_EXT,
+ EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
+ EGL_RED_SIZE,
+ 16,
+ EGL_GREEN_SIZE,
+ 16,
+ EGL_BLUE_SIZE,
+ 16,
+ EGL_ALPHA_SIZE,
+ 16,
+ EGL_DEPTH_SIZE,
+ 0,
+ EGL_STENCIL_SIZE,
+ Stencil::getStencilSize(),
+ EGL_SURFACE_TYPE,
+ EGL_WINDOW_BIT | swapBehavior,
+ EGL_NONE};
numConfigs = 1;
- if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs, &numConfigs)
- || numConfigs != 1) {
+ if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs,
+ &numConfigs) ||
+ numConfigs != 1) {
LOG_ALWAYS_FATAL(
"Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
@@ -231,23 +246,20 @@
}
void EglManager::createContext() {
- EGLint attribs[] = {
- EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
- EGL_NONE
- };
- mEglContext = eglCreateContext(mEglDisplay,
- EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
+ EGLint attribs[] = {EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION, EGL_NONE};
+ mEglContext = eglCreateContext(
+ mEglDisplay, EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
EGL_NO_CONTEXT, attribs);
- LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
- "Failed to create context, error = %s", eglErrorString());
+ LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT, "Failed to create context, error = %s",
+ eglErrorString());
}
void EglManager::createPBufferSurface() {
LOG_ALWAYS_FATAL_IF(mEglDisplay == EGL_NO_DISPLAY,
- "usePBufferSurface() called on uninitialized GlobalContext!");
+ "usePBufferSurface() called on uninitialized GlobalContext!");
if (mPBufferSurface == EGL_NO_SURFACE) {
- EGLint attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
+ EGLint attribs[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
mPBufferSurface = eglCreatePbufferSurface(mEglDisplay, mEglConfig, attribs);
}
}
@@ -255,8 +267,8 @@
EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
initialize();
- wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB
- && EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
+ wideColorGamut = wideColorGamut && EglExtensions.glColorSpace && EglExtensions.scRGB &&
+ EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
@@ -280,10 +292,7 @@
// We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
// According to section 3.4.1 of the EGL specification, the attributes
// list is considered empty if the first entry is EGL_NONE
- EGLint attribs[] = {
- EGL_NONE, EGL_NONE,
- EGL_NONE
- };
+ EGLint attribs[] = {EGL_NONE, EGL_NONE, EGL_NONE};
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
@@ -302,16 +311,17 @@
#endif
}
- EGLSurface surface = eglCreateWindowSurface(mEglDisplay,
- wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
+ EGLSurface surface = eglCreateWindowSurface(
+ mEglDisplay, wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
- "Failed to create EGLSurface for window %p, eglErr = %s",
- (void*) window, eglErrorString());
+ "Failed to create EGLSurface for window %p, eglErr = %s", (void*)window,
+ eglErrorString());
if (mSwapBehavior != SwapBehavior::Preserved) {
- LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_DESTROYED) == EGL_FALSE,
+ LOG_ALWAYS_FATAL_IF(eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
+ EGL_BUFFER_DESTROYED) == EGL_FALSE,
"Failed to set swap behavior to destroyed for window %p, eglErr = %s",
- (void*) window, eglErrorString());
+ (void*)window, eglErrorString());
}
return surface;
@@ -353,11 +363,11 @@
if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
if (errOut) {
*errOut = eglGetError();
- ALOGW("Failed to make current on surface %p, error=%s",
- (void*)surface, egl_error_str(*errOut));
+ ALOGW("Failed to make current on surface %p, error=%s", (void*)surface,
+ egl_error_str(*errOut));
} else {
- LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s",
- (void*)surface, eglErrorString());
+ LOG_ALWAYS_FATAL("Failed to make current on surface %p, error=%s", (void*)surface,
+ eglErrorString());
}
}
mCurrentSurface = surface;
@@ -369,21 +379,20 @@
EGLint EglManager::queryBufferAge(EGLSurface surface) {
switch (mSwapBehavior) {
- case SwapBehavior::Discard:
- return 0;
- case SwapBehavior::Preserved:
- return 1;
- case SwapBehavior::BufferAge:
- EGLint bufferAge;
- eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge);
- return bufferAge;
+ case SwapBehavior::Discard:
+ return 0;
+ case SwapBehavior::Preserved:
+ return 1;
+ case SwapBehavior::BufferAge:
+ EGLint bufferAge;
+ eglQuerySurface(mEglDisplay, surface, EGL_BUFFER_AGE_EXT, &bufferAge);
+ return bufferAge;
}
return 0;
}
Frame EglManager::beginFrame(EGLSurface surface) {
- LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
- "Tried to beginFrame on EGL_NO_SURFACE!");
+ LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE, "Tried to beginFrame on EGL_NO_SURFACE!");
makeCurrent(surface);
Frame frame;
frame.mSurface = surface;
@@ -401,7 +410,7 @@
frame.map(dirty, rects);
if (!eglSetDamageRegionKHR(mEglDisplay, frame.mSurface, rects, 1)) {
LOG_ALWAYS_FATAL("Failed to set damage region on surface %p, error=%s",
- (void*)frame.mSurface, eglErrorString());
+ (void*)frame.mSurface, eglErrorString());
}
}
#endif
@@ -412,7 +421,6 @@
}
bool EglManager::swapBuffers(const Frame& frame, const SkRect& screenDirty) {
-
if (CC_UNLIKELY(Properties::waitForGpuCompletion)) {
ATRACE_NAME("Finishing GPU work");
fence();
@@ -420,8 +428,7 @@
EGLint rects[4];
frame.map(screenDirty, rects);
- eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects,
- screenDirty.isEmpty() ? 0 : 1);
+ eglSwapBuffersWithDamageKHR(mEglDisplay, frame.mSurface, rects, screenDirty.isEmpty() ? 0 : 1);
EGLint err = eglGetError();
if (CC_LIKELY(err == EGL_SUCCESS)) {
@@ -431,20 +438,18 @@
// For some reason our surface was destroyed out from under us
// This really shouldn't happen, but if it does we can recover easily
// by just not trying to use the surface anymore
- ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...",
- err, frame.mSurface);
+ ALOGW("swapBuffers encountered EGL error %d on %p, halting rendering...", err,
+ frame.mSurface);
return false;
}
- LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering",
- err, egl_error_str(err));
+ LOG_ALWAYS_FATAL("Encountered EGL error %d %s during rendering", err, egl_error_str(err));
// Impossible to hit this, but the compiler doesn't know that
return false;
}
void EglManager::fence() {
EGLSyncKHR fence = eglCreateSyncKHR(mEglDisplay, EGL_SYNC_FENCE_KHR, NULL);
- eglClientWaitSyncKHR(mEglDisplay, fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
+ eglClientWaitSyncKHR(mEglDisplay, fence, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, EGL_FOREVER_KHR);
eglDestroySyncKHR(mEglDisplay, fence);
}
@@ -452,17 +457,17 @@
if (mSwapBehavior != SwapBehavior::Preserved) return false;
bool preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR,
- preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
+ preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED);
if (!preserved) {
- ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s",
- (void*) surface, eglErrorString());
+ ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", (void*)surface,
+ eglErrorString());
// Maybe it's already set?
EGLint swapBehavior;
if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) {
preserved = (swapBehavior == EGL_BUFFER_PRESERVED);
} else {
- ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p",
- (void*) surface, eglErrorString());
+ ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", (void*)surface,
+ eglErrorString());
}
}
diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h
index 2982c23..ef9effb 100644
--- a/libs/hwui/renderthread/EglManager.h
+++ b/libs/hwui/renderthread/EglManager.h
@@ -16,9 +16,9 @@
#ifndef EGLMANAGER_H
#define EGLMANAGER_H
-#include <cutils/compiler.h>
#include <EGL/egl.h>
#include <SkRect.h>
+#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
#include <utils/StrongPointer.h>
diff --git a/libs/hwui/renderthread/Frame.h b/libs/hwui/renderthread/Frame.h
index 99996fe..d266faa 100644
--- a/libs/hwui/renderthread/Frame.h
+++ b/libs/hwui/renderthread/Frame.h
@@ -19,7 +19,7 @@
#include <stdint.h>
struct SkRect;
-typedef void *EGLSurface;
+typedef void* EGLSurface;
namespace android {
namespace uirenderer {
@@ -28,9 +28,7 @@
class Frame {
public:
Frame(int32_t width, int32_t height, int32_t bufferAge)
- : mWidth(width)
- , mHeight(height)
- , mBufferAge(bufferAge) { }
+ : mWidth(width), mHeight(height), mBufferAge(bufferAge) {}
int32_t width() const { return mWidth; }
int32_t height() const { return mHeight; }
@@ -57,4 +55,3 @@
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
-
diff --git a/libs/hwui/renderthread/IRenderPipeline.h b/libs/hwui/renderthread/IRenderPipeline.h
index cfc71cb..246ab26 100644
--- a/libs/hwui/renderthread/IRenderPipeline.h
+++ b/libs/hwui/renderthread/IRenderPipeline.h
@@ -34,11 +34,7 @@
namespace renderthread {
-enum class MakeCurrentResult {
- AlreadyCurrent,
- Failed,
- Succeeded
-};
+enum class MakeCurrentResult { AlreadyCurrent, Failed, Succeeded };
enum class ColorMode {
Srgb,
@@ -53,14 +49,13 @@
virtual MakeCurrentResult makeCurrent() = 0;
virtual Frame getFrame() = 0;
virtual bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) = 0;
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut, const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) = 0;
virtual bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
+ FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
@@ -69,11 +64,11 @@
virtual bool isContextReady() = 0;
virtual void onDestroyHardwareResources() = 0;
virtual void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) = 0;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) = 0;
virtual TaskManager* getTaskManager() = 0;
- virtual bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) = 0;
+ virtual bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) = 0;
virtual bool pinImages(std::vector<SkImage*>& mutableImages) = 0;
virtual bool pinImages(LsaVector<sk_sp<Bitmap>>& images) = 0;
virtual void unpinImages() = 0;
diff --git a/libs/hwui/renderthread/OpenGLPipeline.cpp b/libs/hwui/renderthread/OpenGLPipeline.cpp
index 7283eb1..f3103fd 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.cpp
+++ b/libs/hwui/renderthread/OpenGLPipeline.cpp
@@ -20,9 +20,9 @@
#include "EglManager.h"
#include "Frame.h"
#include "GlLayer.h"
+#include "OpenGLReadback.h"
#include "ProfileRenderer.h"
#include "renderstate/RenderState.h"
-#include "OpenGLReadback.h"
#include <cutils/properties.h>
#include <strings.h>
@@ -32,9 +32,7 @@
namespace renderthread {
OpenGLPipeline::OpenGLPipeline(RenderThread& thread)
- : mEglManager(thread.eglManager())
- , mRenderThread(thread) {
-}
+ : mEglManager(thread.eglManager()), mRenderThread(thread) {}
MakeCurrentResult OpenGLPipeline::makeCurrent() {
// TODO: Figure out why this workaround is needed, see b/13913604
@@ -51,23 +49,21 @@
Frame OpenGLPipeline::getFrame() {
LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
- "drawRenderNode called on a context with no surface!");
+ "drawRenderNode called on a context with no surface!");
return mEglManager.beginFrame(mEglSurface);
}
bool OpenGLPipeline::draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) {
-
+ const FrameBuilder::LightGeometry& lightGeometry,
+ LayerUpdateQueue* layerUpdateQueue, const Rect& contentDrawBounds,
+ bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) {
mEglManager.damageFrame(frame, dirty);
bool drew = false;
-
auto& caches = Caches::getInstance();
FrameBuilder frameBuilder(dirty, frame.width(), frame.height(), lightGeometry, caches);
@@ -76,8 +72,8 @@
frameBuilder.deferRenderNodeScene(renderNodes, contentDrawBounds);
- BakedOpRenderer renderer(caches, mRenderThread.renderState(),
- opaque, wideColorGamut, lightInfo);
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut,
+ lightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
ProfileRenderer profileRenderer(renderer);
profiler->draw(profileRenderer);
@@ -100,8 +96,7 @@
}
bool OpenGLPipeline::swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) {
-
+ FrameInfo* currentFrameInfo, bool* requireSwap) {
GL_CHECKPOINT(LOW);
// Even if we decided to cancel the frame, from the perspective of jank
@@ -123,13 +118,13 @@
layer->updateTexImage();
layer->apply();
return OpenGLReadbackImpl::copyLayerInto(mRenderThread,
- static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
+ static_cast<GlLayer&>(*layer->backingLayer()), bitmap);
}
static Layer* createLayer(RenderState& renderState, uint32_t layerWidth, uint32_t layerHeight,
- SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
- GlLayer* layer = new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha,
- mode, blend);
+ SkColorFilter* colorFilter, int alpha, SkBlendMode mode, bool blend) {
+ GlLayer* layer =
+ new GlLayer(renderState, layerWidth, layerHeight, colorFilter, alpha, mode, blend);
Caches::getInstance().textureState().activateTexture(0);
layer->generateTexture();
return layer;
@@ -147,7 +142,6 @@
}
bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) {
-
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
mEglSurface = EGL_NO_SURFACE;
@@ -184,14 +178,16 @@
}
void OpenGLPipeline::renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) {
- static const std::vector< sp<RenderNode> > emptyNodeList;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque,
+ bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) {
+ static const std::vector<sp<RenderNode>> emptyNodeList;
auto& caches = Caches::getInstance();
FrameBuilder frameBuilder(*layerUpdateQueue, lightGeometry, caches);
layerUpdateQueue->clear();
// TODO: Handle wide color gamut contexts
- BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut, lightInfo);
+ BakedOpRenderer renderer(caches, mRenderThread.renderState(), opaque, wideColorGamut,
+ lightInfo);
LOG_ALWAYS_FATAL_IF(renderer.didDraw(), "shouldn't draw in buildlayer case");
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
@@ -205,13 +201,14 @@
}
bool OpenGLPipeline::createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) {
+ const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) {
RenderState& renderState = mRenderThread.renderState();
OffscreenBufferPool& layerPool = renderState.layerPool();
bool transformUpdateNeeded = false;
if (node->getLayer() == nullptr) {
- node->setLayer(layerPool.get(renderState,
- node->getWidth(), node->getHeight(), wideColorGamut));
+ node->setLayer(
+ layerPool.get(renderState, node->getWidth(), node->getHeight(), wideColorGamut));
transformUpdateNeeded = true;
} else if (!layerMatchesWH(node->getLayer(), node->getWidth(), node->getHeight())) {
// TODO: remove now irrelevant, currently enqueued damage (respecting damage ordering)
@@ -273,8 +270,7 @@
class AutoEglFence {
public:
- AutoEglFence(EGLDisplay display)
- : mDisplay(display) {
+ AutoEglFence(EGLDisplay display) : mDisplay(display) {
fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
}
@@ -285,17 +281,17 @@
}
EGLSyncKHR fence = EGL_NO_SYNC_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoEglImage {
public:
- AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer)
- : mDisplay(display) {
- EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
- image = eglCreateImageKHR(display, EGL_NO_CONTEXT,
- EGL_NATIVE_BUFFER_ANDROID, clientBuffer, imageAttrs);
+ AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
+ EGLint imageAttrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
+ image = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, clientBuffer,
+ imageAttrs);
}
~AutoEglImage() {
@@ -305,21 +301,19 @@
}
EGLImageKHR image = EGL_NO_IMAGE_KHR;
+
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoGlTexture {
public:
- AutoGlTexture(uirenderer::Caches& caches)
- : mCaches(caches) {
+ AutoGlTexture(uirenderer::Caches& caches) : mCaches(caches) {
glGenTextures(1, &mTexture);
caches.textureState().bindTexture(mTexture);
}
- ~AutoGlTexture() {
- mCaches.textureState().deleteTexture(mTexture);
- }
+ ~AutoGlTexture() { mCaches.textureState().deleteTexture(mTexture); }
private:
uirenderer::Caches& mCaches;
@@ -327,18 +321,17 @@
};
static bool uploadBitmapToGraphicBuffer(uirenderer::Caches& caches, SkBitmap& bitmap,
- GraphicBuffer& buffer, GLint format, GLint type) {
+ GraphicBuffer& buffer, GLint format, GLint type) {
EGLDisplay display = eglGetCurrentDisplay();
- LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY,
- "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
// The EGL image is later bound to a 2D texture
- EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer.getNativeBuffer();
+ EGLClientBuffer clientBuffer = (EGLClientBuffer)buffer.getNativeBuffer();
AutoEglImage autoImage(display, clientBuffer);
if (autoImage.image == EGL_NO_IMAGE_KHR) {
ALOGW("Could not create EGL image, err =%s",
- uirenderer::renderthread::EglManager::eglErrorString());
+ uirenderer::renderthread::EglManager::eglErrorString());
return false;
}
AutoGlTexture glTexture(caches);
@@ -346,8 +339,8 @@
GL_CHECKPOINT(MODERATE);
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(),
- format, type, bitmap.getPixels());
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format, type,
+ bitmap.getPixels());
GL_CHECKPOINT(MODERATE);
@@ -362,7 +355,7 @@
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
// pipeline flush (similar to what a glFlush() would do.)
EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
- EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
+ EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
return false;
@@ -373,24 +366,24 @@
// TODO: handle SRGB sanely
static PixelFormat internalFormatToPixelFormat(GLint internalFormat) {
switch (internalFormat) {
- case GL_LUMINANCE:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_SRGB8_ALPHA8:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_RGBA:
- return PIXEL_FORMAT_RGBA_8888;
- case GL_RGB:
- return PIXEL_FORMAT_RGB_565;
- case GL_RGBA16F:
- return PIXEL_FORMAT_RGBA_FP16;
- default:
- LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
- return PIXEL_FORMAT_UNKNOWN;
+ case GL_LUMINANCE:
+ return PIXEL_FORMAT_RGBA_8888;
+ case GL_SRGB8_ALPHA8:
+ return PIXEL_FORMAT_RGBA_8888;
+ case GL_RGBA:
+ return PIXEL_FORMAT_RGBA_8888;
+ case GL_RGB:
+ return PIXEL_FORMAT_RGB_565;
+ case GL_RGBA16F:
+ return PIXEL_FORMAT_RGBA_FP16;
+ default:
+ LOG_ALWAYS_FATAL("Unsupported bitmap colorType: %d", internalFormat);
+ return PIXEL_FORMAT_UNKNOWN;
}
}
sk_sp<Bitmap> OpenGLPipeline::allocateHardwareBitmap(RenderThread& renderThread,
- SkBitmap& skBitmap) {
+ SkBitmap& skBitmap) {
renderThread.eglManager().initialize();
uirenderer::Caches& caches = uirenderer::Caches::getInstance();
@@ -404,13 +397,14 @@
bool hasLinearBlending = caches.extensions().hasLinearBlending();
GLint format, type, internalFormat;
uirenderer::Texture::colorTypeToGlFormatAndType(caches, skBitmap.colorType(),
- needSRGB && hasLinearBlending, &internalFormat, &format, &type);
+ needSRGB && hasLinearBlending, &internalFormat,
+ &format, &type);
PixelFormat pixelFormat = internalFormatToPixelFormat(internalFormat);
- sp<GraphicBuffer> buffer = new GraphicBuffer(info.width(), info.height(), pixelFormat,
- GraphicBuffer::USAGE_HW_TEXTURE |
- GraphicBuffer::USAGE_SW_WRITE_NEVER |
- GraphicBuffer::USAGE_SW_READ_NEVER,
+ sp<GraphicBuffer> buffer = new GraphicBuffer(
+ info.width(), info.height(), pixelFormat,
+ GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
+ GraphicBuffer::USAGE_SW_READ_NEVER,
std::string("Bitmap::allocateHardwareBitmap pid [") + std::to_string(getpid()) + "]");
status_t error = buffer->initCheck();
@@ -420,8 +414,8 @@
}
SkBitmap bitmap;
- if (CC_UNLIKELY(uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(),
- hasLinearBlending))) {
+ if (CC_UNLIKELY(
+ uirenderer::Texture::hasUnsupportedColorType(skBitmap.info(), hasLinearBlending))) {
sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
bitmap = uirenderer::Texture::uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
} else {
diff --git a/libs/hwui/renderthread/OpenGLPipeline.h b/libs/hwui/renderthread/OpenGLPipeline.h
index 1f467c1..118007c 100644
--- a/libs/hwui/renderthread/OpenGLPipeline.h
+++ b/libs/hwui/renderthread/OpenGLPipeline.h
@@ -16,9 +16,9 @@
#pragma once
-#include "CanvasContext.h"
#include "BakedOpDispatcher.h"
#include "BakedOpRenderer.h"
+#include "CanvasContext.h"
#include "FrameBuilder.h"
#include "IRenderPipeline.h"
@@ -34,14 +34,13 @@
MakeCurrentResult makeCurrent() override;
Frame getFrame() override;
bool draw(const Frame& frame, const SkRect& screenDirty, const SkRect& dirty,
- const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue,
- const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo,
- const std::vector< sp<RenderNode> >& renderNodes,
- FrameInfoVisualizer* profiler) override;
+ const FrameBuilder::LightGeometry& lightGeometry, LayerUpdateQueue* layerUpdateQueue,
+ const Rect& contentDrawBounds, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo,
+ const std::vector<sp<RenderNode>>& renderNodes,
+ FrameInfoVisualizer* profiler) override;
bool swapBuffers(const Frame& frame, bool drew, const SkRect& screenDirty,
- FrameInfo* currentFrameInfo, bool* requireSwap) override;
+ FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) override;
@@ -50,11 +49,11 @@
bool isContextReady() override;
void onDestroyHardwareResources() override;
void renderLayers(const FrameBuilder::LightGeometry& lightGeometry,
- LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
- const BakedOpRenderer::LightInfo& lightInfo) override;
+ LayerUpdateQueue* layerUpdateQueue, bool opaque, bool wideColorGamut,
+ const BakedOpRenderer::LightInfo& lightInfo) override;
TaskManager* getTaskManager() override;
- bool createOrUpdateLayer(RenderNode* node,
- const DamageAccumulator& damageAccumulator, bool wideColorGamut) override;
+ bool createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator,
+ bool wideColorGamut) override;
bool pinImages(std::vector<SkImage*>& mutableImages) override { return false; }
bool pinImages(LsaVector<sk_sp<Bitmap>>& images) override;
void unpinImages() override;
@@ -62,8 +61,7 @@
static void destroyLayer(RenderNode* node);
static void prepareToDraw(const RenderThread& thread, Bitmap* bitmap);
static void invokeFunctor(const RenderThread& thread, Functor* functor);
- static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread,
- SkBitmap& skBitmap);
+ static sk_sp<Bitmap> allocateHardwareBitmap(RenderThread& thread, SkBitmap& skBitmap);
private:
EglManager& mEglManager;
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 2f406da..79e46ed 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -22,11 +22,11 @@
#include "Readback.h"
#include "Rect.h"
#include "pipeline/skia/VectorDrawableAtlas.h"
+#include "renderstate/RenderState.h"
#include "renderthread/CanvasContext.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
-#include "renderstate/RenderState.h"
#include "utils/Macros.h"
#include "utils/TimeUtils.h"
@@ -36,9 +36,9 @@
namespace uirenderer {
namespace renderthread {
-RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode, IContextFactory* contextFactory)
- : mRenderThread(RenderThread::getInstance())
- , mContext(nullptr) {
+RenderProxy::RenderProxy(bool translucent, RenderNode* rootRenderNode,
+ IContextFactory* contextFactory)
+ : mRenderThread(RenderThread::getInstance()), mContext(nullptr) {
mContext = mRenderThread.queue().runSync([&]() -> CanvasContext* {
return CanvasContext::create(mRenderThread, translucent, rootRenderNode, contextFactory);
});
@@ -54,17 +54,13 @@
mDrawFrameTask.setContext(nullptr, nullptr, nullptr);
// This is also a fence as we need to be certain that there are no
// outstanding mDrawFrame tasks posted before it is destroyed
- mRenderThread.queue().runSync([this]() {
- delete mContext;
- });
+ mRenderThread.queue().runSync([this]() { delete mContext; });
mContext = nullptr;
}
}
void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) {
- mRenderThread.queue().post([this, swapBehavior]() {
- mContext->setSwapBehavior(swapBehavior);
- });
+ mRenderThread.queue().post([this, swapBehavior]() { mContext->setSwapBehavior(swapBehavior); });
}
bool RenderProxy::loadSystemProperties() {
@@ -83,57 +79,42 @@
void RenderProxy::setName(const char* name) {
// block since name/value pointers owned by caller
// TODO: Support move arguments
- mRenderThread.queue().runSync([this, name]() {
- mContext->setName(std::string(name));
- });
+ mRenderThread.queue().runSync([this, name]() { mContext->setName(std::string(name)); });
}
void RenderProxy::initialize(const sp<Surface>& surface) {
- mRenderThread.queue().post([this, surf = surface]() mutable {
- mContext->setSurface(std::move(surf));
- });
+ mRenderThread.queue().post(
+ [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}
void RenderProxy::updateSurface(const sp<Surface>& surface) {
- mRenderThread.queue().post([this, surf = surface]() mutable {
- mContext->setSurface(std::move(surf));
- });
+ mRenderThread.queue().post(
+ [ this, surf = surface ]() mutable { mContext->setSurface(std::move(surf)); });
}
bool RenderProxy::pauseSurface(const sp<Surface>& surface) {
- return mRenderThread.queue().runSync([this]() -> bool {
- return mContext->pauseSurface();
- });
+ return mRenderThread.queue().runSync([this]() -> bool { return mContext->pauseSurface(); });
}
void RenderProxy::setStopped(bool stopped) {
- mRenderThread.queue().runSync([this, stopped]() {
- mContext->setStopped(stopped);
- });
+ mRenderThread.queue().runSync([this, stopped]() { mContext->setStopped(stopped); });
}
void RenderProxy::setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
- mRenderThread.queue().post([=]() {
- mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha);
- });
+ mRenderThread.queue().post(
+ [=]() { mContext->setup(lightRadius, ambientShadowAlpha, spotShadowAlpha); });
}
void RenderProxy::setLightCenter(const Vector3& lightCenter) {
- mRenderThread.queue().post([=]() {
- mContext->setLightCenter(lightCenter);
- });
+ mRenderThread.queue().post([=]() { mContext->setLightCenter(lightCenter); });
}
void RenderProxy::setOpaque(bool opaque) {
- mRenderThread.queue().post([=]() {
- mContext->setOpaque(opaque);
- });
+ mRenderThread.queue().post([=]() { mContext->setOpaque(opaque); });
}
void RenderProxy::setWideGamut(bool wideGamut) {
- mRenderThread.queue().post([=]() {
- mContext->setWideGamut(wideGamut);
- });
+ mRenderThread.queue().post([=]() { mContext->setWideGamut(wideGamut); });
}
int64_t* RenderProxy::frameInfo() {
@@ -148,9 +129,7 @@
// destroyCanvasAndSurface() needs a fence as when it returns the
// underlying BufferQueue is going to be released from under
// the render thread.
- mRenderThread.queue().runSync([=]() {
- mContext->destroy();
- });
+ mRenderThread.queue().runSync([=]() { mContext->destroy(); });
}
void RenderProxy::invokeFunctor(Functor* functor, bool waitForCompletion) {
@@ -174,15 +153,12 @@
}
void RenderProxy::buildLayer(RenderNode* node) {
- mRenderThread.queue().runSync([&]() {
- mContext->buildLayer(node);
- });
+ mRenderThread.queue().runSync([&]() { mContext->buildLayer(node); });
}
bool RenderProxy::copyLayerInto(DeferredLayerUpdater* layer, SkBitmap& bitmap) {
- return mRenderThread.queue().runSync([&]() -> bool {
- return mContext->copyLayerInto(layer, &bitmap);
- });
+ return mRenderThread.queue().runSync(
+ [&]() -> bool { return mContext->copyLayerInto(layer, &bitmap); });
}
void RenderProxy::pushLayerUpdate(DeferredLayerUpdater* layer) {
@@ -194,52 +170,41 @@
}
void RenderProxy::detachSurfaceTexture(DeferredLayerUpdater* layer) {
- return mRenderThread.queue().runSync([&]() {
- layer->detachSurfaceTexture();
- });
+ return mRenderThread.queue().runSync([&]() { layer->detachSurfaceTexture(); });
}
void RenderProxy::destroyHardwareResources() {
- return mRenderThread.queue().runSync([&]() {
- mContext->destroyHardwareResources();
- });
+ return mRenderThread.queue().runSync([&]() { mContext->destroyHardwareResources(); });
}
void RenderProxy::trimMemory(int level) {
// Avoid creating a RenderThread to do a trimMemory.
if (RenderThread::hasInstance()) {
RenderThread& thread = RenderThread::getInstance();
- thread.queue().post([&thread, level]() {
- CanvasContext::trimMemory(thread, level);
- });
+ thread.queue().post([&thread, level]() { CanvasContext::trimMemory(thread, level); });
}
}
void RenderProxy::overrideProperty(const char* name, const char* value) {
// expensive, but block here since name/value pointers owned by caller
- RenderThread::getInstance().queue().runSync([&]() {
- Properties::overrideProperty(name, value);
- });
+ RenderThread::getInstance().queue().runSync(
+ [&]() { Properties::overrideProperty(name, value); });
}
void RenderProxy::fence() {
- mRenderThread.queue().runSync([](){});
+ mRenderThread.queue().runSync([]() {});
}
void RenderProxy::staticFence() {
- RenderThread::getInstance().queue().runSync([](){});
+ RenderThread::getInstance().queue().runSync([]() {});
}
void RenderProxy::stopDrawing() {
- mRenderThread.queue().runSync([this]() {
- mContext->stopDrawing();
- });
+ mRenderThread.queue().runSync([this]() { mContext->stopDrawing(); });
}
void RenderProxy::notifyFramePending() {
- mRenderThread.queue().post([this]() {
- mContext->notifyFramePending();
- });
+ mRenderThread.queue().post([this]() { mContext->notifyFramePending(); });
}
void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
@@ -258,9 +223,7 @@
}
void RenderProxy::resetProfileInfo() {
- mRenderThread.queue().runSync([=]() {
- mContext->resetFrameStats();
- });
+ mRenderThread.queue().runSync([=]() { mContext->resetFrameStats(); });
}
uint32_t RenderProxy::frameTimePercentile(int percentile) {
@@ -271,14 +234,12 @@
void RenderProxy::dumpGraphicsMemory(int fd) {
auto& thread = RenderThread::getInstance();
- thread.queue().runSync([&]() {
- thread.dumpGraphicsMemory(fd);
- });
+ thread.queue().runSync([&]() { thread.dumpGraphicsMemory(fd); });
}
void RenderProxy::setProcessStatsBuffer(int fd) {
auto& rt = RenderThread::getInstance();
- rt.queue().post([&rt, fd = dup(fd)]() {
+ rt.queue().post([&rt, fd = dup(fd) ]() {
rt.globalProfileData().switchStorageToAshmem(fd);
close(fd);
});
@@ -286,9 +247,7 @@
void RenderProxy::rotateProcessStatsBuffer() {
auto& rt = RenderThread::getInstance();
- rt.queue().post([&rt]() {
- rt.globalProfileData().rotateStorage();
- });
+ rt.queue().post([&rt]() { rt.globalProfileData().rotateStorage(); });
}
int RenderProxy::getRenderThreadTid() {
@@ -296,21 +255,15 @@
}
void RenderProxy::addRenderNode(RenderNode* node, bool placeFront) {
- mRenderThread.queue().post([=]() {
- mContext->addRenderNode(node, placeFront);
- });
+ mRenderThread.queue().post([=]() { mContext->addRenderNode(node, placeFront); });
}
void RenderProxy::removeRenderNode(RenderNode* node) {
- mRenderThread.queue().post([=]() {
- mContext->removeRenderNode(node);
- });
+ mRenderThread.queue().post([=]() { mContext->removeRenderNode(node); });
}
void RenderProxy::drawRenderNode(RenderNode* node) {
- mRenderThread.queue().runSync([=]() {
- mContext->prepareAndDraw(node);
- });
+ mRenderThread.queue().runSync([=]() { mContext->prepareAndDraw(node); });
}
void RenderProxy::setContentDrawBounds(int left, int top, int right, int bottom) {
@@ -318,25 +271,23 @@
}
void RenderProxy::serializeDisplayListTree() {
- mRenderThread.queue().post([=]() {
- mContext->serializeDisplayListTree();
- });
+ mRenderThread.queue().post([=]() { mContext->serializeDisplayListTree(); });
}
void RenderProxy::addFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
- mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
+ mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
mContext->addFrameMetricsObserver(observer.get());
});
}
void RenderProxy::removeFrameMetricsObserver(FrameMetricsObserver* observerPtr) {
- mRenderThread.queue().post([this, observer = sp{observerPtr}]() {
+ mRenderThread.queue().post([ this, observer = sp{observerPtr} ]() {
mContext->removeFrameMetricsObserver(observer.get());
});
}
-int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top,
- int right, int bottom, SkBitmap* bitmap) {
+int RenderProxy::copySurfaceInto(sp<Surface>& surface, int left, int top, int right, int bottom,
+ SkBitmap* bitmap) {
auto& thread = RenderThread::getInstance();
return static_cast<int>(thread.queue().runSync([&]() -> auto {
return thread.readback().copySurfaceInto(*surface, Rect(left, top, right, bottom), bitmap);
@@ -372,19 +323,17 @@
sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
auto& thread = RenderThread::getInstance();
- return thread.queue().runSync([&]() -> auto {
- return thread.allocateHardwareBitmap(bitmap);
- });
+ return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); });
}
int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
RenderThread& thread = RenderThread::getInstance();
if (Properties::isSkiaEnabled() && gettid() == thread.getTid()) {
- //TODO: fix everything that hits this. We should never be triggering a readback ourselves.
- return (int) thread.readback().copyGraphicBufferInto(buffer, bitmap);
+ // TODO: fix everything that hits this. We should never be triggering a readback ourselves.
+ return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
} else {
return thread.queue().runSync([&]() -> int {
- return (int) thread.readback().copyGraphicBufferInto(buffer, bitmap);
+ return (int)thread.readback().copyGraphicBufferInto(buffer, bitmap);
});
}
}
@@ -392,9 +341,8 @@
void RenderProxy::onBitmapDestroyed(uint32_t pixelRefId) {
if (!RenderThread::hasInstance()) return;
RenderThread& thread = RenderThread::getInstance();
- thread.queue().post([&thread, pixelRefId]() {
- thread.renderState().onBitmapDestroyed(pixelRefId);
- });
+ thread.queue().post(
+ [&thread, pixelRefId]() { thread.renderState().onBitmapDestroyed(pixelRefId); });
}
void RenderProxy::disableVsync() {
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index b46d9cc..bc57d92 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -17,16 +17,16 @@
#ifndef RENDERPROXY_H_
#define RENDERPROXY_H_
-#include <cutils/compiler.h>
#include <SkBitmap.h>
-#include <utils/Functor.h>
+#include <cutils/compiler.h>
#include <gui/Surface.h>
+#include <utils/Functor.h>
#include "../FrameMetricsObserver.h"
#include "../IContextFactory.h"
-#include "hwui/Bitmap.h"
#include "DrawFrameTask.h"
#include "SwapBehavior.h"
+#include "hwui/Bitmap.h"
namespace android {
class GraphicBuffer;
@@ -44,11 +44,11 @@
class RenderProxyBridge;
namespace DumpFlags {
- enum {
- FrameStats = 1 << 0,
- Reset = 1 << 1,
- JankStats = 1 << 2,
- };
+enum {
+ FrameStats = 1 << 0,
+ Reset = 1 << 1,
+ JankStats = 1 << 2,
+};
};
/*
@@ -73,8 +73,7 @@
ANDROID_API void updateSurface(const sp<Surface>& surface);
ANDROID_API bool pauseSurface(const sp<Surface>& surface);
ANDROID_API void setStopped(bool stopped);
- ANDROID_API void setup(float lightRadius,
- uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+ ANDROID_API void setup(float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setLightCenter(const Vector3& lightCenter);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API void setWideGamut(bool wideGamut);
@@ -121,8 +120,8 @@
ANDROID_API void removeFrameMetricsObserver(FrameMetricsObserver* observer);
ANDROID_API long getDroppedFrameReportCount();
- ANDROID_API static int copySurfaceInto(sp<Surface>& surface,
- int left, int top, int right, int bottom, SkBitmap* bitmap);
+ ANDROID_API static int copySurfaceInto(sp<Surface>& surface, int left, int top, int right,
+ int bottom, SkBitmap* bitmap);
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
diff --git a/libs/hwui/renderthread/RenderTask.h b/libs/hwui/renderthread/RenderTask.h
index a7acf91..c56a357 100644
--- a/libs/hwui/renderthread/RenderTask.h
+++ b/libs/hwui/renderthread/RenderTask.h
@@ -53,7 +53,7 @@
ANDROID_API virtual void run() = 0;
RenderTask* mNext;
- nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock
+ nsecs_t mRunAt; // nano-seconds on the SYSTEM_TIME_MONOTONIC clock
};
class SignalingRenderTask : public RenderTask {
@@ -75,8 +75,7 @@
class MethodInvokeRenderTask : public RenderTask {
public:
- explicit MethodInvokeRenderTask(RunnableMethod method)
- : mMethod(method), mReturnPtr(nullptr) {}
+ explicit MethodInvokeRenderTask(RunnableMethod method) : mMethod(method), mReturnPtr(nullptr) {}
void* payload() { return mData; }
void setReturnPtr(void** retptr) { mReturnPtr = retptr; }
@@ -89,6 +88,7 @@
// Commit suicide
delete this;
}
+
private:
RunnableMethod mMethod;
char mData[METHOD_INVOKE_PAYLOAD_SIZE];
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index f3bb120..574bb02 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,17 +16,18 @@
#include "RenderThread.h"
-#include "hwui/Bitmap.h"
-#include "renderstate/RenderState.h"
-#include "renderthread/OpenGLPipeline.h"
-#include "pipeline/skia/SkiaOpenGLReadback.h"
-#include "pipeline/skia/SkiaOpenGLPipeline.h"
-#include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "pipeline/skia/ShaderCache.h"
#include "CanvasContext.h"
#include "EglManager.h"
#include "OpenGLReadback.h"
#include "RenderProxy.h"
#include "VulkanManager.h"
+#include "hwui/Bitmap.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaOpenGLReadback.h"
+#include "pipeline/skia/SkiaVulkanPipeline.h"
+#include "renderstate/RenderState.h"
+#include "renderthread/OpenGLPipeline.h"
#include "utils/FatVector.h"
#include <gui/DisplayEventReceiver.h>
@@ -64,7 +65,8 @@
return *sInstance;
}
-RenderThread::RenderThread() : ThreadBase()
+RenderThread::RenderThread()
+ : ThreadBase()
, mDisplayEventReceiver(nullptr)
, mVsyncRequested(false)
, mFrameCallbackTaskPending(false)
@@ -83,17 +85,18 @@
LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
mDisplayEventReceiver = new DisplayEventReceiver();
status_t status = mDisplayEventReceiver->initCheck();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver "
- "failed with status: %d", status);
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
+ "Initialization of DisplayEventReceiver "
+ "failed with status: %d",
+ status);
// Register the FD
- mLooper->addFd(mDisplayEventReceiver->getFd(), 0,
- Looper::EVENT_INPUT, RenderThread::displayEventReceiverCallback, this);
+ mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT,
+ RenderThread::displayEventReceiverCallback, this);
}
void RenderThread::initThreadLocals() {
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &mDisplayInfo);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
nsecs_t frameIntervalNanos = static_cast<nsecs_t>(1000000000 / mDisplayInfo.fps);
@@ -103,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) {
@@ -133,18 +137,17 @@
break;
}
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
- FILE *file = fdopen(fd, "a");
+ FILE* file = fdopen(fd, "a");
fprintf(file, "\n%s\n", cachesOutput.string());
fprintf(file, "\nPipeline=%s\n", pipeline.string());
fflush(file);
}
Readback& RenderThread::readback() {
-
if (!mReadback) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
@@ -159,7 +162,7 @@
mReadback = new skiapipeline::SkiaOpenGLReadback(*this);
break;
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
}
@@ -178,19 +181,21 @@
int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
ALOGE("Display event receiver pipe was closed or an error occurred. "
- "events=0x%x", events);
- return 0; // remove the callback
+ "events=0x%x",
+ events);
+ return 0; // remove the callback
}
if (!(events & Looper::EVENT_INPUT)) {
ALOGW("Received spurious callback for unhandled poll event. "
- "events=0x%x", events);
- return 1; // keep the callback
+ "events=0x%x",
+ events);
+ return 1; // keep the callback
}
reinterpret_cast<RenderThread*>(data)->drainDisplayEventQueue();
- return 1; // keep the callback
+ return 1; // keep the callback
}
static nsecs_t latestVsyncEvent(DisplayEventReceiver* receiver) {
@@ -201,9 +206,9 @@
for (ssize_t i = 0; i < n; i++) {
const DisplayEventReceiver::Event& ev = buf[i];
switch (ev.header.type) {
- case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
- latest = ev.header.timestamp;
- break;
+ case DisplayEventReceiver::DISPLAY_EVENT_VSYNC:
+ latest = ev.header.timestamp;
+ break;
}
}
}
@@ -222,9 +227,7 @@
ATRACE_NAME("queue mFrameCallbackTask");
mFrameCallbackTaskPending = true;
nsecs_t runAt = (vsyncEvent + DISPATCH_FRAME_CALLBACKS_DELAY);
- queue().postAt(runAt, [this]() {
- dispatchFrameCallbacks();
- });
+ queue().postAt(runAt, [this]() { dispatchFrameCallbacks(); });
}
}
}
@@ -240,7 +243,8 @@
// Assume one of them will probably animate again so preemptively
// request the next vsync in case it occurs mid-frame
requestVsync();
- for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end(); it++) {
+ for (std::set<IFrameCallback*>::iterator it = callbacks.begin(); it != callbacks.end();
+ it++) {
(*it)->doFrame();
}
}
@@ -250,8 +254,7 @@
if (!mVsyncRequested) {
mVsyncRequested = true;
status_t status = mDisplayEventReceiver->requestNextVsync();
- LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
- "requestNextVsync failed with status: %d", status);
+ LOG_ALWAYS_FATAL_IF(status != NO_ERROR, "requestNextVsync failed with status: %d", status);
}
}
@@ -265,8 +268,8 @@
if (mPendingRegistrationFrameCallbacks.size() && !mFrameCallbackTaskPending) {
drainDisplayEventQueue();
- mFrameCallbacks.insert(
- mPendingRegistrationFrameCallbacks.begin(), mPendingRegistrationFrameCallbacks.end());
+ mFrameCallbacks.insert(mPendingRegistrationFrameCallbacks.begin(),
+ mPendingRegistrationFrameCallbacks.end());
mPendingRegistrationFrameCallbacks.clear();
requestVsync();
}
@@ -310,7 +313,7 @@
case RenderPipelineType::SkiaVulkan:
return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
default:
- LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t) renderType);
+ LOG_ALWAYS_FATAL("canvas context type %d not supported", (int32_t)renderType);
break;
}
return nullptr;
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index e1d61c5..d17a509 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -25,16 +25,16 @@
#include "thread/ThreadBase.h"
#include <GrContext.h>
-#include <cutils/compiler.h>
#include <SkBitmap.h>
+#include <cutils/compiler.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
#include <utils/Thread.h>
+#include <thread/ThreadBase.h>
#include <memory>
#include <mutex>
#include <set>
-#include <thread/ThreadBase.h>
namespace android {
@@ -65,8 +65,8 @@
class RenderThread : private ThreadBase {
PREVENT_COPY_AND_ASSIGN(RenderThread);
-public:
+public:
WorkQueue& queue() { return ThreadBase::queue(); }
// Mimics android.view.Choreographer
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index 6c2575f..b82c5d1 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -19,10 +19,7 @@
namespace uirenderer {
namespace renderthread {
-TimeLord::TimeLord()
- : mFrameIntervalNanos(milliseconds_to_nanoseconds(16))
- , mFrameTimeNanos(0) {
-}
+TimeLord::TimeLord() : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)), mFrameTimeNanos(0) {}
bool TimeLord::vsyncReceived(nsecs_t vsync) {
if (vsync > mFrameTimeNanos) {
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 2195143..1d8cdd6 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -31,11 +31,10 @@
namespace uirenderer {
namespace renderthread {
-#define GET_PROC(F) m ## F = (PFN_vk ## F) vkGetInstanceProcAddr(instance, "vk" #F)
-#define GET_DEV_PROC(F) m ## F = (PFN_vk ## F) vkGetDeviceProcAddr(device, "vk" #F)
+#define GET_PROC(F) m##F = (PFN_vk##F)vkGetInstanceProcAddr(instance, "vk" #F)
+#define GET_DEV_PROC(F) m##F = (PFN_vk##F)vkGetDeviceProcAddr(device, "vk" #F)
-VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {
-}
+VulkanManager::VulkanManager(RenderThread& thread) : mRenderThread(thread) {}
void VulkanManager::destroy() {
if (!hasVkContext()) return;
@@ -51,12 +50,14 @@
}
void VulkanManager::initialize() {
- if (hasVkContext()) { return; }
+ if (hasVkContext()) {
+ return;
+ }
auto canPresent = [](VkInstance, VkPhysicalDevice, uint32_t) { return true; };
mBackendContext.reset(GrVkBackendContext::Create(vkGetInstanceProcAddr, vkGetDeviceProcAddr,
- &mPresentQueueIndex, canPresent));
+ &mPresentQueueIndex, canPresent));
// Get all the addresses of needed vulkan functions
VkInstance instance = mBackendContext->fInstance;
@@ -99,15 +100,18 @@
// this needs to be on the render queue
commandPoolInfo.queueFamilyIndex = mBackendContext->fGraphicsQueueIndex;
commandPoolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
- SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice,
- &commandPoolInfo, nullptr, &mCommandPool);
+ SkDEBUGCODE(VkResult res =) mCreateCommandPool(mBackendContext->fDevice, &commandPoolInfo,
+ nullptr, &mCommandPool);
SkASSERT(VK_SUCCESS == res);
}
mGetDeviceQueue(mBackendContext->fDevice, mPresentQueueIndex, 0, &mPresentQueue);
- mRenderThread.setGrContext(GrContext::Create(kVulkan_GrBackend,
- (GrBackendContext) mBackendContext.get()));
+ GrContextOptions options;
+ options.fDisableDistanceFieldPaths = true;
+ mRenderThread.cacheManager().configureContext(&options);
+ mRenderThread.setGrContext(
+ GrContext::Create(kVulkan_GrBackend, (GrBackendContext)mBackendContext.get(), options));
DeviceInfo::initialize(mRenderThread.getGrContext()->caps()->maxRenderTargetSize());
if (Properties::enablePartialUpdates && Properties::useBufferAge) {
@@ -127,13 +131,13 @@
surface->mCurrentBackbufferIndex = 0;
}
- VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
- surface->mCurrentBackbufferIndex;
+ VulkanSurface::BackbufferInfo* backbuffer =
+ surface->mBackbuffers + surface->mCurrentBackbufferIndex;
// Before we reuse a backbuffer, make sure its fences have all signaled so that we can safely
// reuse its commands buffers.
- VkResult res = mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences,
- true, UINT64_MAX);
+ VkResult res =
+ mWaitForFences(mBackendContext->fDevice, 2, backbuffer->mUsageFences, true, UINT64_MAX);
if (res != VK_SUCCESS) {
return nullptr;
}
@@ -141,7 +145,6 @@
return backbuffer;
}
-
SkSurface* VulkanManager::getBackbufferSurface(VulkanSurface* surface) {
VulkanSurface::BackbufferInfo* backbuffer = getAvailableBackbuffer(surface);
SkASSERT(backbuffer);
@@ -154,7 +157,8 @@
// The acquire will signal the attached mAcquireSemaphore. We use this to know the image has
// finished presenting and that it is safe to begin sending new commands to the returned image.
res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+ backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
+ &backbuffer->mImageIndex);
if (VK_ERROR_SURFACE_LOST_KHR == res) {
// need to figure out how to create a new vkSurface without the platformData*
@@ -172,7 +176,8 @@
// acquire the image
res = mAcquireNextImageKHR(mBackendContext->fDevice, surface->mSwapchain, UINT64_MAX,
- backbuffer->mAcquireSemaphore, VK_NULL_HANDLE, &backbuffer->mImageIndex);
+ backbuffer->mAcquireSemaphore, VK_NULL_HANDLE,
+ &backbuffer->mImageIndex);
if (VK_SUCCESS != res) {
return nullptr;
@@ -182,25 +187,25 @@
// set up layout transfer from initial to color attachment
VkImageLayout layout = surface->mImageInfos[backbuffer->mImageIndex].mImageLayout;
SkASSERT(VK_IMAGE_LAYOUT_UNDEFINED == layout || VK_IMAGE_LAYOUT_PRESENT_SRC_KHR == layout);
- VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
- VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT :
- VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
+ VkPipelineStageFlags srcStageMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout)
+ ? VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT
+ : VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
VkPipelineStageFlags dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
- VkAccessFlags srcAccessMask = (VK_IMAGE_LAYOUT_UNDEFINED == layout) ?
- 0 : VK_ACCESS_MEMORY_READ_BIT;
+ VkAccessFlags srcAccessMask =
+ (VK_IMAGE_LAYOUT_UNDEFINED == layout) ? 0 : VK_ACCESS_MEMORY_READ_BIT;
VkAccessFlags dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
- mPresentQueueIndex, // srcQueueFamilyIndex
- mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
+ NULL, // pNext
+ srcAccessMask, // outputMask
+ dstAccessMask, // inputMask
+ layout, // oldLayout
+ VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
+ mPresentQueueIndex, // srcQueueFamilyIndex
+ mBackendContext->fGraphicsQueueIndex, // dstQueueFamilyIndex
+ surface->mImages[backbuffer->mImageIndex], // image
+ {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
};
mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[0], 0);
@@ -210,8 +215,8 @@
info.flags = 0;
mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[0], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0,
- 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+ mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[0], srcStageMask, dstStageMask, 0, 0,
+ nullptr, 0, nullptr, 1, &imageMemoryBarrier);
mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[0]);
@@ -235,7 +240,7 @@
GrVkImageInfo* imageInfo;
sk_sp<SkSurface> skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface;
skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
- SkSurface::kFlushRead_BackendHandleAccess);
+ SkSurface::kFlushRead_BackendHandleAccess);
imageInfo->updateImageLayout(VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
surface->mBackbuffer = std::move(skSurface);
@@ -246,14 +251,14 @@
if (surface->mBackbuffers) {
for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
mWaitForFences(mBackendContext->fDevice, 2, surface->mBackbuffers[i].mUsageFences, true,
- UINT64_MAX);
+ UINT64_MAX);
surface->mBackbuffers[i].mImageIndex = -1;
mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mAcquireSemaphore,
- nullptr);
+ nullptr);
mDestroySemaphore(mBackendContext->fDevice, surface->mBackbuffers[i].mRenderSemaphore,
- nullptr);
+ nullptr);
mFreeCommandBuffers(mBackendContext->fDevice, mCommandPool, 2,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[0], 0);
mDestroyFence(mBackendContext->fDevice, surface->mBackbuffers[i].mUsageFences[1], 0);
}
@@ -290,11 +295,11 @@
void VulkanManager::createBuffers(VulkanSurface* surface, VkFormat format, VkExtent2D extent) {
mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
- nullptr);
+ nullptr);
SkASSERT(surface->mImageCount);
surface->mImages = new VkImage[surface->mImageCount];
- mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain,
- &surface->mImageCount, surface->mImages);
+ mGetSwapchainImagesKHR(mBackendContext->fDevice, surface->mSwapchain, &surface->mImageCount,
+ surface->mImages);
SkSurfaceProps props(0, kUnknown_SkPixelGeometry);
@@ -303,7 +308,7 @@
for (uint32_t i = 0; i < surface->mImageCount; ++i) {
GrVkImageInfo info;
info.fImage = surface->mImages[i];
- info.fAlloc = { VK_NULL_HANDLE, 0, 0, 0 };
+ info.fAlloc = {VK_NULL_HANDLE, 0, 0, 0};
info.fImageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
info.fImageTiling = VK_IMAGE_TILING_OPTIMAL;
info.fFormat = format;
@@ -312,8 +317,8 @@
GrBackendRenderTarget backendRT(extent.width, extent.height, 0, 0, info);
VulkanSurface::ImageInfo& imageInfo = surface->mImageInfos[i];
- imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(mRenderThread.getGrContext(),
- backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props);
+ imageInfo.mSurface = SkSurface::MakeFromBackendRenderTarget(
+ mRenderThread.getGrContext(), backendRT, kTopLeft_GrSurfaceOrigin, nullptr, &props);
}
SkASSERT(mCommandPool != VK_NULL_HANDLE);
@@ -343,16 +348,16 @@
for (uint32_t i = 0; i < surface->mImageCount + 1; ++i) {
SkDEBUGCODE(VkResult res);
surface->mBackbuffers[i].mImageIndex = -1;
- SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mAcquireSemaphore);
- SkDEBUGCODE(res = ) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
- &surface->mBackbuffers[i].mRenderSemaphore);
- SkDEBUGCODE(res = ) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
- surface->mBackbuffers[i].mTransitionCmdBuffers);
- SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[0]);
- SkDEBUGCODE(res = ) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
- &surface->mBackbuffers[i].mUsageFences[1]);
+ SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ &surface->mBackbuffers[i].mAcquireSemaphore);
+ SkDEBUGCODE(res =) mCreateSemaphore(mBackendContext->fDevice, &semaphoreInfo, nullptr,
+ &surface->mBackbuffers[i].mRenderSemaphore);
+ SkDEBUGCODE(res =) mAllocateCommandBuffers(mBackendContext->fDevice, &commandBuffersInfo,
+ surface->mBackbuffers[i].mTransitionCmdBuffers);
+ SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ &surface->mBackbuffers[i].mUsageFences[0]);
+ SkDEBUGCODE(res =) mCreateFence(mBackendContext->fDevice, &fenceInfo, nullptr,
+ &surface->mBackbuffers[i].mUsageFences[1]);
SkASSERT(VK_SUCCESS == res);
}
surface->mCurrentBackbufferIndex = surface->mImageCount;
@@ -362,35 +367,36 @@
// check for capabilities
VkSurfaceCapabilitiesKHR caps;
VkResult res = mGetPhysicalDeviceSurfaceCapabilitiesKHR(mBackendContext->fPhysicalDevice,
- surface->mVkSurface, &caps);
+ surface->mVkSurface, &caps);
if (VK_SUCCESS != res) {
return false;
}
uint32_t surfaceFormatCount;
res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, nullptr);
+ &surfaceFormatCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
FatVector<VkSurfaceFormatKHR, 4> surfaceFormats(surfaceFormatCount);
res = mGetPhysicalDeviceSurfaceFormatsKHR(mBackendContext->fPhysicalDevice, surface->mVkSurface,
- &surfaceFormatCount, surfaceFormats.data());
+ &surfaceFormatCount, surfaceFormats.data());
if (VK_SUCCESS != res) {
return false;
}
uint32_t presentModeCount;
res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
- surface->mVkSurface, &presentModeCount, nullptr);
+ surface->mVkSurface, &presentModeCount, nullptr);
if (VK_SUCCESS != res) {
return false;
}
FatVector<VkPresentModeKHR, VK_PRESENT_MODE_RANGE_SIZE_KHR> presentModes(presentModeCount);
res = mGetPhysicalDeviceSurfacePresentModesKHR(mBackendContext->fPhysicalDevice,
- surface->mVkSurface, &presentModeCount, presentModes.data());
+ surface->mVkSurface, &presentModeCount,
+ presentModes.data());
if (VK_SUCCESS != res) {
return false;
}
@@ -420,12 +426,12 @@
VK_IMAGE_USAGE_TRANSFER_DST_BIT;
SkASSERT((caps.supportedUsageFlags & usageFlags) == usageFlags);
SkASSERT(caps.supportedTransforms & caps.currentTransform);
- SkASSERT(caps.supportedCompositeAlpha & (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR |
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
+ SkASSERT(caps.supportedCompositeAlpha &
+ (VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR | VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR));
VkCompositeAlphaFlagBitsKHR composite_alpha =
- (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR) ?
- VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR :
- VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
+ (caps.supportedCompositeAlpha & VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR)
+ ? VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR
+ : VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
// Pick our surface format. For now, just make sure it matches our sRGB request:
VkFormat surfaceFormat = VK_FORMAT_UNDEFINED;
@@ -470,7 +476,7 @@
swapchainCreateInfo.imageArrayLayers = 1;
swapchainCreateInfo.imageUsage = usageFlags;
- uint32_t queueFamilies[] = { mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex };
+ uint32_t queueFamilies[] = {mBackendContext->fGraphicsQueueIndex, mPresentQueueIndex};
if (mBackendContext->fGraphicsQueueIndex != mPresentQueueIndex) {
swapchainCreateInfo.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
swapchainCreateInfo.queueFamilyIndexCount = 2;
@@ -488,7 +494,7 @@
swapchainCreateInfo.oldSwapchain = surface->mSwapchain;
res = mCreateSwapchainKHR(mBackendContext->fDevice, &swapchainCreateInfo, nullptr,
- &surface->mSwapchain);
+ &surface->mSwapchain);
if (VK_SUCCESS != res) {
return false;
}
@@ -507,7 +513,6 @@
return true;
}
-
VulkanSurface* VulkanManager::createSurface(ANativeWindow* window) {
initialize();
@@ -524,21 +529,20 @@
surfaceCreateInfo.flags = 0;
surfaceCreateInfo.window = window;
- VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo,
- nullptr, &surface->mVkSurface);
+ VkResult res = mCreateAndroidSurfaceKHR(mBackendContext->fInstance, &surfaceCreateInfo, nullptr,
+ &surface->mVkSurface);
if (VK_SUCCESS != res) {
delete surface;
return nullptr;
}
-SkDEBUGCODE(
- VkBool32 supported;
- res = mGetPhysicalDeviceSurfaceSupportKHR(mBackendContext->fPhysicalDevice,
- mPresentQueueIndex, surface->mVkSurface, &supported);
- // All physical devices and queue families on Android must be capable of presentation with any
- // native window.
- SkASSERT(VK_SUCCESS == res && supported);
-);
+ SkDEBUGCODE(VkBool32 supported; res = mGetPhysicalDeviceSurfaceSupportKHR(
+ mBackendContext->fPhysicalDevice, mPresentQueueIndex,
+ surface->mVkSurface, &supported);
+ // All physical devices and queue families on Android must be capable of
+ // presentation with any
+ // native window.
+ SkASSERT(VK_SUCCESS == res && supported););
if (!createSwapchain(surface)) {
destroySurface(surface);
@@ -573,11 +577,9 @@
VkAccessFlags flags = 0;
if (VK_IMAGE_LAYOUT_GENERAL == layout) {
flags = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
- VK_ACCESS_TRANSFER_WRITE_BIT |
- VK_ACCESS_TRANSFER_READ_BIT |
- VK_ACCESS_SHADER_READ_BIT |
- VK_ACCESS_HOST_WRITE_BIT | VK_ACCESS_HOST_READ_BIT;
+ VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_TRANSFER_WRITE_BIT |
+ VK_ACCESS_TRANSFER_READ_BIT | VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
+ VK_ACCESS_HOST_READ_BIT;
} else if (VK_IMAGE_LAYOUT_PREINITIALIZED == layout) {
flags = VK_ACCESS_HOST_WRITE_BIT;
} else if (VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL == layout) {
@@ -600,12 +602,12 @@
mDeviceWaitIdle(mBackendContext->fDevice);
}
- VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
- surface->mCurrentBackbufferIndex;
+ VulkanSurface::BackbufferInfo* backbuffer =
+ surface->mBackbuffers + surface->mCurrentBackbufferIndex;
GrVkImageInfo* imageInfo;
SkSurface* skSurface = surface->mImageInfos[backbuffer->mImageIndex].mSurface.get();
skSurface->getRenderTargetHandle((GrBackendObject*)&imageInfo,
- SkSurface::kFlushRead_BackendHandleAccess);
+ SkSurface::kFlushRead_BackendHandleAccess);
// Check to make sure we never change the actually wrapped image
SkASSERT(imageInfo->fImage == surface->mImages[backbuffer->mImageIndex]);
@@ -618,16 +620,16 @@
VkAccessFlags dstAccessMask = VK_ACCESS_MEMORY_READ_BIT;
VkImageMemoryBarrier imageMemoryBarrier = {
- VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
- NULL, // pNext
- srcAccessMask, // outputMask
- dstAccessMask, // inputMask
- layout, // oldLayout
- VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
- mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
- mPresentQueueIndex, // dstQueueFamilyIndex
- surface->mImages[backbuffer->mImageIndex], // image
- { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 } // subresourceRange
+ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER, // sType
+ NULL, // pNext
+ srcAccessMask, // outputMask
+ dstAccessMask, // inputMask
+ layout, // oldLayout
+ VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
+ mBackendContext->fGraphicsQueueIndex, // srcQueueFamilyIndex
+ mPresentQueueIndex, // dstQueueFamilyIndex
+ surface->mImages[backbuffer->mImageIndex], // image
+ {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1} // subresourceRange
};
mResetCommandBuffer(backbuffer->mTransitionCmdBuffers[1], 0);
@@ -636,8 +638,8 @@
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
info.flags = 0;
mBeginCommandBuffer(backbuffer->mTransitionCmdBuffers[1], &info);
- mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0,
- 0, nullptr, 0, nullptr, 1, &imageMemoryBarrier);
+ mCmdPipelineBarrier(backbuffer->mTransitionCmdBuffers[1], srcStageMask, dstStageMask, 0, 0,
+ nullptr, 0, nullptr, 1, &imageMemoryBarrier);
mEndCommandBuffer(backbuffer->mTransitionCmdBuffers[1]);
surface->mImageInfos[backbuffer->mImageIndex].mImageLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
@@ -661,16 +663,15 @@
// Submit present operation to present queue. We use a semaphore here to make sure all rendering
// to the image is complete and that the layout has been change to present on the graphics
// queue.
- const VkPresentInfoKHR presentInfo =
- {
- VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
- NULL, // pNext
- 1, // waitSemaphoreCount
- &backbuffer->mRenderSemaphore, // pWaitSemaphores
- 1, // swapchainCount
- &surface->mSwapchain, // pSwapchains
- &backbuffer->mImageIndex, // pImageIndices
- NULL // pResults
+ const VkPresentInfoKHR presentInfo = {
+ VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, // sType
+ NULL, // pNext
+ 1, // waitSemaphoreCount
+ &backbuffer->mRenderSemaphore, // pWaitSemaphores
+ 1, // swapchainCount
+ &surface->mSwapchain, // pSwapchains
+ &backbuffer->mImageIndex, // pImageIndices
+ NULL // pResults
};
mQueuePresentKHR(mPresentQueue, &presentInfo);
@@ -682,10 +683,10 @@
}
int VulkanManager::getAge(VulkanSurface* surface) {
- VulkanSurface::BackbufferInfo* backbuffer = surface->mBackbuffers +
- surface->mCurrentBackbufferIndex;
- if (mSwapBehavior == SwapBehavior::Discard
- || surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
+ VulkanSurface::BackbufferInfo* backbuffer =
+ surface->mBackbuffers + surface->mCurrentBackbufferIndex;
+ if (mSwapBehavior == SwapBehavior::Discard ||
+ surface->mImageInfos[backbuffer->mImageIndex].mInvalid) {
return 0;
}
uint16_t lastUsed = surface->mImageInfos[backbuffer->mImageIndex].mLastUsed;
diff --git a/libs/hwui/renderthread/VulkanManager.h b/libs/hwui/renderthread/VulkanManager.h
index d225b3f..b9898a7 100644
--- a/libs/hwui/renderthread/VulkanManager.h
+++ b/libs/hwui/renderthread/VulkanManager.h
@@ -37,13 +37,14 @@
private:
friend class VulkanManager;
struct BackbufferInfo {
- uint32_t mImageIndex; // image this is associated with
- VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
- VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
- VkCommandBuffer mTransitionCmdBuffers[2]; // to transition layout between present and render
+ uint32_t mImageIndex; // image this is associated with
+ VkSemaphore mAcquireSemaphore; // we signal on this for acquisition of image
+ VkSemaphore mRenderSemaphore; // we wait on this for rendering to be done
+ VkCommandBuffer
+ mTransitionCmdBuffers[2]; // to transition layout between present and render
// We use these fences to make sure the above Command buffers have finished their work
// before attempting to reuse them or destroy them.
- VkFence mUsageFences[2];
+ VkFence mUsageFences[2];
};
struct ImageInfo {
@@ -118,11 +119,16 @@
VulkanSurface::BackbufferInfo* getAvailableBackbuffer(VulkanSurface* surface);
// simple wrapper class that exists only to initialize a pointer to NULL
- template <typename FNPTR_TYPE> class VkPtr {
+ template <typename FNPTR_TYPE>
+ class VkPtr {
public:
VkPtr() : fPtr(NULL) {}
- VkPtr operator=(FNPTR_TYPE ptr) { fPtr = ptr; return *this; }
+ VkPtr operator=(FNPTR_TYPE ptr) {
+ fPtr = ptr;
+ return *this;
+ }
operator FNPTR_TYPE() const { return fPtr; }
+
private:
FNPTR_TYPE fPtr;
};
@@ -183,4 +189,3 @@
} /* namespace android */
#endif /* VULKANMANAGER_H */
-
diff --git a/libs/hwui/service/GraphicsStatsService.cpp b/libs/hwui/service/GraphicsStatsService.cpp
index f7a90b0..3ac1a45 100644
--- a/libs/hwui/service/GraphicsStatsService.cpp
+++ b/libs/hwui/service/GraphicsStatsService.cpp
@@ -25,10 +25,10 @@
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
+#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
-#include <sys/mman.h>
namespace android {
namespace uirenderer {
@@ -42,8 +42,8 @@
constexpr int sHistogramSize = ProfileData::HistogramSize();
static bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto,
- const std::string& package, int versionCode, int64_t startTime, int64_t endTime,
- const ProfileData* data);
+ const std::string& package, int versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data);
static void dumpAsTextToFd(service::GraphicsStatsProto* proto, int outFd);
class FileDescriptor {
@@ -57,6 +57,7 @@
}
bool valid() { return mFd != -1; }
operator int() { return mFd; }
+
private:
int mFd;
};
@@ -68,21 +69,13 @@
int GetErrno() { return mCopyAdapter.mErrno; }
- virtual bool Next(void** data, int* size) override {
- return mImpl.Next(data, size);
- }
+ virtual bool Next(void** data, int* size) override { return mImpl.Next(data, size); }
- virtual void BackUp(int count) override {
- mImpl.BackUp(count);
- }
+ virtual void BackUp(int count) override { mImpl.BackUp(count); }
- virtual int64 ByteCount() const override {
- return mImpl.ByteCount();
- }
+ virtual int64 ByteCount() const override { return mImpl.ByteCount(); }
- bool Flush() {
- return mImpl.Flush();
- }
+ bool Flush() { return mImpl.Flush(); }
private:
struct FDAdapter : public io::CopyingOutputStream {
@@ -95,7 +88,7 @@
virtual bool Write(const void* buffer, int size) override {
int ret;
while (size) {
- ret = TEMP_FAILURE_RETRY( write(mFd, buffer, size) );
+ ret = TEMP_FAILURE_RETRY(write(mFd, buffer, size));
if (ret <= 0) {
mErrno = errno;
return false;
@@ -110,8 +103,8 @@
io::CopyingOutputStreamAdaptor mImpl;
};
-bool GraphicsStatsService::parseFromFile(const std::string& path, service::GraphicsStatsProto* output) {
-
+bool GraphicsStatsService::parseFromFile(const std::string& path,
+ service::GraphicsStatsProto* output) {
FileDescriptor fd{open(path.c_str(), O_RDONLY)};
if (!fd.valid()) {
int err = errno;
@@ -129,7 +122,7 @@
// we get an unexpected error
if (err != ENOENT) {
ALOGW("Failed to fstat '%s', errno=%d (%s) (st_size %d)", path.c_str(), err,
- strerror(err), (int) sb.st_size);
+ strerror(err), (int)sb.st_size);
}
return false;
}
@@ -154,14 +147,15 @@
io::ArrayInputStream input{data, dataSize};
bool success = output->ParseFromZeroCopyStream(&input);
if (!success) {
- ALOGW("Parse failed on '%s' error='%s'",
- path.c_str(), output->InitializationErrorString().c_str());
+ ALOGW("Parse failed on '%s' error='%s'", path.c_str(),
+ output->InitializationErrorString().c_str());
}
return success;
}
bool mergeProfileDataIntoProto(service::GraphicsStatsProto* proto, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
+ int versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data) {
if (proto->stats_start() == 0 || proto->stats_start() > startTime) {
proto->set_stats_start(startTime);
}
@@ -173,24 +167,23 @@
auto summary = proto->mutable_summary();
summary->set_total_frames(summary->total_frames() + data->totalFrameCount());
summary->set_janky_frames(summary->janky_frames() + data->jankFrameCount());
- summary->set_missed_vsync_count(
- summary->missed_vsync_count() + data->jankTypeCount(kMissedVsync));
- summary->set_high_input_latency_count(
- summary->high_input_latency_count() + data->jankTypeCount(kHighInputLatency));
- summary->set_slow_ui_thread_count(
- summary->slow_ui_thread_count() + data->jankTypeCount(kSlowUI));
- summary->set_slow_bitmap_upload_count(
- summary->slow_bitmap_upload_count() + data->jankTypeCount(kSlowSync));
- summary->set_slow_draw_count(
- summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
+ summary->set_missed_vsync_count(summary->missed_vsync_count() +
+ data->jankTypeCount(kMissedVsync));
+ summary->set_high_input_latency_count(summary->high_input_latency_count() +
+ data->jankTypeCount(kHighInputLatency));
+ summary->set_slow_ui_thread_count(summary->slow_ui_thread_count() +
+ data->jankTypeCount(kSlowUI));
+ summary->set_slow_bitmap_upload_count(summary->slow_bitmap_upload_count() +
+ data->jankTypeCount(kSlowSync));
+ summary->set_slow_draw_count(summary->slow_draw_count() + data->jankTypeCount(kSlowRT));
bool creatingHistogram = false;
if (proto->histogram_size() == 0) {
proto->mutable_histogram()->Reserve(sHistogramSize);
creatingHistogram = true;
} else if (proto->histogram_size() != sHistogramSize) {
- ALOGE("Histogram size mismatch, proto is %d expected %d",
- proto->histogram_size(), sHistogramSize);
+ ALOGE("Histogram size mismatch, proto is %d expected %d", proto->histogram_size(),
+ sHistogramSize);
return false;
}
int index = 0;
@@ -205,7 +198,8 @@
} else {
bucket = proto->mutable_histogram(index);
if (bucket->render_millis() != static_cast<int32_t>(entry.renderTimeMs)) {
- ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(), entry.renderTimeMs);
+ ALOGW("Frame time mistmatch %d vs. %u", bucket->render_millis(),
+ entry.renderTimeMs);
hitMergeError = true;
return;
}
@@ -232,7 +226,7 @@
// This isn't a full validation, just enough that we can deref at will
if (proto->package_name().empty() || !proto->has_summary()) {
ALOGW("Skipping dump, invalid package_name() '%s' or summary %d",
- proto->package_name().c_str(), proto->has_summary());
+ proto->package_name().c_str(), proto->has_summary());
return;
}
dprintf(fd, "\nPackage: %s", proto->package_name().c_str());
@@ -242,7 +236,7 @@
auto summary = proto->summary();
dprintf(fd, "\nTotal frames rendered: %d", summary.total_frames());
dprintf(fd, "\nJanky frames: %d (%.2f%%)", summary.janky_frames(),
- (float) summary.janky_frames() / (float) summary.total_frames() * 100.0f);
+ (float)summary.janky_frames() / (float)summary.total_frames() * 100.0f);
dprintf(fd, "\n50th percentile: %dms", findPercentile(proto, 50));
dprintf(fd, "\n90th percentile: %dms", findPercentile(proto, 90));
dprintf(fd, "\n95th percentile: %dms", findPercentile(proto, 95));
@@ -260,7 +254,8 @@
}
void GraphicsStatsService::saveBuffer(const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
+ int versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data) {
service::GraphicsStatsProto statsProto;
if (!parseFromFile(path, &statsProto)) {
statsProto.Clear();
@@ -275,8 +270,8 @@
return;
}
if (statsProto.package_name().empty() || !statsProto.has_summary()) {
- ALOGE("missing package_name() '%s' summary %d",
- statsProto.package_name().c_str(), statsProto.has_summary());
+ ALOGE("missing package_name() '%s' summary %d", statsProto.package_name().c_str(),
+ statsProto.has_summary());
return;
}
int outFd = open(path.c_str(), O_CREAT | O_RDWR | O_TRUNC, 0660);
@@ -288,8 +283,8 @@
int wrote = write(outFd, &sCurrentFileVersion, sHeaderSize);
if (wrote != sHeaderSize) {
int err = errno;
- ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)",
- path.c_str(), wrote, err, strerror(err));
+ ALOGW("Failed to write header to '%s', returned=%d errno=%d (%s)", path.c_str(), wrote, err,
+ strerror(err));
close(outFd);
return;
}
@@ -297,8 +292,8 @@
FileOutputStreamLite output(outFd);
bool success = statsProto.SerializeToZeroCopyStream(&output) && output.Flush();
if (output.GetErrno() != 0) {
- ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)",
- outFd, path.c_str(), output.GetErrno(), strerror(output.GetErrno()));
+ ALOGW("Error writing to fd=%d, path='%s' err=%d (%s)", outFd, path.c_str(),
+ output.GetErrno(), strerror(output.GetErrno()));
success = false;
} else if (!success) {
ALOGW("Serialize failed on '%s' unknown error", path.c_str());
@@ -313,6 +308,7 @@
int fd() { return mFd; }
DumpType type() { return mType; }
service::GraphicsStatsServiceDumpProto& proto() { return mProto; }
+
private:
int mFd;
DumpType mType;
@@ -323,19 +319,20 @@
return new Dump(outFd, type);
}
-void GraphicsStatsService::addToDump(Dump* dump, const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data) {
+void GraphicsStatsService::addToDump(Dump* dump, const std::string& path,
+ const std::string& package, int versionCode, int64_t startTime,
+ int64_t endTime, const ProfileData* data) {
service::GraphicsStatsProto statsProto;
if (!path.empty() && !parseFromFile(path, &statsProto)) {
statsProto.Clear();
}
- if (data && !mergeProfileDataIntoProto(
- &statsProto, package, versionCode, startTime, endTime, data)) {
+ if (data &&
+ !mergeProfileDataIntoProto(&statsProto, package, versionCode, startTime, endTime, data)) {
return;
}
if (!statsProto.IsInitialized()) {
ALOGW("Failed to load profile data from path '%s' and data %p",
- path.empty() ? "<empty>" : path.c_str(), data);
+ path.empty() ? "<empty>" : path.c_str(), data);
return;
}
diff --git a/libs/hwui/service/GraphicsStatsService.h b/libs/hwui/service/GraphicsStatsService.h
index d0fd60e..7ddc219 100644
--- a/libs/hwui/service/GraphicsStatsService.h
+++ b/libs/hwui/service/GraphicsStatsService.h
@@ -44,11 +44,13 @@
};
ANDROID_API static void saveBuffer(const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data);
+ int versionCode, int64_t startTime, int64_t endTime,
+ const ProfileData* data);
ANDROID_API static Dump* createDump(int outFd, DumpType type);
- ANDROID_API static void addToDump(Dump* dump, const std::string& path, const std::string& package,
- int versionCode, int64_t startTime, int64_t endTime, const ProfileData* data);
+ ANDROID_API static void addToDump(Dump* dump, const std::string& path,
+ const std::string& package, int versionCode,
+ int64_t startTime, int64_t endTime, const ProfileData* data);
ANDROID_API static void addToDump(Dump* dump, const std::string& path);
ANDROID_API static void finishDump(Dump* dump);
diff --git a/libs/hwui/tests/common/BitmapAllocationTestUtils.h b/libs/hwui/tests/common/BitmapAllocationTestUtils.h
index 2988979..312b60b 100644
--- a/libs/hwui/tests/common/BitmapAllocationTestUtils.h
+++ b/libs/hwui/tests/common/BitmapAllocationTestUtils.h
@@ -27,17 +27,17 @@
class BitmapAllocationTestUtils {
public:
- static sk_sp<Bitmap> allocateHeapBitmap(int width, int height,
- SkColorType colorType, std::function<void(SkBitmap& bitmap)> setup) {
- sk_sp<Bitmap> bitmap = TestUtils::createBitmap(width, height, colorType);
- SkBitmap skBitmap;
- bitmap->getSkBitmap(&skBitmap);
- setup(skBitmap);
- return bitmap;
+ static sk_sp<Bitmap> allocateHeapBitmap(int width, int height, SkColorType colorType,
+ std::function<void(SkBitmap& bitmap)> setup) {
+ sk_sp<Bitmap> bitmap = TestUtils::createBitmap(width, height, colorType);
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ setup(skBitmap);
+ return bitmap;
}
- static sk_sp<Bitmap> allocateHardwareBitmap(int width, int height,
- SkColorType colorType, std::function<void(SkBitmap& bitmap)> setup) {
+ static sk_sp<Bitmap> allocateHardwareBitmap(int width, int height, SkColorType colorType,
+ std::function<void(SkBitmap& bitmap)> setup) {
SkBitmap skBitmap;
SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
skBitmap.setInfo(info);
@@ -46,8 +46,8 @@
return Bitmap::allocateHardwareBitmap(skBitmap);
}
- typedef sk_sp<Bitmap> (*BitmapAllocator) (int, int, SkColorType,
- std::function<void(SkBitmap& bitmap)> setup);
+ typedef sk_sp<Bitmap> (*BitmapAllocator)(int, int, SkColorType,
+ std::function<void(SkBitmap& bitmap)> setup);
template <class T, BitmapAllocator allocator>
static test::TestScene* createBitmapAllocationScene(const TestScene::Options&) {
@@ -55,22 +55,16 @@
}
template <class BaseScene>
- static bool registerBitmapAllocationScene(std::string name, std::string description) {
- TestScene::registerScene({
- name + "GlTex",
- description + " (GlTex version).",
- createBitmapAllocationScene<BaseScene, &allocateHeapBitmap>
- });
+ static bool registerBitmapAllocationScene(std::string name, std::string description) {
+ TestScene::registerScene({name + "GlTex", description + " (GlTex version).",
+ createBitmapAllocationScene<BaseScene, &allocateHeapBitmap>});
- TestScene::registerScene({
- name + "EglImage",
- description + " (EglImage version).",
- createBitmapAllocationScene<BaseScene, &allocateHardwareBitmap>
- });
+ TestScene::registerScene({name + "EglImage", description + " (EglImage version).",
+ createBitmapAllocationScene<BaseScene, &allocateHardwareBitmap>});
return true;
}
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/LeakChecker.cpp b/libs/hwui/tests/common/LeakChecker.cpp
index fe38ec9..5b36154 100644
--- a/libs/hwui/tests/common/LeakChecker.cpp
+++ b/libs/hwui/tests/common/LeakChecker.cpp
@@ -19,10 +19,10 @@
#include "Caches.h"
#include "TestUtils.h"
-#include <cstdio>
-#include <iostream>
#include <memunreachable/memunreachable.h>
#include <unistd.h>
+#include <cstdio>
+#include <iostream>
#include <unordered_set>
using namespace std;
@@ -45,12 +45,12 @@
merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes);
merged.num_allocations = max(merged.num_allocations, info.num_allocations);
for (auto& leak : info.leaks) {
- if (addrs.find(leak.begin) == addrs.end()) {
- merged.leaks.push_back(leak);
- merged.num_leaks++;
- merged.leak_bytes += leak.size;
- addrs.insert(leak.begin);
- }
+ if (addrs.find(leak.begin) == addrs.end()) {
+ merged.leaks.push_back(leak);
+ merged.num_leaks++;
+ merged.leak_bytes += leak.size;
+ addrs.insert(leak.begin);
+ }
}
}
@@ -59,7 +59,7 @@
cout << endl << "Leaked memory!" << endl;
if (!merged.leaks[0].backtrace.num_frames) {
cout << "Re-run with 'export LIBC_DEBUG_MALLOC_OPTIONS=backtrace' to get backtraces"
- << endl;
+ << endl;
}
cout << merged.ToString(false);
}
diff --git a/libs/hwui/tests/common/LeakChecker.h b/libs/hwui/tests/common/LeakChecker.h
index cdf47d6..e43df17 100644
--- a/libs/hwui/tests/common/LeakChecker.h
+++ b/libs/hwui/tests/common/LeakChecker.h
@@ -22,7 +22,7 @@
class LeakChecker {
public:
static void checkForLeaks();
-}; // class TestUtils
+}; // class TestUtils
} /* namespace test */
} /* namespace uirenderer */
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 1e30d23..92b6cbd 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -24,24 +24,23 @@
static const int IDENT_DISPLAYEVENT = 1;
-static android::DisplayInfo DUMMY_DISPLAY {
- 1080, //w
- 1920, //h
- 320.0, // xdpi
- 320.0, // ydpi
- 60.0, // fps
- 2.0, // density
- 0, // orientation
- false, // secure?
- 0, // appVsyncOffset
- 0, // presentationDeadline
+static android::DisplayInfo DUMMY_DISPLAY{
+ 1080, // w
+ 1920, // h
+ 320.0, // xdpi
+ 320.0, // ydpi
+ 60.0, // fps
+ 2.0, // density
+ 0, // orientation
+ false, // secure?
+ 0, // appVsyncOffset
+ 0, // presentationDeadline
};
DisplayInfo getBuiltInDisplay() {
#if !HWUI_NULL_GPU
DisplayInfo display;
- sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
- ISurfaceComposer::eDisplayIdMain));
+ sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &display);
LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
return display;
@@ -56,8 +55,8 @@
TestContext::TestContext() {
mLooper = new Looper(true);
mSurfaceComposerClient = new SurfaceComposerClient();
- mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT,
- Looper::EVENT_INPUT, nullptr, nullptr);
+ mLooper->addFd(mDisplayEventReceiver.getFd(), IDENT_DISPLAYEVENT, Looper::EVENT_INPUT, nullptr,
+ nullptr);
}
TestContext::~TestContext() {}
@@ -78,13 +77,11 @@
}
void TestContext::createWindowSurface() {
- mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"),
- gDisplay.w, gDisplay.h, PIXEL_FORMAT_RGBX_8888);
+ mSurfaceControl = mSurfaceComposerClient->createSurface(String8("HwuiTest"), gDisplay.w,
+ gDisplay.h, PIXEL_FORMAT_RGBX_8888);
SurfaceComposerClient::Transaction t;
- t.setLayer(mSurfaceControl, 0x7FFFFFF)
- .show(mSurfaceControl)
- .apply();
+ t.setLayer(mSurfaceControl, 0x7FFFFFF).show(mSurfaceControl).apply();
mSurface = mSurfaceControl->getSurface();
}
@@ -124,10 +121,11 @@
// Drain it
DisplayEventReceiver::Event buf[100];
- while (mDisplayEventReceiver.getEvents(buf, 100) > 0) { }
+ while (mDisplayEventReceiver.getEvents(buf, 100) > 0) {
+ }
#endif
}
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index 312988b..0996f4d 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -17,24 +17,24 @@
#ifndef TESTCONTEXT_H
#define TESTCONTEXT_H
+#include <gui/BufferItemConsumer.h>
#include <gui/DisplayEventReceiver.h>
#include <gui/ISurfaceComposer.h>
-#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/SurfaceControl.h>
-#include <gui/Surface.h>
#include <ui/DisplayInfo.h>
#include <utils/Looper.h>
-#include <thread>
#include <atomic>
+#include <thread>
namespace android {
namespace uirenderer {
namespace test {
extern DisplayInfo gDisplay;
-#define dp(x) ((x) * android::uirenderer::test::gDisplay.density)
+#define dp(x) ((x)*android::uirenderer::test::gDisplay.density)
DisplayInfo getBuiltInDisplay();
@@ -45,8 +45,7 @@
// Must be called before surface();
void setRenderOffscreen(bool renderOffscreen) {
- LOG_ALWAYS_FATAL_IF(mSurface.get(),
- "Must be called before surface is created");
+ LOG_ALWAYS_FATAL_IF(mSurface.get(), "Must be called before surface is created");
mRenderOffscreen = renderOffscreen;
}
@@ -68,8 +67,8 @@
bool mRenderOffscreen;
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
#endif
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.cpp b/libs/hwui/tests/common/TestListViewSceneBase.cpp
index 38c4848..a7f4d4d 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.cpp
+++ b/libs/hwui/tests/common/TestListViewSceneBase.cpp
@@ -35,17 +35,17 @@
for (int y = 0; y < height + (heightWithSpacing - 1); y += heightWithSpacing) {
int id = mListItems.size();
auto setup = std::bind(&TestListViewSceneBase::createListItem, this, std::placeholders::_1,
- std::placeholders::_2, id, mItemWidth, mItemHeight);
- auto node = TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth,
- y + mItemHeight, setup);
+ std::placeholders::_2, id, mItemWidth, mItemHeight);
+ auto node =
+ TestUtils::createNode(mItemLeft, y, mItemLeft + mItemWidth, y + mItemHeight, setup);
mListItems.push_back(node);
}
mListView = TestUtils::createNode(0, 0, width, height,
- [this](RenderProperties& props, Canvas& canvas) {
- for (size_t ci = 0; ci < mListItems.size(); ci++) {
- canvas.drawRenderNode(mListItems[ci].get());
- }
- });
+ [this](RenderProperties& props, Canvas& canvas) {
+ for (size_t ci = 0; ci < mListItems.size(); ci++) {
+ canvas.drawRenderNode(mListItems[ci].get());
+ }
+ });
canvas.drawColor(Color::Grey_500, SkBlendMode::kSrcOver);
canvas.drawRenderNode(mListView.get());
@@ -56,8 +56,8 @@
int itemIndexOffset = scrollPx / (mItemSpacing + mItemHeight);
int pxOffset = -(scrollPx % (mItemSpacing + mItemHeight));
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(mListView->stagingProperties().getWidth(),
- mListView->stagingProperties().getHeight()));
+ std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+ mListView->stagingProperties().getWidth(), mListView->stagingProperties().getHeight()));
for (size_t ci = 0; ci < mListItems.size(); ci++) {
// update item position
auto listItem = mListItems[(ci + itemIndexOffset) % mListItems.size()];
@@ -72,6 +72,6 @@
mListView->setStagingDisplayList(canvas->finishRecording());
}
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestListViewSceneBase.h b/libs/hwui/tests/common/TestListViewSceneBase.h
index ed6867a..ab0d3c7 100644
--- a/libs/hwui/tests/common/TestListViewSceneBase.h
+++ b/libs/hwui/tests/common/TestListViewSceneBase.h
@@ -15,9 +15,9 @@
*/
#pragma once
-#include "TestScene.h"
#include <RenderNode.h>
#include <RenderProperties.h>
+#include "TestScene.h"
namespace android {
namespace uirenderer {
@@ -25,20 +25,21 @@
class TestListViewSceneBase : public TestScene {
public:
- virtual void createListItem(RenderProperties& props, Canvas& canvas, int id,
- int itemWidth, int itemHeight) = 0;
+ virtual void createListItem(RenderProperties& props, Canvas& canvas, int id, int itemWidth,
+ int itemHeight) = 0;
+
private:
int mItemHeight;
int mItemSpacing;
int mItemWidth;
int mItemLeft;
sp<RenderNode> mListView;
- std::vector< sp<RenderNode> > mListItems;
+ std::vector<sp<RenderNode> > mListItems;
void createContent(int width, int height, Canvas& canvas) override;
void doFrame(int frameNr) override;
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestScene.h b/libs/hwui/tests/common/TestScene.h
index f6f7c62..5cd90c5 100644
--- a/libs/hwui/tests/common/TestScene.h
+++ b/libs/hwui/tests/common/TestScene.h
@@ -52,9 +52,8 @@
class Registrar {
public:
- explicit Registrar(const TestScene::Info& info) {
- TestScene::registerScene(info);
- }
+ explicit Registrar(const TestScene::Info& info) { TestScene::registerScene(info); }
+
private:
Registrar() = delete;
Registrar(const Registrar&) = delete;
@@ -69,6 +68,6 @@
static void registerScene(const Info& info);
};
-} // namespace test
-} // namespace uirenderer
-} // namespace android
+} // namespace test
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index e613776..1e42425 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -16,17 +16,17 @@
#include "TestUtils.h"
-#include "hwui/Paint.h"
#include "DeferredLayerUpdater.h"
+#include "hwui/Paint.h"
+#include <SkClipStack.h>
#include <minikin/Layout.h>
-#include <renderthread/EglManager.h>
-#include <renderthread/OpenGLPipeline.h>
#include <pipeline/skia/SkiaOpenGLPipeline.h>
#include <pipeline/skia/SkiaVulkanPipeline.h>
+#include <renderthread/EglManager.h>
+#include <renderthread/OpenGLPipeline.h>
#include <renderthread/VulkanManager.h>
#include <utils/Unicode.h>
-#include <SkClipStack.h>
#include <SkGlyphCache.h>
@@ -44,10 +44,10 @@
int endG = (end >> 8) & 0xff;
int endB = end & 0xff;
- return (int)((startA + (int)(fraction * (endA - startA))) << 24)
- | (int)((startR + (int)(fraction * (endR - startR))) << 16)
- | (int)((startG + (int)(fraction * (endG - startG))) << 8)
- | (int)((startB + (int)(fraction * (endB - startB))));
+ return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
+ (int)((startR + (int)(fraction * (endR - startR))) << 16) |
+ (int)((startG + (int)(fraction * (endG - startG))) << 8) |
+ (int)((startB + (int)(fraction * (endB - startB))));
}
sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
@@ -77,15 +77,16 @@
// updateLayer so it's ready to draw
layerUpdater->updateLayer(true, Matrix4::identity().data);
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
- static_cast<GlLayer*>(layerUpdater->backingLayer())->setRenderTarget(
- GL_TEXTURE_EXTERNAL_OES);
+ static_cast<GlLayer*>(layerUpdater->backingLayer())
+ ->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
}
return layerUpdater;
}
void TestUtils::layoutTextUnscaled(const SkPaint& paint, const char* text,
- std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
- float* outTotalAdvance, Rect* outBounds) {
+ std::vector<glyph_t>* outGlyphs,
+ std::vector<float>* outPositions, float* outTotalAdvance,
+ Rect* outBounds) {
Rect bounds;
float totalAdvance = 0;
SkSurfaceProps surfaceProps(0, kUnknown_SkPixelGeometry);
@@ -118,19 +119,18 @@
*outTotalAdvance = totalAdvance;
}
-
-void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, float x, float y) {
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, float x,
+ float y) {
auto utf16 = asciiToUtf16(text);
canvas->drawText(utf16.get(), 0, strlen(text), strlen(text), x, y, minikin::Bidi::LTR, paint,
- nullptr);
+ nullptr);
}
-void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, const SkPath& path) {
+void TestUtils::drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
+ const SkPath& path) {
auto utf16 = asciiToUtf16(text);
canvas->drawTextOnPath(utf16.get(), strlen(text), minikin::Bidi::LTR, path, 0, 0, paint,
- nullptr);
+ nullptr);
}
void TestUtils::TestTask::run() {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index c383fcf..1bfa046 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -22,11 +22,11 @@
#include <Properties.h>
#include <Rect.h>
#include <RenderNode.h>
+#include <Snapshot.h>
#include <hwui/Bitmap.h>
#include <pipeline/skia/SkiaRecordingCanvas.h>
#include <renderstate/RenderState.h>
#include <renderthread/RenderThread.h>
-#include <Snapshot.h>
#include <RecordedOp.h>
#include <RecordingCanvas.h>
@@ -36,85 +36,88 @@
namespace android {
namespace uirenderer {
-#define EXPECT_MATRIX_APPROX_EQ(a, b) \
- EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
+#define EXPECT_MATRIX_APPROX_EQ(a, b) EXPECT_TRUE(TestUtils::matricesAreApproxEqual(a, b))
-#define EXPECT_RECT_APPROX_EQ(a, b) \
- EXPECT_TRUE(MathUtils::areEqual((a).left, (b).left) \
- && MathUtils::areEqual((a).top, (b).top) \
- && MathUtils::areEqual((a).right, (b).right) \
- && MathUtils::areEqual((a).bottom, (b).bottom));
+#define EXPECT_RECT_APPROX_EQ(a, b) \
+ EXPECT_TRUE(MathUtils::areEqual((a).left, (b).left) && \
+ MathUtils::areEqual((a).top, (b).top) && \
+ MathUtils::areEqual((a).right, (b).right) && \
+ MathUtils::areEqual((a).bottom, (b).bottom));
-#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
- EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
- if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
- EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
- } else { \
- ADD_FAILURE() << "ClipState not a rect"; \
- }
+#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
+ EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
+ if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
+ EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
+ } else { \
+ ADD_FAILURE() << "ClipState not a rect"; \
+ }
#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
- TEST(test_case_name, test_name##_##pipeline) { \
- RenderPipelineType oldType = Properties::getRenderPipelineType(); \
- Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
- functionCall; \
- Properties::overrideRenderPipelineType(oldType); \
+ TEST(test_case_name, test_name##_##pipeline) { \
+ RenderPipelineType oldType = Properties::getRenderPipelineType(); \
+ Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
+ functionCall; \
+ Properties::overrideRenderPipelineType(oldType); \
};
/**
* Like gtests' TEST, but only runs with the OpenGL RenderPipelineType
*/
-#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_HwuiTest { \
- public: \
- static void doTheThing(); \
- }; \
- INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \
- test_case_name##_##test_name##_HwuiTest::doTheThing()) \
+#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_HwuiTest { \
+ public: \
+ static void doTheThing(); \
+ }; \
+ INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \
+ test_case_name##_##test_name##_HwuiTest::doTheThing()) \
void test_case_name##_##test_name##_HwuiTest::doTheThing()
#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \
- INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
- TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing))
+ INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
+ TestUtils::runOnRenderThread( \
+ test_case_name##_##test_name##_RenderThreadTest::doTheThing))
/**
* Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
* (for e.g. accessing its RenderState)
*/
-#define RENDERTHREAD_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+#define RENDERTHREAD_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
+ static void doTheThing(renderthread::RenderThread& renderThread); \
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
/* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+ renderthread::RenderThread& renderThread)
/**
* Like RENDERTHREAD_TEST, but only runs with the OpenGL RenderPipelineType
*/
-#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
+#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+ renderthread::RenderThread& renderThread)
/**
* Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes
*/
-#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
- class test_case_name##_##test_name##_RenderThreadTest { \
- public: \
- static void doTheThing(renderthread::RenderThread& renderThread); \
- }; \
- INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
+ class test_case_name##_##test_name##_RenderThreadTest { \
+ public: \
+ static void doTheThing(renderthread::RenderThread& renderThread); \
+ }; \
+ INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
/* Temporarily disabling Vulkan until we can figure out a way to stub out the driver */ \
- /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
- void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+ /* INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); */ \
+ void test_case_name##_##test_name##_RenderThreadTest::doTheThing( \
+ renderthread::RenderThread& renderThread)
/**
* Sets a property value temporarily, generally for the duration of a test, restoring the previous
@@ -125,14 +128,11 @@
template <typename T>
class ScopedProperty {
public:
- ScopedProperty(T& property, T newValue)
- : mPropertyPtr(&property)
- , mOldValue(property) {
+ ScopedProperty(T& property, T newValue) : mPropertyPtr(&property), mOldValue(property) {
property = newValue;
}
- ~ScopedProperty() {
- *mPropertyPtr = mOldValue;
- }
+ ~ScopedProperty() { *mPropertyPtr = mOldValue; }
+
private:
T* mPropertyPtr;
T mOldValue;
@@ -142,18 +142,15 @@
public:
class SignalingDtor {
public:
- SignalingDtor()
- : mSignal(nullptr) {}
- explicit SignalingDtor(int* signal)
- : mSignal(signal) {}
- void setSignal(int* signal) {
- mSignal = signal;
- }
+ SignalingDtor() : mSignal(nullptr) {}
+ explicit SignalingDtor(int* signal) : mSignal(signal) {}
+ void setSignal(int* signal) { mSignal = signal; }
~SignalingDtor() {
if (mSignal) {
(*mSignal)++;
}
}
+
private:
int* mSignal;
};
@@ -181,7 +178,7 @@
}
static sk_sp<Bitmap> createBitmap(int width, int height,
- SkColorType colorType = kN32_SkColorType) {
+ SkColorType colorType = kN32_SkColorType) {
SkImageInfo info = SkImageInfo::Make(width, height, colorType, kPremul_SkAlphaType);
return Bitmap::allocateHeapBitmap(info);
}
@@ -199,15 +196,16 @@
renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
const SkMatrix& transform);
- template<class CanvasType>
- static std::unique_ptr<DisplayList> createDisplayList(int width, int height,
- std::function<void(CanvasType& canvas)> canvasCallback) {
+ template <class CanvasType>
+ static std::unique_ptr<DisplayList> createDisplayList(
+ int width, int height, std::function<void(CanvasType& canvas)> canvasCallback) {
CanvasType canvas(width, height);
canvasCallback(canvas);
return std::unique_ptr<DisplayList>(canvas.finishRecording());
}
- static sp<RenderNode> createNode(int left, int top, int right, int bottom,
+ static sp<RenderNode> createNode(
+ int left, int top, int right, int bottom,
std::function<void(RenderProperties& props, Canvas& canvas)> setup) {
#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
@@ -219,8 +217,8 @@
RenderProperties& props = node->mutateStagingProperties();
props.setLeftTopRightBottom(left, top, right, bottom);
if (setup) {
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(props.getWidth(),
- props.getHeight()));
+ std::unique_ptr<Canvas> canvas(
+ Canvas::create_recording_canvas(props.getWidth(), props.getHeight()));
setup(props, *canvas.get());
node->setStagingDisplayList(canvas->finishRecording());
}
@@ -228,8 +226,9 @@
return node;
}
- template<class RecordingCanvasType>
- static sp<RenderNode> createNode(int left, int top, int right, int bottom,
+ template <class RecordingCanvasType>
+ static sp<RenderNode> createNode(
+ int left, int top, int right, int bottom,
std::function<void(RenderProperties& props, RecordingCanvasType& canvas)> setup) {
#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
@@ -249,22 +248,23 @@
return node;
}
- static void recordNode(RenderNode& node,
- std::function<void(Canvas&)> contentCallback) {
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- node.stagingProperties().getWidth(), node.stagingProperties().getHeight()));
- contentCallback(*canvas.get());
- node.setStagingDisplayList(canvas->finishRecording());
+ static void recordNode(RenderNode& node, std::function<void(Canvas&)> contentCallback) {
+ std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+ node.stagingProperties().getWidth(), node.stagingProperties().getHeight()));
+ contentCallback(*canvas.get());
+ node.setStagingDisplayList(canvas->finishRecording());
}
- static sp<RenderNode> createSkiaNode(int left, int top, int right, int bottom,
- std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)> setup,
+ static sp<RenderNode> createSkiaNode(
+ int left, int top, int right, int bottom,
+ std::function<void(RenderProperties& props, skiapipeline::SkiaRecordingCanvas& canvas)>
+ setup,
const char* name = nullptr, skiapipeline::SkiaDisplayList* displayList = nullptr) {
- #if HWUI_NULL_GPU
+#if HWUI_NULL_GPU
// if RenderNodes are being sync'd/used, device info will be needed, since
// DeviceInfo::maxTextureSize() affects layer property
DeviceInfo::initialize();
- #endif
+#endif
sp<RenderNode> node = new RenderNode();
if (name) {
node->setName(name);
@@ -276,8 +276,8 @@
}
if (setup) {
std::unique_ptr<skiapipeline::SkiaRecordingCanvas> canvas(
- new skiapipeline::SkiaRecordingCanvas(nullptr,
- props.getWidth(), props.getHeight()));
+ new skiapipeline::SkiaRecordingCanvas(nullptr, props.getWidth(),
+ props.getHeight()));
setup(props, *canvas.get());
node->setStagingDisplayList(canvas->finishRecording());
}
@@ -306,8 +306,7 @@
class TestTask : public renderthread::RenderTask {
public:
- explicit TestTask(RtCallback rtCallback)
- : rtCallback(rtCallback) {}
+ explicit TestTask(RtCallback rtCallback) : rtCallback(rtCallback) {}
virtual ~TestTask() {}
virtual void run() override;
RtCallback rtCallback;
@@ -318,39 +317,37 @@
*/
static void runOnRenderThread(RtCallback rtCallback) {
TestTask task(rtCallback);
- renderthread::RenderThread::getInstance().queue().runSync([&]() {
- task.run();
- });
+ renderthread::RenderThread::getInstance().queue().runSync([&]() { task.run(); });
}
- static bool isRenderThreadRunning() {
- return renderthread::RenderThread::hasInstance();
- }
+ static bool isRenderThreadRunning() { return renderthread::RenderThread::hasInstance(); }
static SkColor interpolateColor(float fraction, SkColor start, SkColor end);
static void layoutTextUnscaled(const SkPaint& paint, const char* text,
- std::vector<glyph_t>* outGlyphs, std::vector<float>* outPositions,
- float* outTotalAdvance, Rect* outBounds);
+ std::vector<glyph_t>* outGlyphs,
+ std::vector<float>* outPositions, float* outTotalAdvance,
+ Rect* outBounds);
- static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, float x, float y);
+ static void drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint, float x,
+ float y);
- static void drawUtf8ToCanvas(Canvas* canvas, const char* text,
- const SkPaint& paint, const SkPath& path);
+ static void drawUtf8ToCanvas(Canvas* canvas, const char* text, const SkPaint& paint,
+ const SkPath& path);
static std::unique_ptr<uint16_t[]> asciiToUtf16(const char* str);
class MockFunctor : public Functor {
- public:
- virtual status_t operator ()(int what, void* data) {
- mLastMode = what;
- return DrawGlInfo::kStatusDone;
- }
- int getLastMode() const { return mLastMode; }
- private:
- int mLastMode = -1;
- };
+ public:
+ virtual status_t operator()(int what, void* data) {
+ mLastMode = what;
+ return DrawGlInfo::kStatusDone;
+ }
+ int getLastMode() const { return mLastMode; }
+
+ private:
+ int mLastMode = -1;
+ };
static SkColor getColor(const sk_sp<SkSurface>& surface, int x, int y);
@@ -369,7 +366,8 @@
if (displayList) {
if (displayList->isSkiaDL()) {
for (auto&& childDr : static_cast<skiapipeline::SkiaDisplayList*>(
- const_cast<DisplayList*>(displayList))->mChildNodes) {
+ const_cast<DisplayList*>(displayList))
+ ->mChildNodes) {
syncHierarchyPropertiesAndDisplayListImpl(childDr.getRenderNode());
}
} else {
@@ -380,7 +378,7 @@
}
}
-}; // class TestUtils
+}; // class TestUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
index be58d09..1d3d607 100644
--- a/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapFillrate.cpp
@@ -32,8 +32,7 @@
class BitmapFillrate : public TestScene {
public:
BitmapFillrate(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TestScene()
- , mAllocator(allocator) { }
+ : TestScene(), mAllocator(allocator) {}
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
@@ -41,7 +40,7 @@
createNode(canvas, 0xA0CDDC39, width / 3, height / 3, width, height);
createNode(canvas, 0x90009688, width / 3, 0, width, height);
createNode(canvas, 0xA0FF5722, 0, height / 3, width, height);
- createNode(canvas, 0x9000796B, width / 6, height/6, width, height);
+ createNode(canvas, 0x9000796B, width / 6, height / 6, width, height);
createNode(canvas, 0xA0FFC107, width / 6, 0, width, height);
}
@@ -52,23 +51,23 @@
mNodes[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
- void createNode(Canvas& canvas, SkColor color, int left, int top,
- int width, int height) {
+ void createNode(Canvas& canvas, SkColor color, int left, int top, int width, int height) {
int itemWidth = 2 * width / 3;
int itemHeight = 2 * height / 3;
- auto card = TestUtils::createNode(left, top, left + itemWidth , top + itemHeight,
+ auto card = TestUtils::createNode(
+ left, top, left + itemWidth, top + itemHeight,
[this, itemWidth, itemHeight, color](RenderProperties& props, Canvas& canvas) {
- sk_sp<Bitmap> bitmap = mAllocator(itemWidth, itemHeight, kRGBA_8888_SkColorType,
- [color](SkBitmap& skBitmap) {
- skBitmap.eraseColor(color);
- });
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ sk_sp<Bitmap> bitmap =
+ mAllocator(itemWidth, itemHeight, kRGBA_8888_SkColorType,
+ [color](SkBitmap& skBitmap) { skBitmap.eraseColor(color); });
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
canvas.drawRenderNode(card.get());
mNodes.push_back(card);
}
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
- std::vector< sp<RenderNode> > mNodes;
+ std::vector<sp<RenderNode> > mNodes;
};
\ No newline at end of file
diff --git a/libs/hwui/tests/common/scenes/BitmapShaders.cpp b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
index 0f2dc03..15039b5 100644
--- a/libs/hwui/tests/common/scenes/BitmapShaders.cpp
+++ b/libs/hwui/tests/common/scenes/BitmapShaders.cpp
@@ -14,56 +14,52 @@
* limitations under the License.
*/
-#include "TestSceneBase.h"
-#include "utils/Color.h"
-#include "tests/common/BitmapAllocationTestUtils.h"
#include <SkImagePriv.h>
+#include "TestSceneBase.h"
+#include "tests/common/BitmapAllocationTestUtils.h"
+#include "utils/Color.h"
class BitmapShaders;
-static bool _BitmapShaders(
- BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>(
- "bitmapShader", "Draws bitmap shaders with repeat and mirror modes."));
+static bool _BitmapShaders(BitmapAllocationTestUtils::registerBitmapAllocationScene<BitmapShaders>(
+ "bitmapShader", "Draws bitmap shaders with repeat and mirror modes."));
class BitmapShaders : public TestScene {
public:
BitmapShaders(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TestScene()
- , mAllocator(allocator) { }
+ : TestScene(), mAllocator(allocator) {}
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
- sk_sp<Bitmap> hwuiBitmap = mAllocator(200, 200, kRGBA_8888_SkColorType,
- [](SkBitmap& skBitmap) {
- skBitmap.eraseColor(Color::White);
- SkCanvas skCanvas(skBitmap);
- SkPaint skPaint;
- skPaint.setColor(Color::Red_500);
- skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
- skPaint.setColor(Color::Blue_500);
- skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
- });
+ sk_sp<Bitmap> hwuiBitmap =
+ mAllocator(200, 200, kRGBA_8888_SkColorType, [](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(Color::White);
+ SkCanvas skCanvas(skBitmap);
+ SkPaint skPaint;
+ skPaint.setColor(Color::Red_500);
+ skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+ skPaint.setColor(Color::Blue_500);
+ skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+ });
SkPaint paint;
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = hwuiBitmap->makeImage(&colorFilter);
- sk_sp<SkShader> repeatShader = image->makeShader(
- SkShader::TileMode::kRepeat_TileMode,
- SkShader::TileMode::kRepeat_TileMode,
- nullptr);
+ sk_sp<SkShader> repeatShader =
+ image->makeShader(SkShader::TileMode::kRepeat_TileMode,
+ SkShader::TileMode::kRepeat_TileMode, nullptr);
paint.setShader(std::move(repeatShader));
canvas.drawRoundRect(0, 0, 500, 500, 50.0f, 50.0f, paint);
- sk_sp<SkShader> mirrorShader = image->makeShader(
- SkShader::TileMode::kMirror_TileMode,
- SkShader::TileMode::kMirror_TileMode,
- nullptr);
+ sk_sp<SkShader> mirrorShader =
+ image->makeShader(SkShader::TileMode::kMirror_TileMode,
+ SkShader::TileMode::kMirror_TileMode, nullptr);
paint.setShader(std::move(mirrorShader));
canvas.drawRoundRect(0, 600, 500, 1100, 50.0f, 50.0f, paint);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
BitmapAllocationTestUtils::BitmapAllocator mAllocator;
};
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
index f47e05a..2a016ac 100644
--- a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -19,19 +19,17 @@
class ClippingAnimation;
static TestScene::Registrar _RectGrid(TestScene::Info{
- "clip",
- "Complex clip cases"
- "Low CPU/GPU load.",
- TestScene::simpleCreateScene<ClippingAnimation>
-});
+ "clip",
+ "Complex clip cases"
+ "Low CPU/GPU load.",
+ TestScene::simpleCreateScene<ClippingAnimation>});
class ClippingAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- card = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
{
canvas.clipRect(0, 0, 200, 200, SkClipOp::kIntersect);
diff --git a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
index 21d8d75..bf0aed9 100644
--- a/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/GlyphStressAnimation.cpp
@@ -25,30 +25,28 @@
class GlyphStressAnimation;
static TestScene::Registrar _GlyphStress(TestScene::Info{
- "glyphstress",
- "A stress test for both the glyph cache, and glyph rendering.",
- TestScene::simpleCreateScene<GlyphStressAnimation>
-});
+ "glyphstress", "A stress test for both the glyph cache, and glyph rendering.",
+ TestScene::simpleCreateScene<GlyphStressAnimation>});
class GlyphStressAnimation : public TestScene {
public:
sp<RenderNode> container;
void createContent(int width, int height, Canvas& canvas) override {
container = TestUtils::createNode(0, 0, width, height, nullptr);
- doFrame(0); // update container
+ doFrame(0); // update container
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
canvas.drawRenderNode(container.get());
}
void doFrame(int frameNr) override {
- std::unique_ptr<uint16_t[]> text = TestUtils::asciiToUtf16(
- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ std::unique_ptr<uint16_t[]> text =
+ TestUtils::asciiToUtf16("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
ssize_t textLength = 26 * 2;
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- container->stagingProperties().getWidth(),
- container->stagingProperties().getHeight()));
+ std::unique_ptr<Canvas> canvas(
+ Canvas::create_recording_canvas(container->stagingProperties().getWidth(),
+ container->stagingProperties().getHeight()));
Paint paint;
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
@@ -56,8 +54,8 @@
paint.setColor(Color::Black);
for (int i = 0; i < 5; i++) {
paint.setTextSize(10 + (frameNr % 20) + i * 20);
- canvas->drawText(text.get(), 0, textLength, textLength,
- 0, 100 * (i + 2), minikin::Bidi::FORCE_LTR, paint, nullptr);
+ canvas->drawText(text.get(), 0, textLength, textLength, 0, 100 * (i + 2),
+ minikin::Bidi::FORCE_LTR, paint, nullptr);
}
container->setStagingDisplayList(canvas->finishRecording());
diff --git a/libs/hwui/tests/common/scenes/HwBitmap565.cpp b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
index 18fea3d..cbdb756 100644
--- a/libs/hwui/tests/common/scenes/HwBitmap565.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmap565.cpp
@@ -15,16 +15,14 @@
*/
#include "TestSceneBase.h"
-#include "utils/Color.h"
#include "tests/common/BitmapAllocationTestUtils.h"
+#include "utils/Color.h"
class HwBitmap565;
static TestScene::Registrar _HwBitmap565(TestScene::Info{
- "hwBitmap565",
- "Draws composite shader with hardware bitmap",
- TestScene::simpleCreateScene<HwBitmap565>
-});
+ "hwBitmap565", "Draws composite shader with hardware bitmap",
+ TestScene::simpleCreateScene<HwBitmap565>});
class HwBitmap565 : public TestScene {
public:
@@ -32,18 +30,18 @@
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
- sk_sp<Bitmap> hardwareBitmap = BitmapAllocationTestUtils::allocateHardwareBitmap(200, 200,
- kRGB_565_SkColorType, [](SkBitmap& skBitmap) {
- skBitmap.eraseColor(Color::White);
- SkCanvas skCanvas(skBitmap);
- SkPaint skPaint;
- skPaint.setColor(Color::Red_500);
- skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
- skPaint.setColor(Color::Blue_500);
- skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
- });
+ sk_sp<Bitmap> hardwareBitmap = BitmapAllocationTestUtils::allocateHardwareBitmap(
+ 200, 200, kRGB_565_SkColorType, [](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(Color::White);
+ SkCanvas skCanvas(skBitmap);
+ SkPaint skPaint;
+ skPaint.setColor(Color::Red_500);
+ skCanvas.drawRect(SkRect::MakeWH(100, 100), skPaint);
+ skPaint.setColor(Color::Blue_500);
+ skCanvas.drawRect(SkRect::MakeXYWH(100, 100, 100, 100), skPaint);
+ });
canvas.drawBitmap(*hardwareBitmap, 10.0f, 10.0f, nullptr);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
};
\ No newline at end of file
diff --git a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
index 960b053..f137562 100644
--- a/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
+++ b/libs/hwui/tests/common/scenes/HwBitmapInCompositeShader.cpp
@@ -17,17 +17,15 @@
#include "TestSceneBase.h"
#include "utils/Color.h"
-#include <ui/PixelFormat.h>
#include <SkGradientShader.h>
#include <SkImagePriv.h>
+#include <ui/PixelFormat.h>
class HwBitmapInCompositeShader;
static TestScene::Registrar _HwBitmapInCompositeShader(TestScene::Info{
- "hwbitmapcompositeshader",
- "Draws composite shader with hardware bitmap",
- TestScene::simpleCreateScene<HwBitmapInCompositeShader>
-});
+ "hwbitmapcompositeshader", "Draws composite shader with hardware bitmap",
+ TestScene::simpleCreateScene<HwBitmapInCompositeShader>});
class HwBitmapInCompositeShader : public TestScene {
public:
@@ -35,16 +33,15 @@
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
- uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE
- | GraphicBuffer::USAGE_SW_READ_NEVER
- | GRALLOC_USAGE_SW_WRITE_RARELY;
+ uint32_t usage = GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_READ_NEVER |
+ GRALLOC_USAGE_SW_WRITE_RARELY;
sp<GraphicBuffer> buffer = new GraphicBuffer(400, 200, PIXEL_FORMAT_RGBA_8888, usage);
unsigned char* pixels = nullptr;
buffer->lock(GraphicBuffer::USAGE_SW_WRITE_RARELY, ((void**)&pixels));
- size_t size = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride()
- * buffer->getHeight();
+ size_t size =
+ bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride() * buffer->getHeight();
memset(pixels, 0, size);
for (int i = 0; i < 6000; i++) {
pixels[4000 + 4 * i + 0] = 255;
@@ -61,8 +58,8 @@
SkColor colors[2];
colors[0] = Color::Black;
colors[1] = Color::White;
- sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(center, 50, colors, nullptr,
- 2, SkShader::TileMode::kRepeat_TileMode);
+ sk_sp<SkShader> gradientShader = SkGradientShader::MakeRadial(
+ center, 50, colors, nullptr, 2, SkShader::TileMode::kRepeat_TileMode);
sk_sp<SkShader> compositeShader(
SkShader::MakeComposeShader(hardwareShader, gradientShader, SkBlendMode::kDstATop));
@@ -72,12 +69,12 @@
canvas.drawRoundRect(0, 0, 400, 200, 10.0f, 10.0f, paint);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
sk_sp<SkShader> createBitmapShader(Bitmap& bitmap) {
sk_sp<SkColorFilter> colorFilter;
sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
return image->makeShader(SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode);
+ SkShader::TileMode::kClamp_TileMode);
}
};
diff --git a/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp b/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
index 3a230ae..cac2fb3 100644
--- a/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/HwLayerAnimation.cpp
@@ -19,22 +19,20 @@
class HwLayerAnimation;
static TestScene::Registrar _HwLayer(TestScene::Info{
- "hwlayer",
- "A nested pair of nodes with LAYER_TYPE_HARDWARE set on each. "
- "Tests the hardware layer codepath.",
- TestScene::simpleCreateScene<HwLayerAnimation>
-});
+ "hwlayer",
+ "A nested pair of nodes with LAYER_TYPE_HARDWARE set on each. "
+ "Tests the hardware layer codepath.",
+ TestScene::simpleCreateScene<HwLayerAnimation>});
class HwLayerAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- card = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
props.mutateLayerProperties().setType(LayerType::RenderLayer);
canvas.drawColor(0xFF0000FF, SkBlendMode::kSrcOver);
});
- canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
canvas.drawRenderNode(card.get());
}
void doFrame(int frameNr) override {
diff --git a/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp b/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
index d841132..77a59df 100644
--- a/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/HwLayerSizeAnimation.cpp
@@ -19,29 +19,27 @@
class HwLayerSizeAnimation;
static TestScene::Registrar _HwLayerSize(TestScene::Info{
- "hwlayersize",
- "A nested pair of nodes with LayerType::RenderLayer(hardware) set on the child and "
- "LayerType::None on the parent. "
- "Tests animating the size of a hardware layer.",
- TestScene::simpleCreateScene<HwLayerSizeAnimation>
-});
+ "hwlayersize",
+ "A nested pair of nodes with LayerType::RenderLayer(hardware) set on the child and "
+ "LayerType::None on the parent. "
+ "Tests animating the size of a hardware layer.",
+ TestScene::simpleCreateScene<HwLayerSizeAnimation>});
class HwLayerSizeAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- card = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
props.mutateLayerProperties().setType(LayerType::RenderLayer);
canvas.drawColor(0xFF0000FF, SkBlendMode::kSrcOver);
});
- canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver); // background
canvas.drawRenderNode(card.get());
}
void doFrame(int frameNr) override {
int curFrame = frameNr % 150;
- //we animate left and top coordinates, which in turn animates width and
- //height (bottom/right coordinates are fixed)
+ // we animate left and top coordinates, which in turn animates width and
+ // height (bottom/right coordinates are fixed)
card->mutateStagingProperties().setLeftTop(curFrame, curFrame);
card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
diff --git a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
index b7357e1..58c9980 100644
--- a/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListOfFadedTextAnimation.cpp
@@ -22,15 +22,14 @@
class ListOfFadedTextAnimation;
static TestScene::Registrar _ListOfFadedTextAnimation(TestScene::Info{
- "fadingedges",
- "A mock ListView of scrolling text with faded edge. Doesn't re-bind/re-record views"
- "as they are recycled, so won't upload much content (either glyphs, or bitmaps).",
- TestScene::simpleCreateScene<ListOfFadedTextAnimation>
-});
+ "fadingedges",
+ "A mock ListView of scrolling text with faded edge. Doesn't re-bind/re-record views"
+ "as they are recycled, so won't upload much content (either glyphs, or bitmaps).",
+ TestScene::simpleCreateScene<ListOfFadedTextAnimation>});
class ListOfFadedTextAnimation : public TestListViewSceneBase {
- void createListItem(RenderProperties& props, Canvas& canvas, int id,
- int itemWidth, int itemHeight) override {
+ void createListItem(RenderProperties& props, Canvas& canvas, int id, int itemWidth,
+ int itemHeight) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
int length = dp(100);
canvas.saveLayer(0, 0, length, itemHeight, nullptr, SaveFlags::HasAlphaLayer);
@@ -44,8 +43,8 @@
pts[1].set(0, 1);
SkColor colors[2] = {Color::Black, Color::Transparent};
- sk_sp<SkShader> s(SkGradientShader::MakeLinear(pts, colors, NULL, 2,
- SkShader::kClamp_TileMode));
+ sk_sp<SkShader> s(
+ SkGradientShader::MakeLinear(pts, colors, NULL, 2, SkShader::kClamp_TileMode));
SkMatrix matrix;
matrix.setScale(1, length);
diff --git a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
index c1144be..d7ec288 100644
--- a/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ListViewAnimation.cpp
@@ -22,11 +22,11 @@
class ListViewAnimation;
static TestScene::Registrar _ListView(TestScene::Info{
- "listview",
- "A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are recycled, so"
- "won't upload much content (either glyphs, or bitmaps).",
- TestScene::simpleCreateScene<ListViewAnimation>
-});
+ "listview",
+ "A mock ListView of scrolling content. Doesn't re-bind/re-record views as they are "
+ "recycled, so"
+ "won't upload much content (either glyphs, or bitmaps).",
+ TestScene::simpleCreateScene<ListViewAnimation>});
class ListViewAnimation : public TestListViewSceneBase {
sk_sp<Bitmap> createRandomCharIcon(int cardHeight) {
@@ -42,15 +42,15 @@
paint.setColor(randomColor);
canvas.drawCircle(size / 2, size / 2, size / 2, paint);
- bool bgDark = SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor)
- < 128 * 3;
+ bool bgDark =
+ SkColorGetR(randomColor) + SkColorGetG(randomColor) + SkColorGetB(randomColor) <
+ 128 * 3;
paint.setColor(bgDark ? Color::White : Color::Grey_700);
paint.setTextAlign(SkPaint::kCenter_Align);
paint.setTextSize(size / 2);
char charToShow = 'A' + (rand() % 26);
- const SkPoint pos[] = {{
- SkIntToScalar(size / 2),
- /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
+ const SkPoint pos[] = {{SkIntToScalar(size / 2),
+ /*approximate centering*/ SkFloatToScalar(size * 0.7f)}};
canvas.drawPosText(&charToShow, 1, pos, paint);
return bitmap;
}
@@ -72,8 +72,8 @@
return bitmap;
}
- void createListItem(RenderProperties& props, Canvas& canvas, int cardId,
- int itemWidth, int itemHeight) override {
+ void createListItem(RenderProperties& props, Canvas& canvas, int cardId, int itemWidth,
+ int itemHeight) override {
static sk_sp<Bitmap> filledBox(createBoxBitmap(true));
static sk_sp<Bitmap> strokedBox(createBoxBitmap(false));
// TODO: switch to using round rect clipping, once merging correctly handles that
@@ -92,7 +92,7 @@
TestUtils::drawUtf8ToCanvas(&canvas, buf, textPaint, itemHeight, dp(25));
textPaint.setTextSize(dp(15));
TestUtils::drawUtf8ToCanvas(&canvas, "This is some more text on the card", textPaint,
- itemHeight, dp(45));
+ itemHeight, dp(45));
auto randomIcon = createRandomCharIcon(itemHeight);
canvas.drawBitmap(*randomIcon, dp(10), dp(10), nullptr);
diff --git a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
index 68051d6..a24cae0 100644
--- a/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OpPropAnimation.cpp
@@ -20,10 +20,8 @@
class OpPropAnimation;
static TestScene::Registrar _Shapes(TestScene::Info{
- "opprops",
- "A minimal demonstration of CanvasProperty drawing operations.",
- TestScene::simpleCreateScene<OpPropAnimation>
-});
+ "opprops", "A minimal demonstration of CanvasProperty drawing operations.",
+ TestScene::simpleCreateScene<OpPropAnimation>});
class OpPropAnimation : public TestScene {
public:
@@ -42,8 +40,9 @@
sp<RenderNode> content;
void createContent(int width, int height, Canvas& canvas) override {
- content = TestUtils::createNode(0, 0, width, height,
- [this, width, height](RenderProperties& props, Canvas& canvas) {
+ content = TestUtils::createNode(0, 0, width, height, [this, width, height](
+ RenderProperties& props,
+ Canvas& canvas) {
mPaint->value.setAntiAlias(true);
mPaint->value.setColor(Color::Blue_500);
@@ -54,9 +53,9 @@
mCircleY->value = height * 0.75;
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(),
- mRoundRectRight.get(), mRoundRectBottom.get(),
- mRoundRectRx.get(), mRoundRectRy.get(), mPaint.get());
+ canvas.drawRoundRect(mRoundRectLeft.get(), mRoundRectTop.get(), mRoundRectRight.get(),
+ mRoundRectBottom.get(), mRoundRectRx.get(), mRoundRectRy.get(),
+ mPaint.get());
canvas.drawCircle(mCircleX.get(), mCircleY.get(), mCircleRadius.get(), mPaint.get());
});
canvas.drawRenderNode(content.get());
diff --git a/libs/hwui/tests/common/scenes/OvalAnimation.cpp b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
index d6fd604..4ff868b 100644
--- a/libs/hwui/tests/common/scenes/OvalAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/OvalAnimation.cpp
@@ -19,19 +19,15 @@
class OvalAnimation;
-static TestScene::Registrar _Oval(TestScene::Info{
- "oval",
- "Draws 1 oval.",
- TestScene::simpleCreateScene<OvalAnimation>
-});
+static TestScene::Registrar _Oval(TestScene::Info{"oval", "Draws 1 oval.",
+ TestScene::simpleCreateScene<OvalAnimation>});
class OvalAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- card = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(Color::Black);
diff --git a/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp b/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
index bc04d81..fb1b000 100644
--- a/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/PartialDamageAnimation.cpp
@@ -19,22 +19,18 @@
class PartialDamageAnimation;
static TestScene::Registrar _PartialDamage(TestScene::Info{
- "partialdamage",
- "Tests the partial invalidation path. Draws a grid of rects and animates 1 "
- "of them, should be low CPU & GPU load if EGL_EXT_buffer_age or "
- "EGL_KHR_partial_update is supported by the device & are enabled in hwui.",
- TestScene::simpleCreateScene<PartialDamageAnimation>
-});
+ "partialdamage",
+ "Tests the partial invalidation path. Draws a grid of rects and animates 1 "
+ "of them, should be low CPU & GPU load if EGL_EXT_buffer_age or "
+ "EGL_KHR_partial_update is supported by the device & are enabled in hwui.",
+ TestScene::simpleCreateScene<PartialDamageAnimation>});
class PartialDamageAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
static SkColor COLORS[] = {
- 0xFFF44336,
- 0xFF9C27B0,
- 0xFF2196F3,
- 0xFF4CAF50,
+ 0xFFF44336, 0xFF9C27B0, 0xFF2196F3, 0xFF4CAF50,
};
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
@@ -42,11 +38,11 @@
for (int x = dp(16); x < (width - dp(116)); x += dp(116)) {
for (int y = dp(16); y < (height - dp(116)); y += dp(116)) {
SkColor color = COLORS[static_cast<int>((y / dp(116))) % 4];
- sp<RenderNode> card = TestUtils::createNode(x, y,
- x + dp(100), y + dp(100),
- [color](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(color, SkBlendMode::kSrcOver);
- });
+ sp<RenderNode> card =
+ TestUtils::createNode(x, y, x + dp(100), y + dp(100),
+ [color](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ });
canvas.drawRenderNode(card.get());
cards.push_back(card);
}
@@ -59,8 +55,7 @@
cards[0]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
TestUtils::recordNode(*cards[0], [curFrame](Canvas& canvas) {
- SkColor color = TestUtils::interpolateColor(
- curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0);
+ SkColor color = TestUtils::interpolateColor(curFrame / 150.0f, 0xFFF44336, 0xFFF8BBD0);
canvas.drawColor(color, SkBlendMode::kSrcOver);
});
}
diff --git a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
index bc6fc64..1d17a02 100644
--- a/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
+++ b/libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
@@ -19,10 +19,8 @@
class ReadbackFromHardware;
static TestScene::Registrar _SaveLayer(TestScene::Info{
- "readbackFromHBitmap",
- "Allocates hardware bitmap and readback data from it.",
- TestScene::simpleCreateScene<ReadbackFromHardware>
-});
+ "readbackFromHBitmap", "Allocates hardware bitmap and readback data from it.",
+ TestScene::simpleCreateScene<ReadbackFromHardware>});
class ReadbackFromHardware : public TestScene {
public:
@@ -41,7 +39,7 @@
}
void createContent(int width, int height, Canvas& canvas) override {
- canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
sk_sp<Bitmap> hardwareBitmap(createHardwareBitmap());
@@ -50,7 +48,7 @@
SkBitmap canvasBitmap;
sk_sp<Bitmap> heapBitmap(TestUtils::createBitmap(hardwareBitmap->width(),
- hardwareBitmap->height(), &canvasBitmap));
+ hardwareBitmap->height(), &canvasBitmap));
SkCanvas skCanvas(canvasBitmap);
skCanvas.drawBitmap(readback, 0, 0);
@@ -59,5 +57,5 @@
canvas.drawBitmap(*hardwareBitmap, 0, 500, nullptr);
}
- void doFrame(int frameNr) override { }
+ void doFrame(int frameNr) override {}
};
diff --git a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
index 8256024..3480a0f 100644
--- a/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RecentsAnimation.cpp
@@ -20,20 +20,16 @@
class RecentsAnimation;
static TestScene::Registrar _Recents(TestScene::Info{
- "recents",
- "A recents-like scrolling list of textures. "
- "Consists of updating a texture every frame",
- TestScene::simpleCreateScene<RecentsAnimation>
-});
+ "recents",
+ "A recents-like scrolling list of textures. "
+ "Consists of updating a texture every frame",
+ TestScene::simpleCreateScene<RecentsAnimation>});
class RecentsAnimation : public TestScene {
public:
void createContent(int width, int height, Canvas& renderer) override {
static SkColor COLORS[] = {
- Color::Red_500,
- Color::Purple_500,
- Color::Blue_500,
- Color::Green_500,
+ Color::Red_500, Color::Purple_500, Color::Blue_500, Color::Green_500,
};
thumbnailSize = std::min(std::min(width, height) / 2, 720);
@@ -65,25 +61,26 @@
mCards[ci]->mutateStagingProperties().setTranslationY(curFrame);
mCards[ci]->setPropertyFieldsDirty(RenderNode::Y);
}
- mThumbnail.eraseColor(TestUtils::interpolateColor(
- curFrame / 150.0f, Color::Green_500, Color::DeepOrange_500));
+ mThumbnail.eraseColor(TestUtils::interpolateColor(curFrame / 150.0f, Color::Green_500,
+ Color::DeepOrange_500));
}
private:
sp<RenderNode> createCard(int x, int y, int width, int height, Bitmap& thumb) {
- return TestUtils::createNode(x, y, x + width, y + height,
+ return TestUtils::createNode(
+ x, y, x + width, y + height,
[&thumb, width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(dp(16));
- props.mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
- props.mutableOutline().setShouldClip(true);
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1);
+ props.mutableOutline().setShouldClip(true);
- canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
- canvas.drawBitmap(thumb, 0, 0, thumb.width(), thumb.height(),
- 0, 0, width, height, nullptr);
- });
+ canvas.drawColor(Color::Grey_200, SkBlendMode::kSrcOver);
+ canvas.drawBitmap(thumb, 0, 0, thumb.width(), thumb.height(), 0, 0, width,
+ height, nullptr);
+ });
}
SkBitmap mThumbnail;
- std::vector< sp<RenderNode> > mCards;
+ std::vector<sp<RenderNode> > mCards;
int thumbnailSize;
};
diff --git a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
index 668eec6..6a3b6a5 100644
--- a/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RectGridAnimation.cpp
@@ -14,17 +14,15 @@
* limitations under the License.
*/
-
#include "TestSceneBase.h"
class RectGridAnimation;
static TestScene::Registrar _RectGrid(TestScene::Info{
- "rectgrid",
- "A dense grid of 1x1 rects that should visually look like a single rect. "
- "Low CPU/GPU load.",
- TestScene::simpleCreateScene<RectGridAnimation>
-});
+ "rectgrid",
+ "A dense grid of 1x1 rects that should visually look like a single rect. "
+ "Low CPU/GPU load.",
+ TestScene::simpleCreateScene<RectGridAnimation>});
class RectGridAnimation : public TestScene {
public:
@@ -33,13 +31,12 @@
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
- card = TestUtils::createNode(50, 50, 250, 250,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(50, 50, 250, 250, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(0xFFFF00FF, SkBlendMode::kSrcOver);
SkRegion region;
- for (int xOffset = 0; xOffset < 200; xOffset+=2) {
- for (int yOffset = 0; yOffset < 200; yOffset+=2) {
+ for (int xOffset = 0; xOffset < 200; xOffset += 2) {
+ for (int yOffset = 0; yOffset < 200; yOffset += 2) {
region.op(xOffset, yOffset, xOffset + 1, yOffset + 1, SkRegion::kUnion_Op);
}
}
diff --git a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
index 4b6632d..314e922 100644
--- a/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/RoundRectClippingAnimation.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#include "TestSceneBase.h"
#include <vector>
@@ -23,10 +22,9 @@
public:
int mSpacing, mSize;
- RoundRectClippingAnimation(int spacing, int size)
- : mSpacing(spacing), mSize(size) {}
+ RoundRectClippingAnimation(int spacing, int size) : mSpacing(spacing), mSize(size) {}
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
@@ -35,13 +33,13 @@
for (int x = 0; x < width; x += mSpacing) {
for (int y = 0; y < height; y += mSpacing) {
auto color = BrightColors[ci++ % BrightColorsCount];
- auto card = TestUtils::createNode(x, y, x + mSize, y + mSize,
- [&](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(color, SkBlendMode::kSrcOver);
- props.mutableOutline().setRoundRect(0, 0,
- props.getWidth(), props.getHeight(), mSize * .25, 1);
- props.mutableOutline().setShouldClip(true);
- });
+ auto card = TestUtils::createNode(
+ x, y, x + mSize, y + mSize, [&](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ props.mutableOutline().setRoundRect(0, 0, props.getWidth(),
+ props.getHeight(), mSize * .25, 1);
+ props.mutableOutline().setShouldClip(true);
+ });
canvas.drawRenderNode(card.get());
cards.push_back(card);
}
@@ -61,17 +59,15 @@
};
static TestScene::Registrar _RoundRectClippingGpu(TestScene::Info{
- "roundRectClipping-gpu",
- "A bunch of RenderNodes with round rect clipping outlines that's GPU limited.",
- [](const TestScene::Options&) -> test::TestScene* {
- return new RoundRectClippingAnimation(dp(40), dp(200));
- }
-});
+ "roundRectClipping-gpu",
+ "A bunch of RenderNodes with round rect clipping outlines that's GPU limited.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(40), dp(200));
+ }});
static TestScene::Registrar _RoundRectClippingCpu(TestScene::Info{
- "roundRectClipping-cpu",
- "A bunch of RenderNodes with round rect clipping outlines that's CPU limited.",
- [](const TestScene::Options&) -> test::TestScene* {
- return new RoundRectClippingAnimation(dp(20), dp(20));
- }
-});
+ "roundRectClipping-cpu",
+ "A bunch of RenderNodes with round rect clipping outlines that's CPU limited.",
+ [](const TestScene::Options&) -> test::TestScene* {
+ return new RoundRectClippingAnimation(dp(20), dp(20));
+ }});
diff --git a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
index d678af9..75b231d 100644
--- a/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayer2Animation.cpp
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-#include "TestSceneBase.h"
-#include <string>
#include <hwui/Paint.h>
#include <minikin/Layout.h>
+#include <string>
+#include "TestSceneBase.h"
class SaveLayer2Animation;
static TestScene::Registrar _SaveLayer(TestScene::Info{
- "savelayer2",
- "Interleaving 20 drawText/drawRect ops with saveLayer"
- "Tests the clipped saveLayer performance and FBO switching overhead.",
- TestScene::simpleCreateScene<SaveLayer2Animation>
-});
+ "savelayer2",
+ "Interleaving 20 drawText/drawRect ops with saveLayer"
+ "Tests the clipped saveLayer performance and FBO switching overhead.",
+ TestScene::simpleCreateScene<SaveLayer2Animation>});
class SaveLayer2Animation : public TestScene {
public:
@@ -37,7 +36,7 @@
canvas.drawColor(SkColorSetARGB(255, 255, 0, 0), SkBlendMode::kSrcOver);
SkIRect bounds = SkIRect::MakeWH(width, height);
int regions = 20;
- int smallRectHeight = (bounds.height()/regions);
+ int smallRectHeight = (bounds.height() / regions);
int padding = smallRectHeight / 4;
int top = bounds.fTop;
@@ -46,27 +45,26 @@
mGreenPaint.setColor(SkColorSetARGB(255, 0, 255, 0));
mGreenPaint.setTextSize(padding);
- //interleave drawText and drawRect with saveLayer ops
+ // interleave drawText and drawRect with saveLayer ops
for (int i = 0; i < regions; i++, top += smallRectHeight) {
- canvas.saveLayer(bounds.fLeft, top, bounds.fRight, top + padding,
- &mBluePaint, SaveFlags::ClipToLayer | SaveFlags::MatrixClip);
+ canvas.saveLayer(bounds.fLeft, top, bounds.fRight, top + padding, &mBluePaint,
+ SaveFlags::ClipToLayer | SaveFlags::MatrixClip);
canvas.drawColor(SkColorSetARGB(255, 255, 255, 0), SkBlendMode::kSrcOver);
std::string stri = std::to_string(i);
std::string offscreen = "offscreen line " + stri;
std::unique_ptr<uint16_t[]> offtext = TestUtils::asciiToUtf16(offscreen.c_str());
- canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(),
- bounds.fLeft, top + padding, minikin::Bidi::FORCE_LTR, mBluePaint, nullptr);
+ canvas.drawText(offtext.get(), 0, offscreen.length(), offscreen.length(), bounds.fLeft,
+ top + padding, minikin::Bidi::FORCE_LTR, mBluePaint, nullptr);
canvas.restore();
canvas.drawRect(bounds.fLeft, top + padding, bounds.fRight,
- top + smallRectHeight - padding, mBluePaint);
+ top + smallRectHeight - padding, mBluePaint);
std::string onscreen = "onscreen line " + stri;
std::unique_ptr<uint16_t[]> ontext = TestUtils::asciiToUtf16(onscreen.c_str());
canvas.drawText(ontext.get(), 0, onscreen.length(), onscreen.length(), bounds.fLeft,
- top + smallRectHeight - padding, minikin::Bidi::FORCE_LTR, mGreenPaint,
- nullptr);
+ top + smallRectHeight - padding, minikin::Bidi::FORCE_LTR, mGreenPaint,
+ nullptr);
}
}
- void doFrame(int frameNr) override {
- }
+ void doFrame(int frameNr) override {}
};
diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
index 7e8a7d9..02dd42f 100644
--- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp
@@ -19,20 +19,19 @@
class SaveLayerAnimation;
static TestScene::Registrar _SaveLayer(TestScene::Info{
- "savelayer",
- "A nested pair of clipped saveLayer operations. "
- "Tests the clipped saveLayer codepath. Draws content into offscreen buffers and back again.",
- TestScene::simpleCreateScene<SaveLayerAnimation>
-});
+ "savelayer",
+ "A nested pair of clipped saveLayer operations. "
+ "Tests the clipped saveLayer codepath. Draws content into offscreen buffers and back "
+ "again.",
+ TestScene::simpleCreateScene<SaveLayerAnimation>});
class SaveLayerAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
- card = TestUtils::createNode(0, 0, 400, 800,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, 400, 800, [](RenderProperties& props, Canvas& canvas) {
// nested clipped saveLayers
canvas.saveLayerAlpha(0, 0, 400, 400, 200, SaveFlags::ClipToLayer);
canvas.drawColor(Color::Green_700, SkBlendMode::kSrcOver);
@@ -45,7 +44,7 @@
// single unclipped saveLayer
canvas.save(SaveFlags::MatrixClip);
canvas.translate(0, 400);
- canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0)); // unclipped
+ canvas.saveLayerAlpha(100, 100, 300, 300, 128, SaveFlags::Flags(0)); // unclipped
SkPaint paint;
paint.setAntiAlias(true);
paint.setColor(Color::Green_700);
diff --git a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
index 0a69b62..bdc991b 100644
--- a/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGrid2Animation.cpp
@@ -19,15 +19,14 @@
class ShadowGrid2Animation;
static TestScene::Registrar _ShadowGrid2(TestScene::Info{
- "shadowgrid2",
- "A dense grid of rounded rects that cast a shadow. This is a higher CPU load "
- "variant of shadowgrid. Very high CPU load, high GPU load.",
- TestScene::simpleCreateScene<ShadowGrid2Animation>
-});
+ "shadowgrid2",
+ "A dense grid of rounded rects that cast a shadow. This is a higher CPU load "
+ "variant of shadowgrid. Very high CPU load, high GPU load.",
+ TestScene::simpleCreateScene<ShadowGrid2Animation>});
class ShadowGrid2Animation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
@@ -50,14 +49,16 @@
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
return TestUtils::createNode(x, y, x + width, y + height,
- [width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(dp(16));
- props.mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
- props.mutableOutline().setShouldClip(true);
- canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
- });
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, width, height,
+ dp(6), 1);
+ props.mutableOutline().setShouldClip(true);
+ canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
index 4a02429..a12fd4d 100644
--- a/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowGridAnimation.cpp
@@ -19,15 +19,14 @@
class ShadowGridAnimation;
static TestScene::Registrar _ShadowGrid(TestScene::Info{
- "shadowgrid",
- "A grid of rounded rects that cast a shadow. Simplified scenario of an "
- "Android TV-style launcher interface. High CPU/GPU load.",
- TestScene::simpleCreateScene<ShadowGridAnimation>
-});
+ "shadowgrid",
+ "A grid of rounded rects that cast a shadow. Simplified scenario of an "
+ "Android TV-style launcher interface. High CPU/GPU load.",
+ TestScene::simpleCreateScene<ShadowGridAnimation>});
class ShadowGridAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
@@ -50,14 +49,16 @@
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
return TestUtils::createNode(x, y, x + width, y + height,
- [width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(dp(16));
- props.mutableOutline().setRoundRect(0, 0, width, height, dp(6), 1);
- props.mutableOutline().setShouldClip(true);
- canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
- });
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(dp(16));
+ props.mutableOutline().setRoundRect(0, 0, width, height,
+ dp(6), 1);
+ props.mutableOutline().setShouldClip(true);
+ canvas.drawColor(0xFFEEEEEE, SkBlendMode::kSrcOver);
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
index fac3968..9f59910 100644
--- a/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShadowShaderAnimation.cpp
@@ -19,23 +19,22 @@
class ShadowShaderAnimation;
static TestScene::Registrar _ShadowShader(TestScene::Info{
- "shadowshader",
- "A set of overlapping shadowed areas with simple tessellation useful for"
- " benchmarking shadow shader performance.",
- TestScene::simpleCreateScene<ShadowShaderAnimation>
-});
+ "shadowshader",
+ "A set of overlapping shadowed areas with simple tessellation useful for"
+ " benchmarking shadow shader performance.",
+ TestScene::simpleCreateScene<ShadowShaderAnimation>});
class ShadowShaderAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
canvas.insertReorderBarrier(true);
int outset = 50;
for (int i = 0; i < 10; i++) {
- sp<RenderNode> card = createCard(outset, outset,
- width - (outset * 2), height - (outset * 2));
+ sp<RenderNode> card =
+ createCard(outset, outset, width - (outset * 2), height - (outset * 2));
canvas.drawRenderNode(card.get());
cards.push_back(card);
}
@@ -50,19 +49,24 @@
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
return TestUtils::createNode(x, y, x + width, y + height,
- [width, height](RenderProperties& props, Canvas& canvas) {
- props.setElevation(1000);
+ [width, height](RenderProperties& props, Canvas& canvas) {
+ props.setElevation(1000);
- // Set 0 radius, no clipping, so shadow is easy to compute. Slightly transparent outline
- // to signal contents aren't opaque (not necessary though, as elevation is so high, no
- // inner content to cut out)
- props.mutableOutline().setRoundRect(0, 0, width, height, 0, 0.99f);
- props.mutableOutline().setShouldClip(false);
+ // Set 0 radius, no clipping, so shadow is easy to compute.
+ // Slightly transparent outline
+ // to signal contents aren't opaque (not necessary though,
+ // as elevation is so high, no
+ // inner content to cut out)
+ props.mutableOutline().setRoundRect(0, 0, width, height, 0,
+ 0.99f);
+ props.mutableOutline().setShouldClip(false);
- // don't draw anything to card's canvas - we just want the shadow
- });
+ // don't draw anything to card's canvas - we just want the
+ // shadow
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
index 09e70eb..0d87776 100644
--- a/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/ShapeAnimation.cpp
@@ -21,79 +21,75 @@
class ShapeAnimation;
-static TestScene::Registrar _Shapes(TestScene::Info{
- "shapes",
- "A grid of shape drawing test cases.",
- TestScene::simpleCreateScene<ShapeAnimation>
-});
+static TestScene::Registrar _Shapes(TestScene::Info{"shapes", "A grid of shape drawing test cases.",
+ TestScene::simpleCreateScene<ShapeAnimation>});
class ShapeAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
- card = TestUtils::createNode(0, 0, width, height,
- [width](RenderProperties& props, Canvas& canvas) {
- std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
- [](Canvas& canvas, float size, const SkPaint& paint) {
- canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- canvas.drawOval(0, 0, size, size, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- SkPath diamondPath;
- diamondPath.moveTo(size / 2, 0);
- diamondPath.lineTo(size, size / 2);
- diamondPath.lineTo(size / 2, size);
- diamondPath.lineTo(0, size / 2);
- diamondPath.close();
- canvas.drawPath(diamondPath, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- float data[] = {0, 0, size, size, 0, size, size, 0 };
- canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- float data[] = {0, 0, size, size, 0, size, size, 0 };
- canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- canvas.drawRect(0, 0, size, size, paint);
- },
- [](Canvas& canvas, float size, const SkPaint& paint) {
- float rad = size / 4;
- canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
- }
- };
- float cellSpace = dp(4);
- float cellSize = floorf(width / 7 - cellSpace);
+ card = TestUtils::createNode(
+ 0, 0, width, height, [width](RenderProperties& props, Canvas& canvas) {
+ std::function<void(Canvas&, float, const SkPaint&)> ops[] = {
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ canvas.drawArc(0, 0, size, size, 50, 189, true, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ canvas.drawOval(0, 0, size, size, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ SkPath diamondPath;
+ diamondPath.moveTo(size / 2, 0);
+ diamondPath.lineTo(size, size / 2);
+ diamondPath.lineTo(size / 2, size);
+ diamondPath.lineTo(0, size / 2);
+ diamondPath.close();
+ canvas.drawPath(diamondPath, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ float data[] = {0, 0, size, size, 0, size, size, 0};
+ canvas.drawLines(data, sizeof(data) / sizeof(float), paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ float data[] = {0, 0, size, size, 0, size, size, 0};
+ canvas.drawPoints(data, sizeof(data) / sizeof(float), paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ canvas.drawRect(0, 0, size, size, paint);
+ },
+ [](Canvas& canvas, float size, const SkPaint& paint) {
+ float rad = size / 4;
+ canvas.drawRoundRect(0, 0, size, size, rad, rad, paint);
+ }};
+ float cellSpace = dp(4);
+ float cellSize = floorf(width / 7 - cellSpace);
- // each combination of strokeWidth + style gets a column
- int outerCount = canvas.save(SaveFlags::MatrixClip);
- SkPaint paint;
- paint.setAntiAlias(true);
- SkPaint::Style styles[] = {
- SkPaint::kStroke_Style, SkPaint::kFill_Style, SkPaint::kStrokeAndFill_Style };
- for (auto style : styles) {
- paint.setStyle(style);
- for (auto strokeWidth : { 0.0f, 0.5f, 8.0f }) {
- paint.setStrokeWidth(strokeWidth);
- // fill column with each op
- int middleCount = canvas.save(SaveFlags::MatrixClip);
- for (auto op : ops) {
- int innerCount = canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
- canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- op(canvas, cellSize, paint);
- canvas.restoreToCount(innerCount);
- canvas.translate(cellSize + cellSpace, 0);
+ // each combination of strokeWidth + style gets a column
+ int outerCount = canvas.save(SaveFlags::MatrixClip);
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ SkPaint::Style styles[] = {SkPaint::kStroke_Style, SkPaint::kFill_Style,
+ SkPaint::kStrokeAndFill_Style};
+ for (auto style : styles) {
+ paint.setStyle(style);
+ for (auto strokeWidth : {0.0f, 0.5f, 8.0f}) {
+ paint.setStrokeWidth(strokeWidth);
+ // fill column with each op
+ int middleCount = canvas.save(SaveFlags::MatrixClip);
+ for (auto op : ops) {
+ int innerCount = canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(0, 0, cellSize, cellSize, SkClipOp::kIntersect);
+ canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
+ op(canvas, cellSize, paint);
+ canvas.restoreToCount(innerCount);
+ canvas.translate(cellSize + cellSpace, 0);
+ }
+ canvas.restoreToCount(middleCount);
+ canvas.translate(0, cellSize + cellSpace);
+ }
}
- canvas.restoreToCount(middleCount);
- canvas.translate(0, cellSize + cellSpace);
- }
- }
- canvas.restoreToCount(outerCount);
- });
+ canvas.restoreToCount(outerCount);
+ });
canvas.drawColor(Color::Grey_500, SkBlendMode::kSrcOver);
canvas.drawRenderNode(card.get());
}
diff --git a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
index a63a585..ff0cb370 100644
--- a/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleColorMatrixAnimation.cpp
@@ -22,15 +22,15 @@
class SimpleColorMatrixAnimation;
static TestScene::Registrar _SimpleColorMatrix(TestScene::Info{
- "simpleColorMatrix",
- "A color matrix shader benchmark for the simple scale/translate case, which has R, G, and B "
- "all scaled and translated the same amount.",
- TestScene::simpleCreateScene<SimpleColorMatrixAnimation>
-});
+ "simpleColorMatrix",
+ "A color matrix shader benchmark for the simple scale/translate case, which has R, G, and "
+ "B "
+ "all scaled and translated the same amount.",
+ TestScene::simpleCreateScene<SimpleColorMatrixAnimation>});
class SimpleColorMatrixAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
@@ -46,38 +46,41 @@
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
- return TestUtils::createNode(x, y, x + width, y + height,
+ return TestUtils::createNode(
+ x, y, x + width, y + height,
[width, height](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
- float matrix[20] = { 0 };
+ SkPaint paint;
+ float matrix[20] = {0};
- // Simple scale/translate case where R, G, and B are all treated equivalently
- matrix[SkColorMatrix::kR_Scale] = 1.1f;
- matrix[SkColorMatrix::kG_Scale] = 1.1f;
- matrix[SkColorMatrix::kB_Scale] = 1.1f;
- matrix[SkColorMatrix::kA_Scale] = 0.5f;
+ // Simple scale/translate case where R, G, and B are all treated equivalently
+ matrix[SkColorMatrix::kR_Scale] = 1.1f;
+ matrix[SkColorMatrix::kG_Scale] = 1.1f;
+ matrix[SkColorMatrix::kB_Scale] = 1.1f;
+ matrix[SkColorMatrix::kA_Scale] = 0.5f;
- matrix[SkColorMatrix::kR_Trans] = 5.0f;
- matrix[SkColorMatrix::kG_Trans] = 5.0f;
- matrix[SkColorMatrix::kB_Trans] = 5.0f;
- matrix[SkColorMatrix::kA_Trans] = 10.0f;
+ matrix[SkColorMatrix::kR_Trans] = 5.0f;
+ matrix[SkColorMatrix::kG_Trans] = 5.0f;
+ matrix[SkColorMatrix::kB_Trans] = 5.0f;
+ matrix[SkColorMatrix::kA_Trans] = 10.0f;
- paint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
+ paint.setColorFilter(SkColorFilter::MakeMatrixFilterRowMajor255(matrix));
- // set a shader so it's not likely for the matrix to be optimized away (since a clever
- // enough renderer might apply it directly to the paint color)
- float pos[] = { 0, 1 };
- SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
- SkColor colors[2] = { Color::DeepPurple_500, Color::DeepOrange_500 };
- paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
- SkShader::kClamp_TileMode));
+ // set a shader so it's not likely for the matrix to be optimized away (since a
+ // clever
+ // enough renderer might apply it directly to the paint color)
+ float pos[] = {0, 1};
+ SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
+ SkColor colors[2] = {Color::DeepPurple_500, Color::DeepOrange_500};
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors, pos, 2,
+ SkShader::kClamp_TileMode));
- // overdraw several times to emphasize shader cost
- for (int i = 0; i < 10; i++) {
- canvas.drawRect(i, i, width, height, paint);
- }
- });
+ // overdraw several times to emphasize shader cost
+ for (int i = 0; i < 10; i++) {
+ canvas.drawRect(i, i, width, height, paint);
+ }
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
index 053eb6d..016c65c 100644
--- a/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/SimpleGradientAnimation.cpp
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
#include "TestSceneBase.h"
#include <SkGradientShader.h>
@@ -22,14 +21,13 @@
class SimpleGradientAnimation;
static TestScene::Registrar _SimpleGradient(TestScene::Info{
- "simpleGradient",
- "A benchmark of shader performance of linear, 2 color gradients with black in them.",
- TestScene::simpleCreateScene<SimpleGradientAnimation>
-});
+ "simpleGradient",
+ "A benchmark of shader performance of linear, 2 color gradients with black in them.",
+ TestScene::simpleCreateScene<SimpleGradientAnimation>});
class SimpleGradientAnimation : public TestScene {
public:
- std::vector< sp<RenderNode> > cards;
+ std::vector<sp<RenderNode> > cards;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
@@ -45,21 +43,23 @@
cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
}
}
+
private:
sp<RenderNode> createCard(int x, int y, int width, int height) {
- return TestUtils::createNode(x, y, x + width, y + height,
+ return TestUtils::createNode(
+ x, y, x + width, y + height,
[width, height](RenderProperties& props, Canvas& canvas) {
- float pos[] = { 0, 1 };
- SkPoint pts[] = { SkPoint::Make(0, 0), SkPoint::Make(width, height) };
- SkPaint paint;
- // overdraw several times to emphasize shader cost
- for (int i = 0; i < 10; i++) {
- // use i%2 start position to pick 2 color combo with black in it
- SkColor colors[3] = { Color::Transparent, Color::Black, Color::Cyan_500 };
- paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
- SkShader::kClamp_TileMode));
- canvas.drawRect(i, i, width, height, paint);
- }
- });
+ float pos[] = {0, 1};
+ SkPoint pts[] = {SkPoint::Make(0, 0), SkPoint::Make(width, height)};
+ SkPaint paint;
+ // overdraw several times to emphasize shader cost
+ for (int i = 0; i < 10; i++) {
+ // use i%2 start position to pick 2 color combo with black in it
+ SkColor colors[3] = {Color::Transparent, Color::Black, Color::Cyan_500};
+ paint.setShader(SkGradientShader::MakeLinear(pts, colors + (i % 2), pos, 2,
+ SkShader::kClamp_TileMode));
+ canvas.drawRect(i, i, width, height, paint);
+ }
+ });
}
};
diff --git a/libs/hwui/tests/common/scenes/TextAnimation.cpp b/libs/hwui/tests/common/scenes/TextAnimation.cpp
index 438f877..b9ce24b 100644
--- a/libs/hwui/tests/common/scenes/TextAnimation.cpp
+++ b/libs/hwui/tests/common/scenes/TextAnimation.cpp
@@ -19,19 +19,16 @@
class TextAnimation;
-static TestScene::Registrar _Text(TestScene::Info{
- "text",
- "Draws a bunch of text.",
- TestScene::simpleCreateScene<TextAnimation>
-});
+static TestScene::Registrar _Text(TestScene::Info{"text", "Draws a bunch of text.",
+ TestScene::simpleCreateScene<TextAnimation>});
class TextAnimation : public TestScene {
public:
sp<RenderNode> card;
void createContent(int width, int height, Canvas& canvas) override {
canvas.drawColor(Color::White, SkBlendMode::kSrcOver);
- card = TestUtils::createNode(0, 0, width, height,
- [](RenderProperties& props, Canvas& canvas) {
+ card = TestUtils::createNode(0, 0, width, height, [](RenderProperties& props,
+ Canvas& canvas) {
SkPaint paint;
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
index 04fc2d4..c845e6c 100644
--- a/libs/hwui/tests/common/scenes/TvApp.cpp
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -14,40 +14,42 @@
* limitations under the License.
*/
+#include "SkBlendMode.h"
#include "TestSceneBase.h"
#include "tests/common/BitmapAllocationTestUtils.h"
-#include "SkBlendMode.h"
class TvApp;
class TvAppNoRoundedCorner;
class TvAppColorFilter;
class TvAppNoRoundedCornerColorFilter;
-static bool _TvApp(
- BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
- "tvapp", "A dense grid of cards:"
- "with rounded corner, using overlay RenderNode for dimming."));
+static bool _TvApp(BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
+ "tvapp",
+ "A dense grid of cards:"
+ "with rounded corner, using overlay RenderNode for dimming."));
static bool _TvAppNoRoundedCorner(
BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCorner>(
- "tvapp_norc", "A dense grid of cards:"
+ "tvapp_norc",
+ "A dense grid of cards:"
"no rounded corner, using overlay RenderNode for dimming"));
static bool _TvAppColorFilter(
BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppColorFilter>(
- "tvapp_cf", "A dense grid of cards:"
+ "tvapp_cf",
+ "A dense grid of cards:"
"with rounded corner, using ColorFilter for dimming"));
static bool _TvAppNoRoundedCornerColorFilter(
BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCornerColorFilter>(
- "tvapp_norc_cf", "A dense grid of cards:"
+ "tvapp_norc_cf",
+ "A dense grid of cards:"
"no rounded corner, using ColorFilter for dimming"));
class TvApp : public TestScene {
public:
TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TestScene()
- , mAllocator(allocator) { }
+ : TestScene(), mAllocator(allocator) {}
sp<RenderNode> mBg;
std::vector<sp<RenderNode>> mCards;
@@ -66,9 +68,7 @@
canvas.insertReorderBarrier(true);
mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
- [](SkBitmap& skBitmap) {
- skBitmap.eraseColor(0xFF0000FF);
- });
+ [](SkBitmap& skBitmap) { skBitmap.eraseColor(0xFF0000FF); });
for (int y = dp(18) - dp(178); y < height - dp(18); y += dp(178)) {
bool isFirstCard = true;
@@ -90,69 +90,64 @@
}
private:
- sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top,
- int width, int height) {
- return TestUtils::createNode(left, top, left + width , top + height,
+ sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top, int width,
+ int height) {
+ return TestUtils::createNode(
+ left, top, left + width, top + height,
[this, width, height, color](RenderProperties& props, Canvas& canvas) {
- sk_sp<Bitmap> bitmap = mAllocator(width, height, kRGBA_8888_SkColorType,
- [color](SkBitmap& skBitmap) {
- skBitmap.eraseColor(color);
- });
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ sk_sp<Bitmap> bitmap =
+ mAllocator(width, height, kRGBA_8888_SkColorType,
+ [color](SkBitmap& skBitmap) { skBitmap.eraseColor(color); });
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
}
- sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top,
- int width, int height, sk_sp<Bitmap>bitmap) {
- return TestUtils::createNode(left, top, left + width , top + height,
- [bitmap](RenderProperties& props, Canvas& canvas) {
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top, int width, int height,
+ sk_sp<Bitmap> bitmap) {
+ return TestUtils::createNode(left, top, left + width, top + height,
+ [bitmap](RenderProperties& props, Canvas& canvas) {
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
}
- sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top,
- int width, int height, const char* text, const char* text2) {
- return TestUtils::createNode(left, top, left + width , top + height,
- [text, text2](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
+ sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top, int width, int height,
+ const char* text, const char* text2) {
+ return TestUtils::createNode(left, top, left + width, top + height,
+ [text, text2](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setTextSize(24);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(24);
- paint.setColor(Color::Black);
- TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
- paint.setTextSize(20);
- TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
+ paint.setColor(Color::Black);
+ TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
+ paint.setTextSize(20);
+ TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
- });
+ });
}
- sp<RenderNode> createColorNode(Canvas& canvas, int left, int top,
- int width, int height, SkColor color) {
- return TestUtils::createNode(left, top, left + width , top + height,
- [color](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(color, SkBlendMode::kSrcOver);
- });
+ sp<RenderNode> createColorNode(Canvas& canvas, int left, int top, int width, int height,
+ SkColor color) {
+ return TestUtils::createNode(left, top, left + width, top + height,
+ [color](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(color, SkBlendMode::kSrcOver);
+ });
}
- virtual bool useSingleBitmap() {
- return false;
- }
+ virtual bool useSingleBitmap() { return false; }
- virtual float roundedCornerRadius() {
- return dp(2);
- }
+ virtual float roundedCornerRadius() { return dp(2); }
// when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image
- virtual bool useOverlay() {
- return true;
- }
+ virtual bool useOverlay() { return true; }
sp<RenderNode> createCard(int x, int y, int width, int height, bool selected) {
- return TestUtils::createNode(x, y, x + width, y + height,
- [width, height, selected, this](RenderProperties& props, Canvas& canvas) {
+ return TestUtils::createNode(x, y, x + width, y + height, [width, height, selected, this](
+ RenderProperties& props,
+ Canvas& canvas) {
if (selected) {
props.setElevation(dp(16));
props.setScaleX(1.2);
@@ -161,12 +156,14 @@
props.mutableOutline().setRoundRect(0, 0, width, height, roundedCornerRadius(), 1);
props.mutableOutline().setShouldClip(true);
- sk_sp<Bitmap> bitmap = useSingleBitmap() ? mSingleBitmap
- : mAllocator(width, dp(120), kRGBA_8888_SkColorType, [this](SkBitmap& skBitmap) {
- skBitmap.eraseColor(0xFF000000 | ((mSeed << 3) & 0xFF));
- });
- sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120),
- bitmap);
+ sk_sp<Bitmap> bitmap =
+ useSingleBitmap() ? mSingleBitmap
+ : mAllocator(width, dp(120), kRGBA_8888_SkColorType,
+ [this](SkBitmap& skBitmap) {
+ skBitmap.eraseColor(0xFF000000 |
+ ((mSeed << 3) & 0xFF));
+ });
+ sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120), bitmap);
canvas.drawRenderNode(cardImage.get());
mCachedBitmaps.push_back(bitmap);
mImages.push_back(cardImage);
@@ -176,12 +173,14 @@
mSeed++;
char buffer2[128];
sprintf(buffer2, "Studio %d", mSeed2++);
- sp<RenderNode> infoArea = createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
+ sp<RenderNode> infoArea =
+ createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
canvas.drawRenderNode(infoArea.get());
mInfoAreas.push_back(infoArea);
if (useOverlay()) {
- sp<RenderNode> overlayColor = createColorNode(canvas, 0, 0, width, height, 0x00000000);
+ sp<RenderNode> overlayColor =
+ createColorNode(canvas, 0, 0, width, height, 0x00000000);
canvas.drawRenderNode(overlayColor.get());
mOverlays.push_back(overlayColor);
}
@@ -196,30 +195,28 @@
// re-recording card's canvas, not necessary but to add some burden to CPU
std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
- card->stagingProperties().getWidth(),
- card->stagingProperties().getHeight()));
+ card->stagingProperties().getWidth(), card->stagingProperties().getHeight()));
sp<RenderNode> image = mImages[ci];
sp<RenderNode> infoArea = mInfoAreas[ci];
cardcanvas->drawRenderNode(infoArea.get());
if (useOverlay()) {
- cardcanvas->drawRenderNode(image.get());
+ cardcanvas->drawRenderNode(image.get());
// re-recording card overlay's canvas, animating overlay color alpha
sp<RenderNode> overlay = mOverlays[ci];
- std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- overlay->stagingProperties().getWidth(),
- overlay->stagingProperties().getHeight()));
+ std::unique_ptr<Canvas> canvas(
+ Canvas::create_recording_canvas(overlay->stagingProperties().getWidth(),
+ overlay->stagingProperties().getHeight()));
canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
overlay->setStagingDisplayList(canvas->finishRecording());
cardcanvas->drawRenderNode(overlay.get());
} else {
// re-recording image node's canvas, animating ColorFilter
std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
- image->stagingProperties().getWidth(),
- image->stagingProperties().getHeight()));
+ image->stagingProperties().getWidth(), image->stagingProperties().getHeight()));
SkPaint paint;
- sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter((curFrame % 150) << 24,
- SkBlendMode::kSrcATop));
+ sk_sp<SkColorFilter> filter(
+ SkColorFilter::MakeModeFilter((curFrame % 150) << 24, SkBlendMode::kSrcATop));
paint.setColorFilter(filter);
sk_sp<Bitmap> bitmap = mCachedBitmaps[ci];
canvas->drawBitmap(*bitmap, 0, 0, &paint);
@@ -233,42 +230,27 @@
class TvAppNoRoundedCorner : public TvApp {
public:
- TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TvApp(allocator) { }
+ TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
-
- virtual float roundedCornerRadius() override {
- return dp(0);
- }
+ virtual float roundedCornerRadius() override { return dp(0); }
};
class TvAppColorFilter : public TvApp {
public:
- TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TvApp(allocator) { }
+ TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator) : TvApp(allocator) {}
private:
-
- virtual bool useOverlay() override {
- return false;
- }
+ virtual bool useOverlay() override { return false; }
};
class TvAppNoRoundedCornerColorFilter : public TvApp {
public:
TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
- : TvApp(allocator) { }
+ : TvApp(allocator) {}
private:
+ virtual float roundedCornerRadius() override { return dp(0); }
- virtual float roundedCornerRadius() override {
- return dp(0);
- }
-
- virtual bool useOverlay() override {
- return false;
- }
+ virtual bool useOverlay() override { return false; }
};
-
-
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index f8d6397..3eb58a9 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -16,11 +16,11 @@
#include "AnimationContext.h"
#include "RenderNode.h"
+#include "renderthread/RenderProxy.h"
+#include "renderthread/RenderTask.h"
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/scenes/TestSceneBase.h"
-#include "renderthread/RenderProxy.h"
-#include "renderthread/RenderTask.h"
#include <benchmark/benchmark.h>
#include <gui/Surface.h>
@@ -39,7 +39,7 @@
}
};
-template<class T>
+template <class T>
class ModifiedMovingAverage {
public:
explicit ModifiedMovingAverage(int weight) : mWeight(weight) {}
@@ -53,9 +53,7 @@
return mAverage;
}
- T average() {
- return mAverage;
- }
+ T average() { return mAverage; }
private:
bool mHasValue = false;
@@ -64,8 +62,8 @@
};
void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts,
- benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
- double durationInS) {
+ benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
+ double durationInS) {
using namespace benchmark;
struct ReportInfo {
@@ -74,10 +72,8 @@
};
static std::array<ReportInfo, 4> REPORTS = {
- ReportInfo { 50, "_50th" },
- ReportInfo { 90, "_90th" },
- ReportInfo { 95, "_95th" },
- ReportInfo { 99, "_99th" },
+ ReportInfo{50, "_50th"}, ReportInfo{90, "_90th"}, ReportInfo{95, "_95th"},
+ ReportInfo{99, "_99th"},
};
// Although a vector is used, it must stay with only a single element
@@ -111,7 +107,7 @@
}
void run(const TestScene::Info& info, const TestScene::Options& opts,
- benchmark::BenchmarkReporter* reporter) {
+ benchmark::BenchmarkReporter* reporter) {
// Switch to the real display
gDisplay = getBuiltInDisplay();
@@ -126,15 +122,14 @@
const int height = gDisplay.h;
sp<Surface> surface = testContext.surface();
- sp<RenderNode> rootNode = TestUtils::createNode(0, 0, width, height,
- [&scene, width, height](RenderProperties& props, Canvas& canvas) {
- props.setClipToBounds(false);
- scene->createContent(width, height, canvas);
- });
+ sp<RenderNode> rootNode = TestUtils::createNode(
+ 0, 0, width, height, [&scene, width, height](RenderProperties& props, Canvas& canvas) {
+ props.setClipToBounds(false);
+ scene->createContent(width, height, canvas);
+ });
ContextFactory factory;
- std::unique_ptr<RenderProxy> proxy(new RenderProxy(false,
- rootNode.get(), &factory));
+ std::unique_ptr<RenderProxy> proxy(new RenderProxy(false, rootNode.get(), &factory));
proxy->loadSystemProperties();
proxy->initialize(surface);
float lightX = width / 2.0;
@@ -182,8 +177,7 @@
nsecs_t end = systemTime(CLOCK_MONOTONIC);
if (reporter) {
- outputBenchmarkReport(info, opts, reporter, proxy.get(),
- (end - start) / (double) s2ns(1));
+ outputBenchmarkReport(info, opts, reporter, proxy.get(), (end - start) / (double)s2ns(1));
} else {
proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats);
}
diff --git a/libs/hwui/tests/macrobench/main.cpp b/libs/hwui/tests/macrobench/main.cpp
index 1f56222..f1ff939 100644
--- a/libs/hwui/tests/macrobench/main.cpp
+++ b/libs/hwui/tests/macrobench/main.cpp
@@ -17,24 +17,24 @@
#include "tests/common/LeakChecker.h"
#include "tests/common/TestScene.h"
+#include "Properties.h"
#include "hwui/Typeface.h"
#include "protos/hwui.pb.h"
-#include "Properties.h"
-#include <benchmark/benchmark.h>
#include <../src/sysinfo.h>
+#include <benchmark/benchmark.h>
#include <getopt.h>
+#include <pthread.h>
#include <stdio.h>
-#include <string>
#include <unistd.h>
+#include <string>
#include <unordered_map>
#include <vector>
-#include <pthread.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
using namespace android;
using namespace android::uirenderer;
@@ -46,7 +46,7 @@
std::unique_ptr<benchmark::BenchmarkReporter> gBenchmarkReporter;
void run(const TestScene::Info& info, const TestScene::Options& opts,
- benchmark::BenchmarkReporter* reporter);
+ benchmark::BenchmarkReporter* reporter);
static void printHelp() {
printf(R"(
@@ -82,7 +82,7 @@
do {
int toPrint = dlen;
if (toPrint > 50) {
- char* found = (char*) memrchr(col2, ' ', 50);
+ char* found = (char*)memrchr(col2, ' ', 50);
if (found) {
toPrint = found - col2;
} else {
@@ -94,7 +94,8 @@
col2 += toPrint;
dlen -= toPrint;
while (*col2 == ' ') {
- col2++; dlen--;
+ col2++;
+ dlen--;
}
} while (dlen > 0);
printf("\n");
@@ -120,7 +121,7 @@
}
pid_t pid = getpid();
- int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long) pid);
+ int towrite = snprintf(buffer, BUF_SIZE, "%ld", (long)pid);
if (towrite >= BUF_SIZE) {
fprintf(stderr, "Buffer wasn't large enough?\n");
} else {
@@ -161,18 +162,17 @@
}
static const struct option LONG_OPTIONS[] = {
- { "frames", required_argument, nullptr, 'f' },
- { "repeat", required_argument, nullptr, 'r' },
- { "help", no_argument, nullptr, 'h' },
- { "list", no_argument, nullptr, LongOpts::List },
- { "wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu },
- { "report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime },
- { "cpuset", required_argument, nullptr, LongOpts::CpuSet },
- { "benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat },
- { "onscreen", no_argument, nullptr, LongOpts::Onscreen },
- { "offscreen", no_argument, nullptr, LongOpts::Offscreen },
- { 0, 0, 0, 0 }
-};
+ {"frames", required_argument, nullptr, 'f'},
+ {"repeat", required_argument, nullptr, 'r'},
+ {"help", no_argument, nullptr, 'h'},
+ {"list", no_argument, nullptr, LongOpts::List},
+ {"wait-for-gpu", no_argument, nullptr, LongOpts::WaitForGpu},
+ {"report-frametime", optional_argument, nullptr, LongOpts::ReportFrametime},
+ {"cpuset", required_argument, nullptr, LongOpts::CpuSet},
+ {"benchmark_format", required_argument, nullptr, LongOpts::BenchmarkFormat},
+ {"onscreen", no_argument, nullptr, LongOpts::Onscreen},
+ {"offscreen", no_argument, nullptr, LongOpts::Offscreen},
+ {0, 0, 0, 0}};
static const char* SHORT_OPTIONS = "c:r:h";
@@ -182,97 +182,95 @@
opterr = 0;
while (true) {
-
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long(argc, argv, SHORT_OPTIONS, LONG_OPTIONS, &option_index);
- if (c == -1)
- break;
+ if (c == -1) break;
switch (c) {
- case 0:
- // Option set a flag, don't need to do anything
- // (although none of the current LONG_OPTIONS do this...)
- break;
+ case 0:
+ // Option set a flag, don't need to do anything
+ // (although none of the current LONG_OPTIONS do this...)
+ break;
- case LongOpts::List:
- listTests();
- exit(EXIT_SUCCESS);
- break;
+ case LongOpts::List:
+ listTests();
+ exit(EXIT_SUCCESS);
+ break;
- case 'c':
- gOpts.count = atoi(optarg);
- if (!gOpts.count) {
- fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
- error = true;
- }
- break;
-
- case 'r':
- gRepeatCount = atoi(optarg);
- if (!gRepeatCount) {
- fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
- error = true;
- } else {
- gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
- }
- break;
-
- case LongOpts::ReportFrametime:
- if (optarg) {
- gOpts.reportFrametimeWeight = atoi(optarg);
- if (!gOpts.reportFrametimeWeight) {
- fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+ case 'c':
+ gOpts.count = atoi(optarg);
+ if (!gOpts.count) {
+ fprintf(stderr, "Invalid frames argument '%s'\n", optarg);
error = true;
}
- } else {
- gOpts.reportFrametimeWeight = 10;
- }
- break;
-
- case LongOpts::WaitForGpu:
- Properties::waitForGpuCompletion = true;
- break;
-
- case LongOpts::CpuSet:
- if (!optarg) {
- error = true;
break;
- }
- moveToCpuSet(optarg);
- break;
- case LongOpts::BenchmarkFormat:
- if (!optarg) {
- error = true;
+ case 'r':
+ gRepeatCount = atoi(optarg);
+ if (!gRepeatCount) {
+ fprintf(stderr, "Invalid repeat argument '%s'\n", optarg);
+ error = true;
+ } else {
+ gRepeatCount = (gRepeatCount > 0 ? gRepeatCount : INT_MAX);
+ }
break;
- }
- if (!setBenchmarkFormat(optarg)) {
- error = true;
- }
- break;
- case LongOpts::Onscreen:
- gOpts.renderOffscreen = false;
- break;
+ case LongOpts::ReportFrametime:
+ if (optarg) {
+ gOpts.reportFrametimeWeight = atoi(optarg);
+ if (!gOpts.reportFrametimeWeight) {
+ fprintf(stderr, "Invalid report frametime weight '%s'\n", optarg);
+ error = true;
+ }
+ } else {
+ gOpts.reportFrametimeWeight = 10;
+ }
+ break;
- case LongOpts::Offscreen:
- gOpts.renderOffscreen = true;
- break;
+ case LongOpts::WaitForGpu:
+ Properties::waitForGpuCompletion = true;
+ break;
- case 'h':
- printHelp();
- exit(EXIT_SUCCESS);
- break;
+ case LongOpts::CpuSet:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ moveToCpuSet(optarg);
+ break;
- case '?':
- fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
+ case LongOpts::BenchmarkFormat:
+ if (!optarg) {
+ error = true;
+ break;
+ }
+ if (!setBenchmarkFormat(optarg)) {
+ error = true;
+ }
+ break;
+
+ case LongOpts::Onscreen:
+ gOpts.renderOffscreen = false;
+ break;
+
+ case LongOpts::Offscreen:
+ gOpts.renderOffscreen = true;
+ break;
+
+ case 'h':
+ printHelp();
+ exit(EXIT_SUCCESS);
+ break;
+
+ case '?':
+ fprintf(stderr, "Unrecognized option '%s'\n", argv[optind - 1]);
// fall-through
- default:
- error = true;
- break;
+ default:
+ error = true;
+ break;
}
}
diff --git a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
index 3089447..0aaf773 100644
--- a/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
+++ b/libs/hwui/tests/microbench/DisplayListCanvasBench.cpp
@@ -114,7 +114,7 @@
}
BENCHMARK(BM_DisplayListCanvas_record_simpleBitmapView);
-class NullClient: public CanvasStateClient {
+class NullClient : public CanvasStateClient {
void onViewportInitialized() override {}
void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
GLuint getTargetFbo() const override { return 0; }
@@ -161,8 +161,7 @@
BENCHMARK(BM_CanvasState_translate);
void BM_DisplayListCanvas_basicViewGroupDraw(benchmark::State& benchState) {
- sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100,
- [](auto& props, auto& canvas) {
+ sp<RenderNode> child = TestUtils::createNode(50, 50, 100, 100, [](auto& props, auto& canvas) {
canvas.drawColor(0xFFFFFFFF, SkBlendMode::kSrcOver);
});
@@ -171,7 +170,7 @@
while (benchState.KeepRunning()) {
canvas->resetRecording(200, 200);
- canvas->translate(0, 0); // mScrollX, mScrollY
+ canvas->translate(0, 0); // mScrollX, mScrollY
// Clip to padding
// Can expect ~25% of views to have clip to padding with a non-null padding
diff --git a/libs/hwui/tests/microbench/FontBench.cpp b/libs/hwui/tests/microbench/FontBench.cpp
index df3d041..4e9b540 100644
--- a/libs/hwui/tests/microbench/FontBench.cpp
+++ b/libs/hwui/tests/microbench/FontBench.cpp
@@ -37,8 +37,8 @@
std::vector<float> positions;
float totalAdvance;
uirenderer::Rect bounds;
- TestUtils::layoutTextUnscaled(paint, "This is a test",
- &glyphs, &positions, &totalAdvance, &bounds);
+ TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance,
+ &bounds);
fontRenderer.precache(&paint, glyphs.data(), glyphs.size(), SkMatrix::I());
diff --git a/libs/hwui/tests/microbench/FrameBuilderBench.cpp b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
index a5e85df..b621766 100644
--- a/libs/hwui/tests/microbench/FrameBuilderBench.cpp
+++ b/libs/hwui/tests/microbench/FrameBuilderBench.cpp
@@ -16,17 +16,17 @@
#include <benchmark/benchmark.h>
-#include "BakedOpState.h"
#include "BakedOpDispatcher.h"
#include "BakedOpRenderer.h"
+#include "BakedOpState.h"
#include "FrameBuilder.h"
#include "LayerUpdateQueue.h"
#include "RecordedOp.h"
#include "RecordingCanvas.h"
+#include "Vector.h"
#include "tests/common/TestContext.h"
#include "tests/common/TestScene.h"
#include "tests/common/TestUtils.h"
-#include "Vector.h"
#include <vector>
@@ -35,25 +35,25 @@
using namespace android::uirenderer::renderthread;
using namespace android::uirenderer::test;
-const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
-const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50};
+const BakedOpRenderer::LightInfo sLightInfo = {128, 128};
static sp<RenderNode> createTestNode() {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10));
- SkPaint paint;
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10));
+ SkPaint paint;
- // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
- // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
- canvas.save(SaveFlags::MatrixClip);
- for (int i = 0; i < 30; i++) {
- canvas.translate(0, 10);
- canvas.drawRect(0, 0, 10, 10, paint);
- canvas.drawBitmap(*bitmap, 5, 0, nullptr);
- }
- canvas.restore();
- });
+ // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+ // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+ canvas.save(SaveFlags::MatrixClip);
+ for (int i = 0; i < 30; i++) {
+ canvas.translate(0, 10);
+ canvas.drawRect(0, 0, 10, 10, paint);
+ canvas.drawBitmap(*bitmap, 5, 0, nullptr);
+ }
+ canvas.restore();
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
return node;
}
@@ -62,8 +62,8 @@
TestUtils::runOnRenderThread([&state](RenderThread& thread) {
auto node = createTestNode();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*node);
benchmark::DoNotOptimize(&frameBuilder);
}
@@ -79,8 +79,7 @@
Caches& caches = Caches::getInstance();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, caches);
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry, caches);
frameBuilder.deferRenderNode(*node);
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
@@ -92,16 +91,17 @@
BENCHMARK(BM_FrameBuilder_deferAndRender);
static sp<RenderNode> getSyncedSceneNode(const char* sceneName) {
- gDisplay = getBuiltInDisplay(); // switch to real display if present
+ gDisplay = getBuiltInDisplay(); // switch to real display if present
TestContext testContext;
TestScene::Options opts;
std::unique_ptr<TestScene> scene(TestScene::testMap()[sceneName].createScene(opts));
- sp<RenderNode> rootNode = TestUtils::createNode<RecordingCanvas>(0, 0, gDisplay.w, gDisplay.h,
- [&scene](RenderProperties& props, RecordingCanvas& canvas) {
- scene->createContent(gDisplay.w, gDisplay.h, canvas);
- });
+ sp<RenderNode> rootNode = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, gDisplay.w, gDisplay.h,
+ [&scene](RenderProperties& props, RecordingCanvas& canvas) {
+ scene->createContent(gDisplay.w, gDisplay.h, canvas);
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(rootNode);
return rootNode;
@@ -117,9 +117,8 @@
state.SetLabel(sceneName);
auto node = getSyncedSceneNode(sceneName);
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h),
- gDisplay.w, gDisplay.h,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w,
+ gDisplay.h, sLightGeometry, Caches::getInstance());
frameBuilder.deferRenderNode(*node);
benchmark::DoNotOptimize(&frameBuilder);
}
@@ -137,9 +136,8 @@
Caches& caches = Caches::getInstance();
while (state.KeepRunning()) {
- FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h),
- gDisplay.w, gDisplay.h,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(gDisplay.w, gDisplay.h), gDisplay.w,
+ gDisplay.h, sLightGeometry, Caches::getInstance());
frameBuilder.deferRenderNode(*node);
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index b43c4c3..00ae8c1 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -24,7 +24,9 @@
using namespace android;
using namespace android::uirenderer;
-static const char* sPathString = "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10";
+static const char* sPathString =
+ "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 "
+ "8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10";
void BM_PathParser_parseStringPathForSkPath(benchmark::State& state) {
SkPath skPath;
diff --git a/libs/hwui/tests/microbench/RenderNodeBench.cpp b/libs/hwui/tests/microbench/RenderNodeBench.cpp
index a5bed00..206dcd5 100644
--- a/libs/hwui/tests/microbench/RenderNodeBench.cpp
+++ b/libs/hwui/tests/microbench/RenderNodeBench.cpp
@@ -30,4 +30,3 @@
}
}
BENCHMARK(BM_RenderNode_create);
-
diff --git a/libs/hwui/tests/microbench/ShadowBench.cpp b/libs/hwui/tests/microbench/ShadowBench.cpp
index a0fc6e8..12da783 100644
--- a/libs/hwui/tests/microbench/ShadowBench.cpp
+++ b/libs/hwui/tests/microbench/ShadowBench.cpp
@@ -18,9 +18,9 @@
#include "Matrix.h"
#include "Rect.h"
+#include "TessellationCache.h"
#include "Vector.h"
#include "VertexBuffer.h"
-#include "TessellationCache.h"
#include <SkPath.h>
@@ -40,22 +40,13 @@
void createShadowTestData(ShadowTestData* out) {
static float SAMPLE_DRAW_TRANSFORM[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 0, 0, 0, 1,
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1,
};
static float SAMPLE_CASTERXY[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 32, 32, 0, 1,
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 32, 32, 0, 1,
};
static float SAMPLE_CASTERZ[] = {
- 1, 0, 0, 0,
- 0, 1, 0, 0,
- 0, 0, 1, 0,
- 32, 32, 32, 1,
+ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 32, 32, 32, 1,
};
static Rect SAMPLE_CLIP(0, 0, 1536, 2048);
static Vector3 SAMPLE_LIGHT_CENTER{768, -400, 1600};
@@ -69,12 +60,11 @@
out->lightRadius = SAMPLE_LIGHT_RADIUS;
}
-static inline void tessellateShadows(ShadowTestData& testData, bool opaque,
- const SkPath& shape, VertexBuffer* ambient, VertexBuffer* spot) {
- tessellateShadows(&testData.drawTransform, &testData.localClip,
- opaque, &shape, &testData.casterTransformXY,
- &testData.casterTransformZ, testData.lightCenter,
- testData.lightRadius, *ambient, *spot);
+static inline void tessellateShadows(ShadowTestData& testData, bool opaque, const SkPath& shape,
+ VertexBuffer* ambient, VertexBuffer* spot) {
+ tessellateShadows(&testData.drawTransform, &testData.localClip, opaque, &shape,
+ &testData.casterTransformXY, &testData.casterTransformZ, testData.lightCenter,
+ testData.lightRadius, *ambient, *spot);
}
void BM_TessellateShadows_roundrect_opaque(benchmark::State& state) {
diff --git a/libs/hwui/tests/microbench/TaskManagerBench.cpp b/libs/hwui/tests/microbench/TaskManagerBench.cpp
index 67cb428..4153bae 100644
--- a/libs/hwui/tests/microbench/TaskManagerBench.cpp
+++ b/libs/hwui/tests/microbench/TaskManagerBench.cpp
@@ -31,10 +31,9 @@
class TrivialProcessor : public TaskProcessor<char> {
public:
- explicit TrivialProcessor(TaskManager* manager)
- : TaskProcessor(manager) {}
+ explicit TrivialProcessor(TaskManager* manager) : TaskProcessor(manager) {}
virtual ~TrivialProcessor() {}
- virtual void onProcess(const sp<Task<char> >& task) override {
+ virtual void onProcess(const sp<Task<char>>& task) override {
TrivialTask* t = static_cast<TrivialTask*>(task.get());
t->setResult(reinterpret_cast<intptr_t>(t) % 16 == 0 ? 'a' : 'b');
}
@@ -43,7 +42,7 @@
class TestThread : public ThreadBase, public virtual RefBase {};
void BM_TaskManager_allocateTask(benchmark::State& state) {
- std::vector<sp<TrivialTask> > tasks;
+ std::vector<sp<TrivialTask>> tasks;
tasks.reserve(state.max_iterations);
while (state.KeepRunning()) {
@@ -56,7 +55,7 @@
void BM_TaskManager_enqueueTask(benchmark::State& state) {
TaskManager taskManager;
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
- std::vector<sp<TrivialTask> > tasks;
+ std::vector<sp<TrivialTask>> tasks;
tasks.reserve(state.max_iterations);
while (state.KeepRunning()) {
@@ -74,7 +73,7 @@
void BM_TaskManager_enqueueRunDeleteTask(benchmark::State& state) {
TaskManager taskManager;
sp<TrivialProcessor> processor(new TrivialProcessor(&taskManager));
- std::vector<sp<TrivialTask> > tasks;
+ std::vector<sp<TrivialTask>> tasks;
tasks.reserve(state.max_iterations);
while (state.KeepRunning()) {
@@ -99,11 +98,9 @@
int expected = 0;
while (state.KeepRunning()) {
expected++;
- thread->queue().post([&counter](){
- counter++;
- });
+ thread->queue().post([&counter]() { counter++; });
}
- thread->queue().runSync([](){});
+ thread->queue().runSync([]() {});
thread->requestExit();
thread->join();
@@ -121,9 +118,7 @@
int expected = 0;
while (state.KeepRunning()) {
- tasks.emplace_back(thread->queue().async([expected]() -> int {
- return expected + 1;
- }));
+ tasks.emplace_back(thread->queue().async([expected]() -> int { return expected + 1; }));
expected++;
}
state.ResumeTiming();
diff --git a/libs/hwui/tests/scripts/prep_taieye.sh b/libs/hwui/tests/scripts/prep_taieye.sh
new file mode 100755
index 0000000..503f6d5
--- /dev/null
+++ b/libs/hwui/tests/scripts/prep_taieye.sh
@@ -0,0 +1,50 @@
+nr=$(adb shell cat /proc/cpuinfo | grep processor | wc -l)
+cpubase=/sys/devices/system/cpu
+
+adb root
+adb wait-for-device
+adb shell stop vendor.perfd
+adb shell stop thermal-engine
+
+S=1036800
+cpu=0
+# Changing governor and frequency in one core will be automatically applied
+# to other cores in the cluster
+while [ $((cpu < 4)) -eq 1 ]; do
+ echo "Setting cpu ${cpu} to $S hz"
+ adb shell "echo userspace > $cpubase/cpu${cpu}/cpufreq/scaling_governor"
+ adb shell "echo 1 > $cpubase/cpu${cpu}/online"
+ adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_max_freq"
+ adb shell "echo $S > $cpubase/cpu${cpu}/cpufreq/scaling_min_freq"
+ cpu=$(($cpu + 1))
+done
+
+while [ $((cpu < $nr)) -eq 1 ]; do
+ echo "disable cpu $cpu"
+ adb shell "echo 0 > $cpubase/cpu${cpu}/online"
+ cpu=$(($cpu + 1))
+done
+
+echo "setting GPU bus and idle timer"
+adb shell "echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split"
+adb shell "echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on"
+adb shell "echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer"
+
+#0 762 1144 1525 2288 3143 4173 5195 5859 7759 9887 11863 13763
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,gpubw/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,gpubw/max_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,cpubw/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,cpubw/max_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,mincpubw/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,mincpubw/max_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,memlat-cpu0/min_freq"
+adb shell "echo 7759 > /sys/class/devfreq/soc\:qcom,memlat-cpu0/max_freq"
+
+# 180000000 257000000 342000000 414000000 515000000 596000000 670000000 710000000
+echo "performance mode, 342 MHz"
+adb shell "echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor"
+adb shell "echo 342000000 > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq"
+adb shell "echo 342000000 > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq"
+
+adb shell "echo 4 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel"
+adb shell "echo 4 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel"
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index b0ef11f..09f0b06 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -20,8 +20,8 @@
#include <BakedOpRenderer.h>
#include <FrameBuilder.h>
#include <LayerUpdateQueue.h>
-#include <hwui/Paint.h>
#include <RecordedOp.h>
+#include <hwui/Paint.h>
#include <tests/common/TestUtils.h>
#include <utils/Color.h>
@@ -32,19 +32,20 @@
using namespace android::uirenderer;
static BakedOpRenderer::LightInfo sLightInfo;
-const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
+const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50};
class ValidatingBakedOpRenderer : public BakedOpRenderer {
public:
- ValidatingBakedOpRenderer(RenderState& renderState, std::function<void(const Glop& glop)> validator)
+ ValidatingBakedOpRenderer(RenderState& renderState,
+ std::function<void(const Glop& glop)> validator)
: BakedOpRenderer(Caches::getInstance(), renderState, true, false, sLightInfo)
, mValidator(validator) {
mGlopReceiver = ValidatingGlopReceiver;
}
+
private:
static void ValidatingGlopReceiver(BakedOpRenderer& renderer, const Rect* dirtyBounds,
- const ClipBase* clip, const Glop& glop) {
-
+ const ClipBase* clip, const Glop& glop) {
auto vbor = reinterpret_cast<ValidatingBakedOpRenderer*>(&renderer);
vbor->mValidator(glop);
}
@@ -54,7 +55,8 @@
typedef void (*TestBakedOpReceiver)(BakedOpRenderer&, const BakedOpState&);
static void testUnmergedGlopDispatch(renderthread::RenderThread& renderThread, RecordedOp* op,
- std::function<void(const Glop& glop)> glopVerifier, int expectedGlopCount = 1) {
+ std::function<void(const Glop& glop)> glopVerifier,
+ int expectedGlopCount = 1) {
// Create op, and wrap with basic state.
LinearAllocator allocator;
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 100));
@@ -62,22 +64,22 @@
ASSERT_NE(nullptr, state);
int glopCount = 0;
- auto glopReceiver = [&glopVerifier, &glopCount, &expectedGlopCount] (const Glop& glop) {
+ auto glopReceiver = [&glopVerifier, &glopCount, &expectedGlopCount](const Glop& glop) {
ASSERT_LE(glopCount++, expectedGlopCount) << expectedGlopCount << "glop(s) expected";
glopVerifier(glop);
};
ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
- // Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
-#define X(Type) \
- [](BakedOpRenderer& renderer, const BakedOpState& state) { \
- BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
- },
+// Dispatch based on op type created, similar to Frame/LayerBuilder dispatch behavior
+#define X(Type) \
+ [](BakedOpRenderer& renderer, const BakedOpState& state) { \
+ BakedOpDispatcher::on##Type(renderer, static_cast<const Type&>(*(state.op)), state); \
+ },
static TestBakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(X);
#undef X
unmergedReceivers[op->opId](renderer, *state);
ASSERT_EQ(expectedGlopCount, glopCount) << "Exactly " << expectedGlopCount
- << "Glop(s) expected";
+ << "Glop(s) expected";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
@@ -88,7 +90,7 @@
float intervals[] = {1.0f, 1.0f};
strokePaint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
- auto textureGlopVerifier = [] (const Glop& glop) {
+ auto textureGlopVerifier = [](const Glop& glop) {
// validate glop produced by renderPathTexture (so texture, unit quad)
auto texture = glop.fill.texture.texture;
ASSERT_NE(nullptr, texture);
@@ -116,16 +118,15 @@
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
SkPaint layerPaint;
layerPaint.setAlpha(128);
- OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
+ OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
- testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
- ADD_FAILURE() << "Nothing should happen";
- }, 0);
+ testUnmergedGlopDispatch(renderThread, &op,
+ [](const Glop& glop) { ADD_FAILURE() << "Nothing should happen"; }, 0);
}
static int getGlopTransformFlags(renderthread::RenderThread& renderThread, RecordedOp* op) {
int result = 0;
- testUnmergedGlopDispatch(renderThread, op, [&result] (const Glop& glop) {
+ testUnmergedGlopDispatch(renderThread, op, [&result](const Glop& glop) {
result = glop.transform.transformFlags;
});
return result;
@@ -144,7 +145,7 @@
const float points[4] = {0.5, 0.5, 1.0, 1.0};
PointsOp antiAliasedPointsOp(bounds, Matrix4::identity(), nullptr, &aaPaint, points, 4);
EXPECT_EQ(TransformFlags::None, getGlopTransformFlags(renderThread, &antiAliasedPointsOp))
- << "Expect no offset for AA points.";
+ << "Expect no offset for AA points.";
PointsOp pointsOp(bounds, Matrix4::identity(), nullptr, &paint, points, 4);
EXPECT_EQ(TransformFlags::OffsetByFudgeFactor, getGlopTransformFlags(renderThread, &pointsOp))
<< "Expect an offset for non-AA points.";
@@ -158,21 +159,21 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
- android::Paint shadowPaint;
- shadowPaint.setColor(SK_ColorRED);
+ android::Paint shadowPaint;
+ shadowPaint.setColor(SK_ColorRED);
- SkScalar sigma = Blur::convertRadiusToSigma(5);
- shadowPaint.setLooper(SkBlurDrawLooper::Make(SK_ColorWHITE, sigma, 3, 3));
+ SkScalar sigma = Blur::convertRadiusToSigma(5);
+ shadowPaint.setLooper(SkBlurDrawLooper::Make(SK_ColorWHITE, sigma, 3, 3));
- TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25);
- TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50);
- });
+ TestUtils::drawUtf8ToCanvas(&canvas, "A", shadowPaint, 25, 25);
+ TestUtils::drawUtf8ToCanvas(&canvas, "B", shadowPaint, 50, 50);
+ });
- int glopCount = 0;
- auto glopReceiver = [&glopCount] (const Glop& glop) {
+ int glopCount = 0;
+ auto glopReceiver = [&glopCount](const Glop& glop) {
if (glopCount < 2) {
// two white shadows
EXPECT_EQ(FloatColor({1, 1, 1, 1}), glop.fill.color);
@@ -185,8 +186,8 @@
ValidatingBakedOpRenderer renderer(renderThread.renderState(), glopReceiver);
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -194,15 +195,15 @@
}
static void validateLayerDraw(renderthread::RenderThread& renderThread,
- std::function<void(const Glop& glop)> validator) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ std::function<void(const Glop& glop)> validator) {
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
- // provide different blend mode, so decoration draws contrast
- props.mutateLayerProperties().setXferMode(SkBlendMode::kSrc);
- canvas.drawColor(Color::Black, SkBlendMode::kSrcOver);
- });
+ // provide different blend mode, so decoration draws contrast
+ props.mutateLayerProperties().setXferMode(SkBlendMode::kSrc);
+ canvas.drawColor(Color::Black, SkBlendMode::kSrcOver);
+ });
OffscreenBuffer** layerHandle = node->getLayerHandle();
auto syncedNode = TestUtils::getSyncedNode(node);
@@ -211,12 +212,12 @@
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
*layerHandle = &layer;
{
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(0, 0, 100, 100));
ValidatingBakedOpRenderer renderer(renderThread.renderState(), validator);
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
@@ -233,8 +234,8 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, layerUpdateProperties) {
- for (bool debugOverdraw : { false, true }) {
- for (bool debugLayersUpdates : { false, true }) {
+ for (bool debugOverdraw : {false, true}) {
+ for (bool debugLayersUpdates : {false, true}) {
ScopedProperty<bool> ovdProp(Properties::debugOverdraw, debugOverdraw);
ScopedProperty<bool> lupProp(Properties::debugLayersUpdates, debugLayersUpdates);
@@ -253,8 +254,8 @@
// blend srcover, different from that of layer
EXPECT_EQ(GLenum(GL_ONE), glop.blend.src);
EXPECT_EQ(GLenum(GL_ONE_MINUS_SRC_ALPHA), glop.blend.dst);
- EXPECT_EQ(makeFloatColor(debugLayersUpdates ? 0x7f00ff00 : 0),
- glop.fill.color) << "Should be transparent green if debugLayersUpdates";
+ EXPECT_EQ(makeFloatColor(debugLayersUpdates ? 0x7f00ff00 : 0), glop.fill.color)
+ << "Should be transparent green if debugLayersUpdates";
} else if (glopCount < 7) {
// 3 - 6 - overdraw indicator overlays, if present
EXPECT_TRUE(glop.fill.colorEnabled);
@@ -279,7 +280,7 @@
SkPath path;
path.addRect(SkRect::MakeXYWH(1.5, 3.8, 100, 90));
PathOp op(bounds, Matrix4::identity(), nullptr, &paint, &path);
- testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
+ testUnmergedGlopDispatch(renderThread, &op, [](const Glop& glop) {
auto texture = glop.fill.texture.texture;
ASSERT_NE(nullptr, texture);
EXPECT_EQ(1, reinterpret_cast<PathTexture*>(texture)->left);
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
index 38e106a..1a3ec39 100644
--- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -22,11 +22,11 @@
using namespace android::uirenderer;
-const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+const BakedOpRenderer::LightInfo sLightInfo = {128, 128};
RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
- BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(),
- true, false, sLightInfo);
+ BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, false,
+ sLightInfo);
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u);
layer.dirty(Rect(200, 200));
@@ -38,9 +38,9 @@
layer.dirty(Rect(200, 200));
{
- renderer.startRepaintLayer(&layer, Rect(100, 200)); // repainting left side
+ renderer.startRepaintLayer(&layer, Rect(100, 200)); // repainting left side
EXPECT_TRUE(layer.region.isRect());
- //ALOGD("bounds %d %d %d %d", RECT_ARGS(layer.region.getBounds()));
+ // ALOGD("bounds %d %d %d %d", RECT_ARGS(layer.region.getBounds()));
EXPECT_EQ(android::Rect(100, 0, 200, 200), layer.region.getBounds())
<< "Left side being repainted, so right side should be clear";
renderer.endLayer();
@@ -48,7 +48,7 @@
// right side is now only dirty portion
{
- renderer.startRepaintLayer(&layer, Rect(100, 0, 200, 200)); // repainting right side
+ renderer.startRepaintLayer(&layer, Rect(100, 0, 200, 200)); // repainting right side
EXPECT_TRUE(layer.region.isEmpty())
<< "Now right side being repainted, so region should be entirely clear";
renderer.endLayer();
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index d51db2e..6f8e249 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -38,7 +38,7 @@
ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
EXPECT_EQ(Rect(100, 200), state.clipRect());
- EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
+ EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
}
{
@@ -72,14 +72,14 @@
auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
- << "Local clip rect should be 100x200, offset by -10,-20";
+ << "Local clip rect should be 100x200, offset by -10,-20";
}
{
// recorded with transform + parent transform
auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
- << "Local clip rect should be 90x190, offset by -10,-20";
+ << "Local clip rect should be 90x190, offset by -10,-20";
}
}
@@ -96,62 +96,51 @@
};
const static StrokeTestCase sStrokeTestCases[] = {
- {
- 1, HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
- }
- },
- {
- 1, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
- EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
- }
- },
- {
- 1, 20, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
- }
- },
+ {1, HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
+ }},
+ {1, SEMI_HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
+ EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
+ }},
+ {1, 20,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
+ }},
- // 3x3 scale:
- {
- 3, HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
- EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
- }
- },
- {
- 3, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
- EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
- }
- },
- {
- 3, 20, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
- EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
- }
- },
+ // 3x3 scale:
+ {3, HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
+ EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
+ }},
+ {3, SEMI_HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
+ EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
+ }},
+ {3, 20,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
+ EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
+ }},
- // 0.5f x 0.5f scale
- {
- 0.5f, HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
- }
- },
- {
- 0.5f, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
- EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
- }
- },
- {
- 0.5f, 20, [](const ResolvedRenderState& state) {
- EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
- EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
- }
- }
-};
+ // 0.5f x 0.5f scale
+ {0.5f, HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
+ }},
+ {0.5f, SEMI_HAIRLINE,
+ [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
+ EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
+ }},
+ {0.5f, 20, [](const ResolvedRenderState& state) {
+ EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
+ EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
+ }}};
TEST(ResolvedRenderState, construct_expandForStroke) {
LinearAllocator allocator;
@@ -163,8 +152,7 @@
strokedPaint.setStrokeWidth(testCase.strokeWidth);
ClipRect clip(Rect(200, 200));
- RectOp recordedOp(Rect(50, 50, 150, 150),
- Matrix4::identity(), &clip, &strokedPaint);
+ RectOp recordedOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &strokedPaint);
Matrix4 snapshotMatrix;
snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
@@ -204,16 +192,18 @@
LinearAllocator allocator;
{
- auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
- BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+ auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
+ BakedOpState* bakedState =
+ BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed";
EXPECT_EQ(0u, allocator.usedSize()) << "no serialization, even for clip,"
- "since op is quick rejected based on snapshot clip";
+ "since op is quick rejected based on snapshot clip";
}
{
auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
- BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
+ BakedOpState* bakedState =
+ BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed";
EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op";
@@ -232,12 +222,13 @@
paint.setStrokeWidth(0.0f);
ClipRect clip(Rect(100, 200));
RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
- auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
- auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::StyleDefined, false);
+ auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
+ auto bakedState = BakedOpState::tryStrokeableOpConstruct(
+ allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false);
EXPECT_EQ(nullptr, bakedState);
- EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
+ EXPECT_GT(8u,
+ allocator.usedSize()); // no significant allocation space used for rejected op
}
{
// check simple unscaled expansion
@@ -247,8 +238,8 @@
ClipRect clip(Rect(200, 200));
RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
- auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::StyleDefined, false);
+ auto bakedState = BakedOpState::tryStrokeableOpConstruct(
+ allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false);
ASSERT_NE(nullptr, bakedState);
EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
@@ -262,8 +253,8 @@
ClipRect clip(Rect(200, 200));
RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
- auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
- BakedOpState::StrokeBehavior::Forced, false);
+ auto bakedState = BakedOpState::tryStrokeableOpConstruct(
+ allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::Forced, false);
ASSERT_NE(nullptr, bakedState);
EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
@@ -271,5 +262,5 @@
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/CacheManagerTests.cpp b/libs/hwui/tests/unit/CacheManagerTests.cpp
index 6115162..b1106f0 100644
--- a/libs/hwui/tests/unit/CacheManagerTests.cpp
+++ b/libs/hwui/tests/unit/CacheManagerTests.cpp
@@ -35,7 +35,8 @@
GrContext* grContext = renderThread.getGrContext();
ASSERT_TRUE(grContext != nullptr);
- // create pairs of offscreen render targets and images until we exceed the backgroundCacheSizeLimit
+ // create pairs of offscreen render targets and images until we exceed the
+ // backgroundCacheSizeLimit
std::vector<sk_sp<SkSurface>> surfaces;
while (getCacheUsage(grContext) <= renderThread.cacheManager().getBackgroundCacheSize()) {
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index ef5ce0d..28cff5b 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -35,8 +35,8 @@
RENDERTHREAD_TEST(CanvasContext, create) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
ASSERT_FALSE(canvasContext->hasSurface());
diff --git a/libs/hwui/tests/unit/CanvasStateTests.cpp b/libs/hwui/tests/unit/CanvasStateTests.cpp
index c41313a..4c03811 100644
--- a/libs/hwui/tests/unit/CanvasStateTests.cpp
+++ b/libs/hwui/tests/unit/CanvasStateTests.cpp
@@ -21,14 +21,14 @@
#include "hwui/Canvas.h"
#include "utils/LinearAllocator.h"
-#include <gtest/gtest.h>
-#include <SkPath.h>
#include <SkClipOp.h>
+#include <SkPath.h>
+#include <gtest/gtest.h>
namespace android {
namespace uirenderer {
-class NullClient: public CanvasStateClient {
+class NullClient : public CanvasStateClient {
void onViewportInitialized() override {}
void onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
GLuint getTargetFbo() const override { return 0; }
@@ -47,8 +47,7 @@
TEST(CanvasState, gettersAndSetters) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
ASSERT_EQ(state.getWidth(), 200);
ASSERT_EQ(state.getHeight(), 200);
@@ -65,8 +64,7 @@
TEST(CanvasState, simpleClipping) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
state.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(100, 100));
@@ -80,8 +78,7 @@
TEST(CanvasState, complexClipping) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
state.save(SaveFlags::MatrixClip);
{
@@ -116,8 +113,7 @@
TEST(CanvasState, saveAndRestore) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
state.save(SaveFlags::Clip);
{
@@ -125,7 +121,7 @@
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
}
state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(200, 200)); // verify restore
Matrix4 simpleTranslate;
simpleTranslate.loadTranslate(10, 10, 0);
@@ -140,27 +136,25 @@
TEST(CanvasState, saveAndRestoreButNotTooMuch) {
CanvasState state(sNullClient);
- state.initializeSaveStack(200, 200,
- 0, 0, 200, 200, Vector3());
+ state.initializeSaveStack(200, 200, 0, 0, 200, 200, Vector3());
- state.save(SaveFlags::Matrix); // NOTE: clip not saved
+ state.save(SaveFlags::Matrix); // NOTE: clip not saved
{
state.clipRect(0, 0, 10, 10, SkClipOp::kIntersect);
ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10));
}
state.restore();
- ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
+ ASSERT_EQ(state.getRenderTargetClipBounds(), Rect(10, 10)); // verify not restored
Matrix4 simpleTranslate;
simpleTranslate.loadTranslate(10, 10, 0);
- state.save(SaveFlags::Clip); // NOTE: matrix not saved
+ state.save(SaveFlags::Clip); // NOTE: matrix not saved
{
state.translate(10, 10, 0);
EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate));
}
state.restore();
- EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
+ EXPECT_TRUE(approxEqual(*state.currentTransform(), simpleTranslate)); // verify not restored
}
-
}
}
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index d4d7919..450bb67 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <SkPath.h>
#include <SkRegion.h>
+#include <gtest/gtest.h>
#include "ClipArea.h"
@@ -194,7 +194,8 @@
{
auto origRectClip = area.serializeClip(allocator);
ASSERT_NE(nullptr, origRectClip);
- EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+ EXPECT_EQ(origRectClip,
+ area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
}
// rect
@@ -208,11 +209,13 @@
ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
EXPECT_EQ(Rect(100, 100, 200, 200), resolvedClip->rect);
- EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
+ EXPECT_EQ(resolvedClip,
+ area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
<< "Must return previous serialization, since input is same";
ClipRect recordedClip2(Rect(100, 100));
- EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
+ EXPECT_NE(resolvedClip,
+ area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
<< "Shouldn't return previous serialization, since matrix location is different";
}
@@ -222,7 +225,8 @@
area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
{
ClipRect recordedClip(Rect(100, 100));
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
+ auto resolvedClip =
+ area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
ASSERT_NE(nullptr, resolvedClip);
ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
@@ -243,8 +247,9 @@
Matrix4 translate10x20;
translate10x20.loadTranslate(10, 20, 0);
- auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip,
- translate10x20); // Note: only translate for now, others not handled correctly
+ auto resolvedClip = area.serializeIntersectedClip(
+ allocator, &recordedClip,
+ translate10x20); // Note: only translate for now, others not handled correctly
ASSERT_NE(nullptr, resolvedClip);
ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
@@ -267,7 +272,8 @@
ClipRect recordedClip(Rect(100.12, 100.74));
Matrix4 translateScale;
translateScale.loadTranslate(100, 100, 0);
- translateScale.scale(2, 3, 1); // recorded clip will have non-int coords, even after transform
+ translateScale.scale(2, 3,
+ 1); // recorded clip will have non-int coords, even after transform
auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
ASSERT_NE(nullptr, resolvedClip);
EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
@@ -343,5 +349,5 @@
EXPECT_EQ(SkIRect::MakeLTRB(-4, 1, -2, 3), region.getBounds());
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index 87d897e..b8b5050 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -50,7 +50,6 @@
glLayer->setRenderTarget(GL_TEXTURE_EXTERNAL_OES);
}
-
// the backing layer should now have all the properties applied.
if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
diff --git a/libs/hwui/tests/unit/FatVectorTests.cpp b/libs/hwui/tests/unit/FatVectorTests.cpp
index 64b0ba1..8523e6c 100644
--- a/libs/hwui/tests/unit/FatVectorTests.cpp
+++ b/libs/hwui/tests/unit/FatVectorTests.cpp
@@ -22,12 +22,11 @@
using namespace android;
using namespace android::uirenderer;
-template<class VectorType>
+template <class VectorType>
static bool allocationIsInternal(VectorType& v) {
// allocation array (from &v[0] to &v[0] + v.capacity) is
// located within the vector object itself
- return (char*)(&v) <= (char*)(&v[0])
- && (char*)(&v + 1) >= (char*)(&v[0] + v.capacity());
+ return (char*)(&v) <= (char*)(&v[0]) && (char*)(&v + 1) >= (char*)(&v[0] + v.capacity());
}
TEST(FatVector, baseline) {
diff --git a/libs/hwui/tests/unit/FatalTestCanvas.h b/libs/hwui/tests/unit/FatalTestCanvas.h
index 03d9496..9693ce7 100644
--- a/libs/hwui/tests/unit/FatalTestCanvas.h
+++ b/libs/hwui/tests/unit/FatalTestCanvas.h
@@ -16,15 +16,14 @@
#pragma once
-#include <gtest/gtest.h>
#include <SkCanvas.h>
+#include <gtest/gtest.h>
namespace {
class TestCanvasBase : public SkCanvas {
public:
- TestCanvasBase(int width, int height) : SkCanvas(width, height) {
- }
+ TestCanvasBase(int width, int height) : SkCanvas(width, height) {}
void onDrawAnnotation(const SkRect&, const char key[], SkData* value) {
ADD_FAILURE() << "onDrawAnnotation not expected in this test";
}
@@ -32,35 +31,33 @@
ADD_FAILURE() << "onDrawDRRect not expected in this test";
}
void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
- const SkPaint& paint) {
+ const SkPaint& paint) {
ADD_FAILURE() << "onDrawText not expected in this test";
}
void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
- const SkPaint& paint) {
+ const SkPaint& paint) {
ADD_FAILURE() << "onDrawPosText not expected in this test";
}
void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) {
+ const SkPaint& paint) {
ADD_FAILURE() << "onDrawPosTextH not expected in this test";
}
void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
- const SkMatrix* matrix, const SkPaint& paint) {
+ const SkMatrix* matrix, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextOnPath not expected in this test";
}
void onDrawTextRSXform(const void* text, size_t byteLength, const SkRSXform[],
- const SkRect* cullRect, const SkPaint& paint) {
+ const SkRect* cullRect, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextRSXform not expected in this test";
}
void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint) {
ADD_FAILURE() << "onDrawTextBlob not expected in this test";
}
void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texCoords[4],
- SkBlendMode, const SkPaint& paint) {
+ SkBlendMode, const SkPaint& paint) {
ADD_FAILURE() << "onDrawPatch not expected in this test";
}
- void onDrawPaint(const SkPaint&) {
- ADD_FAILURE() << "onDrawPaint not expected in this test";
- }
+ void onDrawPaint(const SkPaint&) { ADD_FAILURE() << "onDrawPaint not expected in this test"; }
void onDrawRect(const SkRect&, const SkPaint&) {
ADD_FAILURE() << "onDrawRect not expected in this test";
}
@@ -71,7 +68,7 @@
ADD_FAILURE() << "onDrawOval not expected in this test";
}
void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
- const SkPaint&) {
+ const SkPaint&) {
ADD_FAILURE() << "onDrawArc not expected in this test";
}
void onDrawRRect(const SkRRect&, const SkPaint&) {
@@ -84,7 +81,7 @@
ADD_FAILURE() << "onDrawVertices not expected in this test";
}
void onDrawAtlas(const SkImage*, const SkRSXform[], const SkRect[], const SkColor[], int count,
- SkBlendMode, const SkRect* cull, const SkPaint*) {
+ SkBlendMode, const SkRect* cull, const SkPaint*) {
ADD_FAILURE() << "onDrawAtlas not expected in this test";
}
void onDrawPath(const SkPath&, const SkPaint&) {
@@ -94,29 +91,29 @@
ADD_FAILURE() << "onDrawImage not expected in this test";
}
void onDrawImageRect(const SkImage*, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) {
+ SrcRectConstraint) {
ADD_FAILURE() << "onDrawImageRect not expected in this test";
}
void onDrawImageNine(const SkImage*, const SkIRect& center, const SkRect& dst, const SkPaint*) {
ADD_FAILURE() << "onDrawImageNine not expected in this test";
}
void onDrawImageLattice(const SkImage*, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
ADD_FAILURE() << "onDrawImageLattice not expected in this test";
}
void onDrawBitmap(const SkBitmap&, SkScalar dx, SkScalar dy, const SkPaint*) {
ADD_FAILURE() << "onDrawBitmap not expected in this test";
}
void onDrawBitmapRect(const SkBitmap&, const SkRect*, const SkRect&, const SkPaint*,
- SrcRectConstraint) {
+ SrcRectConstraint) {
ADD_FAILURE() << "onDrawBitmapRect not expected in this test";
}
void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
ADD_FAILURE() << "onDrawBitmapNine not expected in this test";
}
void onDrawBitmapLattice(const SkBitmap&, const Lattice& lattice, const SkRect& dst,
- const SkPaint*) {
+ const SkPaint*) {
ADD_FAILURE() << "onDrawBitmapLattice not expected in this test";
}
void onClipRRect(const SkRRect& rrect, SkClipOp, ClipEdgeStyle) {
@@ -128,14 +125,11 @@
void onClipRegion(const SkRegion& deviceRgn, SkClipOp) {
ADD_FAILURE() << "onClipRegion not expected in this test";
}
- void onDiscard() {
- ADD_FAILURE() << "onDiscard not expected in this test";
- }
+ void onDiscard() { ADD_FAILURE() << "onDiscard not expected in this test"; }
void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) {
ADD_FAILURE() << "onDrawPicture not expected in this test";
}
- int mDrawCounter = 0; //counts how may draw calls of any kind were made to this canvas
+ int mDrawCounter = 0; // counts how may draw calls of any kind were made to this canvas
};
-
}
\ No newline at end of file
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
index ee20236..c78f131 100644
--- a/libs/hwui/tests/unit/FontRendererTests.cpp
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -40,16 +40,16 @@
std::vector<float> positions;
float totalAdvance;
Rect bounds;
- TestUtils::layoutTextUnscaled(paint, "This is a test",
- &glyphs, &positions, &totalAdvance, &bounds);
+ TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance,
+ &bounds);
for (int radius : {28, 20, 2}) {
- auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(),
- radius, positions.data());
+ auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(), radius,
+ positions.data());
ASSERT_NE(nullptr, result.image);
EXPECT_FALSE(isZero(result.image, result.width * result.height));
- EXPECT_LE(bounds.getWidth() + radius * 2, (int) result.width);
- EXPECT_LE(bounds.getHeight() + radius * 2, (int) result.height);
+ EXPECT_LE(bounds.getWidth() + radius * 2, (int)result.width);
+ EXPECT_LE(bounds.getHeight() + radius * 2, (int)result.height);
delete result.image;
}
}
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index fcdd814..e56d2f8 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -30,7 +30,7 @@
namespace android {
namespace uirenderer {
-const FrameBuilder::LightGeometry sLightGeometry = { {100, 100, 100}, 50};
+const FrameBuilder::LightGeometry sLightGeometry = {{100, 100, 100}, 50};
/**
* Virtual class implemented by each test to redirect static operation / state transitions to
@@ -56,23 +56,21 @@
virtual void startRepaintLayer(OffscreenBuffer*, const Rect& repaintRect) {
ADD_FAILURE() << "Layer repaint not expected in this test";
}
- virtual void endLayer() {
- ADD_FAILURE() << "Layer updates not expected in this test";
- }
+ virtual void endLayer() { ADD_FAILURE() << "Layer updates not expected in this test"; }
virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
virtual void endFrame(const Rect& repaintRect) {}
- // define virtual defaults for single draw methods
-#define X(Type) \
+// define virtual defaults for single draw methods
+#define X(Type) \
virtual void on##Type(const Type&, const BakedOpState&) { \
- ADD_FAILURE() << #Type " not expected in this test"; \
+ ADD_FAILURE() << #Type " not expected in this test"; \
}
MAP_RENDERABLE_OPS(X)
#undef X
- // define virtual defaults for merged draw methods
-#define X(Type) \
- virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
+// define virtual defaults for merged draw methods
+#define X(Type) \
+ virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \
ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \
}
MAP_MERGEABLE_OPS(X)
@@ -90,18 +88,18 @@
*/
class TestDispatcher {
public:
- // define single op methods, which redirect to TestRendererBase
-#define X(Type) \
+// define single op methods, which redirect to TestRendererBase
+#define X(Type) \
static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \
- renderer.on##Type(op, state); \
+ renderer.on##Type(op, state); \
}
MAP_RENDERABLE_OPS(X);
#undef X
- // define merged op methods, which redirect to TestRendererBase
-#define X(Type) \
+// define merged op methods, which redirect to TestRendererBase
+#define X(Type) \
static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \
- renderer.onMerged##Type##s(opList); \
+ renderer.onMerged##Type##s(opList); \
}
MAP_MERGEABLE_OPS(X);
#undef X
@@ -123,24 +121,22 @@
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(3, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(3, mIndex++); }
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
- canvas.drawRect(0, 0, 100, 200, SkPaint());
- canvas.drawBitmap(*bitmap, 10, 10, nullptr);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
+ canvas.drawRect(0, 0, 100, 200, SkPaint());
+ canvas.drawBitmap(*bitmap, 10, 10, nullptr);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SimpleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
+ EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
@@ -156,14 +152,14 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint strokedPaint;
- strokedPaint.setStrokeWidth(10);
- canvas.drawPoint(50, 50, strokedPaint);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint strokedPaint;
+ strokedPaint.setStrokeWidth(10);
+ canvas.drawPoint(50, 50, strokedPaint);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 200), 100, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SimpleStrokeTestRenderer renderer;
@@ -171,7 +167,6 @@
EXPECT_EQ(1, renderer.getIndex());
}
-
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, arcStrokeClip) {
class ArcStrokeClipTestRenderer : public TestRendererBase {
public:
@@ -184,15 +179,15 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect);
- SkPaint aaPaint;
- aaPaint.setAntiAlias(true);
- canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.clipRect(25, 25, 175, 175, SkClipOp::kIntersect);
+ SkPaint aaPaint;
+ aaPaint.setAntiAlias(true);
+ canvas.drawArc(25, 25, 175, 175, 40, 180, true, aaPaint);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ArcStrokeClipTestRenderer renderer;
@@ -201,15 +196,15 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty
+ canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect); // intersection should be empty
canvas.drawRect(0, 0, 400, 400, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -228,30 +223,30 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(10, 10,
- kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(
+ 10, 10,
+ kAlpha_8_SkColorType)); // Disable merging by using alpha 8 bitmap
- // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
- // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
- canvas.save(SaveFlags::MatrixClip);
- for (int i = 0; i < LOOPS; i++) {
- canvas.translate(0, 10);
- canvas.drawRect(0, 0, 10, 10, SkPaint());
- canvas.drawBitmap(*bitmap, 5, 0, nullptr);
- }
- canvas.restore();
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ // Alternate between drawing rects and bitmaps, with bitmaps overlapping rects.
+ // Rects don't overlap bitmaps, so bitmaps should be brought to front as a group.
+ canvas.save(SaveFlags::MatrixClip);
+ for (int i = 0; i < LOOPS; i++) {
+ canvas.translate(0, 10);
+ canvas.drawRect(0, 0, 10, 10, SkPaint());
+ canvas.drawBitmap(*bitmap, 5, 0, nullptr);
+ }
+ canvas.restore();
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SimpleBatchingTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(2 * LOOPS, renderer.getIndex())
- << "Expect number of ops = 2 * loop count";
+ EXPECT_EQ(2 * LOOPS, renderer.getIndex()) << "Expect number of ops = 2 * loop count";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) {
@@ -261,19 +256,19 @@
EXPECT_EQ(0, mIndex++);
EXPECT_EQ(Rect(5, 10, 55, 60), state.computedState.clippedBounds);
EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom,
- state.computedState.clipSideFlags);
+ state.computedState.clipSideFlags);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
- frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
- *TestUtils::getSyncedNode(node));
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
+ frameBuilder.deferRenderNode(5, 10, Rect(50, 50), // translate + clip node
+ *TestUtils::getSyncedNode(node));
DeferRenderNodeTranslateClipTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -287,27 +282,27 @@
const Rect& clippedBounds = state.computedState.clippedBounds;
Matrix4 expected;
switch (mIndex++) {
- case 0:
- // background - left side
- EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
- expected.loadTranslate(100, 100, 0);
- break;
- case 1:
- // background - top side
- EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
- expected.loadTranslate(100, 100, 0);
- break;
- case 2:
- // content
- EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
- expected.loadTranslate(-50, -50, 0);
- break;
- case 3:
- // overlay
- EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
- break;
- default:
- ADD_FAILURE() << "Too many rects observed";
+ case 0:
+ // background - left side
+ EXPECT_EQ(Rect(600, 100, 700, 500), clippedBounds);
+ expected.loadTranslate(100, 100, 0);
+ break;
+ case 1:
+ // background - top side
+ EXPECT_EQ(Rect(100, 400, 600, 500), clippedBounds);
+ expected.loadTranslate(100, 100, 0);
+ break;
+ case 2:
+ // content
+ EXPECT_EQ(Rect(100, 100, 700, 500), clippedBounds);
+ expected.loadTranslate(-50, -50, 0);
+ break;
+ case 3:
+ // overlay
+ EXPECT_EQ(Rect(0, 0, 800, 200), clippedBounds);
+ break;
+ default:
+ ADD_FAILURE() << "Too many rects observed";
}
EXPECT_EQ(expected, state.computedState.transform);
}
@@ -318,31 +313,32 @@
transparentPaint.setAlpha(128);
// backdrop
- nodes.push_back(TestUtils::createNode<RecordingCanvas>(100, 100, 700, 500, // 600x400
+ nodes.push_back(TestUtils::createNode<RecordingCanvas>(
+ 100, 100, 700, 500, // 600x400
[&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 600, 400, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 600, 400, transparentPaint);
+ }));
// content
- Rect contentDrawBounds(150, 150, 650, 450); // 500x300
- nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
- [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 600, transparentPaint);
- }));
+ Rect contentDrawBounds(150, 150, 650, 450); // 500x300
+ nodes.push_back(TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 800, 600, [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 800, 600, transparentPaint);
+ }));
// overlay
- nodes.push_back(TestUtils::createNode<RecordingCanvas>(0, 0, 800, 600,
- [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 200, transparentPaint);
- }));
+ nodes.push_back(TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 800, 600, [&transparentPaint](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 800, 200, transparentPaint);
+ }));
for (auto& node : nodes) {
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
}
{
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
DeferRenderNodeSceneTestRenderer renderer;
@@ -363,8 +359,8 @@
{
// Validate no crashes if any nodes are missing DisplayLists
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
FailRenderer renderer;
@@ -396,24 +392,22 @@
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(0, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(1, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(1, mIndex++); }
};
- auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // no drawn content
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // no drawn content
+ });
// Draw, but pass node without draw content, so no work is done for primary frame
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EmptyWithFbo0TestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
EXPECT_EQ(2, renderer.getIndex()) << "No drawing content produced,"
- " but fbo0 update lifecycle should still be observed";
+ " but fbo0 update lifecycle should still be observed";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
@@ -425,17 +419,17 @@
<< "Last rect should occlude others.";
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.drawRect(10, 10, 190, 190, SkPaint());
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.drawRect(10, 10, 190, 190, SkPaint());
+ });
// Damage (and therefore clip) is same as last draw, subset of renderable area.
// This means last op occludes other contents, and they'll be rejected to avoid overdraw.
- FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 190, 190), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EXPECT_EQ(3u, node->getDisplayList()->getOps().size())
@@ -447,38 +441,38 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
- static sk_sp<Bitmap> opaqueBitmap(TestUtils::createBitmap(50, 50,
- SkColorType::kRGB_565_SkColorType));
- static sk_sp<Bitmap> transpBitmap(TestUtils::createBitmap(50, 50,
- SkColorType::kAlpha_8_SkColorType));
+ static sk_sp<Bitmap> opaqueBitmap(
+ TestUtils::createBitmap(50, 50, SkColorType::kRGB_565_SkColorType));
+ static sk_sp<Bitmap> transpBitmap(
+ TestUtils::createBitmap(50, 50, SkColorType::kAlpha_8_SkColorType));
class AvoidOverdrawBitmapsTestRenderer : public TestRendererBase {
public:
void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
- switch(mIndex++) {
- case 0:
- EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
- break;
- case 1:
- EXPECT_EQ(transpBitmap.get(), op.bitmap);
- break;
- default:
- ADD_FAILURE() << "Only two ops expected.";
+ switch (mIndex++) {
+ case 0:
+ EXPECT_EQ(opaqueBitmap.get(), op.bitmap);
+ break;
+ case 1:
+ EXPECT_EQ(transpBitmap.get(), op.bitmap);
+ break;
+ default:
+ ADD_FAILURE() << "Only two ops expected.";
}
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 50, 50,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 50, 50, SkPaint());
- canvas.drawRect(0, 0, 50, 50, SkPaint());
- canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 50, 50, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawRect(0, 0, 50, 50, SkPaint());
+ canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
- // only the below draws should remain, since they're
- canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr);
- canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50,
- sLightGeometry, Caches::getInstance());
+ // only the below draws should remain, since they're
+ canvas.drawBitmap(*opaqueBitmap, 0, 0, nullptr);
+ canvas.drawBitmap(*transpBitmap, 0, 0, nullptr);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(50, 50), 50, 50, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
EXPECT_EQ(5u, node->getDisplayList()->getOps().size())
@@ -498,32 +492,32 @@
EXPECT_EQ(4u, opList.count);
EXPECT_EQ(Rect(10, 10, 90, 90), opList.clip);
EXPECT_EQ(OpClipSideFlags::Left | OpClipSideFlags::Top | OpClipSideFlags::Right,
- opList.clipSideFlags);
+ opList.clipSideFlags);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(20, 20));
- // left side clipped (to inset left half)
- canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 0, 40, nullptr);
+ // left side clipped (to inset left half)
+ canvas.clipRect(10, 0, 50, 100, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 0, 40, nullptr);
- // top side clipped (to inset top half)
- canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 40, 0, nullptr);
+ // top side clipped (to inset top half)
+ canvas.clipRect(0, 10, 100, 50, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 40, 0, nullptr);
- // right side clipped (to inset right half)
- canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 80, 40, nullptr);
+ // right side clipped (to inset right half)
+ canvas.clipRect(50, 0, 90, 100, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 80, 40, nullptr);
- // bottom not clipped, just abutting (inset bottom half)
- canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace_deprecated);
- canvas.drawBitmap(*bitmap, 40, 70, nullptr);
- });
+ // bottom not clipped, just abutting (inset bottom half)
+ canvas.clipRect(0, 50, 100, 90, SkClipOp::kReplace_deprecated);
+ canvas.drawBitmap(*bitmap, 40, 70, nullptr);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ClippedMergingTestRenderer renderer;
@@ -536,23 +530,23 @@
public:
void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPath path;
- path.addCircle(200, 200, 200, SkPath::kCW_Direction);
- canvas.save(SaveFlags::MatrixClip);
- canvas.clipPath(&path, SkClipOp::kIntersect);
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setTextSize(50);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPath path;
+ path.addCircle(200, 200, 200, SkPath::kCW_Direction);
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipPath(&path, SkClipOp::kIntersect);
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 200);
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
RegionClipStopsMergeTestRenderer renderer;
@@ -572,17 +566,17 @@
EXPECT_EQ(OpClipSideFlags::None, opList.states[1]->computedState.clipSideFlags);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
SkPaint paint;
paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
paint.setAntiAlias(true);
paint.setTextSize(50);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 0); // will be top clipped
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100); // not clipped
});
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextMergingTestRenderer renderer;
@@ -603,30 +597,28 @@
EXPECT_EQ(5u, opList.count);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 2000,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint textPaint;
- textPaint.setAntiAlias(true);
- textPaint.setTextSize(20);
- textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
- textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- for (int i = 0; i < LOOPS; i++) {
- TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
- }
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 2000, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint textPaint;
+ textPaint.setAntiAlias(true);
+ textPaint.setTextSize(20);
+ textPaint.setFlags(textPaint.getFlags() | SkPaint::kStrikeThruText_ReserveFlag);
+ textPaint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ for (int i = 0; i < LOOPS; i++) {
+ TestUtils::drawUtf8ToCanvas(&canvas, "test text", textPaint, 10, 100 * (i + 1));
+ }
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 2000), 200, 2000, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextStrikethroughTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(2 * LOOPS, renderer.getIndex())
- << "Expect number of ops = 2 * loop count";
+ EXPECT_EQ(2 * LOOPS, renderer.getIndex()) << "Expect number of ops = 2 * loop count";
}
-static auto styles = {
- SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
+static auto styles = {SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style};
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
class TextStyleTestRenderer : public TestRendererBase {
@@ -659,23 +651,23 @@
EXPECT_EQ(stroke, outsetFill);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
- paint.setAntiAlias(true);
- paint.setTextSize(50);
- paint.setStrokeWidth(10);
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ paint.setStrokeWidth(10);
- // draw 3 copies of the same text overlapping, each with a different style.
- // They'll get merged, but with
- for (auto style : styles) {
- paint.setStyle(style);
- TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
- }
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ // draw 3 copies of the same text overlapping, each with a different style.
+ // They'll get merged, but with
+ for (auto style : styles) {
+ paint.setStyle(style);
+ TestUtils::drawUtf8ToCanvas(&canvas, "Test string1", paint, 100, 100);
+ }
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextStyleTestRenderer renderer;
frameBuilder.replayBakedOps<TestDispatcher>(renderer);
@@ -696,19 +688,19 @@
}
};
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
- canvas.drawLayer(layerUpdater.get());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(50, 50, 150, 150, SkClipOp::kIntersect);
+ canvas.drawLayer(layerUpdater.get());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextureLayerClipLocalMatrixTestRenderer renderer;
@@ -728,19 +720,19 @@
}
};
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(30, 40);
- canvas.drawLayer(layerUpdater.get());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(30, 40);
+ canvas.drawLayer(layerUpdater.get());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
TextureLayerCombineMatricesTestRenderer renderer;
@@ -749,20 +741,20 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_reject) {
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
EXPECT_EQ(Layer::Api::OpenGL, layerUpdater->backingLayer()->getApi());
GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
- glLayer->setRenderTarget(GL_NONE); // Should be rejected
+ glLayer->setRenderTarget(GL_NONE); // Should be rejected
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.drawLayer(layerUpdater.get());
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&layerUpdater](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.drawLayer(layerUpdater.get());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -779,14 +771,14 @@
Functor noopFunctor;
// 1 million pixel tall view, scrolled down 80%
- auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 1000000,
- [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.translate(0, -800000);
- canvas.callDrawGLFunction(&noopFunctor, nullptr);
- });
+ auto scrolledFunctorView = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 1000000, [&noopFunctor](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.translate(0, -800000);
+ canvas.callDrawGLFunction(&noopFunctor, nullptr);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(scrolledFunctorView));
FunctorTestRenderer renderer;
@@ -804,14 +796,14 @@
}
};
- auto unclippedColorView = TestUtils::createNode<RecordingCanvas>(0, 0, 10, 10,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setClipToBounds(false);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto unclippedColorView = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 10, 10, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setClipToBounds(false);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(unclippedColorView));
ColorTestRenderer renderer;
@@ -823,42 +815,42 @@
class RenderNodeTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
- switch(mIndex++) {
- case 0:
- EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
- EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- break;
- case 1:
- EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
- EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
- break;
- default:
- ADD_FAILURE();
+ switch (mIndex++) {
+ case 0:
+ EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds);
+ EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+ break;
+ case 1:
+ EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clippedBounds);
+ EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+ break;
+ default:
+ ADD_FAILURE();
}
}
};
- auto child = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [&child](RenderProperties& props, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(0, 0, 200, 200, paint);
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [&child](RenderProperties& props, RecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(0, 0, 200, 200, paint);
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(40, 40);
- canvas.drawRenderNode(child.get());
- canvas.restore();
- });
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(40, 40);
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
RenderNodeTestRenderer renderer;
@@ -877,15 +869,15 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200));
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(200, 200));
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ });
// clip to small area, should see in receiver
- FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 20, 30, 40), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ClippedTestRenderer renderer;
@@ -901,9 +893,7 @@
EXPECT_EQ(180u, height);
return nullptr;
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(1, mIndex++);
EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
@@ -926,15 +916,15 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
- canvas.drawRect(10, 10, 190, 190, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, SaveFlags::ClipToLayer);
+ canvas.drawRect(10, 10, 190, 190, SkPaint());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerSimpleTestRenderer renderer;
@@ -955,13 +945,15 @@
if (index == 0) {
EXPECT_EQ(400u, width);
EXPECT_EQ(400u, height);
- return (OffscreenBuffer*) 0x400;
+ return (OffscreenBuffer*)0x400;
} else if (index == 3) {
EXPECT_EQ(800u, width);
EXPECT_EQ(800u, height);
- return (OffscreenBuffer*) 0x800;
- } else { ADD_FAILURE(); }
- return (OffscreenBuffer*) nullptr;
+ return (OffscreenBuffer*)0x800;
+ } else {
+ ADD_FAILURE();
+ }
+ return (OffscreenBuffer*)nullptr;
}
void endLayer() override {
int index = mIndex++;
@@ -970,26 +962,28 @@
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(7, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(9, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(9, mIndex++); }
void onRectOp(const RectOp& op, const BakedOpState& state) override {
const int index = mIndex++;
if (index == 1) {
- EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner rect
} else if (index == 4) {
- EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
- } else { ADD_FAILURE(); }
+ EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer rect
+ } else {
+ ADD_FAILURE();
+ }
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
const int index = mIndex++;
if (index == 5) {
EXPECT_EQ((OffscreenBuffer*)0x400, *op.layerHandle);
- EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
+ EXPECT_EQ(Rect(400, 400), op.unmappedBounds); // inner layer
} else if (index == 8) {
EXPECT_EQ((OffscreenBuffer*)0x800, *op.layerHandle);
- EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
- } else { ADD_FAILURE(); }
+ EXPECT_EQ(Rect(800, 800), op.unmappedBounds); // outer layer
+ } else {
+ ADD_FAILURE();
+ }
}
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
const int index = mIndex++;
@@ -998,26 +992,26 @@
EXPECT_EQ((OffscreenBuffer*)0x400, offscreenBuffer);
} else if (index == 11) {
EXPECT_EQ((OffscreenBuffer*)0x800, offscreenBuffer);
- } else { ADD_FAILURE(); }
+ } else {
+ ADD_FAILURE();
+ }
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 800, 800,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
- {
- canvas.drawRect(0, 0, 800, 800, SkPaint());
- canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
- {
- canvas.drawRect(0, 0, 400, 400, SkPaint());
- }
- canvas.restore();
- }
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 800, 800, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(0, 0, 800, 800, 128, SaveFlags::ClipToLayer);
+ {
+ canvas.drawRect(0, 0, 800, 800, SkPaint());
+ canvas.saveLayerAlpha(0, 0, 400, 400, 128, SaveFlags::ClipToLayer);
+ { canvas.drawRect(0, 0, 400, 400, SkPaint()); }
+ canvas.restore();
+ }
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 800), 800, 800, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerNestedTestRenderer renderer;
@@ -1026,21 +1020,21 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_contentRejection) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.save(SaveFlags::MatrixClip);
- canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
- canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.clipRect(200, 200, 400, 400, SkClipOp::kIntersect);
+ canvas.saveLayerAlpha(200, 200, 400, 400, 128, SaveFlags::ClipToLayer);
- // draw within save layer may still be recorded, but shouldn't be drawn
- canvas.drawRect(200, 200, 400, 400, SkPaint());
+ // draw within save layer may still be recorded, but shouldn't be drawn
+ canvas.drawRect(200, 200, 400, 400, SkPaint());
- canvas.restore();
- canvas.restore();
- });
+ canvas.restore();
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -1077,15 +1071,15 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedSimpleTestRenderer renderer;
@@ -1110,16 +1104,16 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
- 128, (SaveFlags::Flags)(0));
+ auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
+ canvas.saveLayerAlpha(10.95f, 10.5f, 189.75f, 189.25f, // values should all round out
+ 128, (SaveFlags::Flags)(0));
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
});
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedRoundTestRenderer renderer;
@@ -1162,21 +1156,21 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
- int restoreTo = canvas.save(SaveFlags::MatrixClip);
- canvas.scale(2, 2);
- canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
- canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
- canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
- canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- canvas.restoreToCount(restoreTo);
- });
+ int restoreTo = canvas.save(SaveFlags::MatrixClip);
+ canvas.scale(2, 2);
+ canvas.saveLayerAlpha(0, 0, 5, 5, 128, SaveFlags::MatrixClip);
+ canvas.saveLayerAlpha(95, 0, 100, 5, 128, SaveFlags::MatrixClip);
+ canvas.saveLayerAlpha(0, 95, 5, 100, 128, SaveFlags::MatrixClip);
+ canvas.saveLayerAlpha(95, 95, 100, 100, 128, SaveFlags::MatrixClip);
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.restoreToCount(restoreTo);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedMergedClearsTestRenderer renderer;
@@ -1209,17 +1203,17 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // save smaller than clip, so we get unclipped behavior
- canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
- canvas.drawRect(0, 0, 200, 200, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // save smaller than clip, so we get unclipped behavior
+ canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(0, 0, 200, 200, SkPaint());
+ canvas.restore();
+ });
// draw with partial screen dirty, and assert we see that rect later
- FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(50, 50, 150, 150), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedClearClipTestRenderer renderer;
@@ -1228,17 +1222,17 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_reject) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // unclipped savelayer + rect both in area that won't intersect with dirty
- canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
- canvas.drawRect(100, 100, 200, 200, SkPaint());
- canvas.restore();
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // unclipped savelayer + rect both in area that won't intersect with dirty
+ canvas.saveLayerAlpha(100, 100, 200, 200, 128, (SaveFlags::Flags)(0));
+ canvas.drawRect(100, 100, 200, 200, SkPaint());
+ canvas.restore();
+ });
// draw with partial screen dirty that doesn't intersect with savelayer
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
FailRenderer renderer;
@@ -1253,7 +1247,7 @@
class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
- EXPECT_EQ(0, mIndex++); // savelayer first
+ EXPECT_EQ(0, mIndex++); // savelayer first
return (OffscreenBuffer*)0xabcd;
}
void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1275,9 +1269,7 @@
int index = mIndex++;
EXPECT_TRUE(index == 4 || index == 10);
}
- void endLayer() override {
- EXPECT_EQ(5, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(5, mIndex++); }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(6, mIndex++);
}
@@ -1285,28 +1277,27 @@
EXPECT_EQ(9, mIndex++);
EXPECT_EQ((OffscreenBuffer*)0xabcd, *op.layerHandle);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(11, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(11, mIndex++); }
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
EXPECT_EQ(12, mIndex++);
EXPECT_EQ((OffscreenBuffer*)0xabcd, offscreenBuffer);
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 600, 600, // 500x500 triggers clipping
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 600, 600, // 500x500 triggers clipping
[](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
- canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
- canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
- canvas.drawRect(200, 200, 300, 300, SkPaint());
- canvas.restore();
- canvas.restore();
- canvas.restore();
- });
+ canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.saveLayerAlpha(100, 100, 400, 400, 128, SaveFlags::ClipToLayer); // clipped
+ canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.drawRect(200, 200, 300, 300, SkPaint());
+ canvas.restore();
+ canvas.restore();
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(600, 600), 600, 600, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
SaveLayerUnclippedComplexTestRenderer renderer;
@@ -1332,27 +1323,23 @@
EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
<< "Damage rect should be used to clip layer content";
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
EXPECT_EQ(3, mIndex++);
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(5, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(5, mIndex++); }
};
- auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
OffscreenBuffer** layerHandle = node->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would
@@ -1362,11 +1349,11 @@
auto syncedNode = TestUtils::getSyncedNode(node);
// only enqueue partial damage
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -1388,7 +1375,7 @@
class HwLayerComplexTestRenderer : public TestRendererBase {
public:
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
- EXPECT_EQ(3, mIndex++); // savelayer first
+ EXPECT_EQ(3, mIndex++); // savelayer first
return (OffscreenBuffer*)0xabcd;
}
void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1401,7 +1388,9 @@
// starting outer layer
EXPECT_EQ(200u, offscreenBuffer->viewportWidth);
EXPECT_EQ(200u, offscreenBuffer->viewportHeight);
- } else { ADD_FAILURE(); }
+ } else {
+ ADD_FAILURE();
+ }
}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
int index = mIndex++;
@@ -1411,7 +1400,9 @@
} else if (index == 7) {
// outer layer's rect (grey)
EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- } else { ADD_FAILURE(); }
+ } else {
+ ADD_FAILURE();
+ }
}
void endLayer() override {
int index = mIndex++;
@@ -1431,49 +1422,49 @@
} else if (index == 11) {
EXPECT_EQ(200u, layer->viewportWidth);
EXPECT_EQ(200u, layer->viewportHeight);
- } else { ADD_FAILURE(); }
+ } else {
+ ADD_FAILURE();
+ }
}
- void endFrame(const Rect& repaintRect) override {
- EXPECT_EQ(12, mIndex++);
- }
+ void endFrame(const Rect& repaintRect) override { EXPECT_EQ(12, mIndex++); }
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
EXPECT_EQ(13, mIndex++);
}
};
- auto child = TestUtils::createNode<RecordingCanvas>(50, 50, 150, 150,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 50, 50, 150, 150, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
OffscreenBuffer childLayer(renderThread.renderState(), Caches::getInstance(), 100, 100);
*(child->getLayerHandle()) = &childLayer;
RenderNode* childPtr = child.get();
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(0, 0, 200, 200, paint);
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [childPtr](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(0, 0, 200, 200, paint);
- canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
- canvas.drawRenderNode(childPtr);
- canvas.restore();
- });
+ canvas.saveLayerAlpha(50, 50, 150, 150, 128, SaveFlags::ClipToLayer);
+ canvas.drawRenderNode(childPtr);
+ canvas.restore();
+ });
OffscreenBuffer parentLayer(renderThread.renderState(), Caches::getInstance(), 200, 200);
*(parent->getLayerHandle()) = &parentLayer;
auto syncedNode = TestUtils::getSyncedNode(parent);
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(100, 100));
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(200, 200));
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -1486,7 +1477,6 @@
*(parent->getLayerHandle()) = nullptr;
}
-
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
class BuildLayerTestRenderer : public TestRendererBase {
public:
@@ -1505,9 +1495,7 @@
EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
<< "Damage rect should be used to clip layer content";
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
ADD_FAILURE() << "Primary frame draw not expected in this test";
}
@@ -1516,11 +1504,11 @@
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(10, 10, 110, 110,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 10, 10, 110, 110, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
OffscreenBuffer** layerHandle = node->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would
@@ -1530,7 +1518,7 @@
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
// only enqueue partial damage
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(node.get(), Rect(25, 25, 75, 75));
// Draw, but pass empty node list, so no work is done for primary frame
@@ -1552,65 +1540,69 @@
canvas->drawRect(0, 0, 100, 100, paint);
}
static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [expectedDrawOrder](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ });
node->mutateStagingProperties().setTranslationZ(z);
node->setPropertyFieldsDirty(RenderNode::TRANSLATION_Z);
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
-static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
+static void drawOrderedNode(
+ Canvas* canvas, uint8_t expectedDrawOrder,
std::function<void(RenderProperties& props, RecordingCanvas& canvas)> setup) {
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100,
[expectedDrawOrder, setup](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- if (setup) {
- setup(props, canvas);
- }
- });
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ if (setup) {
+ setup(props, canvas);
+ }
+ });
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
class ZReorderTestRenderer : public TestRendererBase {
public:
void onRectOp(const RectOp& op, const BakedOpState& state) override {
- int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
+ int expectedOrder = SkColorGetB(op.paint->getColor()); // extract order from blue channel
EXPECT_EQ(expectedOrder, mIndex++) << "An op was drawn out of order";
}
};
-} // end anonymous namespace
+} // end anonymous namespace
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, zReorder) {
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.insertReorderBarrier(false);
- drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
- drawOrderedRect(&canvas, 1);
- canvas.insertReorderBarrier(true);
- drawOrderedNode(&canvas, 6, 2.0f);
- drawOrderedRect(&canvas, 3);
- drawOrderedNode(&canvas, 4, 0.0f);
- drawOrderedRect(&canvas, 5);
- drawOrderedNode(&canvas, 2, -2.0f);
- drawOrderedNode(&canvas, 7, 2.0f);
- canvas.insertReorderBarrier(false);
- drawOrderedRect(&canvas, 8);
- drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
- canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
- drawOrderedRect(&canvas, 11);
- drawOrderedNode(&canvas, 10, -1.0f);
- canvas.insertReorderBarrier(false);
- canvas.insertReorderBarrier(true); //test with two empty reorder sections
- canvas.insertReorderBarrier(true);
- canvas.insertReorderBarrier(false);
- drawOrderedRect(&canvas, 12);
- });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
+ drawOrderedNode(&canvas, 0,
+ 10.0f); // in reorder=false at this point, so played inorder
+ drawOrderedRect(&canvas, 1);
+ canvas.insertReorderBarrier(true);
+ drawOrderedNode(&canvas, 6, 2.0f);
+ drawOrderedRect(&canvas, 3);
+ drawOrderedNode(&canvas, 4, 0.0f);
+ drawOrderedRect(&canvas, 5);
+ drawOrderedNode(&canvas, 2, -2.0f);
+ drawOrderedNode(&canvas, 7, 2.0f);
+ canvas.insertReorderBarrier(false);
+ drawOrderedRect(&canvas, 8);
+ drawOrderedNode(&canvas, 9,
+ -10.0f); // in reorder=false at this point, so played inorder
+ canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op
+ drawOrderedRect(&canvas, 11);
+ drawOrderedNode(&canvas, 10, -1.0f);
+ canvas.insertReorderBarrier(false);
+ canvas.insertReorderBarrier(true); // test with two empty reorder sections
+ canvas.insertReorderBarrier(true);
+ canvas.insertReorderBarrier(false);
+ drawOrderedRect(&canvas, 12);
+ });
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ZReorderTestRenderer renderer;
@@ -1628,28 +1620,28 @@
Matrix4 expectedMatrix;
switch (index) {
- case 0:
- EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
- EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
- expectedMatrix.loadIdentity();
- EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
- break;
- case 1:
- EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
- EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
- expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
- ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
- EXPECT_EQ(Rect(-35, -30, 45, 50),
- Rect(state.computedState.localProjectionPathMask->getBounds()));
- break;
- case 2:
- EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
- EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
- expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
- EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
- break;
- default:
- ADD_FAILURE();
+ case 0:
+ EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
+ EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
+ expectedMatrix.loadIdentity();
+ EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ break;
+ case 1:
+ EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
+ EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
+ expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
+ ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+ EXPECT_EQ(Rect(-35, -30, 45, 50),
+ Rect(state.computedState.localProjectionPathMask->getBounds()));
+ break;
+ case 2:
+ EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
+ EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
+ expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
+ EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
+ break;
+ default:
+ ADD_FAILURE();
}
EXPECT_EQ(expectedMatrix, state.computedState.transform);
}
@@ -1663,47 +1655,51 @@
* The parent is scrolled by scrollX/scrollY, but this does not affect the background
* (which isn't affected by scroll).
*/
- auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(scrollX);
- properties.setTranslationY(scrollY);
+ auto receiverBackground = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
- auto projectingRipple = TestUtils::createNode<RecordingCanvas>(50, 0, 100, 50,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(-10, -10, 60, 60, paint);
- });
- auto child = TestUtils::createNode<RecordingCanvas>(0, 50, 100, 100,
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
+ auto projectingRipple = TestUtils::createNode<RecordingCanvas>(
+ 50, 0, 100, 50, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(-10, -10, 60, 60, paint);
+ });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 0, 50, 100, 100,
[&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorBLUE);
- canvas.drawRect(0, 0, 100, 50, paint);
- canvas.drawRenderNode(projectingRipple.get());
- });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawRect(0, 0, 100, 50, paint);
+ canvas.drawRenderNode(projectingRipple.get());
+ });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- canvas.restore();
- });
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(-scrollX,
+ -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ProjectionReorderTestRenderer renderer;
@@ -1723,9 +1719,7 @@
EXPECT_EQ(1, mIndex++);
ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
@@ -1737,60 +1731,64 @@
expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
EXPECT_EQ(expected, state.computedState.transform);
EXPECT_EQ(Rect(-85, -80, 295, 300),
- Rect(state.computedState.localProjectionPathMask->getBounds()));
+ Rect(state.computedState.localProjectionPathMask->getBounds()));
}
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(5, mIndex++);
ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
}
};
- auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(scrollX);
- properties.setTranslationY(scrollY);
+ auto receiverBackground = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
- canvas.drawRect(0, 0, 400, 400, SkPaint());
- });
- auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
- });
- auto child = TestUtils::createNode<RecordingCanvas>(100, 100, 300, 300,
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+ auto projectingRipple = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+ });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 100, 100, 300, 300,
[&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.mutateLayerProperties().setType(LayerType::RenderLayer);
- canvas.drawRenderNode(projectingRipple.get());
- canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
- });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ properties.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.drawRenderNode(projectingRipple.get());
+ canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
+ });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
- canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- });
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+ canvas.translate(-scrollX,
+ -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ });
OffscreenBuffer** layerHandle = child->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would, setting windowTransform
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
Matrix4 windowTransform;
- windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
+ windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
layer.setWindowTransform(windowTransform);
*layerHandle = &layer;
auto syncedNode = TestUtils::getSyncedNode(parent);
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -1819,37 +1817,41 @@
EXPECT_TRUE(state.computedState.transform.isIdentity());
}
};
- auto receiverBackground = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- canvas.drawRect(0, 0, 400, 400, SkPaint());
- });
- auto projectingRipple = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& properties, RecordingCanvas& canvas) {
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(scrollX);
- properties.setTranslationY(scrollY);
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(0, 0, 200, 200, SkPaint());
- });
- auto child = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ auto receiverBackground = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setProjectionReceiver(true);
+ canvas.drawRect(0, 0, 400, 400, SkPaint());
+ });
+ auto projectingRipple = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& properties, RecordingCanvas& canvas) {
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(scrollX);
+ properties.setTranslationY(scrollY);
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(0, 0, 200, 200, SkPaint());
+ });
+ auto child = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400,
[&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
- // Record time clip will be ignored by projectee
- canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
+ // Record time clip will be ignored by projectee
+ canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
- canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(projectingRipple.get());
- });
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 400, 400,
+ canvas.translate(-scrollX,
+ -scrollY); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(projectingRipple.get());
+ });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 400, 400,
[&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- });
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(400, 400), 400, 400, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ProjectionChildScrollTestRenderer renderer;
@@ -1859,14 +1861,14 @@
// creates a 100x100 shadow casting node with provided translationZ
static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
- return TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setTranslationZ(translationZ);
- properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ return TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [translationZ](RenderProperties& properties, RecordingCanvas& canvas) {
+ properties.setTranslationZ(translationZ);
+ properties.mutableOutline().setRoundRect(0, 0, 100, 100, 0.0f, 1.0f);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) {
@@ -1887,14 +1889,14 @@
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowTestRenderer renderer;
@@ -1917,9 +1919,7 @@
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endLayer() override {
- EXPECT_EQ(3, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(3, mIndex++); }
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
@@ -1928,19 +1928,20 @@
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // save/restore outside of reorderBarrier, so they don't get moved out of place
- canvas.translate(20, 10);
- int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- canvas.insertReorderBarrier(false);
- canvas.restoreToCount(count);
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // save/restore outside of reorderBarrier, so they don't get moved out of place
+ canvas.translate(20, 10);
+ int count = canvas.saveLayerAlpha(30, 50, 130, 150, 128, SaveFlags::ClipToLayer);
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ canvas.insertReorderBarrier(false);
+ canvas.restoreToCount(count);
+ });
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 50},
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowSaveLayerTestRenderer renderer;
@@ -1963,38 +1964,37 @@
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(2, mIndex++);
}
- void endLayer() override {
- EXPECT_EQ(3, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(3, mIndex++); }
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(4, mIndex++);
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(50, 60, 150, 160,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- props.mutateLayerProperties().setType(LayerType::RenderLayer);
- canvas.insertReorderBarrier(true);
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(20, 10);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- canvas.restore();
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 50, 60, 150, 160, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.mutateLayerProperties().setType(LayerType::RenderLayer);
+ canvas.insertReorderBarrier(true);
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(20, 10);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ canvas.restore();
+ });
OffscreenBuffer** layerHandle = parent->getLayerHandle();
// create RenderNode's layer here in same way prepareTree would, setting windowTransform
OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 100, 100);
Matrix4 windowTransform;
- windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
+ windowTransform.loadTranslate(50, 60, 0); // total transform of layer's origin
layer.setWindowTransform(windowTransform);
*layerHandle = &layer;
auto syncedNode = TestUtils::getSyncedNode(parent);
- LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+ LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 30}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 30},
+ Caches::getInstance());
frameBuilder.deferLayers(layerUpdateQueue);
frameBuilder.deferRenderNode(*syncedNode);
@@ -2018,14 +2018,15 @@
EXPECT_TRUE(index == 2 || index == 3);
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0001f).get());
+ });
FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 50},
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowLayeringTestRenderer renderer;
@@ -2045,17 +2046,18 @@
EXPECT_EQ(1, mIndex++);
}
};
- auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- // Apply a clip before the reorder barrier/shadow casting child is drawn.
- // This clip must be applied to the shadow cast by the child.
- canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
- canvas.insertReorderBarrier(true);
- canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
- });
+ auto parent = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ // Apply a clip before the reorder barrier/shadow casting child is drawn.
+ // This clip must be applied to the shadow cast by the child.
+ canvas.clipRect(25, 25, 75, 75, SkClipOp::kIntersect);
+ canvas.insertReorderBarrier(true);
+ canvas.drawRenderNode(createWhiteRectShadowCaster(5.0f).get());
+ });
FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- (FrameBuilder::LightGeometry) {{ 100, 100, 100 }, 50}, Caches::getInstance());
+ (FrameBuilder::LightGeometry){{100, 100, 100}, 50},
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(parent));
ShadowClippingTestRenderer renderer;
@@ -2063,11 +2065,13 @@
EXPECT_EQ(2, renderer.getIndex());
}
-static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
+static void testProperty(
+ std::function<void(RenderProperties&)> propSetupCallback,
std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
class PropertyTestRenderer : public TestRendererBase {
public:
- explicit PropertyTestRenderer(std::function<void(const RectOp&, const BakedOpState&)> callback)
+ explicit PropertyTestRenderer(
+ std::function<void(const RectOp&, const BakedOpState&)> callback)
: mCallback(callback) {}
void onRectOp(const RectOp& op, const BakedOpState& state) override {
EXPECT_EQ(mIndex++, 0);
@@ -2076,16 +2080,16 @@
std::function<void(const RectOp&, const BakedOpState&)> mCallback;
};
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
- propSetupCallback(props);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [propSetupCallback](RenderProperties& props, RecordingCanvas& canvas) {
+ propSetupCallback(props);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
PropertyTestRenderer renderer(opValidateCallback);
@@ -2094,78 +2098,89 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
- testProperty([](RenderProperties& properties) {
- properties.setAlpha(0.5f);
- properties.setHasOverlappingRendering(false);
- }, [](const RectOp& op, const BakedOpState& state) {
- EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setAlpha(0.5f);
+ properties.setHasOverlappingRendering(false);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ EXPECT_EQ(0.5f, state.alpha) << "Alpha should be applied directly to op";
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropClipping) {
- testProperty([](RenderProperties& properties) {
- properties.setClipToBounds(true);
- properties.setClipBounds(Rect(10, 20, 300, 400));
- }, [](const RectOp& op, const BakedOpState& state) {
- EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
- << "Clip rect should be intersection of node bounds and clip bounds";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setClipToBounds(true);
+ properties.setClipBounds(Rect(10, 20, 300, 400));
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ EXPECT_EQ(Rect(10, 20, 100, 100), state.computedState.clippedBounds)
+ << "Clip rect should be intersection of node bounds and clip bounds";
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropRevealClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableRevealClip().set(true, 50, 50, 25);
- }, [](const RectOp& op, const BakedOpState& state) {
- ASSERT_NE(nullptr, state.roundRectClipState);
- EXPECT_TRUE(state.roundRectClipState->highPriority);
- EXPECT_EQ(25, state.roundRectClipState->radius);
- EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableRevealClip().set(true, 50, 50, 25);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ ASSERT_NE(nullptr, state.roundRectClipState);
+ EXPECT_TRUE(state.roundRectClipState->highPriority);
+ EXPECT_EQ(25, state.roundRectClipState->radius);
+ EXPECT_EQ(Rect(50, 50, 50, 50), state.roundRectClipState->innerRect);
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOutlineClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableOutline().setShouldClip(true);
- properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
- }, [](const RectOp& op, const BakedOpState& state) {
- ASSERT_NE(nullptr, state.roundRectClipState);
- EXPECT_FALSE(state.roundRectClipState->highPriority);
- EXPECT_EQ(5, state.roundRectClipState->radius);
- EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableOutline().setShouldClip(true);
+ properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ ASSERT_NE(nullptr, state.roundRectClipState);
+ EXPECT_FALSE(state.roundRectClipState->highPriority);
+ EXPECT_EQ(5, state.roundRectClipState->radius);
+ EXPECT_EQ(Rect(15, 25, 25, 35), state.roundRectClipState->innerRect);
+ });
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropTransform) {
- testProperty([](RenderProperties& properties) {
- properties.setLeftTopRightBottom(10, 10, 110, 110);
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setLeftTopRightBottom(10, 10, 110, 110);
- SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
- properties.setStaticMatrix(&staticMatrix);
+ SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
+ properties.setStaticMatrix(&staticMatrix);
- // ignored, since static overrides animation
- SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
- properties.setAnimationMatrix(&animationMatrix);
+ // ignored, since static overrides animation
+ SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
+ properties.setAnimationMatrix(&animationMatrix);
- properties.setTranslationX(10);
- properties.setTranslationY(20);
- properties.setScaleX(0.5f);
- properties.setScaleY(0.7f);
- }, [](const RectOp& op, const BakedOpState& state) {
- Matrix4 matrix;
- matrix.loadTranslate(10, 10, 0); // left, top
- matrix.scale(1.2f, 1.2f, 1); // static matrix
- // ignore animation matrix, since static overrides it
+ properties.setTranslationX(10);
+ properties.setTranslationY(20);
+ properties.setScaleX(0.5f);
+ properties.setScaleY(0.7f);
+ },
+ [](const RectOp& op, const BakedOpState& state) {
+ Matrix4 matrix;
+ matrix.loadTranslate(10, 10, 0); // left, top
+ matrix.scale(1.2f, 1.2f, 1); // static matrix
+ // ignore animation matrix, since static overrides it
- // translation xy
- matrix.translate(10, 20);
+ // translation xy
+ matrix.translate(10, 20);
- // scale xy (from default pivot - center)
- matrix.translate(50, 50);
- matrix.scale(0.5f, 0.7f, 1);
- matrix.translate(-50, -50);
- EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
- << "Op draw matrix must match expected combination of transformation properties";
- });
+ // scale xy (from default pivot - center)
+ matrix.translate(50, 50);
+ matrix.scale(0.5f, 0.7f, 1);
+ matrix.translate(-50, -50);
+ EXPECT_MATRIX_APPROX_EQ(matrix, state.computedState.transform)
+ << "Op draw matrix must match expected combination of transformation "
+ "properties";
+ });
}
struct SaveLayerAlphaData {
@@ -2186,11 +2201,10 @@
* (for efficiency, and to fit in layer size constraints) based on parent clip.
*/
void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
- std::function<void(RenderProperties&)> propSetupCallback) {
+ std::function<void(RenderProperties&)> propSetupCallback) {
class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
public:
- explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
- : mOutData(outData) {}
+ explicit SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData) : mOutData(outData) {}
OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
EXPECT_EQ(0, mIndex++);
@@ -2204,9 +2218,7 @@
mOutData->rectClippedBounds = state.computedState.clippedBounds;
mOutData->rectMatrix = state.computedState.transform;
}
- void endLayer() override {
- EXPECT_EQ(2, mIndex++);
- }
+ void endLayer() override { EXPECT_EQ(2, mIndex++); }
void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
EXPECT_EQ(3, mIndex++);
mOutData->drawLayerMatrix = state.computedState.transform;
@@ -2214,27 +2226,29 @@
void recycleTemporaryLayer(OffscreenBuffer* offscreenBuffer) override {
EXPECT_EQ(4, mIndex++);
}
+
private:
SaveLayerAlphaData* mOutData;
};
ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
<< "Node must be bigger than max texture size to exercise saveLayer codepath";
- auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 10000, 10000,
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 10000, 10000,
[&propSetupCallback](RenderProperties& properties, RecordingCanvas& canvas) {
- properties.setHasOverlappingRendering(true);
- properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
- // apply other properties
- propSetupCallback(properties);
+ properties.setHasOverlappingRendering(true);
+ properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
+ // apply other properties
+ propSetupCallback(properties);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 10000, 10000, paint);
- });
- auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 10000, 10000, paint);
+ });
+ auto syncedNode = TestUtils::getSyncedNode(node); // sync before querying height
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*syncedNode);
SaveLayerAlphaClipTestRenderer renderer(outObservedData);
@@ -2247,8 +2261,8 @@
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
SaveLayerAlphaData observedData;
testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
- properties.setTranslationX(10); // offset rendering content
- properties.setTranslationY(-2000); // offset rendering content
+ properties.setTranslationX(10); // offset rendering content
+ properties.setTranslationY(-2000); // offset rendering content
});
EXPECT_EQ(190u, observedData.layerWidth);
EXPECT_EQ(200u, observedData.layerHeight);
@@ -2260,7 +2274,7 @@
<< "expect content to be translated as part of being clipped";
expected.loadTranslate(10, 0, 0);
EXPECT_MATRIX_APPROX_EQ(expected, observedData.drawLayerMatrix)
- << "expect drawLayer to be translated as part of being clipped";
+ << "expect drawLayer to be translated as part of being clipped";
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
@@ -2306,14 +2320,14 @@
<< "Expect resolved clip to be intersection of viewport clip and clip op";
}
};
- auto node = TestUtils::createNode<RecordingCanvas>(20, 20, 30, 30,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto node = TestUtils::createNode<RecordingCanvas>(
+ 20, 20, 30, 30, [](RenderProperties& props, RecordingCanvas& canvas) {
+ canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
- FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeLTRB(10, 10, 40, 40), 50, 50, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
ClipReplaceTestRenderer renderer;
@@ -2329,21 +2343,22 @@
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2360,22 +2375,24 @@
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 2
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //drawn as 3
- props.setProjectionReceiver(true);
- } ); //nodeE
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // drawn as 2
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // drawn as 3
+ props.setProjectionReceiver(true);
+ }); // nodeE
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2391,20 +2408,21 @@
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) {
- //not having a projection receiver is an undefined behavior
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 255,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // not having a projection receiver is an undefined behavior
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2420,20 +2438,21 @@
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2442,21 +2461,23 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) {
- //having a node that is projected on itself is an undefined/unexpected behavior
- props.setProjectionReceiver(true);
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 255,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ // having a node that is projected on itself is an
+ // undefined/unexpected behavior
+ props.setProjectionReceiver(true);
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2465,9 +2486,9 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) {
- //TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
- //bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
- //tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
+ // TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
+ // bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
+ // tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
/* R is backward projected on B. R is not expected to be drawn (see Sibling2 outcome below),
but for some reason it is drawn.
A
@@ -2475,21 +2496,21 @@
/ | \
B C R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- } ); //nodeC
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) {}); // nodeC
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2506,23 +2527,27 @@
/ | \
B C R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- } ); //nodeC
- drawOrderedNode(&canvas, 255, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeG
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // G
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // C
+ }); // nodeC
+ drawOrderedNode(&canvas, 255,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeG
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2540,21 +2565,23 @@
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectionReceiver(true);
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- } ); //nodeB
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) {
+ props.setProjectionReceiver(true);
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeB
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2570,24 +2597,28 @@
/ \
G R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2603,24 +2634,28 @@
/ \
G R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeG
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeG
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // R
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2638,26 +2673,31 @@
|
R
*/
- auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
- [](RenderProperties& props, RecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, RecordingCanvas& canvas) { //B
- props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, RecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, RecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { //D
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, RecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeD
- } ); //nodeC
- }); //nodeA
+ auto nodeA = TestUtils::createNode<RecordingCanvas>(
+ 0, 0, 100, 100, [](RenderProperties& props, RecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // B
+ props.setProjectionReceiver(true);
+ }); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, RecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(
+ &canvas, 4, [](RenderProperties& props, RecordingCanvas& canvas) { // D
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ RecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeD
+ }); // nodeC
+ }); // nodeA
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometry, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometry,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(nodeA));
ZReorderTestRenderer renderer;
@@ -2665,5 +2705,5 @@
EXPECT_EQ(5, renderer.getIndex());
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index caeb6bf..c8bfc99 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -28,8 +28,7 @@
static void expectFillEq(Glop::Fill& expectedFill, Glop::Fill& builtFill) {
EXPECT_EQ(expectedFill.colorEnabled, builtFill.colorEnabled);
- if (expectedFill.colorEnabled)
- EXPECT_EQ(expectedFill.color, builtFill.color);
+ if (expectedFill.colorEnabled) EXPECT_EQ(expectedFill.color, builtFill.color);
EXPECT_EQ(expectedFill.filterMode, builtFill.filterMode);
if (expectedFill.filterMode == ProgramDescription::ColorFilterMode::Blend) {
@@ -38,15 +37,15 @@
Glop::Fill::Filter::Matrix& expectedMatrix = expectedFill.filter.matrix;
Glop::Fill::Filter::Matrix& builtMatrix = expectedFill.filter.matrix;
EXPECT_TRUE(std::memcmp(expectedMatrix.matrix, builtMatrix.matrix,
- sizeof(Glop::Fill::Filter::Matrix::matrix)));
+ sizeof(Glop::Fill::Filter::Matrix::matrix)));
EXPECT_TRUE(std::memcmp(expectedMatrix.vector, builtMatrix.vector,
- sizeof(Glop::Fill::Filter::Matrix::vector)));
+ sizeof(Glop::Fill::Filter::Matrix::vector)));
}
EXPECT_EQ(expectedFill.skiaShaderData.skiaShaderType, builtFill.skiaShaderData.skiaShaderType);
EXPECT_EQ(expectedFill.texture.clamp, builtFill.texture.clamp);
EXPECT_EQ(expectedFill.texture.filter, builtFill.texture.filter);
- EXPECT_TRUE((expectedFill.texture.texture && builtFill.texture.texture)
- || (!expectedFill.texture.texture && !builtFill.texture.texture));
+ EXPECT_TRUE((expectedFill.texture.texture && builtFill.texture.texture) ||
+ (!expectedFill.texture.texture && !builtFill.texture.texture));
if (expectedFill.texture.texture) {
EXPECT_EQ(expectedFill.texture.texture->target(), builtFill.texture.texture->target());
}
@@ -97,22 +96,23 @@
static std::unique_ptr<Glop> blackUnitQuadGlop(RenderState& renderState) {
std::unique_ptr<Glop> glop(new Glop());
- glop->blend = { GL_ZERO, GL_ZERO };
+ glop->blend = {GL_ZERO, GL_ZERO};
glop->mesh.elementCount = 4;
glop->mesh.primitiveMode = GL_TRIANGLE_STRIP;
glop->mesh.indices.indices = nullptr;
glop->mesh.indices.bufferObject = GL_ZERO;
- glop->mesh.vertices = {
- renderState.meshState().getUnitQuadVBO(),
- VertexAttribFlags::None,
- nullptr, nullptr, nullptr,
- kTextureVertexStride };
+ glop->mesh.vertices = {renderState.meshState().getUnitQuadVBO(),
+ VertexAttribFlags::None,
+ nullptr,
+ nullptr,
+ nullptr,
+ kTextureVertexStride};
glop->transform.modelView.loadIdentity();
glop->fill.colorEnabled = true;
glop->fill.color.set(Color::Black);
glop->fill.skiaShaderData.skiaShaderType = kNone_SkiaShaderType;
glop->fill.filterMode = ProgramDescription::ColorFilterMode::None;
- glop->fill.texture = { nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr };
+ glop->fill.texture = {nullptr, GL_INVALID_ENUM, GL_INVALID_ENUM, nullptr};
return glop;
}
diff --git a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
index 8cbd24e..9bfb082 100644
--- a/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
+++ b/libs/hwui/tests/unit/GpuMemoryTrackerTests.cpp
@@ -14,9 +14,8 @@
* limitations under the License.
*/
-
-#include <gtest/gtest.h>
#include <GpuMemoryTracker.h>
+#include <gtest/gtest.h>
#include "renderthread/EglManager.h"
#include "renderthread/RenderThread.h"
@@ -32,9 +31,7 @@
public:
TestGPUObject() : GpuMemoryTracker(GpuObjectType::Texture) {}
- void changeSize(int newSize) {
- notifySizeChanged(newSize);
- }
+ void changeSize(int newSize) { notifySizeChanged(newSize); }
};
// Other tests may have created a renderthread and EGL context.
@@ -42,9 +39,7 @@
// current thread can spoof being a GPU thread
static void destroyEglContext() {
if (TestUtils::isRenderThreadRunning()) {
- TestUtils::runOnRenderThread([](RenderThread& thread) {
- thread.eglManager().destroy();
- });
+ TestUtils::runOnRenderThread([](RenderThread& thread) { thread.eglManager().destroy(); });
}
}
diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp
index a3b346f..6710c71 100644
--- a/libs/hwui/tests/unit/GradientCacheTests.cpp
+++ b/libs/hwui/tests/unit/GradientCacheTests.cpp
@@ -28,12 +28,12 @@
GradientCache cache(extensions);
ASSERT_LT(1000u, cache.getMaxSize()) << "Expect non-trivial size";
- SkColor colors[] = { 0xFF00FF00, 0xFFFF0000, 0xFF0000FF };
- float positions[] = { 1, 2, 3 };
+ SkColor colors[] = {0xFF00FF00, 0xFFFF0000, 0xFF0000FF};
+ float positions[] = {1, 2, 3};
Texture* texture = cache.get(colors, positions, 3);
ASSERT_TRUE(texture);
ASSERT_FALSE(texture->cleanup);
- ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize());
+ ASSERT_EQ((uint32_t)texture->objectSize(), cache.getSize());
ASSERT_TRUE(cache.getSize());
cache.clear();
ASSERT_EQ(cache.getSize(), 0u);
diff --git a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
index fda3a79..30c3b4e 100644
--- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
+++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
@@ -20,10 +20,10 @@
#include <frameworks/base/core/proto/android/service/graphicsstats.pb.h>
-#include <sys/types.h>
-#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <unistd.h>
using namespace android;
@@ -35,8 +35,8 @@
// < 1023 because we need room for the null terminator
if (r <= 0 || r > 1023) {
int err = errno;
- fprintf(stderr, "Failed to read from /proc/self/exe; r=%zd, err=%d (%s)\n",
- r, err, strerror(err));
+ fprintf(stderr, "Failed to read from /proc/self/exe; r=%zd, err=%d (%s)\n", r, err,
+ strerror(err));
exit(EXIT_FAILURE);
}
while (--r > 0) {
@@ -88,8 +88,8 @@
EXPECT_EQ(20, loadedProto.summary().janky_frames());
EXPECT_EQ(100, loadedProto.summary().total_frames());
EXPECT_EQ(mockData.editFrameCounts().size() + mockData.editSlowFrameCounts().size(),
- (size_t) loadedProto.histogram_size());
- for (size_t i = 0; i < (size_t) loadedProto.histogram_size(); i++) {
+ (size_t)loadedProto.histogram_size());
+ for (size_t i = 0; i < (size_t)loadedProto.histogram_size(); i++) {
int expectedCount, expectedBucket;
if (i < mockData.editFrameCounts().size()) {
expectedCount = ((i % 10) + 1) * 2;
@@ -144,8 +144,8 @@
EXPECT_EQ(20 + 50, loadedProto.summary().janky_frames());
EXPECT_EQ(100 + 500, loadedProto.summary().total_frames());
EXPECT_EQ(mockData.editFrameCounts().size() + mockData.editSlowFrameCounts().size(),
- (size_t) loadedProto.histogram_size());
- for (size_t i = 0; i < (size_t) loadedProto.histogram_size(); i++) {
+ (size_t)loadedProto.histogram_size());
+ for (size_t i = 0; i < (size_t)loadedProto.histogram_size(); i++) {
int expectedCount, expectedBucket;
if (i < mockData.editFrameCounts().size()) {
expectedCount = ((i % 10) + 1) * 2;
diff --git a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
index 91c7514..217d63f 100644
--- a/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
+++ b/libs/hwui/tests/unit/LayerUpdateQueueTests.cpp
@@ -51,9 +51,9 @@
EXPECT_EQ(a.get(), queue.entries()[0].renderNode.get());
EXPECT_EQ(Rect(25, 25, 75, 75), queue.entries()[0].damage);
EXPECT_EQ(b.get(), queue.entries()[1].renderNode.get());
- EXPECT_EQ(Rect(100, 100, 200, 200), queue.entries()[1].damage); // clipped to bounds
+ EXPECT_EQ(Rect(100, 100, 200, 200), queue.entries()[1].damage); // clipped to bounds
EXPECT_EQ(c.get(), queue.entries()[2].renderNode.get());
- EXPECT_EQ(Rect(0, 0, 1, 1), queue.entries()[2].damage); // rounded out
+ EXPECT_EQ(Rect(0, 0, 1, 1), queue.entries()[2].damage); // rounded out
}
TEST(LayerUpdateQueue, enqueueUnion) {
@@ -81,6 +81,5 @@
EXPECT_TRUE(queue.entries().empty());
}
-
};
};
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 19d7ef5..20ec084 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "BakedOpRenderer.h"
#include "BakedOpDispatcher.h"
+#include "BakedOpRenderer.h"
#include "FrameBuilder.h"
#include "LayerUpdateQueue.h"
#include "RecordingCanvas.h"
@@ -26,12 +26,11 @@
using namespace android;
using namespace android::uirenderer;
-const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
-const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
+const FrameBuilder::LightGeometry sLightGeometery = {{100, 100, 100}, 50};
+const BakedOpRenderer::LightInfo sLightInfo = {128, 128};
RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayer_overdrawRejection) {
- auto node = TestUtils::createNode(0, 0, 100, 100,
- [](RenderProperties& props, Canvas& canvas) {
+ auto node = TestUtils::createNode(0, 0, 100, 100, [](RenderProperties& props, Canvas& canvas) {
canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
canvas.drawRect(0, 0, 100, 100, SkPaint());
canvas.restore();
@@ -42,16 +41,15 @@
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
- FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100,
- sLightGeometery, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(100, 100), 100, 100, sLightGeometery,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayerUnclipped_simple) {
- auto node = TestUtils::createNode(0, 0, 200, 200,
- [](RenderProperties& props, Canvas& canvas) {
+ auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, Canvas& canvas) {
canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
canvas.drawRect(0, 0, 200, 200, SkPaint());
canvas.restore();
@@ -59,8 +57,8 @@
RenderState& renderState = renderThread.renderState();
Caches& caches = Caches::getInstance();
- FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200,
- sLightGeometery, Caches::getInstance());
+ FrameBuilder frameBuilder(SkRect::MakeWH(200, 200), 200, 200, sLightGeometery,
+ Caches::getInstance());
frameBuilder.deferRenderNode(*TestUtils::getSyncedNode(node));
BakedOpRenderer renderer(caches, renderState, true, false, sLightInfo);
frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index ffcbf12..1038da3 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -43,7 +43,7 @@
}
TEST(LinearAllocator, dtor) {
- int destroyed[10] = { 0 };
+ int destroyed[10] = {0};
{
LinearAllocator la;
for (int i = 0; i < 5; i++) {
@@ -111,7 +111,6 @@
EXPECT_LT(lastLocation, &v[0]);
EXPECT_GT(lastLocation + 20, &v[0]);
-
}
TEST(LsaVector, dtorCheck) {
@@ -126,7 +125,7 @@
vector.emplace_back(new TestUtils::SignalingDtor(&destroyed));
}
EXPECT_EQ(0, destroyed);
- EXPECT_EQ(size, (int) vector.size());
+ EXPECT_EQ(size, (int)vector.size());
}
EXPECT_EQ(size, destroyed);
}
diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp
index eddab87..16a396e 100644
--- a/libs/hwui/tests/unit/MatrixTests.cpp
+++ b/libs/hwui/tests/unit/MatrixTests.cpp
@@ -32,8 +32,7 @@
ASSERT_TRUE(empty.isEmpty());
scaleMatrix.mapRect(empty);
EXPECT_EQ(Rect(170, 215, 250, 1015), empty);
- EXPECT_FALSE(empty.isEmpty())
- << "Empty 'line' rect doesn't remain empty when skewed.";
+ EXPECT_FALSE(empty.isEmpty()) << "Empty 'line' rect doesn't remain empty when skewed.";
}
TEST(Matrix, mapRect_emptyRotate) {
@@ -45,6 +44,5 @@
Rect lineRect(0, 100);
ASSERT_TRUE(lineRect.isEmpty());
skewMatrix.mapRect(lineRect);
- EXPECT_FALSE(lineRect.isEmpty())
- << "Empty 'line' rect doesn't remain empty when rotated.";
+ EXPECT_FALSE(lineRect.isEmpty()) << "Empty 'line' rect doesn't remain empty when rotated.";
}
diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp
index 511d6d2..1573fd3 100644
--- a/libs/hwui/tests/unit/MeshStateTests.cpp
+++ b/libs/hwui/tests/unit/MeshStateTests.cpp
@@ -16,8 +16,8 @@
#include <debug/MockGlesDriver.h>
#include <debug/ScopedReplaceDriver.h>
-#include <gtest/gtest.h>
#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <renderstate/MeshState.h>
#include <tests/common/TestUtils.h>
@@ -32,5 +32,6 @@
EXPECT_CALL(mockGlDriver, glBufferData_(_, _, _, _));
GLuint buffer = 0;
- renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, GL_DYNAMIC_DRAW);
+ renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr,
+ GL_DYNAMIC_DRAW);
}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index 308fef3..0d47367 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <Rect.h>
+#include <gtest/gtest.h>
#include <renderstate/OffscreenBufferPool.h>
#include <tests/common/TestUtils.h>
@@ -56,12 +56,10 @@
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) {
OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
- EXPECT_EQ(Rect(0, 1, 1, 0),
- layerAligned.getTextureCoordinates());
+ EXPECT_EQ(Rect(0, 1, 1, 0), layerAligned.getTextureCoordinates());
OffscreenBuffer layerUnaligned(renderThread.renderState(), Caches::getInstance(), 200u, 225u);
- EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0),
- layerUnaligned.getTextureCoordinates());
+ EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0), layerUnaligned.getTextureCoordinates());
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, dirty) {
@@ -221,7 +219,7 @@
auto hugeLayer = pool.get(renderThread.renderState(), pool.getMaxSize() / 64, 64);
EXPECT_GT(hugeLayer->getSizeInBytes(), pool.getMaxSize());
pool.putOrDelete(hugeLayer);
- EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
+ EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) {
@@ -244,4 +242,3 @@
EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
}
-
diff --git a/libs/hwui/tests/unit/OpDumperTests.cpp b/libs/hwui/tests/unit/OpDumperTests.cpp
index 01840d7..ef30e87 100644
--- a/libs/hwui/tests/unit/OpDumperTests.cpp
+++ b/libs/hwui/tests/unit/OpDumperTests.cpp
@@ -16,8 +16,8 @@
#include <gtest/gtest.h>
-#include "tests/common/TestUtils.h"
#include "OpDumper.h"
+#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
diff --git a/libs/hwui/tests/unit/PathInterpolatorTests.cpp b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
index d7cb23a..d888012 100644
--- a/libs/hwui/tests/unit/PathInterpolatorTests.cpp
+++ b/libs/hwui/tests/unit/PathInterpolatorTests.cpp
@@ -37,55 +37,36 @@
{0.0f, 0.2f, 0.4f, 0.6f, 0.8f, 1.0f},
},
- {
- {
- 0.0f, 0.5f, 0.5178955f, 0.5341797f, 0.5489991f, 0.5625f, 0.5748291f,
- 0.5861328f, 0.60625005f, 0.62402344f, 0.640625f, 0.675f, 0.6951172f,
- 0.71875f, 0.7470703f, 0.78125f, 0.82246095f, 0.84606934f, 0.871875f,
- 0.9000244f, 0.93066406f, 0.96394044f, 1.0f
- },
- {
- 0.0f, 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f,
- 0.06561279f, 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f,
- 0.5932617f, 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f,
- 0.95703125f, 0.97528076f, 0.98876953f, 0.99713135f, 1.0f
- },
- {
- 0.0f, 0.03375840187072754f, 0.13503384590148926f, 0.23630905151367188f,
- 0.336834192276001f, 0.4508626461029053f, 0.564141035079956f,
- 0.6781694889068604f, 0.7921979427337646f, 0.9054763317108154f, 1.0f
- },
- {
- 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0459827296435833f,
- 0.5146934390068054f, 0.8607426285743713f, 0.9776809215545654f, 1.0f
+ {{0.0f, 0.5f, 0.5178955f, 0.5341797f, 0.5489991f, 0.5625f,
+ 0.5748291f, 0.5861328f, 0.60625005f, 0.62402344f, 0.640625f, 0.675f,
+ 0.6951172f, 0.71875f, 0.7470703f, 0.78125f, 0.82246095f, 0.84606934f,
+ 0.871875f, 0.9000244f, 0.93066406f, 0.96394044f, 1.0f},
+ {0.0f, 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f,
+ 0.06561279f, 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f,
+ 0.5932617f, 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f,
+ 0.95703125f, 0.97528076f, 0.98876953f, 0.99713135f, 1.0f},
+ {0.0f, 0.03375840187072754f, 0.13503384590148926f, 0.23630905151367188f,
+ 0.336834192276001f, 0.4508626461029053f, 0.564141035079956f, 0.6781694889068604f,
+ 0.7921979427337646f, 0.9054763317108154f, 1.0f},
+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0459827296435833f, 0.5146934390068054f,
+ 0.8607426285743713f, 0.9776809215545654f, 1.0f
- }
+ }
},
- {
- {
- 0.0f, 0.017895509f, 0.034179688f, 0.048999026f, 0.0625f, 0.0748291f,
- 0.08613282f, 0.10625f, 0.12402344f, 0.140625f, 0.17500001f, 0.19511719f,
- 0.21875f, 0.24707031f, 0.28125f, 0.32246095f, 0.34606934f, 0.371875f,
- 0.4000244f, 0.43066406f, 0.46394044f, 0.5f, 1.0f
- },
- {
- 0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f, 0.06561279f,
- 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f, 0.5932617f,
- 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f, 0.95703125f,
- 0.97528076f, 0.98876953f, 0.99713135f, 1.0f, 1.0f
- },
- {
- 0.0f, 0.102020263671875f, 0.20330810546875f, 0.3165740966796875f,
- 0.43060302734375f, 0.5318756103515625f, 0.6331634521484375f,
- 0.746429443359375f, 0.84771728515625f, 0.9617462158203125f, 1.0f
- },
- {
- 0.0f, 0.14280107617378235f, 0.6245699524879456f, 0.8985776901245117f,
- 0.9887426495552063f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f
- }
- },
-
+ {{0.0f, 0.017895509f, 0.034179688f, 0.048999026f, 0.0625f, 0.0748291f,
+ 0.08613282f, 0.10625f, 0.12402344f, 0.140625f, 0.17500001f, 0.19511719f,
+ 0.21875f, 0.24707031f, 0.28125f, 0.32246095f, 0.34606934f, 0.371875f,
+ 0.4000244f, 0.43066406f, 0.46394044f, 0.5f, 1.0f},
+ {0.0f, 0.0028686523f, 0.011230469f, 0.024719238f, 0.04296875f, 0.06561279f,
+ 0.092285156f, 0.15625f, 0.2319336f, 0.31640625f, 0.5f, 0.5932617f,
+ 0.68359375f, 0.7680664f, 0.84375f, 0.90771484f, 0.9343872f, 0.95703125f,
+ 0.97528076f, 0.98876953f, 0.99713135f, 1.0f, 1.0f},
+ {0.0f, 0.102020263671875f, 0.20330810546875f, 0.3165740966796875f, 0.43060302734375f,
+ 0.5318756103515625f, 0.6331634521484375f, 0.746429443359375f, 0.84771728515625f,
+ 0.9617462158203125f, 1.0f},
+ {0.0f, 0.14280107617378235f, 0.6245699524879456f, 0.8985776901245117f, 0.9887426495552063f,
+ 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f}},
};
@@ -98,13 +79,12 @@
}
TEST(Interpolator, pathInterpolation) {
- for (const TestData& data: sTestDataSet) {
+ for (const TestData& data : sTestDataSet) {
PathInterpolator interpolator(getX(data), getY(data));
for (size_t i = 0; i < data.inFraction.size(); i++) {
EXPECT_FLOAT_EQ(data.outFraction[i], interpolator.interpolate(data.inFraction[i]));
}
}
}
-
}
}
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index dab1f89..5aae15f 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -32,7 +32,7 @@
namespace uirenderer {
static void playbackOps(const DisplayList& displayList,
- std::function<void(const RecordedOp&)> opReceiver) {
+ std::function<void(const RecordedOp&)> opReceiver) {
for (auto& chunk : displayList.getChunks()) {
for (size_t opIndex = chunk.beginOpIndex; opIndex < chunk.endOpIndex; opIndex++) {
RecordedOp* op = displayList.getOps()[opIndex];
@@ -42,7 +42,7 @@
}
static void validateSingleOp(std::unique_ptr<DisplayList>& dl,
- std::function<void(const RecordedOp& op)> opValidator) {
+ std::function<void(const RecordedOp& op)> opValidator) {
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
opValidator(*(dl->getOps()[0]));
}
@@ -82,7 +82,7 @@
canvas.save(SaveFlags::MatrixClip);
canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
canvas.clipRect(100, 100, 200, 200, SkClipOp::kIntersect);
- canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
+ canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
canvas.restore();
});
ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
@@ -120,16 +120,16 @@
EXPECT_EQ(RecordedOpId::ArcOp, ops[0]->opId);
EXPECT_EQ(Rect(200, 200), ops[0]->unmappedBounds);
- EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId)
- << "Circular arcs should be converted to ovals";
+ EXPECT_EQ(RecordedOpId::OvalOp, ops[1]->opId) << "Circular arcs should be converted to ovals";
EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawLines) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
SkPaint paint;
- paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
- float points[] = { 0, 0, 20, 10, 30, 40, 90 }; // NB: only 1 valid line
+ paint.setStrokeWidth(
+ 20); // doesn't affect recorded bounds - would be resolved at bake time
+ float points[] = {0, 0, 20, 10, 30, 40, 90}; // NB: only 1 valid line
canvas.drawLines(&points[0], 7, paint);
});
@@ -143,9 +143,8 @@
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawRect) {
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
- canvas.drawRect(10, 20, 90, 180, SkPaint());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 200, [](RecordingCanvas& canvas) { canvas.drawRect(10, 20, 90, 180, SkPaint()); });
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
auto op = *(dl->getOps()[0]);
@@ -168,7 +167,7 @@
});
ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
ASSERT_EQ(RecordedOpId::RectOp, dl->getOps()[0]->opId)
- << "Non-rounded rects should be converted";
+ << "Non-rounded rects should be converted";
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs) {
@@ -221,17 +220,17 @@
ASSERT_EQ(8u, ops.size());
int index = 0;
- EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough
+ EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId); // no underline or strikethrough
EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough only
EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline only
EXPECT_EQ(RecordedOpId::TextOp, ops[index++]->opId);
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline
- EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // underline
+ EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
@@ -329,15 +328,14 @@
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(RecordingCanvas, textureLayer) {
- auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
- SkMatrix::MakeTrans(5, 5));
+ auto layerUpdater =
+ TestUtils::createTextureLayerUpdater(renderThread, 100, 100, SkMatrix::MakeTrans(5, 5));
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
- [&layerUpdater](RecordingCanvas& canvas) {
- canvas.drawLayer(layerUpdater.get());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200,
+ [&layerUpdater](RecordingCanvas& canvas) { canvas.drawLayer(layerUpdater.get()); });
- validateSingleOp(dl, [] (const RecordedOp& op) {
+ validateSingleOp(dl, [](const RecordedOp& op) {
ASSERT_EQ(RecordedOpId::TextureLayerOp, op.opId);
ASSERT_TRUE(op.localMatrix.isIdentity()) << "Op must not apply matrix at record time.";
});
@@ -352,26 +350,26 @@
int count = 0;
playbackOps(*dl, [&count](const RecordedOp& op) {
Matrix4 expectedMatrix;
- switch(count++) {
- case 0:
- EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_EQ(nullptr, op.localClip);
- EXPECT_TRUE(op.localMatrix.isIdentity());
- break;
- case 1:
- EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- expectedMatrix.loadTranslate(-10, -20, 0);
- EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
- break;
- case 2:
- EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
- // Don't bother asserting recording state data - it's not used
- break;
- default:
- ADD_FAILURE();
+ switch (count++) {
+ case 0:
+ EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_TRUE(op.localMatrix.isIdentity());
+ break;
+ case 1:
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ expectedMatrix.loadTranslate(-10, -20, 0);
+ EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
+ break;
+ case 2:
+ EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId);
+ // Don't bother asserting recording state data - it's not used
+ break;
+ default:
+ ADD_FAILURE();
}
});
EXPECT_EQ(3, count);
@@ -379,14 +377,14 @@
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rounding) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer);
- canvas.drawRect(20, 20, 80, 80, SkPaint());
- canvas.restore();
- });
- int count = 0;
- playbackOps(*dl, [&count](const RecordedOp& op) {
- Matrix4 expectedMatrix;
- switch(count++) {
+ canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer);
+ canvas.drawRect(20, 20, 80, 80, SkPaint());
+ canvas.restore();
+ });
+ int count = 0;
+ playbackOps(*dl, [&count](const RecordedOp& op) {
+ Matrix4 expectedMatrix;
+ switch (count++) {
case 0:
EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
EXPECT_EQ(Rect(10, 10, 90, 90), op.unmappedBounds) << "Expect bounds rounded out";
@@ -402,9 +400,9 @@
break;
default:
ADD_FAILURE();
- }
- });
- EXPECT_EQ(3, count);
+ }
+ });
+ EXPECT_EQ(3, count);
}
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_missingRestore) {
@@ -424,31 +422,31 @@
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
- canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
canvas.drawRect(10, 20, 190, 180, SkPaint());
canvas.restore();
});
int count = 0;
playbackOps(*dl, [&count](const RecordedOp& op) {
- switch(count++) {
- case 0:
- EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_EQ(nullptr, op.localClip);
- EXPECT_TRUE(op.localMatrix.isIdentity());
- break;
- case 1:
- EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_EQ(nullptr, op.localClip);
- EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
- EXPECT_TRUE(op.localMatrix.isIdentity());
- break;
- case 2:
- EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
- // Don't bother asserting recording state data - it's not used
- break;
- default:
- ADD_FAILURE();
+ switch (count++) {
+ case 0:
+ EXPECT_EQ(RecordedOpId::BeginUnclippedLayerOp, op.opId);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_TRUE(op.localMatrix.isIdentity());
+ break;
+ case 1:
+ EXPECT_EQ(RecordedOpId::RectOp, op.opId);
+ EXPECT_EQ(nullptr, op.localClip);
+ EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
+ EXPECT_TRUE(op.localMatrix.isIdentity());
+ break;
+ case 2:
+ EXPECT_EQ(RecordedOpId::EndUnclippedLayerOp, op.opId);
+ // Don't bother asserting recording state data - it's not used
+ break;
+ default:
+ ADD_FAILURE();
}
});
EXPECT_EQ(3, count);
@@ -458,7 +456,7 @@
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
canvas.clipRect(10, 20, 190, 180, SkClipOp::kIntersect);
- canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
+ canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
canvas.drawRect(10, 20, 190, 180, SkPaint());
canvas.restore();
canvas.restore();
@@ -487,7 +485,7 @@
if (count++ == 1) {
Matrix4 expectedMatrix;
EXPECT_EQ(RecordedOpId::RectOp, op.opId);
- EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
+ EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
// intersection of viewport and saveLayer bounds, in layer space;
EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
expectedMatrix.loadTranslate(-100, -100, 0);
@@ -564,7 +562,7 @@
OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rejectBegin) {
auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
canvas.save(SaveFlags::MatrixClip);
- canvas.translate(0, -20); // avoid identity case
+ canvas.translate(0, -20); // avoid identity case
// empty clip rect should force layer + contents to be rejected
canvas.clipRect(0, -20, 200, -20, SkClipOp::kIntersect);
canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
@@ -577,37 +575,38 @@
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_rejection) {
- auto child = TestUtils::createNode(50, 50, 150, 150,
- [](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto child =
+ TestUtils::createNode(50, 50, 150, 150, [](RenderProperties& props, Canvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&child](RecordingCanvas& canvas) {
- canvas.clipRect(0, 0, 0, 0, SkClipOp::kIntersect); // empty clip, reject node
- canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node...
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&child](RecordingCanvas& canvas) {
+ canvas.clipRect(0, 0, 0, 0, SkClipOp::kIntersect); // empty clip, reject node
+ canvas.drawRenderNode(child.get()); // shouldn't crash when rejecting node...
+ });
ASSERT_TRUE(dl->isEmpty());
}
OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_projection) {
- sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
- [](RenderProperties& props, Canvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ sp<RenderNode> background =
+ TestUtils::createNode(50, 50, 150, 150, [](RenderProperties& props, Canvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
{
background->mutateStagingProperties().setProjectionReceiver(false);
// NO RECEIVER PRESENT
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
- [&background](RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- canvas.drawRenderNode(background.get());
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&background](RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.drawRenderNode(background.get());
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
EXPECT_EQ(-1, dl->projectionReceiveIndex)
<< "no projection receiver should have been observed";
}
@@ -615,18 +614,17 @@
background->mutateStagingProperties().setProjectionReceiver(true);
// RECEIVER PRESENT
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200,
- [&background](RecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- canvas.drawRenderNode(background.get());
- canvas.drawRect(0, 0, 100, 100, SkPaint());
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&background](RecordingCanvas& canvas) {
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ canvas.drawRenderNode(background.get());
+ canvas.drawRect(0, 0, 100, 100, SkPaint());
+ });
ASSERT_EQ(3u, dl->getOps().size()) << "Must be three ops";
auto op = dl->getOps()[1];
EXPECT_EQ(RecordedOpId::RenderNodeOp, op->opId);
- EXPECT_EQ(1, dl->projectionReceiveIndex)
- << "correct projection receiver not identified";
+ EXPECT_EQ(1, dl->projectionReceiveIndex) << "correct projection receiver not identified";
// verify the behavior works even though projection receiver hasn't been sync'd yet
EXPECT_TRUE(background->stagingProperties().isProjectionReceiver());
@@ -718,17 +716,18 @@
OPENGL_PIPELINE_TEST(RecordingCanvas, refPaint) {
SkPaint paint;
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
- paint.setColor(SK_ColorBLUE);
- // first two should use same paint
- canvas.drawRect(0, 0, 200, 10, paint);
- SkPaint paintCopy(paint);
- canvas.drawRect(0, 10, 200, 20, paintCopy);
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 200, 200, [&paint](RecordingCanvas& canvas) {
+ paint.setColor(SK_ColorBLUE);
+ // first two should use same paint
+ canvas.drawRect(0, 0, 200, 10, paint);
+ SkPaint paintCopy(paint);
+ canvas.drawRect(0, 10, 200, 20, paintCopy);
- // only here do we use different paint ptr
- paint.setColor(SK_ColorRED);
- canvas.drawRect(0, 20, 200, 30, paint);
- });
+ // only here do we use different paint ptr
+ paint.setColor(SK_ColorRED);
+ canvas.drawRect(0, 20, 200, 30, paint);
+ });
auto ops = dl->getOps();
ASSERT_EQ(3u, ops.size());
@@ -745,56 +744,58 @@
OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmap) {
sk_sp<Bitmap> bitmap(TestUtils::createBitmap(100, 100));
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 100,
+ [&bitmap](RecordingCanvas& canvas) { canvas.drawBitmap(*bitmap, 0, 0, nullptr); });
auto& bitmaps = dl->getBitmapResources();
EXPECT_EQ(1u, bitmaps.size());
}
OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
- SkPaint paint;
- SkBitmap skBitmap;
- bitmap->getSkBitmap(&skBitmap);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> shader = image->makeShader(
- SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode,
- nullptr);
- paint.setShader(std::move(shader));
- canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
- });
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 100, [&bitmap](RecordingCanvas& canvas) {
+ SkPaint paint;
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ sk_sp<SkImage> image =
+ SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
+ sk_sp<SkShader> shader =
+ image->makeShader(SkShader::TileMode::kClamp_TileMode,
+ SkShader::TileMode::kClamp_TileMode, nullptr);
+ paint.setShader(std::move(shader));
+ canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+ });
auto& bitmaps = dl->getBitmapResources();
EXPECT_EQ(1u, bitmaps.size());
}
OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_composeShader) {
sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
- auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
- SkPaint paint;
- SkBitmap skBitmap;
- bitmap->getSkBitmap(&skBitmap);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> shader1 = image->makeShader(
- SkShader::TileMode::kClamp_TileMode,
- SkShader::TileMode::kClamp_TileMode,
- nullptr);
+ auto dl = TestUtils::createDisplayList<RecordingCanvas>(
+ 100, 100, [&bitmap](RecordingCanvas& canvas) {
+ SkPaint paint;
+ SkBitmap skBitmap;
+ bitmap->getSkBitmap(&skBitmap);
+ sk_sp<SkImage> image =
+ SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
+ sk_sp<SkShader> shader1 =
+ image->makeShader(SkShader::TileMode::kClamp_TileMode,
+ SkShader::TileMode::kClamp_TileMode, nullptr);
- SkPoint center;
- center.set(50, 50);
- SkColor colors[2];
- colors[0] = Color::Black;
- colors[1] = Color::White;
- sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial(center, 50, colors, nullptr, 2,
- SkShader::TileMode::kRepeat_TileMode);
+ SkPoint center;
+ center.set(50, 50);
+ SkColor colors[2];
+ colors[0] = Color::Black;
+ colors[1] = Color::White;
+ sk_sp<SkShader> shader2 = SkGradientShader::MakeRadial(
+ center, 50, colors, nullptr, 2, SkShader::TileMode::kRepeat_TileMode);
- sk_sp<SkShader> composeShader = SkShader::MakeComposeShader(std::move(shader1), std::move(shader2),
- SkBlendMode::kMultiply);
- paint.setShader(std::move(composeShader));
- canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
- });
+ sk_sp<SkShader> composeShader = SkShader::MakeComposeShader(
+ std::move(shader1), std::move(shader2), SkBlendMode::kMultiply);
+ paint.setShader(std::move(composeShader));
+ canvas.drawRoundRect(0, 0, 100, 100, 20.0f, 20.0f, paint);
+ });
auto& bitmaps = dl->getBitmapResources();
EXPECT_EQ(1u, bitmaps.size());
}
@@ -849,5 +850,5 @@
ASSERT_EQ(2, count);
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
index d182d78..dff259f 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -14,25 +14,24 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <SkClipStack.h>
+#include <SkLiteRecorder.h>
+#include <SkSurface_Base.h>
+#include <string.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
+#include "FatalTestCanvas.h"
#include "IContextFactory.h"
+#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
-#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
-#include "SkiaCanvas.h"
-#include <SkSurface_Base.h>
-#include <SkLiteRecorder.h>
-#include <SkClipStack.h>
-#include "FatalTestCanvas.h"
-#include <string.h>
-
using namespace android;
using namespace android::uirenderer;
@@ -40,8 +39,8 @@
using namespace android::uirenderer::skiapipeline;
TEST(RenderNodeDrawable, create) {
- auto rootNode = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto rootNode =
+ TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
@@ -66,47 +65,50 @@
}
static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder, float z) {
- auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
+ auto node = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
[expectedDrawOrder, z](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- props.setTranslationZ(z);
- });
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ props.setTranslationZ(z);
+ });
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
-static void drawOrderedNode(Canvas* canvas, uint8_t expectedDrawOrder,
+static void drawOrderedNode(
+ Canvas* canvas, uint8_t expectedDrawOrder,
std::function<void(RenderProperties& props, SkiaRecordingCanvas& canvas)> setup) {
- auto node = TestUtils::createSkiaNode(0, 0, 100, 100,
+ auto node = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
[expectedDrawOrder, setup](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedRect(&canvas, expectedDrawOrder);
- if (setup) {
- setup(props, canvas);
- }
- });
- canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
+ drawOrderedRect(&canvas, expectedDrawOrder);
+ if (setup) {
+ setup(props, canvas);
+ }
+ });
+ canvas->drawRenderNode(node.get()); // canvas takes reference/sole ownership
}
class ZReorderCanvas : public SkCanvas {
public:
ZReorderCanvas(int width, int height) : SkCanvas(width, height) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
+ int expectedOrder = SkColorGetB(paint.getColor()); // extract order from blue channel
EXPECT_EQ(expectedOrder, mDrawCounter++) << "An op was drawn out of order";
}
int getIndex() { return mDrawCounter; }
+
protected:
int mDrawCounter = 0;
};
-} // end anonymous namespace
+} // end anonymous namespace
TEST(RenderNodeDrawable, zReorder) {
-
- auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto parent = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
canvas.insertReorderBarrier(true);
canvas.insertReorderBarrier(false);
- drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
+ drawOrderedNode(&canvas, 0, 10.0f); // in reorder=false at this point, so played inorder
drawOrderedRect(&canvas, 1);
canvas.insertReorderBarrier(true);
drawOrderedNode(&canvas, 6, 2.0f);
@@ -117,37 +119,36 @@
drawOrderedNode(&canvas, 7, 2.0f);
canvas.insertReorderBarrier(false);
drawOrderedRect(&canvas, 8);
- drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
- canvas.insertReorderBarrier(true); //reorder a node ahead of drawrect op
+ drawOrderedNode(&canvas, 9, -10.0f); // in reorder=false at this point, so played inorder
+ canvas.insertReorderBarrier(true); // reorder a node ahead of drawrect op
drawOrderedRect(&canvas, 11);
drawOrderedNode(&canvas, 10, -1.0f);
canvas.insertReorderBarrier(false);
- canvas.insertReorderBarrier(true); //test with two empty reorder sections
+ canvas.insertReorderBarrier(true); // test with two empty reorder sections
canvas.insertReorderBarrier(true);
canvas.insertReorderBarrier(false);
drawOrderedRect(&canvas, 12);
});
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ZReorderCanvas canvas(100, 100);
RenderNodeDrawable drawable(parent.get(), &canvas, false);
canvas.drawDrawable(&drawable);
EXPECT_EQ(13, canvas.getIndex());
}
-TEST(RenderNodeDrawable, composeOnLayer)
-{
+TEST(RenderNodeDrawable, composeOnLayer) {
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
SkCanvas& canvas = *surface->getCanvas();
canvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- auto rootNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
- recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto rootNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
+ recorder.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
- //attach a layer to the render node
+ // attach a layer to the render node
auto surfaceLayer = SkSurface::MakeRasterN32Premul(1, 1);
auto canvas2 = surfaceLayer->getCanvas();
canvas2->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
@@ -182,39 +183,38 @@
}
}
-TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore)
-{
+TEST(RenderNodeDrawable, saveLayerClipAndMatrixRestore) {
auto surface = SkSurface::MakeRasterN32Premul(400, 800);
SkCanvas& canvas = *surface->getCanvas();
canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
- auto rootNode = TestUtils::createSkiaNode(0, 0, 400, 800,
- [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
- SkPaint layerPaint;
- ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
- EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+ auto rootNode = TestUtils::createSkiaNode(
+ 0, 0, 400, 800, [](RenderProperties& props, SkiaRecordingCanvas& recorder) {
+ SkPaint layerPaint;
+ ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
+ EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- //note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
- recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
- ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
- EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+ // note we don't pass SaveFlags::MatrixClip, but matrix and clip will be saved
+ recorder.saveLayer(0, 0, 400, 400, &layerPaint, SaveFlags::ClipToLayer);
+ ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 400), getRecorderClipBounds(recorder));
+ EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
- ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
+ recorder.clipRect(50, 50, 350, 350, SkClipOp::kIntersect);
+ ASSERT_EQ(SkRect::MakeLTRB(50, 50, 350, 350), getRecorderClipBounds(recorder));
- recorder.translate(300.0f, 400.0f);
- EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
+ recorder.translate(300.0f, 400.0f);
+ EXPECT_EQ(SkMatrix::MakeTrans(300.0f, 400.0f), getRecorderMatrix(recorder));
- recorder.restore();
- ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
- EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
+ recorder.restore();
+ ASSERT_EQ(SkRect::MakeLTRB(0, 0, 400, 800), getRecorderClipBounds(recorder));
+ EXPECT_TRUE(getRecorderMatrix(recorder).isIdentity());
- SkPaint paint;
- paint.setAntiAlias(true);
- paint.setColor(SK_ColorGREEN);
- recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
- });
+ SkPaint paint;
+ paint.setAntiAlias(true);
+ paint.setColor(SK_ColorGREEN);
+ recorder.drawRect(0.0f, 400.0f, 400.0f, 800.0f, paint);
+ });
RenderNodeDrawable drawable(rootNode.get(), &canvas, true);
canvas.drawDrawable(&drawable);
@@ -228,7 +228,7 @@
return new AnimationContext(clock);
}
};
-} // end anonymous namespace
+} // end anonymous namespace
RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorder) {
static const int SCROLL_X = 5;
@@ -238,33 +238,36 @@
ProjectionTestCanvas(int width, int height) : SkCanvas(width, height) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
const int index = mDrawCounter++;
- SkMatrix expectedMatrix;;
+ SkMatrix expectedMatrix;
+ ;
switch (index) {
- case 0: //this is node "B"
- EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
- EXPECT_EQ(SK_ColorWHITE, paint.getColor());
- expectedMatrix.reset();
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
- break;
- case 1: //this is node "P"
- EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
- EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
- expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
- EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50), TestUtils::getLocalClipBounds(this));
- break;
- case 2: //this is node "C"
- EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
- EXPECT_EQ(SK_ColorBLUE, paint.getColor());
- expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
- EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
- break;
- default:
- ADD_FAILURE();
+ case 0: // this is node "B"
+ EXPECT_EQ(SkRect::MakeWH(100, 100), rect);
+ EXPECT_EQ(SK_ColorWHITE, paint.getColor());
+ expectedMatrix.reset();
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, 100, 100), TestUtils::getClipBounds(this));
+ break;
+ case 1: // this is node "P"
+ EXPECT_EQ(SkRect::MakeLTRB(-10, -10, 60, 60), rect);
+ EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
+ expectedMatrix.setTranslate(50 - SCROLL_X, 50 - SCROLL_Y);
+ EXPECT_EQ(SkRect::MakeLTRB(-35, -30, 45, 50),
+ TestUtils::getLocalClipBounds(this));
+ break;
+ case 2: // this is node "C"
+ EXPECT_EQ(SkRect::MakeWH(100, 50), rect);
+ EXPECT_EQ(SK_ColorBLUE, paint.getColor());
+ expectedMatrix.setTranslate(-SCROLL_X, 50 - SCROLL_Y);
+ EXPECT_EQ(SkRect::MakeLTRB(0, 40, 95, 90), TestUtils::getClipBounds(this));
+ break;
+ default:
+ ADD_FAILURE();
}
EXPECT_EQ(expectedMatrix, getTotalMatrix());
}
int getIndex() { return mDrawCounter; }
+
protected:
int mDrawCounter = 0;
};
@@ -277,59 +280,70 @@
* The parent is scrolled by SCROLL_X/SCROLL_Y, but this does not affect the background
* (which isn't affected by scroll).
*/
- auto receiverBackground = TestUtils::createSkiaNode(0, 0, 100, 100,
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(SCROLL_X);
- properties.setTranslationY(SCROLL_Y);
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(SCROLL_X);
+ properties.setTranslationY(SCROLL_Y);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- }, "B");
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ },
+ "B");
- auto projectingRipple = TestUtils::createSkiaNode(50, 0, 100, 50,
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 50, 0, 100, 50,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(-10, -10, 60, 60, paint);
- }, "P");
- auto child = TestUtils::createSkiaNode(0, 50, 100, 100,
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(-10, -10, 60, 60, paint);
+ },
+ "P");
+ auto child = TestUtils::createSkiaNode(
+ 0, 50, 100, 100,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorBLUE);
- canvas.drawRect(0, 0, 100, 50, paint);
- canvas.drawRenderNode(projectingRipple.get());
- }, "C");
- auto parent = TestUtils::createSkiaNode(0, 0, 100, 100,
- [&receiverBackground, &child](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+ SkPaint paint;
+ paint.setColor(SK_ColorBLUE);
+ canvas.drawRect(0, 0, 100, 50, paint);
+ canvas.drawRenderNode(projectingRipple.get());
+ },
+ "C");
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, 100, 100,
+ [&receiverBackground, &child](RenderProperties& properties,
+ SkiaRecordingCanvas& canvas) {
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- canvas.restore();
- }, "A");
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(-SCROLL_X,
+ -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ },
+ "A");
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, parent.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
parent->prepareTree(info);
- //parent(A) -> (receiverBackground, child)
- //child(C) -> (rect[0, 0, 100, 50], projectingRipple)
- //projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards
- //receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
+ // parent(A) -> (receiverBackground, child)
+ // child(C) -> (rect[0, 0, 100, 50], projectingRipple)
+ // projectingRipple(P) -> (rect[-10, -10, 60, 60]) -> projects backwards
+ // receiverBackground(B) -> (rect[0, 0, 100, 100]) -> projection receiver
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ProjectionTestCanvas canvas(100, 100);
RenderNodeDrawable drawable(parent.get(), &canvas, true);
canvas.drawDrawable(&drawable);
@@ -353,17 +367,17 @@
class ProjectionTestCanvas : public SkCanvas {
public:
ProjectionTestCanvas(int* drawCounter)
- : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT)
- , mDrawCounter(drawCounter)
- {}
+ : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT), mDrawCounter(drawCounter) {}
void onDrawArc(const SkRect&, SkScalar startAngle, SkScalar sweepAngle, bool useCenter,
- const SkPaint&) override {
- EXPECT_EQ(0, (*mDrawCounter)++); //part of painting the layer
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT), TestUtils::getClipBounds(this));
+ const SkPaint&) override {
+ EXPECT_EQ(0, (*mDrawCounter)++); // part of painting the layer
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, LAYER_WIDTH, LAYER_HEIGHT),
+ TestUtils::getClipBounds(this));
}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(1, (*mDrawCounter)++);
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT),
+ TestUtils::getClipBounds(this));
}
void onDrawOval(const SkRect&, const SkPaint&) override {
EXPECT_EQ(2, (*mDrawCounter)++);
@@ -378,69 +392,73 @@
class ProjectionLayer : public SkSurface_Base {
public:
ProjectionLayer(int* drawCounter)
- : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
- , mDrawCounter(drawCounter) {
- }
+ : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr)
+ , mDrawCounter(drawCounter) {}
void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override {
EXPECT_EQ(3, (*mDrawCounter)++);
EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X,
- 300 - SCROLL_Y), TestUtils::getClipBounds(this->getCanvas()));
+ 300 - SCROLL_Y),
+ TestUtils::getClipBounds(this->getCanvas()));
}
- SkCanvas* onNewCanvas() override {
- return new ProjectionTestCanvas(mDrawCounter);
- }
- sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
- return nullptr;
- }
- sk_sp<SkImage> onNewImageSnapshot() override {
- return nullptr;
- }
+ SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); }
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
+ sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
void onCopyOnWrite(ContentChangeMode) override {}
int* mDrawCounter;
};
- auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(SCROLL_X);
- properties.setTranslationY(SCROLL_Y);
+ properties.setProjectionReceiver(true);
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(SCROLL_X);
+ properties.setTranslationY(SCROLL_Y);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
- }, "B"); //B
- auto projectingRipple = TestUtils::createSkiaNode(0, 0, LAYER_WIDTH, LAYER_HEIGHT,
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+ },
+ "B"); // B
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 0, 0, LAYER_WIDTH, LAYER_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
- }, "R"); //R
- auto child = TestUtils::createSkiaNode(100, 100, 300, 300,
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+ },
+ "R"); // R
+ auto child = TestUtils::createSkiaNode(
+ 100, 100, 300, 300,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- canvas.drawRenderNode(projectingRipple.get());
- canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
- }, "C"); //C
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ canvas.drawRenderNode(projectingRipple.get());
+ canvas.drawArc(0, 0, LAYER_WIDTH, LAYER_HEIGHT, 0.0f, 280.0f, true, SkPaint());
+ },
+ "C"); // C
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&receiverBackground, &child](RenderProperties& properties,
- SkiaRecordingCanvas& canvas) {
- // Set a rect outline for the projecting ripple to be masked against.
- properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
- canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- }, "A"); //A
+ SkiaRecordingCanvas& canvas) {
+ // Set a rect outline for the projecting ripple to be masked against.
+ properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+ canvas.translate(-SCROLL_X,
+ -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ },
+ "A"); // A
- //prepareTree is required to find, which receivers have backward projected nodes
+ // prepareTree is required to find, which receivers have backward projected nodes
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, parent.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
parent->prepareTree(info);
int drawCounter = 0;
- //set a layer after prepareTree to avoid layer logic there
+ // set a layer after prepareTree to avoid layer logic there
child->animatorProperties().mutateLayerProperties().setType(LayerType::RenderLayer);
sk_sp<SkSurface> surfaceLayer1(new ProjectionLayer(&drawCounter));
child->setLayerSurface(surfaceLayer1);
@@ -450,10 +468,10 @@
LayerUpdateQueue layerUpdateQueue;
layerUpdateQueue.enqueueLayerWithDamage(child.get(),
- android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
+ android::uirenderer::Rect(LAYER_WIDTH, LAYER_HEIGHT));
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
pipeline->renderLayersImpl(layerUpdateQueue, true, false);
- EXPECT_EQ(1, drawCounter); //assert index 0 is drawn on the layer
+ EXPECT_EQ(1, drawCounter); // assert index 0 is drawn on the layer
RenderNodeDrawable drawable(parent.get(), surfaceLayer1->getCanvas(), true);
surfaceLayer1->getCanvas()->drawDrawable(&drawable);
@@ -490,40 +508,50 @@
int mDrawCounter = 0;
};
- auto receiverBackground = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto receiverBackground = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- properties.setProjectionReceiver(true);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
- }, "B"); //B
- auto projectingRipple = TestUtils::createSkiaNode(0, 0, 200, 200,
+ properties.setProjectionReceiver(true);
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
+ },
+ "B"); // B
+ auto projectingRipple = TestUtils::createSkiaNode(
+ 0, 0, 200, 200,
[](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- // scroll doesn't apply to background, so undone via translationX/Y
- // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
- properties.setTranslationX(SCROLL_X);
- properties.setTranslationY(SCROLL_Y);
- properties.setProjectBackwards(true);
- properties.setClipToBounds(false);
- canvas.drawOval(0, 0, 200, 200, SkPaint());
- }, "R"); //R
- auto child = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ // scroll doesn't apply to background, so undone via translationX/Y
+ // NOTE: translationX/Y only! no other transform properties may be set for a proj
+ // receiver!
+ properties.setTranslationX(SCROLL_X);
+ properties.setTranslationY(SCROLL_Y);
+ properties.setProjectBackwards(true);
+ properties.setClipToBounds(false);
+ canvas.drawOval(0, 0, 200, 200, SkPaint());
+ },
+ "R"); // R
+ auto child = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&projectingRipple](RenderProperties& properties, SkiaRecordingCanvas& canvas) {
- // Record time clip will be ignored by projectee
- canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
+ // Record time clip will be ignored by projectee
+ canvas.clipRect(100, 100, 300, 300, SkClipOp::kIntersect);
- canvas.translate(-SCROLL_X, -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
- canvas.drawRenderNode(projectingRipple.get());
- }, "C"); //C
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- [&receiverBackground, &child](RenderProperties& properties,
- SkiaRecordingCanvas& canvas) {
- canvas.drawRenderNode(receiverBackground.get());
- canvas.drawRenderNode(child.get());
- }, "A"); //A
+ canvas.translate(-SCROLL_X,
+ -SCROLL_Y); // Apply scroll (note: bg undoes this internally)
+ canvas.drawRenderNode(projectingRipple.get());
+ },
+ "C"); // C
+ auto parent =
+ TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ [&receiverBackground, &child](RenderProperties& properties,
+ SkiaRecordingCanvas& canvas) {
+ canvas.drawRenderNode(receiverBackground.get());
+ canvas.drawRenderNode(child.get());
+ },
+ "A"); // A
- //prepareTree is required to find, which receivers have backward projected nodes
+ // prepareTree is required to find, which receivers have backward projected nodes
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, parent.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, parent.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
@@ -536,17 +564,16 @@
}
namespace {
-static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode)
-{
+static int drawNode(RenderThread& renderThread, const sp<RenderNode>& renderNode) {
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, renderNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, renderNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
renderNode->prepareTree(info);
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ZReorderCanvas canvas(100, 100);
RenderNodeDrawable drawable(renderNode.get(), &canvas, false);
canvas.drawDrawable(&drawable);
@@ -562,18 +589,18 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
- } ); //nodeB
+ }); // nodeB
drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -586,19 +613,21 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 2
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) { // drawn as 2
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //drawn as 3
- props.setProjectionReceiver(true);
- } ); //nodeE
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // drawn as 3
+ props.setProjectionReceiver(true);
+ }); // nodeE
+ }); // nodeA
EXPECT_EQ(4, drawNode(renderThread, nodeA));
}
@@ -610,17 +639,17 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- //not having a projection receiver is an undefined behavior
+ // not having a projection receiver is an undefined behavior
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(2, drawNode(renderThread, nodeA));
}
@@ -632,17 +661,17 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -654,22 +683,22 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, nullptr); //nodeB
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, nullptr); // nodeB
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- //having a node that is projected on itself is an undefined/unexpected behavior
+ // having a node that is projected on itself is an undefined/unexpected behavior
props.setProjectionReceiver(true);
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(2, drawNode(renderThread, nodeA));
}
-//Note: the outcome for this test is different in HWUI
+// Note: the outcome for this test is different in HWUI
RENDERTHREAD_TEST(RenderNodeDrawable, projectionReorderProjectedSibling) {
/* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
A
@@ -677,18 +706,18 @@
/ | \
B C R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- } ); //nodeC
+ }); // nodeB
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- }); //nodeA
+ }); // nodeR
+ }); // nodeA
EXPECT_EQ(2, drawNode(renderThread, nodeA));
}
@@ -701,20 +730,20 @@
/ | \
B C R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- } ); //nodeC
+ }); // nodeB
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {}); // nodeC
drawOrderedNode(&canvas, 255, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectBackwards(true);
props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeG
- }); //nodeA
+ }); // nodeR
+ }); // nodeG
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -728,18 +757,19 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
props.setProjectionReceiver(true);
drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- } ); //nodeB
- }); //nodeA
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeB
+ }); // nodeA
EXPECT_EQ(3, drawNode(renderThread, nodeA));
}
@@ -751,21 +781,23 @@
/ \
G R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(4, drawNode(renderThread, nodeA));
}
@@ -777,21 +809,23 @@
/ \
G R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeG
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
- } ); //nodeR
- } ); //nodeC
- }); //nodeA
+ }); // nodeB
+ drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 1,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeG
+ drawOrderedNode(&canvas, 3,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // R
+ }); // nodeR
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(4, drawNode(renderThread, nodeA));
}
@@ -805,23 +839,26 @@
|
R
*/
- auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //B
+ auto nodeA = TestUtils::createSkiaNode(0, 0, 100, 100, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) {
+ drawOrderedNode(&canvas, 0, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // B
props.setProjectionReceiver(true);
- } ); //nodeB
- drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //C
- drawOrderedNode(&canvas, 2, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //G
- props.setProjectionReceiver(true);
- } ); //nodeG
- drawOrderedNode(&canvas, 4, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //D
- drawOrderedNode(&canvas, 3, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { //R
- props.setProjectBackwards(true);
- props.setClipToBounds(false);
- } ); //nodeR
- } ); //nodeD
- } ); //nodeC
- }); //nodeA
+ }); // nodeB
+ drawOrderedNode(&canvas, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // C
+ drawOrderedNode(&canvas, 2,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // G
+ props.setProjectionReceiver(true);
+ }); // nodeG
+ drawOrderedNode(&canvas, 4,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) { // D
+ drawOrderedNode(&canvas, 3, [](RenderProperties& props,
+ SkiaRecordingCanvas& canvas) { // R
+ props.setProjectBackwards(true);
+ props.setClipToBounds(false);
+ }); // nodeR
+ }); // nodeD
+ }); // nodeC
+ }); // nodeA
EXPECT_EQ(5, drawNode(renderThread, nodeA));
}
@@ -830,8 +867,7 @@
static const int CANVAS_HEIGHT = 200;
class SimpleTestCanvas : public TestCanvasBase {
public:
- SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ SimpleTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
EXPECT_EQ(0, mDrawCounter++);
}
@@ -841,11 +877,12 @@
};
auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, SkPaint());
- canvas.drawBitmap(*bitmap, 10, 10, nullptr);
- });
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ SkPaint());
+ canvas.drawBitmap(*bitmap, 10, 10, nullptr);
+ });
SimpleTestCanvas canvas;
RenderNodeDrawable drawable(node.get(), &canvas, true);
@@ -858,33 +895,32 @@
static const int CANVAS_HEIGHT = 200;
class ColorTestCanvas : public TestCanvasBase {
public:
- ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ ColorTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawPaint(const SkPaint&) {
switch (mDrawCounter++) {
- case 0:
- EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
- TestUtils::getClipBounds(this));
- break;
- case 1:
- EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
- break;
- default:
- ADD_FAILURE();
+ case 0:
+ EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
+ TestUtils::getClipBounds(this));
+ break;
+ case 1:
+ EXPECT_EQ(SkRect::MakeWH(10, 10), TestUtils::getClipBounds(this));
+ break;
+ default:
+ ADD_FAILURE();
}
}
};
- auto unclippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- props.setClipToBounds(false);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto unclippedColorView = TestUtils::createSkiaNode(
+ 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ props.setClipToBounds(false);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
- auto clippedColorView = TestUtils::createSkiaNode(0, 0, 10, 10,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto clippedColorView = TestUtils::createSkiaNode(
+ 0, 0, 10, 10, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
ColorTestCanvas canvas;
RenderNodeDrawable drawable(unclippedColorView.get(), &canvas, true);
@@ -900,42 +936,43 @@
static const int CANVAS_HEIGHT = 200;
class RenderNodeTestCanvas : public TestCanvasBase {
public:
- RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ RenderNodeTestCanvas() : TestCanvasBase(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
- switch(mDrawCounter++) {
- case 0:
- EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), TestUtils::getClipBounds(this));
- EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
- break;
- case 1:
- EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
- EXPECT_EQ(SK_ColorWHITE, paint.getColor());
- break;
- default:
- ADD_FAILURE();
+ switch (mDrawCounter++) {
+ case 0:
+ EXPECT_EQ(SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT),
+ TestUtils::getClipBounds(this));
+ EXPECT_EQ(SK_ColorDKGRAY, paint.getColor());
+ break;
+ case 1:
+ EXPECT_EQ(SkRect::MakeLTRB(50, 50, 150, 150), TestUtils::getClipBounds(this));
+ EXPECT_EQ(SK_ColorWHITE, paint.getColor());
+ break;
+ default:
+ ADD_FAILURE();
}
}
};
- auto child = TestUtils::createSkiaNode(10, 10, 110, 110,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, 100, 100, paint);
- });
+ auto child = TestUtils::createSkiaNode(
+ 10, 10, 110, 110, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, 100, 100, paint);
+ });
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[&child](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- SkPaint paint;
- paint.setColor(SK_ColorDKGRAY);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
+ SkPaint paint;
+ paint.setColor(SK_ColorDKGRAY);
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
- canvas.save(SaveFlags::MatrixClip);
- canvas.translate(40, 40);
- canvas.drawRenderNode(child.get());
- canvas.restore();
- });
+ canvas.save(SaveFlags::MatrixClip);
+ canvas.translate(40, 40);
+ canvas.drawRenderNode(child.get());
+ canvas.restore();
+ });
RenderNodeTestCanvas canvas;
RenderNodeDrawable drawable(parent.get(), &canvas, true);
@@ -943,7 +980,6 @@
EXPECT_EQ(2, canvas.mDrawCounter);
}
-
TEST(ReorderBarrierDrawable, testShadowMatrix) {
static const int CANVAS_WIDTH = 100;
static const int CANVAS_HEIGHT = 100;
@@ -954,7 +990,6 @@
static const float CASTER_WIDTH = 20.0f;
static const float CASTER_HEIGHT = 20.0f;
-
class ShadowTestCanvas : public SkCanvas {
public:
ShadowTestCanvas(int width, int height) : SkCanvas(width, height) {}
@@ -978,30 +1013,32 @@
// matrix.
mDrawCounter++;
EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X, CASTER_Y), matrix);
- EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X+TRANSLATE_X, CASTER_Y+TRANSLATE_Y),
- getTotalMatrix());
+ EXPECT_EQ(SkMatrix::MakeTrans(CASTER_X + TRANSLATE_X, CASTER_Y + TRANSLATE_Y),
+ getTotalMatrix());
}
+
protected:
int mDrawCounter = 0;
};
- auto parent = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto parent = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.translate(TRANSLATE_X, TRANSLATE_Y);
- canvas.insertReorderBarrier(true);
+ canvas.translate(TRANSLATE_X, TRANSLATE_Y);
+ canvas.insertReorderBarrier(true);
- auto node = TestUtils::createSkiaNode(CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH,
- CASTER_Y + CASTER_HEIGHT,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- props.setElevation(42);
- props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
- props.mutableOutline().setShouldClip(true);
- });
- canvas.drawRenderNode(node.get());
- canvas.insertReorderBarrier(false);
- });
+ auto node = TestUtils::createSkiaNode(
+ CASTER_X, CASTER_Y, CASTER_X + CASTER_WIDTH, CASTER_Y + CASTER_HEIGHT,
+ [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ props.setElevation(42);
+ props.mutableOutline().setRoundRect(0, 0, 20, 20, 5, 1);
+ props.mutableOutline().setShouldClip(true);
+ });
+ canvas.drawRenderNode(node.get());
+ canvas.insertReorderBarrier(false);
+ });
- //create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
+ // create a canvas not backed by any device/pixels, but with dimensions to avoid quick rejection
ShadowTestCanvas canvas(CANVAS_WIDTH, CANVAS_HEIGHT);
RenderNodeDrawable drawable(parent.get(), &canvas, false);
canvas.drawDrawable(&drawable);
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index eda4a9d..0795208 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
@@ -32,21 +32,20 @@
class ContextFactory : public android::uirenderer::IContextFactory {
public:
- android::uirenderer::AnimationContext* createAnimationContext
- (android::uirenderer::renderthread::TimeLord& clock) override {
+ android::uirenderer::AnimationContext* createAnimationContext(
+ android::uirenderer::renderthread::TimeLord& clock) override {
return new android::uirenderer::AnimationContext(clock);
}
};
TEST(RenderNode, hasParents) {
- auto child = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto child = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
auto parent = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
@@ -67,14 +66,13 @@
}
TEST(RenderNode, validity) {
- auto child = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto child = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
auto parent = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
EXPECT_TRUE(child->isValid());
EXPECT_TRUE(parent->isValid());
@@ -111,9 +109,8 @@
EXPECT_TRUE(child->isValid());
EXPECT_TRUE(child->nothingToDraw());
- TestUtils::recordNode(*parent, [&child](Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ TestUtils::recordNode(*parent,
+ [&child](Canvas& canvas) { canvas.drawRenderNode(child.get()); });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent);
@@ -131,18 +128,17 @@
}
TEST(RenderNode, multiTreeValidity) {
- auto child = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
+ auto child = TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
});
auto parent1 = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
auto parent2 = TestUtils::createNode(0, 0, 200, 400,
- [&child](RenderProperties& props, Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ [&child](RenderProperties& props, Canvas& canvas) {
+ canvas.drawRenderNode(child.get());
+ });
EXPECT_TRUE(child->isValid());
EXPECT_TRUE(parent1->isValid());
@@ -200,14 +196,12 @@
});
TestUtils::syncHierarchyPropertiesAndDisplayList(child);
- TestUtils::recordNode(*parent1, [&child](Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ TestUtils::recordNode(*parent1,
+ [&child](Canvas& canvas) { canvas.drawRenderNode(child.get()); });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent1);
- TestUtils::recordNode(*parent2, [&child](Canvas& canvas) {
- canvas.drawRenderNode(child.get());
- });
+ TestUtils::recordNode(*parent2,
+ [&child](Canvas& canvas) { canvas.drawRenderNode(child.get()); });
TestUtils::syncHierarchyPropertiesAndDisplayList(parent2);
EXPECT_TRUE(child->isValid());
@@ -240,9 +234,8 @@
class DecRefOnReleased : public GlFunctorLifecycleListener {
public:
explicit DecRefOnReleased(int* refcnt) : mRefCnt(refcnt) {}
- void onGlFunctorReleased(Functor* functor) override {
- *mRefCnt -= 1;
- }
+ void onGlFunctorReleased(Functor* functor) override { *mRefCnt -= 1; }
+
private:
int* mRefCnt;
};
@@ -251,8 +244,7 @@
sp<DecRefOnReleased> listener(new DecRefOnReleased(&refcnt));
Functor noopFunctor;
- auto node = TestUtils::createNode(0, 0, 200, 400,
- [&](RenderProperties& props, Canvas& canvas) {
+ auto node = TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) {
refcnt++;
canvas.callDrawGLFunction(&noopFunctor, listener.get());
});
@@ -277,17 +269,17 @@
RENDERTHREAD_TEST(RenderNode, prepareTree_nullableDisplayList) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
{
- auto nonNullDLNode = TestUtils::createNode(0, 0, 200, 400,
- [](RenderProperties& props, Canvas& canvas) {
- canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
- });
+ auto nonNullDLNode =
+ TestUtils::createNode(0, 0, 200, 400, [](RenderProperties& props, Canvas& canvas) {
+ canvas.drawColor(Color::Red_500, SkBlendMode::kSrcOver);
+ });
TestUtils::syncHierarchyPropertiesAndDisplayList(nonNullDLNode);
EXPECT_TRUE(nonNullDLNode->getDisplayList());
nonNullDLNode->prepareTree(info);
@@ -304,17 +296,16 @@
}
RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
-
VectorDrawable::Group* group = new VectorDrawable::Group();
sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
- auto rootNode = TestUtils::createNode(0, 0, 200, 400,
- [&](RenderProperties& props, Canvas& canvas) {
- canvas.drawVectorDrawable(vectorDrawable.get());
- });
+ auto rootNode =
+ TestUtils::createNode(0, 0, 200, 400, [&](RenderProperties& props, Canvas& canvas) {
+ canvas.drawVectorDrawable(vectorDrawable.get());
+ });
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_RT_ONLY, *canvasContext.get());
DamageAccumulator damageAccumulator;
LayerUpdateQueue layerUpdateQueue;
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/SkiaBehaviorTests.cpp b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
index 85b12ba..bc742b0 100644
--- a/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
+++ b/libs/hwui/tests/unit/SkiaBehaviorTests.cpp
@@ -16,13 +16,13 @@
#include "tests/common/TestUtils.h"
-#include <gtest/gtest.h>
#include <SkBlurDrawLooper.h>
#include <SkColorMatrixFilter.h>
#include <SkColorSpace.h>
#include <SkImagePriv.h>
#include <SkPathOps.h>
#include <SkShader.h>
+#include <gtest/gtest.h>
using namespace android;
using namespace android::uirenderer;
@@ -42,15 +42,13 @@
TEST(SkiaBehavior, CreateBitmapShader1x1) {
SkBitmap origBitmap = createSkBitmap(1, 1);
sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(origBitmap, kNever_SkCopyPixelsMode);
- sk_sp<SkShader> s = image->makeShader(
- SkShader::kClamp_TileMode,
- SkShader::kRepeat_TileMode,
- nullptr);
+ sk_sp<SkShader> s =
+ image->makeShader(SkShader::kClamp_TileMode, SkShader::kRepeat_TileMode, nullptr);
SkBitmap bitmap;
SkShader::TileMode xy[2];
ASSERT_TRUE(s->isABitmap(&bitmap, nullptr, xy))
- << "1x1 bitmap shader must query as bitmap shader";
+ << "1x1 bitmap shader must query as bitmap shader";
EXPECT_EQ(origBitmap.pixelRef(), bitmap.pixelRef());
}
@@ -63,8 +61,7 @@
TEST(SkiaBehavior, lightingColorFilter_simplify) {
{
- sk_sp<SkColorFilter> filter(
- SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0));
+ sk_sp<SkColorFilter> filter(SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0));
SkColor observedColor;
SkBlendMode observedMode;
@@ -74,8 +71,7 @@
}
{
- sk_sp<SkColorFilter> failFilter(
- SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0x1));
+ sk_sp<SkColorFilter> failFilter(SkColorMatrixFilter::MakeLightingFilter(0x11223344, 0x1));
EXPECT_FALSE(failFilter->asColorMode(nullptr, nullptr));
}
}
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index d84b83d..4138f59 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -16,12 +16,12 @@
#include "tests/common/TestUtils.h"
-#include <gtest/gtest.h>
#include <RecordingCanvas.h>
#include <SkBlurDrawLooper.h>
#include <SkCanvasStateUtils.h>
#include <SkPicture.h>
#include <SkPictureRecorder.h>
+#include <gtest/gtest.h>
using namespace android;
using namespace android::uirenderer;
@@ -88,7 +88,7 @@
sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo);
SkBitmap adobeSkBitmap;
adobeBitmap->getSkBitmap(&adobeSkBitmap);
- *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red
+ *adobeSkBitmap.getAddr32(0, 0) = 0xFF0000F0; // Opaque, almost fully-red
SkImageInfo info = adobeInfo.makeColorSpace(nullptr);
sk_sp<Bitmap> bitmap = Bitmap::allocateHeapBitmap(info);
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index dd8f4b4..88d6dcf 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
@@ -79,7 +79,7 @@
// detach the list that you just attempted to reuse
availableList = renderNode->detachAvailableList();
ASSERT_EQ(availableList.get(), &skiaDL);
- availableList.release(); // prevents an invalid free since our DL is stack allocated
+ availableList.release(); // prevents an invalid free since our DL is stack allocated
// after detaching there should return no available list
availableList = renderNode->detachAvailableList();
@@ -115,8 +115,8 @@
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
ContextFactory contextFactory;
- std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
- renderThread, false, rootNode.get(), &contextFactory));
+ std::unique_ptr<CanvasContext> canvasContext(
+ CanvasContext::create(renderThread, false, rootNode.get(), &contextFactory));
TreeInfo info(TreeInfo::MODE_FULL, *canvasContext.get());
DamageAccumulator damageAccumulator;
info.damageAccumulator = &damageAccumulator;
@@ -126,13 +126,13 @@
// prepare with a clean VD
VectorDrawableRoot cleanVD(new VectorDrawable::Group());
skiaDL.mVectorDrawables.push_back(&cleanVD);
- cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
+ cleanVD.getBitmapUpdateIfDirty(); // this clears the dirty bit
ASSERT_FALSE(cleanVD.isDirty());
ASSERT_FALSE(cleanVD.getPropertyChangeWillBeConsumed());
TestUtils::MockTreeObserver observer;
ASSERT_FALSE(skiaDL.prepareListAndChildren(observer, info, false,
- [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
+ [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
ASSERT_TRUE(cleanVD.getPropertyChangeWillBeConsumed());
// prepare again this time adding a dirty VD
@@ -142,7 +142,7 @@
ASSERT_TRUE(dirtyVD.isDirty());
ASSERT_FALSE(dirtyVD.getPropertyChangeWillBeConsumed());
ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
- [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
+ [](RenderNode*, TreeObserver&, TreeInfo&, bool) {}));
ASSERT_TRUE(dirtyVD.getPropertyChangeWillBeConsumed());
// prepare again this time adding a RenderNode and a callback
@@ -151,13 +151,15 @@
SkCanvas dummyCanvas;
skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
bool hasRun = false;
- ASSERT_TRUE(skiaDL.prepareListAndChildren(observer, info, false,
- [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i, bool r) {
- hasRun = true;
- ASSERT_EQ(renderNode.get(), n);
- ASSERT_EQ(infoPtr, &i);
- ASSERT_FALSE(r);
- }));
+ ASSERT_TRUE(skiaDL.prepareListAndChildren(
+ observer, info, false,
+ [&hasRun, renderNode, infoPtr](RenderNode* n, TreeObserver& observer, TreeInfo& i,
+ bool r) {
+ hasRun = true;
+ ASSERT_EQ(renderNode.get(), n);
+ ASSERT_EQ(infoPtr, &i);
+ ASSERT_FALSE(r);
+ }));
ASSERT_TRUE(hasRun);
canvasContext->destroy();
@@ -169,7 +171,5 @@
sp<RenderNode> renderNode = new RenderNode();
SkCanvas dummyCanvas;
skiaDL.mChildNodes.emplace_back(renderNode.get(), &dummyCanvas);
- skiaDL.updateChildren([renderNode](RenderNode* n) {
- ASSERT_EQ(renderNode.get(), n);
- });
+ skiaDL.updateChildren([renderNode](RenderNode* n) { ASSERT_EQ(renderNode.get(), n); });
}
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index f430ce6..8fdb0e3 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -14,22 +14,22 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
-#include "AnimationContext.h"
-#include "DamageAccumulator.h"
-#include "IContextFactory.h"
-#include "pipeline/skia/SkiaDisplayList.h"
-#include "pipeline/skia/SkiaRecordingCanvas.h"
-#include "pipeline/skia/SkiaOpenGLPipeline.h"
-#include "renderthread/CanvasContext.h"
-#include "tests/common/TestUtils.h"
-#include "SkiaCanvas.h"
#include <SkClipStack.h>
#include <SkLiteRecorder.h>
#include <SkSurface_Base.h>
#include <string.h>
+#include "AnimationContext.h"
+#include "DamageAccumulator.h"
+#include "IContextFactory.h"
+#include "SkiaCanvas.h"
+#include "pipeline/skia/SkiaDisplayList.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
+#include "pipeline/skia/SkiaRecordingCanvas.h"
+#include "renderthread/CanvasContext.h"
+#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
@@ -37,10 +37,10 @@
using namespace android::uirenderer::skiapipeline;
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
- auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
std::vector<sp<RenderNode>> renderNodes;
@@ -51,17 +51,16 @@
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- opaque, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, testOnPrepareTree) {
-
- auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
@@ -71,33 +70,33 @@
android::uirenderer::Rect contentDrawBounds(0, 0, 1, 1);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
{
- //add a pointer to a deleted vector drawable object in the pipeline
+ // add a pointer to a deleted vector drawable object in the pipeline
sp<VectorDrawableRoot> dirtyVD(new VectorDrawableRoot(new VectorDrawable::Group()));
- dirtyVD->mutateProperties()->setScaledSize(5,5);
+ dirtyVD->mutateProperties()->setScaledSize(5, 5);
pipeline->getVectorDrawables()->push_back(dirtyVD.get());
}
- //pipeline should clean list of dirty vector drawables before prepare tree
+ // pipeline should clean list of dirty vector drawables before prepare tree
pipeline->onPrepareTree();
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- //drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- opaque, false, contentDrawBounds, surface);
+ // drawFrame will crash if "SkiaPipeline::onPrepareTree" did not clean invalid VD pointer
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
- auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
- [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
- SkPaint greenPaint;
- greenPaint.setColor(SK_ColorGREEN);
- greenPaint.setStyle(SkPaint::kFill_Style);
- bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
- });
+ auto halfGreenNode = TestUtils::createSkiaNode(
+ 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
+ SkPaint greenPaint;
+ greenPaint.setColor(SK_ColorGREEN);
+ greenPaint.setStyle(SkPaint::kFill_Style);
+ bottomHalfGreenCanvas.drawRect(0, 1, 2, 2, greenPaint);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
std::vector<sp<RenderNode>> renderNodes;
@@ -107,21 +106,21 @@
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- true, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- false, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, false, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned int)SK_ColorTRANSPARENT);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
- auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeXYWH(0, 1, 2, 1);
std::vector<sp<RenderNode>> renderNodes;
@@ -131,8 +130,8 @@
auto surface = SkSurface::MakeRasterN32Premul(2, 2);
surface->getCanvas()->drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes,
- true, false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, true, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 1, 0), SK_ColorBLUE);
ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorRED);
@@ -140,27 +139,27 @@
}
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
- auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
- redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
- });
+ auto redNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
+ redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
+ });
auto surfaceLayer1 = SkSurface::MakeRasterN32Premul(1, 1);
surfaceLayer1->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surfaceLayer1, 0, 0), SK_ColorWHITE);
redNode->setLayerSurface(surfaceLayer1);
- //create a 2nd 2x2 layer and add it to the queue as well.
- //make the layer's dirty area one half of the layer and verify only the dirty half is updated.
- auto blueNode = TestUtils::createSkiaNode(0, 0, 2, 2,
- [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
- blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
- });
+ // create a 2nd 2x2 layer and add it to the queue as well.
+ // make the layer's dirty area one half of the layer and verify only the dirty half is updated.
+ auto blueNode = TestUtils::createSkiaNode(
+ 0, 0, 2, 2, [](RenderProperties& props, SkiaRecordingCanvas& blueCanvas) {
+ blueCanvas.drawColor(SK_ColorBLUE, SkBlendMode::kSrcOver);
+ });
auto surfaceLayer2 = SkSurface::MakeRasterN32Premul(2, 2);
surfaceLayer2->getCanvas()->drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
ASSERT_EQ(TestUtils::getColor(surfaceLayer2, 0, 0), SK_ColorWHITE);
blueNode->setLayerSurface(surfaceLayer2);
- //attach both layers to the update queue
+ // attach both layers to the update queue
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLargest();
layerUpdateQueue.enqueueLayerWithDamage(redNode.get(), dirty);
@@ -170,7 +169,7 @@
bool opaque = true;
FrameBuilder::LightGeometry lightGeometry;
lightGeometry.radius = 1.0f;
- lightGeometry.center = { 0.0f, 0.0f, 0.0f };
+ lightGeometry.center = {0.0f, 0.0f, 0.0f};
BakedOpRenderer::LightInfo lightInfo;
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
pipeline->renderLayers(lightGeometry, &layerUpdateQueue, opaque, false, lightInfo);
@@ -185,16 +184,16 @@
RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
ScopedProperty<bool> prop(Properties::debugOverdraw, true);
- auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- });
+ auto whiteNode = TestUtils::createSkiaNode(
+ 0, 0, 1, 1, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ });
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeXYWH(0, 0, 1, 1);
std::vector<sp<RenderNode>> renderNodes;
renderNodes.push_back(whiteNode);
bool opaque = true;
- //empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw
+ // empty contentDrawBounds is avoiding backdrop/content logic, which would lead to less overdraw
android::uirenderer::Rect contentDrawBounds(0, 0, 0, 0);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
auto surface = SkSurface::MakeRasterN32Premul(1, 1);
@@ -204,39 +203,39 @@
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorBLUE);
// Single draw, should be white.
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorWHITE);
// 1 Overdraw, should be blue blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0d0ff);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0d0ff);
// 2 Overdraw, should be green blended onto white
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffd0ffd0);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffd0ffd0);
// 3 Overdraw, should be pink blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffffc0c0);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffffc0c0);
// 4 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
// 5 Overdraw, should be red blended onto white.
renderNodes.push_back(whiteNode);
- pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque,
- false, contentDrawBounds, surface);
- ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned) 0xffff8080);
+ pipeline->renderFrame(layerUpdateQueue, dirty, renderNodes, opaque, false, contentDrawBounds,
+ surface);
+ ASSERT_EQ(TestUtils::getColor(surface, 0, 0), (unsigned)0xffff8080);
}
namespace {
@@ -246,15 +245,9 @@
DeferLayer() : SkSurface_Base(T().imageInfo(), nullptr) {}
virtual ~DeferLayer() {}
- SkCanvas* onNewCanvas() override {
- return new T();
- }
- sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override {
- return nullptr;
- }
- sk_sp<SkImage> onNewImageSnapshot() override {
- return nullptr;
- }
+ SkCanvas* onNewCanvas() override { return new T(); }
+ sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; }
+ sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; }
T* canvas() { return static_cast<T*>(getCanvas()); }
void onCopyOnWrite(ContentChangeMode) override {}
};
@@ -267,28 +260,28 @@
void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
SkMatrix expected;
switch (mDrawCounter++) {
- case 0:
- // background - left side
- EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this));
- expected.setTranslate(100, 100);
- break;
- case 1:
- // background - top side
- EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this));
- expected.setTranslate(100, 100);
- break;
- case 2:
- // content
- EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this));
- expected.setTranslate(-50, -50);
- break;
- case 3:
- // overlay
- EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this));
- expected.reset();
- break;
- default:
- ADD_FAILURE() << "Too many rects observed";
+ case 0:
+ // background - left side
+ EXPECT_EQ(SkRect::MakeLTRB(600, 100, 700, 500), TestUtils::getClipBounds(this));
+ expected.setTranslate(100, 100);
+ break;
+ case 1:
+ // background - top side
+ EXPECT_EQ(SkRect::MakeLTRB(100, 400, 600, 500), TestUtils::getClipBounds(this));
+ expected.setTranslate(100, 100);
+ break;
+ case 2:
+ // content
+ EXPECT_EQ(SkRect::MakeLTRB(100, 100, 700, 500), TestUtils::getClipBounds(this));
+ expected.setTranslate(-50, -50);
+ break;
+ case 3:
+ // overlay
+ EXPECT_EQ(SkRect::MakeLTRB(0, 0, 800, 600), TestUtils::getClipBounds(this));
+ expected.reset();
+ break;
+ default:
+ ADD_FAILURE() << "Too many rects observed";
}
EXPECT_EQ(expected, getTotalMatrix());
}
@@ -300,23 +293,26 @@
transparentPaint.setAlpha(128);
// backdrop
- nodes.push_back(TestUtils::createSkiaNode(100, 100, 700, 500, // 600x400
+ nodes.push_back(TestUtils::createSkiaNode(
+ 100, 100, 700, 500, // 600x400
[&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 600, 400, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 600, 400, transparentPaint);
+ }));
// content
- android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300
- nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
+ android::uirenderer::Rect contentDrawBounds(150, 150, 650, 450); // 500x300
+ nodes.push_back(TestUtils::createSkiaNode(
+ 0, 0, 800, 600,
[&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 600, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 800, 600, transparentPaint);
+ }));
// overlay
- nodes.push_back(TestUtils::createSkiaNode(0, 0, 800, 600,
+ nodes.push_back(TestUtils::createSkiaNode(
+ 0, 0, 800, 600,
[&transparentPaint](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.drawRect(0, 0, 800, 200, transparentPaint);
- }));
+ canvas.drawRect(0, 0, 800, 200, transparentPaint);
+ }));
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeWH(800, 600);
@@ -331,8 +327,7 @@
static const int CANVAS_HEIGHT = 200;
class ClippedTestCanvas : public SkCanvas {
public:
- ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ ClippedTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawImage(const SkImage*, SkScalar dx, SkScalar dy, const SkPaint*) override {
EXPECT_EQ(0, mDrawCounter++);
EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(this));
@@ -342,18 +337,19 @@
};
std::vector<sp<RenderNode>> nodes;
- nodes.push_back(TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ nodes.push_back(TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
- canvas.drawBitmap(*bitmap, 0, 0, nullptr);
- }));
+ sk_sp<Bitmap> bitmap(TestUtils::createBitmap(CANVAS_WIDTH, CANVAS_HEIGHT));
+ canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+ }));
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLTRB(10, 20, 30, 40);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<ClippedTestCanvas>> surface(new DeferLayer<ClippedTestCanvas>());
pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
- SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
+ SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
@@ -362,8 +358,7 @@
static const int CANVAS_HEIGHT = 50;
class ClipReplaceTestCanvas : public SkCanvas {
public:
- ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {
- }
+ ClipReplaceTestCanvas() : SkCanvas(CANVAS_WIDTH, CANVAS_HEIGHT) {}
void onDrawPaint(const SkPaint&) {
EXPECT_EQ(0, mDrawCounter++);
EXPECT_EQ(SkRect::MakeLTRB(20, 10, 30, 40), TestUtils::getClipBounds(this))
@@ -373,17 +368,17 @@
};
std::vector<sp<RenderNode>> nodes;
- nodes.push_back(TestUtils::createSkiaNode(20, 20, 30, 30,
- [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
- canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
- }));
+ nodes.push_back(TestUtils::createSkiaNode(
+ 20, 20, 30, 30, [](RenderProperties& props, SkiaRecordingCanvas& canvas) {
+ canvas.clipRect(0, -20, 10, 30, SkClipOp::kReplace_deprecated);
+ canvas.drawColor(SK_ColorWHITE, SkBlendMode::kSrcOver);
+ }));
LayerUpdateQueue layerUpdateQueue;
SkRect dirty = SkRect::MakeLTRB(10, 10, 40, 40);
auto pipeline = std::make_unique<SkiaOpenGLPipeline>(renderThread);
sk_sp<DeferLayer<ClipReplaceTestCanvas>> surface(new DeferLayer<ClipReplaceTestCanvas>());
pipeline->renderFrame(layerUpdateQueue, dirty, nodes, true, false,
- SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
+ SkRect::MakeWH(CANVAS_WIDTH, CANVAS_HEIGHT), surface);
EXPECT_EQ(1, surface->canvas()->mDrawCounter);
}
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index 95c6ed6..ad5fdac 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -14,23 +14,23 @@
* limitations under the License.
*/
-#include <gtest/gtest.h>
#include <VectorDrawable.h>
+#include <gtest/gtest.h>
+#include <SkClipStack.h>
+#include <SkLiteRecorder.h>
+#include <SkSurface_Base.h>
+#include <string.h>
#include "AnimationContext.h"
#include "DamageAccumulator.h"
+#include "FatalTestCanvas.h"
#include "IContextFactory.h"
+#include "SkiaCanvas.h"
#include "pipeline/skia/SkiaDisplayList.h"
#include "pipeline/skia/SkiaPipeline.h"
#include "pipeline/skia/SkiaRecordingCanvas.h"
#include "renderthread/CanvasContext.h"
#include "tests/common/TestUtils.h"
-#include "SkiaCanvas.h"
-#include <SkSurface_Base.h>
-#include <SkLiteRecorder.h>
-#include <SkClipStack.h>
-#include "FatalTestCanvas.h"
-#include <string.h>
using namespace android;
using namespace android::uirenderer;
@@ -40,7 +40,7 @@
namespace {
static void testProperty(std::function<void(RenderProperties&)> propSetupCallback,
- std::function<void(const SkCanvas&)> opValidateCallback) {
+ std::function<void(const SkCanvas&)> opValidateCallback) {
static const int CANVAS_WIDTH = 100;
static const int CANVAS_HEIGHT = 100;
class PropertyTestCanvas : public TestCanvasBase {
@@ -57,79 +57,88 @@
std::function<void(const SkCanvas&)> mCallback;
};
- auto node = TestUtils::createSkiaNode(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
+ auto node = TestUtils::createSkiaNode(
+ 0, 0, CANVAS_WIDTH, CANVAS_HEIGHT,
[propSetupCallback](RenderProperties& props, SkiaRecordingCanvas& canvas) {
- propSetupCallback(props);
- SkPaint paint;
- paint.setColor(SK_ColorWHITE);
- canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
- });
+ propSetupCallback(props);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.drawRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT, paint);
+ });
PropertyTestCanvas canvas(opValidateCallback);
RenderNodeDrawable drawable(node.get(), &canvas, true);
canvas.drawDrawable(&drawable);
EXPECT_EQ(1, canvas.mDrawCounter);
}
-
}
TEST(RenderNodeDrawable, renderPropClipping) {
- testProperty([](RenderProperties& properties) {
- properties.setClipToBounds(true);
- properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
- }, [](const SkCanvas& canvas) {
- EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas))
- << "Clip rect should be intersection of node bounds and clip bounds";
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setClipToBounds(true);
+ properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
+ },
+ [](const SkCanvas& canvas) {
+ EXPECT_EQ(SkRect::MakeLTRB(10, 20, 100, 100), TestUtils::getClipBounds(&canvas))
+ << "Clip rect should be intersection of node bounds and clip bounds";
+ });
}
TEST(RenderNodeDrawable, renderPropRevealClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableRevealClip().set(true, 50, 50, 25);
- }, [](const SkCanvas& canvas) {
- EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas));
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableRevealClip().set(true, 50, 50, 25);
+ },
+ [](const SkCanvas& canvas) {
+ EXPECT_EQ(SkRect::MakeLTRB(25, 25, 75, 75), TestUtils::getClipBounds(&canvas));
+ });
}
TEST(RenderNodeDrawable, renderPropOutlineClip) {
- testProperty([](RenderProperties& properties) {
- properties.mutableOutline().setShouldClip(true);
- properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
- }, [](const SkCanvas& canvas) {
- EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas));
- });
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.mutableOutline().setShouldClip(true);
+ properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
+ },
+ [](const SkCanvas& canvas) {
+ EXPECT_EQ(SkRect::MakeLTRB(10, 20, 30, 40), TestUtils::getClipBounds(&canvas));
+ });
}
TEST(RenderNodeDrawable, renderPropTransform) {
- testProperty([](RenderProperties& properties) {
- properties.setLeftTopRightBottom(10, 10, 110, 110);
+ testProperty(
+ [](RenderProperties& properties) {
+ properties.setLeftTopRightBottom(10, 10, 110, 110);
- SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
- properties.setStaticMatrix(&staticMatrix);
+ SkMatrix staticMatrix = SkMatrix::MakeScale(1.2f, 1.2f);
+ properties.setStaticMatrix(&staticMatrix);
- // ignored, since static overrides animation
- SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
- properties.setAnimationMatrix(&animationMatrix);
+ // ignored, since static overrides animation
+ SkMatrix animationMatrix = SkMatrix::MakeTrans(15, 15);
+ properties.setAnimationMatrix(&animationMatrix);
- properties.setTranslationX(10);
- properties.setTranslationY(20);
- properties.setScaleX(0.5f);
- properties.setScaleY(0.7f);
- }, [](const SkCanvas& canvas) {
- Matrix4 matrix;
- matrix.loadTranslate(10, 10, 0); // left, top
- matrix.scale(1.2f, 1.2f, 1); // static matrix
- // ignore animation matrix, since static overrides it
+ properties.setTranslationX(10);
+ properties.setTranslationY(20);
+ properties.setScaleX(0.5f);
+ properties.setScaleY(0.7f);
+ },
+ [](const SkCanvas& canvas) {
+ Matrix4 matrix;
+ matrix.loadTranslate(10, 10, 0); // left, top
+ matrix.scale(1.2f, 1.2f, 1); // static matrix
+ // ignore animation matrix, since static overrides it
- // translation xy
- matrix.translate(10, 20);
+ // translation xy
+ matrix.translate(10, 20);
- // scale xy (from default pivot - center)
- matrix.translate(50, 50);
- matrix.scale(0.5f, 0.7f, 1);
- matrix.translate(-50, -50);
- Matrix4 actual(canvas.getTotalMatrix());
- EXPECT_MATRIX_APPROX_EQ(matrix, actual)
- << "Op draw matrix must match expected combination of transformation properties";
- });
+ // scale xy (from default pivot - center)
+ matrix.translate(50, 50);
+ matrix.scale(0.5f, 0.7f, 1);
+ matrix.translate(-50, -50);
+ Matrix4 actual(canvas.getTotalMatrix());
+ EXPECT_MATRIX_APPROX_EQ(matrix, actual) << "Op draw matrix must match expected "
+ "combination of transformation "
+ "properties";
+ });
}
diff --git a/libs/hwui/tests/unit/SnapshotTests.cpp b/libs/hwui/tests/unit/SnapshotTests.cpp
index 11797a8..9d673c8 100644
--- a/libs/hwui/tests/unit/SnapshotTests.cpp
+++ b/libs/hwui/tests/unit/SnapshotTests.cpp
@@ -32,16 +32,16 @@
LinearAllocator allocator;
ClipRect rect(Rect(0, 0, 75, 75));
{
- auto intersectWithChild = child->serializeIntersectedClip(allocator,
- &rect, Matrix4::identity());
+ auto intersectWithChild =
+ child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
ASSERT_NE(nullptr, intersectWithChild);
EXPECT_EQ(Rect(50, 50, 75, 75), intersectWithChild->rect) << "Expect intersect with child";
}
rect.intersectWithRoot = true;
{
- auto intersectWithRoot = child->serializeIntersectedClip(allocator,
- &rect, Matrix4::identity());
+ auto intersectWithRoot =
+ child->serializeIntersectedClip(allocator, &rect, Matrix4::identity());
ASSERT_NE(nullptr, intersectWithRoot);
EXPECT_EQ(Rect(10, 10, 75, 75), intersectWithRoot->rect) << "Expect intersect with root";
}
diff --git a/libs/hwui/tests/unit/StringUtilsTests.cpp b/libs/hwui/tests/unit/StringUtilsTests.cpp
index b60e96c..04fbb51 100644
--- a/libs/hwui/tests/unit/StringUtilsTests.cpp
+++ b/libs/hwui/tests/unit/StringUtilsTests.cpp
@@ -34,7 +34,7 @@
auto collection = StringUtils::split("GL_ext1 GL_ext2 GL_ext3");
EXPECT_TRUE(collection.has("GL_ext1"));
- EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
+ EXPECT_FALSE(collection.has("GL_ext")); // string present, but not in list
}
TEST(StringUtils, sizePrinter) {
diff --git a/libs/hwui/tests/unit/TestUtilsTests.cpp b/libs/hwui/tests/unit/TestUtilsTests.cpp
index 4905957..742fe42 100644
--- a/libs/hwui/tests/unit/TestUtilsTests.cpp
+++ b/libs/hwui/tests/unit/TestUtilsTests.cpp
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-#include "tests/common/TestUtils.h"
#include "Properties.h"
+#include "tests/common/TestUtils.h"
#include <gtest/gtest.h>
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 8312bda..78d75d6 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -18,8 +18,8 @@
#include "GammaFontRenderer.h"
#include "TextDropShadowCache.h"
-#include "utils/Blur.h"
#include "tests/common/TestUtils.h"
+#include "utils/Blur.h"
#include <SkPaint.h>
@@ -40,15 +40,15 @@
std::vector<float> positions;
float totalAdvance;
uirenderer::Rect bounds;
- TestUtils::layoutTextUnscaled(paint, "This is a test",
- &glyphs, &positions, &totalAdvance, &bounds);
+ TestUtils::layoutTextUnscaled(paint, "This is a test", &glyphs, &positions, &totalAdvance,
+ &bounds);
EXPECT_TRUE(bounds.contains(5, -10, 100, 0)) << "Expect input to be nontrivially sized";
ShadowTexture* texture = cache.get(&paint, glyphs.data(), glyphs.size(), 10, positions.data());
ASSERT_TRUE(texture);
ASSERT_FALSE(texture->cleanup);
- ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize());
+ ASSERT_EQ((uint32_t)texture->objectSize(), cache.getSize());
ASSERT_TRUE(cache.getSize());
cache.clear();
ASSERT_EQ(cache.getSize(), 0u);
diff --git a/libs/hwui/tests/unit/ThreadBaseTests.cpp b/libs/hwui/tests/unit/ThreadBaseTests.cpp
index 7aad348..1168ff2 100644
--- a/libs/hwui/tests/unit/ThreadBaseTests.cpp
+++ b/libs/hwui/tests/unit/ThreadBaseTests.cpp
@@ -31,7 +31,8 @@
sp<TestThread> ret{new TestThread};
ret->start("TestThread");
return ret;
- }();
+ }
+ ();
return *thread;
}
@@ -41,9 +42,7 @@
TEST(ThreadBase, post) {
std::atomic_bool ran(false);
- queue().post([&ran]() {
- ran = true;
- });
+ queue().post([&ran]() { ran = true; });
for (int i = 0; !ran && i < 1000; i++) {
usleep(1);
}
@@ -55,9 +54,7 @@
std::promise<nsecs_t> ranAtPromise;
auto queuedAt = clock::now();
- queue().postDelayed(100_us, [&]() {
- ranAtPromise.set_value(clock::now());
- });
+ queue().postDelayed(100_us, [&]() { ranAtPromise.set_value(clock::now()); });
auto ranAt = ranAtPromise.get_future().get();
auto ranAfter = ranAt - queuedAt;
ASSERT_TRUE(ranAfter > 90_us) << "Ran after " << ns2us(ranAfter) << "us <= 90us";
@@ -80,15 +77,9 @@
pid_t thisTid = gettid();
pid_t thisPid = getpid();
- auto otherTid = queue().async([]() -> auto {
- return gettid();
- });
- auto otherPid = queue().async([]() -> auto {
- return getpid();
- });
- auto result = queue().async([]() -> auto {
- return 42;
- });
+ auto otherTid = queue().async([]() -> auto { return gettid(); });
+ auto otherPid = queue().async([]() -> auto { return getpid(); });
+ auto result = queue().async([]() -> auto { return 42; });
ASSERT_NE(thisTid, otherTid.get());
ASSERT_EQ(thisPid, otherPid.get());
@@ -104,9 +95,7 @@
};
struct Counter {
- Counter(EventCount* count) : mCount(count) {
- mCount->construct++;
- }
+ Counter(EventCount* count) : mCount(count) { mCount->construct++; }
Counter(const Counter& other) : mCount(other.mCount) {
if (mCount) mCount->copy++;
@@ -149,17 +138,13 @@
}
int lifecycleTestHelper(const sp<VirtualLightRefBase>& test) {
- return queue().runSync([t = test]() -> int {
- return t->getStrongCount();
- });
+ return queue().runSync([t = test]()->int { return t->getStrongCount(); });
}
TEST(ThreadBase, lifecycle) {
sp<VirtualLightRefBase> dummyObject{new VirtualLightRefBase};
ASSERT_EQ(1, dummyObject->getStrongCount());
- ASSERT_EQ(2, queue().runSync([dummyObject]() -> int {
- return dummyObject->getStrongCount();
- }));
+ ASSERT_EQ(2, queue().runSync([dummyObject]() -> int { return dummyObject->getStrongCount(); }));
ASSERT_EQ(1, dummyObject->getStrongCount());
ASSERT_EQ(2, lifecycleTestHelper(dummyObject));
ASSERT_EQ(1, dummyObject->getStrongCount());
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
index 1f3eaef..1fcc028 100644
--- a/libs/hwui/tests/unit/TypefaceTests.cpp
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -57,17 +57,16 @@
std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
return std::make_shared<minikin::FontFamily>(
- std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+ std::vector<minikin::Font>({minikin::Font(std::move(font), minikin::FontStyle())}));
}
std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
- return std::vector<std::shared_ptr<minikin::FontFamily>>({ buildFamily(fileName) });
+ return std::vector<std::shared_ptr<minikin::FontFamily>>({buildFamily(fileName)});
}
TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
- std::unique_ptr<Typeface> regular(
- Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
- RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ std::unique_ptr<Typeface> regular(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get()));
// Keep the original to restore it later.
@@ -82,128 +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());
+ std::unique_ptr<Typeface> boldItalic(Typeface::createRelative(nullptr, Typeface::kBoldItalic));
+ 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);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(10, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // 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(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);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(6, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // 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(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);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD),
+ // Typeface.BOLD_ITALIC);
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
@@ -211,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);
- std::unique_ptr<Typeface>
- boldItalic(Typeface::createRelative(base.get(), Typeface::kBoldItalic));
- EXPECT_EQ(7, boldItalic->fStyle.getWeight());
- EXPECT_TRUE(boldItalic->fStyle.getItalic());
+ // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC),
+ // Typeface.BOLD_ITALIC);
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kBoldItalic, boldItalic->fAPIStyle);
}
@@ -247,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,
@@ -256,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,
@@ -265,155 +279,160 @@
// .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,
// Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
// .setWeight(700).setItalic(false).build();
// 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());
+ std::unique_ptr<Typeface> boldItalic(
+ Typeface::createRelative(base.get(), Typeface::kBoldItalic));
+ 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);
}
TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) {
// 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());
+ std::unique_ptr<Typeface> regular(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoRegular), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ 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());
+ std::unique_ptr<Typeface> bold(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoBold), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ 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());
+ std::unique_ptr<Typeface> italic(Typeface::createFromFamilies(
+ makeSingleFamlyVector(kRobotoItalic), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ 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());
+ RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(700, boldItalic->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::ITALIC, boldItalic->fStyle.slant);
EXPECT_EQ(Typeface::kItalic, italic->fAPIStyle);
}
TEST(TypefaceTest, createFromFamilies_Family) {
std::vector<std::shared_ptr<minikin::FontFamily>> families = {
buildFamily(kRobotoRegular), 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(4, typeface->fStyle.getWeight());
- EXPECT_FALSE(typeface->fStyle.getItalic());
+ buildFamily(kRobotoBoldItalic)};
+ std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(
+ std::move(families), RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+ EXPECT_EQ(400, typeface->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, typeface->fStyle.slant);
}
TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) {
std::vector<std::shared_ptr<minikin::FontFamily>> families = {
- 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());
+ 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(700, typeface->fStyle.weight);
+ EXPECT_EQ(minikin::FontSlant::UPRIGHT, typeface->fStyle.slant);
}
} // namespace
diff --git a/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp b/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
index 17f8176..0c95fdd 100644
--- a/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableAtlasTests.cpp
@@ -16,9 +16,9 @@
#include <gtest/gtest.h>
-#include "tests/common/TestUtils.h"
#include <GrRectanizer.h>
#include "pipeline/skia/VectorDrawableAtlas.h"
+#include "tests/common/TestUtils.h"
using namespace android;
using namespace android::uirenderer;
@@ -26,16 +26,16 @@
using namespace android::uirenderer::skiapipeline;
RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, addGetRemove) {
- VectorDrawableAtlas atlas(100*100);
+ VectorDrawableAtlas atlas(100 * 100);
atlas.prepareForDraw(renderThread.getGrContext());
- //create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
+ // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
const int MAX_RECTS = 150;
AtlasEntry VDRects[MAX_RECTS];
sk_sp<SkSurface> atlasSurface;
- //check we are able to allocate new rects
- //check that rects in the atlas do not intersect
+ // check we are able to allocate new rects
+ // check that rects in the atlas do not intersect
for (uint32_t i = 0; i < MAX_RECTS; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
if (0 == i) {
@@ -45,7 +45,7 @@
ASSERT_TRUE(VDRects[i].surface.get() != nullptr);
ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
- //nothing in the atlas should intersect
+ // nothing in the atlas should intersect
if (atlasSurface.get() == VDRects[i].surface.get()) {
for (uint32_t j = 0; j < i; j++) {
if (atlasSurface.get() == VDRects[j].surface.get()) {
@@ -55,16 +55,16 @@
}
}
- //first 1/3 rects should all be in the same surface
- for (uint32_t i = 1; i < MAX_RECTS/3; i++) {
+ // first 1/3 rects should all be in the same surface
+ for (uint32_t i = 1; i < MAX_RECTS / 3; i++) {
ASSERT_NE(VDRects[i].key, VDRects[0].key);
ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
}
- //first rect is using atlas and last is a standalone surface
- ASSERT_NE(VDRects[0].surface.get(), VDRects[MAX_RECTS-1].surface.get());
+ // first rect is using atlas and last is a standalone surface
+ ASSERT_NE(VDRects[0].surface.get(), VDRects[MAX_RECTS - 1].surface.get());
- //check getEntry returns the same surfaces that we had created
+ // check getEntry returns the same surfaces that we had created
for (uint32_t i = 0; i < MAX_RECTS; i++) {
auto VDRect = atlas.getEntry(VDRects[i].key);
ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY);
@@ -74,9 +74,9 @@
atlas.releaseEntry(VDRect.key);
}
- //check that any new rects will be allocated in the atlas, even that rectanizer is full.
- //rects in the atlas should not intersect.
- for (uint32_t i = 0; i < MAX_RECTS/3; i++) {
+ // check that any new rects will be allocated in the atlas, even that rectanizer is full.
+ // rects in the atlas should not intersect.
+ for (uint32_t i = 0; i < MAX_RECTS / 3; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
@@ -87,25 +87,24 @@
}
}
-
RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, disallowSharedSurface) {
- VectorDrawableAtlas atlas(100*100);
- //don't allow to use a shared surface
+ VectorDrawableAtlas atlas(100 * 100);
+ // don't allow to use a shared surface
atlas.setStorageMode(VectorDrawableAtlas::StorageMode::disallowSharedSurface);
atlas.prepareForDraw(renderThread.getGrContext());
- //create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
+ // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
const int MAX_RECTS = 150;
AtlasEntry VDRects[MAX_RECTS];
- //check we are able to allocate new rects
- //check that rects in the atlas use unique surfaces
+ // check we are able to allocate new rects
+ // check that rects in the atlas use unique surfaces
for (uint32_t i = 0; i < MAX_RECTS; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
ASSERT_TRUE(VDRects[i].key != INVALID_ATLAS_KEY);
ASSERT_TRUE(VDRects[i].surface.get() != nullptr);
ASSERT_TRUE(VDRects[i].rect.width() == 10 && VDRects[i].rect.height() == 10);
- //nothing in the atlas should use the same surface
+ // nothing in the atlas should use the same surface
for (uint32_t j = 0; j < i; j++) {
ASSERT_NE(VDRects[i].surface.get(), VDRects[j].surface.get());
}
@@ -113,17 +112,17 @@
}
RENDERTHREAD_SKIA_PIPELINE_TEST(VectorDrawableAtlas, repack) {
- VectorDrawableAtlas atlas(100*100);
+ VectorDrawableAtlas atlas(100 * 100);
ASSERT_FALSE(atlas.isFragmented());
atlas.prepareForDraw(renderThread.getGrContext());
ASSERT_FALSE(atlas.isFragmented());
- //create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
+ // create 150 rects 10x10, which won't fit in the atlas (atlas can fit no more than 100 rects)
const int MAX_RECTS = 150;
AtlasEntry VDRects[MAX_RECTS];
sk_sp<SkSurface> atlasSurface;
- //fill the atlas with check we are able to allocate new rects
+ // fill the atlas with check we are able to allocate new rects
for (uint32_t i = 0; i < MAX_RECTS; i++) {
VDRects[i] = atlas.requestNewEntry(10, 10, renderThread.getGrContext());
if (0 == i) {
@@ -134,13 +133,13 @@
ASSERT_FALSE(atlas.isFragmented());
- //first 1/3 rects should all be in the same surface
- for (uint32_t i = 1; i < MAX_RECTS/3; i++) {
+ // first 1/3 rects should all be in the same surface
+ for (uint32_t i = 1; i < MAX_RECTS / 3; i++) {
ASSERT_NE(VDRects[i].key, VDRects[0].key);
ASSERT_EQ(VDRects[i].surface.get(), atlasSurface.get());
}
- //release all entries
+ // release all entries
for (uint32_t i = 0; i < MAX_RECTS; i++) {
auto VDRect = atlas.getEntry(VDRects[i].key);
ASSERT_TRUE(VDRect.key != INVALID_ATLAS_KEY);
@@ -149,9 +148,9 @@
ASSERT_FALSE(atlas.isFragmented());
- //allocate 4x4 rects, which will fragment the atlas badly, because each entry occupies a 10x10
- //area
- for (uint32_t i = 0; i < 4*MAX_RECTS; i++) {
+ // allocate 4x4 rects, which will fragment the atlas badly, because each entry occupies a 10x10
+ // area
+ for (uint32_t i = 0; i < 4 * MAX_RECTS; i++) {
AtlasEntry entry = atlas.requestNewEntry(4, 4, renderThread.getGrContext());
ASSERT_TRUE(entry.key != INVALID_ATLAS_KEY);
}
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 1c21567..a92cbfd 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -33,195 +33,239 @@
};
const static TestData sTestDataSet[] = {
- // TestData with scientific notation -2e3 etc.
- {
- // Path
- "M2.000000,22.000000l20.000000,0.000000 1e0-2e3z",
- {
- // Verbs
- {'M', 'l', 'z'},
- // Verb sizes
- {2, 4, 0},
- // Points
- {2, 22, 20, 0, 1, -2000},
- },
- [](SkPath* outPath) {
- outPath->moveTo(2, 22);
- outPath->rLineTo(20, 0);
- outPath->rLineTo(1, -2000);
- outPath->close();
- outPath->moveTo(2, 22);
- }
- },
+ // TestData with scientific notation -2e3 etc.
+ {// Path
+ "M2.000000,22.000000l20.000000,0.000000 1e0-2e3z",
+ {
+ // Verbs
+ {'M', 'l', 'z'},
+ // Verb sizes
+ {2, 4, 0},
+ // Points
+ {2, 22, 20, 0, 1, -2000},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(2, 22);
+ outPath->rLineTo(20, 0);
+ outPath->rLineTo(1, -2000);
+ outPath->close();
+ outPath->moveTo(2, 22);
+ }},
- // Comprehensive data, containing all the verbs possible.
- {
- // Path
- "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10",
- {
- // Verbs
- {'M', 'm', 'l', 'L', 'H', 'h', 'V', 'v', 'Q', 'q', 't', 'T', 'C', 'c', 'S', 's', 'A', 'a'},
- // VerbSizes
- {2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, 6, 6, 4, 4, 7, 7},
- // Points
- {1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, }
- },
- [](SkPath* outPath) {
- outPath->moveTo(1.0, 1.0);
- outPath->rMoveTo(2.0, 2.0);
- outPath->rLineTo(3.0, 3.0);
- outPath->lineTo(3.0, 3.0);
- outPath->lineTo(4.0, 3.0);
- outPath->rLineTo(4.0, 0);
- outPath->lineTo(8.0, 5.0);
- outPath->rLineTo(0, 5.0);
- outPath->quadTo(6.0, 6.0, 6.0, 6.0);
- outPath->rQuadTo(6.0, 6.0, 6.0, 6.0);
- outPath->rQuadTo(0.0, 0.0, 7.0, 7.0);
- outPath->quadTo(26.0, 26.0, 7.0, 7.0);
- outPath->cubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
- outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
- outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
- outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
- outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767, 22.8911717921705, 16.737515350332117, 24.986664170401575);
- outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483, 28.644011882390082, 11.155893964798905, 29.37447073281729);
- outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471, 29.954422532383525, 4.0686829203897235, 28.951642951534332);
- outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696, 26.161860541657013, -0.9516429515343354, 23.931317079610267);
- outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987, 19.178055668693663, -1.37447073281729, 16.844106035201087);
- outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546, 12.523358440585524, 3.0133358295984305, 11.262484649667876);
- outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984, 9.552224962671648, 10.000000000000005, 10.0);
- outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881, 12.928932188134523, 2.9289321881345254);
- outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972, 4.870079381441987E-16, 19.999999999999996, 0.0);
- outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112, 1.0542876468501678, 27.071067811865476, 2.9289321881345227);
- outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0, 9.999999999999998);
- outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112, 27.071067811865476, 17.071067811865476);
- outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0, 20.000000000000004, 20.0);
- }
- },
+ // Comprehensive data, containing all the verbs possible.
+ {// Path
+ "M 1 1 m 2 2, l 3 3 L 3 3 H 4 h4 V5 v5, Q6 6 6 6 q 6 6 6 6t 7 7 T 7 7 C 8 8 8 8 8 8 c 8 8 "
+ "8 8 8 8 S 9 9 9 9 s 9 9 9 9 A 10 10 0 1 1 10 10 a 10 10 0 1 1 10 10",
+ {// Verbs
+ {'M', 'm', 'l', 'L', 'H', 'h', 'V', 'v', 'Q', 'q', 't', 'T', 'C', 'c', 'S', 's', 'A',
+ 'a'},
+ // VerbSizes
+ {2, 2, 2, 2, 1, 1, 1, 1, 4, 4, 2, 2, 6, 6, 4, 4, 7, 7},
+ // Points
+ {
+ 1.0, 1.0, 2.0, 2.0, 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 5.0, 5.0, 6.0, 6.0, 6.0,
+ 6.0, 6.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0, 8.0, 8.0,
+ 8.0, 8.0, 8.0, 8.0, 8.0, 8.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 9.0, 10.0,
+ 10.0, 0.0, 1.0, 1.0, 10.0, 10.0, 10.0, 10.0, 0.0, 1.0, 1.0, 10.0, 10.0,
+ }},
+ [](SkPath* outPath) {
+ outPath->moveTo(1.0, 1.0);
+ outPath->rMoveTo(2.0, 2.0);
+ outPath->rLineTo(3.0, 3.0);
+ outPath->lineTo(3.0, 3.0);
+ outPath->lineTo(4.0, 3.0);
+ outPath->rLineTo(4.0, 0);
+ outPath->lineTo(8.0, 5.0);
+ outPath->rLineTo(0, 5.0);
+ outPath->quadTo(6.0, 6.0, 6.0, 6.0);
+ outPath->rQuadTo(6.0, 6.0, 6.0, 6.0);
+ outPath->rQuadTo(0.0, 0.0, 7.0, 7.0);
+ outPath->quadTo(26.0, 26.0, 7.0, 7.0);
+ outPath->cubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
+ outPath->rCubicTo(8.0, 8.0, 8.0, 8.0, 8.0, 8.0);
+ outPath->cubicTo(16.0, 16.0, 9.0, 9.0, 9.0, 9.0);
+ outPath->rCubicTo(0.0, 0.0, 9.0, 9.0, 9.0, 9.0);
+ outPath->cubicTo(18.447775037328352, 20.404243860300607, 17.998389141249767,
+ 22.8911717921705, 16.737515350332117, 24.986664170401575);
+ outPath->cubicTo(15.476641559414468, 27.08215654863265, 13.489843598291483,
+ 28.644011882390082, 11.155893964798905, 29.37447073281729);
+ outPath->cubicTo(8.821944331306327, 30.1049295832445, 6.299226382436471,
+ 29.954422532383525, 4.0686829203897235, 28.951642951534332);
+ outPath->cubicTo(1.838139458342976, 27.94886337068514, 0.05113662931485696,
+ 26.161860541657013, -0.9516429515343354, 23.931317079610267);
+ outPath->cubicTo(-1.9544225323835278, 21.70077361756352, -2.1049295832444987,
+ 19.178055668693663, -1.37447073281729, 16.844106035201087);
+ outPath->cubicTo(-0.6440118823900814, 14.51015640170851, 0.9178434513673546,
+ 12.523358440585524, 3.0133358295984305, 11.262484649667876);
+ outPath->cubicTo(5.108828207829506, 10.001610858750228, 7.5957561396993984,
+ 9.552224962671648, 10.000000000000005, 10.0);
+ outPath->cubicTo(10.0, 7.348852265086975, 11.054287646850167, 4.803576729418881,
+ 12.928932188134523, 2.9289321881345254);
+ outPath->cubicTo(14.803576729418879, 1.0542876468501696, 17.348852265086972,
+ 4.870079381441987E-16, 19.999999999999996, 0.0);
+ outPath->cubicTo(22.65114773491302, -4.870079381441987E-16, 25.19642327058112,
+ 1.0542876468501678, 27.071067811865476, 2.9289321881345227);
+ outPath->cubicTo(28.94571235314983, 4.803576729418878, 30.0, 7.348852265086974, 30.0,
+ 9.999999999999998);
+ outPath->cubicTo(30.0, 12.651147734913023, 28.94571235314983, 15.19642327058112,
+ 27.071067811865476, 17.071067811865476);
+ outPath->cubicTo(25.19642327058112, 18.94571235314983, 22.651147734913028, 20.0,
+ 20.000000000000004, 20.0);
+ }},
- // Check box VectorDrawable path data
- {
- // Path
- "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c 0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 -1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
- {
- {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
- {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
- {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0, 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0, -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
- },
- [](SkPath* outPath) {
- outPath->moveTo(0.0, -1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
- outPath->rLineTo(0.0, 0.0);
- outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
- outPath->close();
- outPath->moveTo(0.0, -1.0);
- outPath->moveTo(7.0, -9.0);
- outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
- outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
- outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
- outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
- outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
- outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
- outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
- outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
- outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
- outPath->close();
- outPath->moveTo(7.0, -9.0);
- }
- },
+ // Check box VectorDrawable path data
+ {// Path
+ "M 0.0,-1.0 l 0.0,0.0 c 0.5522847498,0.0 1.0,0.4477152502 1.0,1.0 l 0.0,0.0 c "
+ "0.0,0.5522847498 -0.4477152502,1.0 -1.0,1.0 l 0.0,0.0 c -0.5522847498,0.0 "
+ "-1.0,-0.4477152502 -1.0,-1.0 l 0.0,0.0 c 0.0,-0.5522847498 0.4477152502,-1.0 1.0,-1.0 Z "
+ "M 7.0,-9.0 c 0.0,0.0 -14.0,0.0 -14.0,0.0 c -1.1044921875,0.0 -2.0,0.8955078125 -2.0,2.0 "
+ "c 0.0,0.0 0.0,14.0 0.0,14.0 c 0.0,1.1044921875 0.8955078125,2.0 2.0,2.0 c 0.0,0.0 "
+ "14.0,0.0 14.0,0.0 c 1.1044921875,0.0 2.0,-0.8955078125 2.0,-2.0 c 0.0,0.0 0.0,-14.0 "
+ "0.0,-14.0 c 0.0,-1.1044921875 -0.8955078125,-2.0 -2.0,-2.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z",
+ {
+ {'M', 'l', 'c', 'l', 'c', 'l', 'c', 'l', 'c', 'Z', 'M',
+ 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'Z'},
+ {2, 2, 6, 2, 6, 2, 6, 2, 6, 0, 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ {0.0, -1.0, 0.0, 0.0, 0.5522848, 0.0, 1.0,
+ 0.44771525, 1.0, 1.0, 0.0, 0.0, 0.0, 0.5522848,
+ -0.44771525, 1.0, -1.0, 1.0, 0.0, 0.0, -0.5522848,
+ 0.0, -1.0, -0.44771525, -1.0, -1.0, 0.0, 0.0,
+ 0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0, 7.0,
+ -9.0, 0.0, 0.0, -14.0, 0.0, -14.0, 0.0,
+ -1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0, 0.0,
+ 0.0, 0.0, 14.0, 0.0, 14.0, 0.0, 1.1044922,
+ 0.8955078, 2.0, 2.0, 2.0, 0.0, 0.0, 14.0,
+ 0.0, 14.0, 0.0, 1.1044922, 0.0, 2.0, -0.8955078,
+ 2.0, -2.0, 0.0, 0.0, 0.0, -14.0, 0.0,
+ -14.0, 0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(0.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.5522848, 0.0, 1.0, 0.44771525, 1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, 0.5522848, -0.44771525, 1.0, -1.0, 1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(-0.5522848, 0.0, -1.0, -0.44771525, -1.0, -1.0);
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rCubicTo(0.0, -0.5522848, 0.44771525, -1.0, 1.0, -1.0);
+ outPath->close();
+ outPath->moveTo(0.0, -1.0);
+ outPath->moveTo(7.0, -9.0);
+ outPath->rCubicTo(0.0, 0.0, -14.0, 0.0, -14.0, 0.0);
+ outPath->rCubicTo(-1.1044922, 0.0, -2.0, 0.8955078, -2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 14.0, 0.0, 14.0);
+ outPath->rCubicTo(0.0, 1.1044922, 0.8955078, 2.0, 2.0, 2.0);
+ outPath->rCubicTo(0.0, 0.0, 14.0, 0.0, 14.0, 0.0);
+ outPath->rCubicTo(1.1044922, 0.0, 2.0, -0.8955078, 2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, -14.0, 0.0, -14.0);
+ outPath->rCubicTo(0.0, -1.1044922, -0.8955078, -2.0, -2.0, -2.0);
+ outPath->rCubicTo(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+ outPath->close();
+ outPath->moveTo(7.0, -9.0);
+ }},
- // pie1 in progress bar
- {
- "M300,70 a230,230 0 1,0 1,0 z",
- {
- {'M', 'a', 'z', },
- {2, 7, 0, },
- {300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0, },
- },
- [](SkPath* outPath) {
- outPath->moveTo(300.0, 70.0);
- outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267, 94.47383115953485, 137.6004913602211, 137.6302781499585);
- outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275, 239.3163266242308, 70.50013586976587, 300.2494566687817);
- outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249, 419.65954850554147, 137.9538527586204, 462.72238058830936);
- outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056, 529.999456521097, 300.49999999999994, 529.999456521097);
- outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176, 505.78521267107726, 463.0461472413797, 462.7223805883093);
- outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891, 361.1825867133324, 530.4998641302341, 300.2494566687815);
- outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844, 180.7867251403819, 463.3995086397787, 137.6302781499583);
- outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255, 70.13246340443492, 300.9999999999996, 70.00000000000003);
- outPath->close();
- outPath->moveTo(300.0, 70.0);
- }
- },
+ // pie1 in progress bar
+ {"M300,70 a230,230 0 1,0 1,0 z",
+ {
+ {
+ 'M', 'a', 'z',
+ },
+ {
+ 2, 7, 0,
+ },
+ {
+ 300.0, 70.0, 230.0, 230.0, 0.0, 1.0, 0.0, 1.0, 0.0,
+ },
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(300.0, 70.0);
+ outPath->cubicTo(239.06697794203706, 70.13246340443499, 180.6164396449267,
+ 94.47383115953485, 137.6004913602211, 137.6302781499585);
+ outPath->cubicTo(94.58454307551551, 180.78672514038215, 70.43390412842275,
+ 239.3163266242308, 70.50013586976587, 300.2494566687817);
+ outPath->cubicTo(70.56636761110899, 361.1825867133326, 94.84418775550249,
+ 419.65954850554147, 137.9538527586204, 462.72238058830936);
+ outPath->cubicTo(181.06351776173827, 505.7852126710772, 239.5668339599056,
+ 529.999456521097, 300.49999999999994, 529.999456521097);
+ outPath->cubicTo(361.43316604009436, 529.999456521097, 419.93648223826176,
+ 505.78521267107726, 463.0461472413797, 462.7223805883093);
+ outPath->cubicTo(506.1558122444976, 419.65954850554135, 530.433632388891,
+ 361.1825867133324, 530.4998641302341, 300.2494566687815);
+ outPath->cubicTo(530.5660958715771, 239.31632662423056, 506.4154569244844,
+ 180.7867251403819, 463.3995086397787, 137.6302781499583);
+ outPath->cubicTo(420.383560355073, 94.47383115953468, 361.93302205796255,
+ 70.13246340443492, 300.9999999999996, 70.00000000000003);
+ outPath->close();
+ outPath->moveTo(300.0, 70.0);
+ }},
- // Random long data
- {
- // Path
- "M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 -0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 -12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z",
- {
- // Verbs
- {'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'C', 'z'},
- // Verb sizes
- {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
- // Points
- {5.3, 13.2, -0.1, 0, -0.3, 0, -0.4, -0.1, -0.3, -0.2, -0.4, -0.7, -0.2, -1, 1.3, -1.9, 2.9, -3.4, 4.9, -4.5, 4.1, -2.2, 9.3, -2.2, 13.4, 0, 1.9, 1.1, 3.6, 2.5, 4.9, 4.4, 0.2, 0.3, 0.1, 0.8, -0.2, 1, -0.3, 0.2, -0.8, 0.1, -1, -0.2, -1.2, -1.7, -2.6, -3, -4.3, -4, -3.7, -2, -8.3, -2, -12, 0, -1.7, 0.9, -3.2, 2.3, -4.3, 4, 5.7, 13.1, 5.5, 13.2, 5.3, 13.2},
- },
- [](SkPath* outPath) {
- outPath->moveTo(5.3, 13.2);
- outPath->rCubicTo(-0.1, 0.0, -0.3, 0.0, -0.4, -0.1);
- outPath->rCubicTo(-0.3, -0.2, -0.4, -0.7, -0.2, -1.0);
- outPath->rCubicTo(1.3, -1.9, 2.9, -3.4, 4.9, -4.5);
- outPath->rCubicTo(4.1, -2.2, 9.3, -2.2, 13.4, 0.0);
- outPath->rCubicTo(1.9, 1.1, 3.6, 2.5, 4.9, 4.4);
- outPath->rCubicTo(0.2, 0.3, 0.1, 0.8, -0.2, 1.0);
- outPath->rCubicTo(-0.3, 0.2, -0.8, 0.1, -1.0, -0.2);
- outPath->rCubicTo(-1.2, -1.7, -2.6, -3.0, -4.3, -4.0);
- outPath->rCubicTo(-3.7, -2.0, -8.3, -2.0, -12.0, 0.0);
- outPath->rCubicTo(-1.7, 0.9, -3.2, 2.3, -4.3, 4.0);
- outPath->cubicTo(5.7, 13.1, 5.5, 13.2, 5.3, 13.2);
- outPath->close();
- outPath->moveTo(5.3, 13.2);
- }
- },
+ // Random long data
+ {// Path
+ "M5.3,13.2c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,-0.2 -0.4,-0.7 -0.2,-1.0c1.3,-1.9 2.9,-3.4 "
+ "4.9,-4.5c4.1,-2.2 9.3,-2.2 13.4,0.0c1.9,1.1 3.6,2.5 4.9,4.4c0.2,0.3 0.1,0.8 "
+ "-0.2,1.0c-0.3,0.2 -0.8,0.1 -1.0,-0.2c-1.2,-1.7 -2.6,-3.0 -4.3,-4.0c-3.7,-2.0 -8.3,-2.0 "
+ "-12.0,0.0c-1.7,0.9 -3.2,2.3 -4.3,4.0C5.7,13.1 5.5,13.2 5.3,13.2z",
+ {
+ // Verbs
+ {'M', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'c', 'C', 'z'},
+ // Verb sizes
+ {2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0},
+ // Points
+ {5.3, 13.2, -0.1, 0, -0.3, 0, -0.4, -0.1, -0.3, -0.2, -0.4, -0.7, -0.2, -1,
+ 1.3, -1.9, 2.9, -3.4, 4.9, -4.5, 4.1, -2.2, 9.3, -2.2, 13.4, 0, 1.9, 1.1,
+ 3.6, 2.5, 4.9, 4.4, 0.2, 0.3, 0.1, 0.8, -0.2, 1, -0.3, 0.2, -0.8, 0.1,
+ -1, -0.2, -1.2, -1.7, -2.6, -3, -4.3, -4, -3.7, -2, -8.3, -2, -12, 0,
+ -1.7, 0.9, -3.2, 2.3, -4.3, 4, 5.7, 13.1, 5.5, 13.2, 5.3, 13.2},
+ },
+ [](SkPath* outPath) {
+ outPath->moveTo(5.3, 13.2);
+ outPath->rCubicTo(-0.1, 0.0, -0.3, 0.0, -0.4, -0.1);
+ outPath->rCubicTo(-0.3, -0.2, -0.4, -0.7, -0.2, -1.0);
+ outPath->rCubicTo(1.3, -1.9, 2.9, -3.4, 4.9, -4.5);
+ outPath->rCubicTo(4.1, -2.2, 9.3, -2.2, 13.4, 0.0);
+ outPath->rCubicTo(1.9, 1.1, 3.6, 2.5, 4.9, 4.4);
+ outPath->rCubicTo(0.2, 0.3, 0.1, 0.8, -0.2, 1.0);
+ outPath->rCubicTo(-0.3, 0.2, -0.8, 0.1, -1.0, -0.2);
+ outPath->rCubicTo(-1.2, -1.7, -2.6, -3.0, -4.3, -4.0);
+ outPath->rCubicTo(-3.7, -2.0, -8.3, -2.0, -12.0, 0.0);
+ outPath->rCubicTo(-1.7, 0.9, -3.2, 2.3, -4.3, 4.0);
+ outPath->cubicTo(5.7, 13.1, 5.5, 13.2, 5.3, 13.2);
+ outPath->close();
+ outPath->moveTo(5.3, 13.2);
+ }},
- // Extreme case with numbers and decimal points crunched together
- {
- // Path
- "l0.0.0.5.0.0.5-0.5.0.0-.5z",
- {
- // Verbs
- {'l', 'z'},
- // Verb sizes
- {10, 0},
- // Points
- {0, 0, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5},
- },
- [](SkPath* outPath) {
- outPath->rLineTo(0.0, 0.0);
- outPath->rLineTo(0.5, 0.0);
- outPath->rLineTo(0.0, 0.5);
- outPath->rLineTo(-0.5, 0.0);
- outPath->rLineTo(0.0, -0.5);
- outPath->close();
- outPath->moveTo(0.0, 0.0);
- }
- },
+ // Extreme case with numbers and decimal points crunched together
+ {// Path
+ "l0.0.0.5.0.0.5-0.5.0.0-.5z",
+ {
+ // Verbs
+ {'l', 'z'},
+ // Verb sizes
+ {10, 0},
+ // Points
+ {0, 0, 0.5, 0, 0, 0.5, -0.5, 0, 0, -0.5},
+ },
+ [](SkPath* outPath) {
+ outPath->rLineTo(0.0, 0.0);
+ outPath->rLineTo(0.5, 0.0);
+ outPath->rLineTo(0.0, 0.5);
+ outPath->rLineTo(-0.5, 0.0);
+ outPath->rLineTo(0.0, -0.5);
+ outPath->close();
+ outPath->moveTo(0.0, 0.0);
+ }},
- // Empty test data
- {
- "",
- {
- // Verbs
- {},
- {},
- {},
- },
- [](SkPath* outPath) {}
- }
+ // Empty test data
+ {"",
+ {
+ // Verbs
+ {},
+ {},
+ {},
+ },
+ [](SkPath* outPath) {}}
};
@@ -231,22 +275,21 @@
};
const StringPath sStringPaths[] = {
- {"3e...3", false}, // Not starting with a verb and ill-formatted float
- {"L.M.F.A.O", false}, // No floats following verbs
- {"m 1 1", true}, // Valid path data
- {"\n \t z", true}, // Valid path data with leading spaces
- {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
- {"f 4 5", false}, // Invalid verb
- {"\r ", false} // Empty string
+ {"3e...3", false}, // Not starting with a verb and ill-formatted float
+ {"L.M.F.A.O", false}, // No floats following verbs
+ {"m 1 1", true}, // Valid path data
+ {"\n \t z", true}, // Valid path data with leading spaces
+ {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
+ {"f 4 5", false}, // Invalid verb
+ {"\r ", false} // Empty string
};
-
static bool hasSameVerbs(const PathData& from, const PathData& to) {
return from.verbs == to.verbs && from.verbSizes == to.verbSizes;
}
TEST(PathParser, parseStringForData) {
- for (TestData testData: sTestDataSet) {
+ for (TestData testData : sTestDataSet) {
PathParser::ParseResult result;
// Test generated path data against the given data.
PathData pathData;
@@ -259,14 +302,14 @@
PathParser::ParseResult result;
PathData pathData;
SkPath skPath;
- PathParser::getPathDataFromAsciiString(&pathData, &result,
- stringPath.stringPath, strlen(stringPath.stringPath));
+ PathParser::getPathDataFromAsciiString(&pathData, &result, stringPath.stringPath,
+ strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
}
TEST(VectorDrawableUtils, createSkPathFromPathData) {
- for (TestData testData: sTestDataSet) {
+ for (TestData testData : sTestDataSet) {
SkPath expectedPath;
testData.skPathLamda(&expectedPath);
SkPath actualPath;
@@ -276,7 +319,7 @@
}
TEST(PathParser, parseAsciiStringForSkPath) {
- for (TestData testData: sTestDataSet) {
+ for (TestData testData : sTestDataSet) {
PathParser::ParseResult result;
size_t length = strlen(testData.pathString);
// Check the return value as well as the SkPath generated.
@@ -293,14 +336,14 @@
PathParser::ParseResult result;
SkPath skPath;
PathParser::parseAsciiStringForSkPath(&skPath, &result, stringPath.stringPath,
- strlen(stringPath.stringPath));
+ strlen(stringPath.stringPath));
EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
}
}
TEST(VectorDrawableUtils, morphPathData) {
- for (TestData fromData: sTestDataSet) {
- for (TestData toData: sTestDataSet) {
+ for (TestData fromData : sTestDataSet) {
+ for (TestData toData : sTestDataSet) {
bool canMorph = VectorDrawableUtils::canMorph(fromData.pathData, toData.pathData);
if (fromData.pathData == toData.pathData) {
EXPECT_TRUE(canMorph);
@@ -314,11 +357,11 @@
TEST(VectorDrawableUtils, interpolatePathData) {
// Interpolate path data with itself and every other path data
- for (TestData fromData: sTestDataSet) {
- for (TestData toData: sTestDataSet) {
+ for (TestData fromData : sTestDataSet) {
+ for (TestData toData : sTestDataSet) {
PathData outData;
bool success = VectorDrawableUtils::interpolatePathData(&outData, fromData.pathData,
- toData.pathData, 0.5);
+ toData.pathData, 0.5);
bool expectedToMorph = hasSameVerbs(fromData.pathData, toData.pathData);
EXPECT_EQ(expectedToMorph, success);
}
@@ -335,12 +378,12 @@
PathData outData;
// Interpolate the two path data with different fractions
for (float fraction : fractions) {
- bool success = VectorDrawableUtils::interpolatePathData(
- &outData, fromPathData, toPathData, fraction);
+ bool success = VectorDrawableUtils::interpolatePathData(&outData, fromPathData,
+ toPathData, fraction);
EXPECT_TRUE(success);
for (size_t i = 0; i < outData.points.size(); i++) {
- float expectedResult = fromPathData.points[i] * (1.0 - fraction) +
- toPathData.points[i] * fraction;
+ float expectedResult =
+ fromPathData.points[i] * (1.0 - fraction) + toPathData.points[i] * fraction;
EXPECT_TRUE(MathUtils::areEqual(expectedResult, outData.points[i]));
}
}
@@ -348,7 +391,7 @@
}
TEST(VectorDrawable, groupProperties) {
- //TODO: Also need to test property sync and dirty flag when properties change.
+ // TODO: Also need to test property sync and dirty flag when properties change.
VectorDrawable::Group group;
VectorDrawable::Group::GroupProperties* properties = group.mutateProperties();
// Test default values, change values through setters and verify the change through getters.
@@ -379,7 +422,6 @@
EXPECT_EQ(0.0f, properties->getPivotY());
properties->setPivotY(1.0f);
EXPECT_EQ(1.0f, properties->getPivotY());
-
}
TEST(VectorDrawable, drawPathWithoutIncrementingShaderRefCount) {
@@ -402,5 +444,5 @@
EXPECT_TRUE(shader->unique());
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/tests/unit/main.cpp b/libs/hwui/tests/unit/main.cpp
index cea84c0..406255d 100644
--- a/libs/hwui/tests/unit/main.cpp
+++ b/libs/hwui/tests/unit/main.cpp
@@ -14,15 +14,15 @@
* limitations under the License.
*/
-#include "gtest/gtest.h"
#include "gmock/gmock.h"
+#include "gtest/gtest.h"
#include "Caches.h"
#include "debug/GlesDriver.h"
#include "debug/NullGlesDriver.h"
#include "hwui/Typeface.h"
-#include "thread/TaskManager.h"
#include "tests/common/LeakChecker.h"
+#include "thread/TaskManager.h"
#include <signal.h>
@@ -31,17 +31,14 @@
using namespace android::uirenderer;
static auto CRASH_SIGNALS = {
- SIGABRT,
- SIGSEGV,
- SIGBUS,
+ SIGABRT, SIGSEGV, SIGBUS,
};
static map<int, struct sigaction> gSigChain;
static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) {
auto testinfo = ::testing::UnitTest::GetInstance()->current_test_info();
- printf("[ FAILED ] %s.%s\n", testinfo->test_case_name(),
- testinfo->name());
+ printf("[ FAILED ] %s.%s\n", testinfo->test_case_name(), testinfo->name());
printf("[ FATAL! ] Process crashed, aborting tests!\n");
fflush(stdout);
@@ -53,9 +50,7 @@
class TypefaceEnvironment : public testing::Environment {
public:
- virtual void SetUp() {
- Typeface::setRobotoTypefaceForTest();
- }
+ virtual void SetUp() { Typeface::setRobotoTypefaceForTest(); }
};
int main(int argc, char* argv[]) {
@@ -83,4 +78,3 @@
test::LeakChecker::checkForLeaks();
return ret;
}
-
diff --git a/libs/hwui/thread/Barrier.h b/libs/hwui/thread/Barrier.h
index 17f82ba9..8faeee6 100644
--- a/libs/hwui/thread/Barrier.h
+++ b/libs/hwui/thread/Barrier.h
@@ -24,8 +24,9 @@
class Barrier {
public:
- explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mOpened(false) { }
- ~Barrier() { }
+ explicit Barrier(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
+ : mType(type), mOpened(false) {}
+ ~Barrier() {}
void open() {
Mutex::Autolock l(mLock);
@@ -47,7 +48,7 @@
mutable Condition mCondition;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BARRIER_H
+#endif // ANDROID_HWUI_BARRIER_H
diff --git a/libs/hwui/thread/Future.h b/libs/hwui/thread/Future.h
index 177eebd..45f3102 100644
--- a/libs/hwui/thread/Future.h
+++ b/libs/hwui/thread/Future.h
@@ -24,11 +24,12 @@
namespace android {
namespace uirenderer {
-template<typename T>
-class Future: public LightRefBase<Future<T> > {
+template <typename T>
+class Future : public LightRefBase<Future<T> > {
public:
- explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE): mBarrier(type), mResult() { }
- ~Future() { }
+ explicit Future(Condition::WakeUpType type = Condition::WAKE_UP_ONE)
+ : mBarrier(type), mResult() {}
+ ~Future() {}
/**
* Returns the result of this future, blocking if
@@ -52,7 +53,7 @@
T mResult;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_FUTURE_H
+#endif // ANDROID_HWUI_FUTURE_H
diff --git a/libs/hwui/thread/Signal.h b/libs/hwui/thread/Signal.h
index 93e6f4c..ffcd4b6 100644
--- a/libs/hwui/thread/Signal.h
+++ b/libs/hwui/thread/Signal.h
@@ -26,8 +26,9 @@
class Signal {
public:
- explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL) : mType(type), mSignaled(false) { }
- ~Signal() { }
+ explicit Signal(Condition::WakeUpType type = Condition::WAKE_UP_ALL)
+ : mType(type), mSignaled(false) {}
+ ~Signal() {}
void signal() {
{
@@ -52,7 +53,7 @@
mutable Condition mCondition;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_SIGNAL_H
+#endif // ANDROID_HWUI_SIGNAL_H
diff --git a/libs/hwui/thread/Task.h b/libs/hwui/thread/Task.h
index 7fcf593..276a22f 100644
--- a/libs/hwui/thread/Task.h
+++ b/libs/hwui/thread/Task.h
@@ -25,36 +25,30 @@
namespace android {
namespace uirenderer {
-class TaskBase: public RefBase {
+class TaskBase : public RefBase {
public:
- TaskBase() { }
- virtual ~TaskBase() { }
+ TaskBase() {}
+ virtual ~TaskBase() {}
};
-template<typename T>
-class Task: public TaskBase {
+template <typename T>
+class Task : public TaskBase {
public:
- Task(): mFuture(new Future<T>()) { }
- virtual ~Task() { }
+ Task() : mFuture(new Future<T>()) {}
+ virtual ~Task() {}
- T getResult() const {
- return mFuture->get();
- }
+ T getResult() const { return mFuture->get(); }
- void setResult(T result) {
- mFuture->produce(result);
- }
+ void setResult(T result) { mFuture->produce(result); }
protected:
- const sp<Future<T> >& future() const {
- return mFuture;
- }
+ const sp<Future<T> >& future() const { return mFuture; }
private:
sp<Future<T> > mFuture;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TASK_H
+#endif // ANDROID_HWUI_TASK_H
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index d346b85..54b55e4 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -17,8 +17,8 @@
#include <sys/resource.h>
#include <sys/sysinfo.h>
-#include "TaskManager.h"
#include "Task.h"
+#include "TaskManager.h"
#include "TaskProcessor.h"
#include "utils/MathUtils.h"
@@ -129,5 +129,5 @@
mSignal.signal();
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/thread/TaskManager.h b/libs/hwui/thread/TaskManager.h
index c9d12bc..29b4fcd 100644
--- a/libs/hwui/thread/TaskManager.h
+++ b/libs/hwui/thread/TaskManager.h
@@ -58,7 +58,7 @@
template <typename T>
friend class TaskProcessor;
- template<typename T>
+ template <typename T>
bool addTask(const sp<Task<T> >& task, const sp<TaskProcessor<T> >& processor) {
return addTaskBase(sp<TaskBase>(task), sp<TaskProcessorBase>(processor));
}
@@ -66,19 +66,18 @@
bool addTaskBase(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor);
struct TaskWrapper {
- TaskWrapper(): mTask(), mProcessor() { }
+ TaskWrapper() : mTask(), mProcessor() {}
- TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor):
- mTask(task), mProcessor(processor) {
- }
+ TaskWrapper(const sp<TaskBase>& task, const sp<TaskProcessorBase>& processor)
+ : mTask(task), mProcessor(processor) {}
sp<TaskBase> mTask;
sp<TaskProcessorBase> mProcessor;
};
- class WorkerThread: public Thread {
+ class WorkerThread : public Thread {
public:
- explicit WorkerThread(const String8& name): mSignal(Condition::WAKE_UP_ONE), mName(name) { }
+ explicit WorkerThread(const String8& name) : mSignal(Condition::WAKE_UP_ONE), mName(name) {}
bool addTask(const TaskWrapper& task);
size_t getTaskCount() const;
@@ -102,7 +101,7 @@
std::vector<sp<WorkerThread> > mThreads;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TASK_MANAGER_H
+#endif // ANDROID_HWUI_TASK_MANAGER_H
diff --git a/libs/hwui/thread/TaskProcessor.h b/libs/hwui/thread/TaskProcessor.h
index 5867450..8117ae6 100644
--- a/libs/hwui/thread/TaskProcessor.h
+++ b/libs/hwui/thread/TaskProcessor.h
@@ -25,19 +25,19 @@
namespace android {
namespace uirenderer {
-class TaskProcessorBase: public RefBase {
+class TaskProcessorBase : public RefBase {
public:
- TaskProcessorBase() { }
- virtual ~TaskProcessorBase() { };
+ TaskProcessorBase() {}
+ virtual ~TaskProcessorBase(){};
virtual void process(const sp<TaskBase>& task) = 0;
};
-template<typename T>
-class TaskProcessor: public TaskProcessorBase {
+template <typename T>
+class TaskProcessor : public TaskProcessorBase {
public:
- explicit TaskProcessor(TaskManager* manager): mManager(manager) { }
- virtual ~TaskProcessor() { }
+ explicit TaskProcessor(TaskManager* manager) : mManager(manager) {}
+ virtual ~TaskProcessor() {}
void add(const sp<Task<T> >& task) {
if (!addImpl(task)) {
@@ -52,7 +52,7 @@
bool addImpl(const sp<Task<T> >& task);
virtual void process(const sp<TaskBase>& task) override {
- sp<Task<T> > realTask = static_cast<Task<T>* >(task.get());
+ sp<Task<T> > realTask = static_cast<Task<T>*>(task.get());
// This is the right way to do it but sp<> doesn't play nice
// sp<Task<T> > realTask = static_cast<sp<Task<T> > >(task);
onProcess(realTask);
@@ -61,7 +61,7 @@
TaskManager* mManager;
};
-template<typename T>
+template <typename T>
bool TaskProcessor<T>::addImpl(const sp<Task<T> >& task) {
if (mManager) {
sp<TaskProcessor<T> > self(this);
@@ -70,7 +70,7 @@
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_TASK_PROCESSOR_H
+#endif // ANDROID_HWUI_TASK_PROCESSOR_H
diff --git a/libs/hwui/thread/ThreadBase.h b/libs/hwui/thread/ThreadBase.h
index 402fd1e..b3fec1f 100644
--- a/libs/hwui/thread/ThreadBase.h
+++ b/libs/hwui/thread/ThreadBase.h
@@ -31,10 +31,7 @@
PREVENT_COPY_AND_ASSIGN(ThreadBase);
public:
- ThreadBase()
- : mLooper(new Looper(false))
- , mQueue([this](){ mLooper->wake(); }, mLock)
- {}
+ ThreadBase() : mLooper(new Looper(false)), mQueue([this]() { mLooper->wake(); }, mLock) {}
WorkQueue& queue() { return mQueue; }
@@ -43,13 +40,9 @@
mLooper->wake();
}
- void start(const char* name = "ThreadBase") {
- Thread::run(name);
- }
+ void start(const char* name = "ThreadBase") { Thread::run(name); }
- void join() {
- Thread::join();
- }
+ void join() { Thread::join(); }
protected:
void waitForWork() {
@@ -64,13 +57,10 @@
if (timeout < 0) timeout = 0;
}
int result = mLooper->pollOnce(timeout);
- LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR,
- "RenderThread Looper POLL_ERROR!");
+ LOG_ALWAYS_FATAL_IF(result == Looper::POLL_ERROR, "RenderThread Looper POLL_ERROR!");
}
- void processQueue() {
- mQueue.process();
- }
+ void processQueue() { mQueue.process(); }
virtual bool threadLoop() override {
while (!exitPending()) {
@@ -87,7 +77,6 @@
std::mutex mLock;
};
-} // namespace android::uirenderer
+} // namespace android::uirenderer
-
-#endif //HWUI_THREADBASE_H
+#endif // HWUI_THREADBASE_H
diff --git a/libs/hwui/thread/WorkQueue.h b/libs/hwui/thread/WorkQueue.h
index fbb24bb..7a6e638 100644
--- a/libs/hwui/thread/WorkQueue.h
+++ b/libs/hwui/thread/WorkQueue.h
@@ -37,6 +37,7 @@
class WorkQueue {
PREVENT_COPY_AND_ASSIGN(WorkQueue);
+
public:
using clock = MonotonicClock;
@@ -57,8 +58,7 @@
public:
WorkQueue(std::function<void()>&& wakeFunc, std::mutex& lock)
- : mWakeFunc(move(wakeFunc))
- , mLock(lock) {}
+ : mWakeFunc(move(wakeFunc)), mLock(lock) {}
void process() {
auto now = clock::now();
@@ -68,9 +68,7 @@
if (mWorkQueue.empty()) return;
toProcess = std::move(mWorkQueue);
auto moveBack = find_if(std::begin(toProcess), std::end(toProcess),
- [&now](WorkItem& item) {
- return item.runAt > now;
- });
+ [&now](WorkItem& item) { return item.runAt > now; });
if (moveBack != std::end(toProcess)) {
mWorkQueue.reserve(std::distance(moveBack, std::end(toProcess)) + 5);
std::move(moveBack, std::end(toProcess), std::back_inserter(mWorkQueue));
@@ -82,22 +80,22 @@
}
}
- template<class F>
+ template <class F>
void postAt(nsecs_t time, F&& func) {
enqueue(WorkItem{time, std::function<void()>(std::forward<F>(func))});
}
- template<class F>
+ template <class F>
void postDelayed(nsecs_t delay, F&& func) {
enqueue(WorkItem{clock::now() + delay, std::function<void()>(std::forward<F>(func))});
}
- template<class F>
+ template <class F>
void post(F&& func) {
postAt(0, std::forward<F>(func));
}
- template<class F>
+ template <class F>
auto async(F&& func) -> std::future<decltype(func())> {
typedef std::packaged_task<decltype(func())()> task_t;
auto task = std::make_shared<task_t>(std::forward<F>(func));
@@ -105,14 +103,14 @@
return task->get_future();
}
- template<class F>
+ template <class F>
auto runSync(F&& func) -> decltype(func()) {
std::packaged_task<decltype(func())()> task{std::forward<F>(func)};
post([&task]() { std::invoke(task); });
return task.get_future().get();
};
- nsecs_t nextWakeup(std::unique_lock<std::mutex> &lock) {
+ nsecs_t nextWakeup(std::unique_lock<std::mutex>& lock) {
if (mWorkQueue.empty()) {
return std::numeric_limits<nsecs_t>::max();
} else {
@@ -125,10 +123,9 @@
bool needsWakeup;
{
std::unique_lock _lock{mLock};
- auto insertAt = std::find_if(std::begin(mWorkQueue), std::end(mWorkQueue),
- [time = item.runAt](WorkItem& item) {
- return item.runAt > time;
- });
+ auto insertAt = std::find_if(
+ std::begin(mWorkQueue), std::end(mWorkQueue),
+ [time = item.runAt](WorkItem & item) { return item.runAt > time; });
needsWakeup = std::begin(mWorkQueue) == insertAt;
mWorkQueue.emplace(insertAt, std::move(item));
}
@@ -143,6 +140,6 @@
std::vector<WorkItem> mWorkQueue;
};
-} // namespace android::uirenderer
+} // namespace android::uirenderer
-#endif //HWUI_WORKQUEUE_H
+#endif // HWUI_WORKQUEUE_H
diff --git a/libs/hwui/utils/Blur.cpp b/libs/hwui/utils/Blur.cpp
index 9b70765..1bc5646 100644
--- a/libs/hwui/utils/Blur.cpp
+++ b/libs/hwui/utils/Blur.cpp
@@ -38,7 +38,7 @@
// is within the conversion error tolerance then we attempt to snap to the
// original integer boundary.
uint32_t Blur::convertRadiusToInt(float radius) {
- const float radiusCeil = ceilf(radius);
+ const float radiusCeil = ceilf(radius);
if (MathUtils::areEqual(radiusCeil, radius)) {
return radiusCeil;
}
@@ -75,46 +75,45 @@
// the blur calculations
// precompute some values
float coeff1 = 1.0f / (sqrt(2.0f * pi) * sigma);
- float coeff2 = - 1.0f / (2.0f * sigma * sigma);
+ float coeff2 = -1.0f / (2.0f * sigma * sigma);
float normalizeFactor = 0.0f;
- for (int32_t r = -intRadius; r <= intRadius; r ++) {
- float floatR = (float) r;
+ for (int32_t r = -intRadius; r <= intRadius; r++) {
+ float floatR = (float)r;
weights[r + intRadius] = coeff1 * pow(e, floatR * floatR * coeff2);
normalizeFactor += weights[r + intRadius];
}
- //Now we need to normalize the weights because all our coefficients need to add up to one
+ // Now we need to normalize the weights because all our coefficients need to add up to one
normalizeFactor = 1.0f / normalizeFactor;
- for (int32_t r = -intRadius; r <= intRadius; r ++) {
+ for (int32_t r = -intRadius; r <= intRadius; r++) {
weights[r + intRadius] *= normalizeFactor;
}
}
-void Blur::horizontal(float* weights, int32_t radius,
- const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
+void Blur::horizontal(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height) {
float blurredPixel = 0.0f;
float currentPixel = 0.0f;
- for (int32_t y = 0; y < height; y ++) {
-
+ for (int32_t y = 0; y < height; y++) {
const uint8_t* input = source + y * width;
uint8_t* output = dest + y * width;
- for (int32_t x = 0; x < width; x ++) {
+ for (int32_t x = 0; x < width; x++) {
blurredPixel = 0.0f;
const float* gPtr = weights;
// Optimization for non-border pixels
if (x > radius && x < (width - radius)) {
- const uint8_t *i = input + (x - radius);
- for (int r = -radius; r <= radius; r ++) {
- currentPixel = (float) (*i);
+ const uint8_t* i = input + (x - radius);
+ for (int r = -radius; r <= radius; r++) {
+ currentPixel = (float)(*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
i++;
}
} else {
- for (int32_t r = -radius; r <= radius; r ++) {
+ for (int32_t r = -radius; r <= radius; r++) {
// Stepping left and right away from the pixel
int validW = x + r;
if (validW < 0) {
@@ -124,40 +123,40 @@
validW = width - 1;
}
- currentPixel = (float) input[validW];
+ currentPixel = (float)input[validW];
blurredPixel += currentPixel * gPtr[0];
gPtr++;
}
}
*output = (uint8_t)blurredPixel;
- output ++;
+ output++;
}
}
}
-void Blur::vertical(float* weights, int32_t radius,
- const uint8_t* source, uint8_t* dest, int32_t width, int32_t height) {
+void Blur::vertical(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height) {
float blurredPixel = 0.0f;
float currentPixel = 0.0f;
- for (int32_t y = 0; y < height; y ++) {
+ for (int32_t y = 0; y < height; y++) {
uint8_t* output = dest + y * width;
- for (int32_t x = 0; x < width; x ++) {
+ for (int32_t x = 0; x < width; x++) {
blurredPixel = 0.0f;
const float* gPtr = weights;
const uint8_t* input = source + x;
// Optimization for non-border pixels
if (y > radius && y < (height - radius)) {
- const uint8_t *i = input + ((y - radius) * width);
- for (int32_t r = -radius; r <= radius; r ++) {
- currentPixel = (float) (*i);
+ const uint8_t* i = input + ((y - radius) * width);
+ for (int32_t r = -radius; r <= radius; r++) {
+ currentPixel = (float)(*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
i += width;
}
} else {
- for (int32_t r = -radius; r <= radius; r ++) {
+ for (int32_t r = -radius; r <= radius; r++) {
int validH = y + r;
// Clamp to zero and width
if (validH < 0) {
@@ -167,17 +166,17 @@
validH = height - 1;
}
- const uint8_t *i = input + validH * width;
- currentPixel = (float) (*i);
+ const uint8_t* i = input + validH * width;
+ currentPixel = (float)(*i);
blurredPixel += currentPixel * gPtr[0];
gPtr++;
}
}
- *output = (uint8_t) blurredPixel;
+ *output = (uint8_t)blurredPixel;
output++;
}
}
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/Blur.h b/libs/hwui/utils/Blur.h
index 3f21832..bec3837 100644
--- a/libs/hwui/utils/Blur.h
+++ b/libs/hwui/utils/Blur.h
@@ -17,8 +17,8 @@
#ifndef ANDROID_HWUI_BLUR_H
#define ANDROID_HWUI_BLUR_H
-#include <stdint.h>
#include <cutils/compiler.h>
+#include <stdint.h>
namespace android {
namespace uirenderer {
@@ -35,13 +35,13 @@
static uint32_t convertRadiusToInt(float radius);
static void generateGaussianWeights(float* weights, float radius);
- static void horizontal(float* weights, int32_t radius, const uint8_t* source,
- uint8_t* dest, int32_t width, int32_t height);
- static void vertical(float* weights, int32_t radius, const uint8_t* source,
- uint8_t* dest, int32_t width, int32_t height);
+ static void horizontal(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
+ static void vertical(float* weights, int32_t radius, const uint8_t* source, uint8_t* dest,
+ int32_t width, int32_t height);
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_HWUI_BLUR_H
+#endif // ANDROID_HWUI_BLUR_H
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index 7d234b0..c2af867 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -41,18 +41,17 @@
const float sRGBParamG = 2.4f;
// This comparison will catch Display P3
- return
- almostEqual(sRGBParamA, transferFunction.fA)
- && almostEqual(sRGBParamB, transferFunction.fB)
- && almostEqual(sRGBParamC, transferFunction.fC)
- && almostEqual(sRGBParamD, transferFunction.fD)
- && almostEqual(sRGBParamE, transferFunction.fE)
- && almostEqual(sRGBParamF, transferFunction.fF)
- && almostEqual(sRGBParamG, transferFunction.fG);
+ return almostEqual(sRGBParamA, transferFunction.fA) &&
+ almostEqual(sRGBParamB, transferFunction.fB) &&
+ almostEqual(sRGBParamC, transferFunction.fC) &&
+ almostEqual(sRGBParamD, transferFunction.fD) &&
+ almostEqual(sRGBParamE, transferFunction.fE) &&
+ almostEqual(sRGBParamF, transferFunction.fF) &&
+ almostEqual(sRGBParamG, transferFunction.fG);
}
return false;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h
index 9c09660..4857a87 100644
--- a/libs/hwui/utils/Color.h
+++ b/libs/hwui/utils/Color.h
@@ -23,114 +23,94 @@
namespace android {
namespace uirenderer {
- namespace Color {
- enum Color {
- Red_500 = 0xFFF44336,
- Pink_500 = 0xFFE91E63,
- Purple_500 = 0xFF9C27B0,
- DeepPurple_500 = 0xFF673AB7,
- Indigo_500 = 0xFF3F51B5,
- Blue_500 = 0xFF2196F3,
- LightBlue_300 = 0xFF4FC3F7,
- LightBlue_500 = 0xFF03A9F4,
- Cyan_500 = 0xFF00BCD4,
- Teal_500 = 0xFF009688,
- Teal_700 = 0xFF00796B,
- Green_500 = 0xFF4CAF50,
- Green_700 = 0xFF388E3C,
- LightGreen_500 = 0xFF8BC34A,
- LightGreen_700 = 0xFF689F38,
- Lime_500 = 0xFFCDDC39,
- Yellow_500 = 0xFFFFEB3B,
- Amber_500 = 0xFFFFC107,
- Orange_500 = 0xFFFF9800,
- DeepOrange_500 = 0xFFFF5722,
- Brown_500 = 0xFF795548,
- Grey_200 = 0xFFEEEEEE,
- Grey_500 = 0xFF9E9E9E,
- Grey_700 = 0xFF616161,
- BlueGrey_500 = 0xFF607D8B,
- Transparent = 0x00000000,
- Black = 0xFF000000,
- White = 0xFFFFFFFF,
- };
- }
+namespace Color {
+enum Color {
+ Red_500 = 0xFFF44336,
+ Pink_500 = 0xFFE91E63,
+ Purple_500 = 0xFF9C27B0,
+ DeepPurple_500 = 0xFF673AB7,
+ Indigo_500 = 0xFF3F51B5,
+ Blue_500 = 0xFF2196F3,
+ LightBlue_300 = 0xFF4FC3F7,
+ LightBlue_500 = 0xFF03A9F4,
+ Cyan_500 = 0xFF00BCD4,
+ Teal_500 = 0xFF009688,
+ Teal_700 = 0xFF00796B,
+ Green_500 = 0xFF4CAF50,
+ Green_700 = 0xFF388E3C,
+ LightGreen_500 = 0xFF8BC34A,
+ LightGreen_700 = 0xFF689F38,
+ Lime_500 = 0xFFCDDC39,
+ Yellow_500 = 0xFFFFEB3B,
+ Amber_500 = 0xFFFFC107,
+ Orange_500 = 0xFFFF9800,
+ DeepOrange_500 = 0xFFFF5722,
+ Brown_500 = 0xFF795548,
+ Grey_200 = 0xFFEEEEEE,
+ Grey_500 = 0xFF9E9E9E,
+ Grey_700 = 0xFF616161,
+ BlueGrey_500 = 0xFF607D8B,
+ Transparent = 0x00000000,
+ Black = 0xFF000000,
+ White = 0xFFFFFFFF,
+};
+}
- static_assert(Color::White == SK_ColorWHITE, "color format has changed");
- static_assert(Color::Black == SK_ColorBLACK, "color format has changed");
+static_assert(Color::White == SK_ColorWHITE, "color format has changed");
+static_assert(Color::Black == SK_ColorBLACK, "color format has changed");
- // Array of bright (500 intensity) colors for synthetic content
- static const Color::Color BrightColors[] = {
- Color::Red_500,
- Color::Pink_500,
- Color::Purple_500,
- Color::DeepPurple_500,
- Color::Indigo_500,
- Color::Blue_500,
- Color::LightBlue_500,
- Color::Cyan_500,
- Color::Teal_500,
- Color::Green_500,
- Color::LightGreen_500,
- Color::Lime_500,
- Color::Yellow_500,
- Color::Amber_500,
- Color::Orange_500,
- Color::DeepOrange_500,
- Color::Brown_500,
- Color::Grey_500,
- Color::BlueGrey_500,
- };
- static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
+// Array of bright (500 intensity) colors for synthetic content
+static const Color::Color BrightColors[] = {
+ Color::Red_500, Color::Pink_500, Color::Purple_500, Color::DeepPurple_500,
+ Color::Indigo_500, Color::Blue_500, Color::LightBlue_500, Color::Cyan_500,
+ Color::Teal_500, Color::Green_500, Color::LightGreen_500, Color::Lime_500,
+ Color::Yellow_500, Color::Amber_500, Color::Orange_500, Color::DeepOrange_500,
+ Color::Brown_500, Color::Grey_500, Color::BlueGrey_500,
+};
+static constexpr int BrightColorsCount = sizeof(BrightColors) / sizeof(Color::Color);
- enum class TransferFunctionType : int8_t {
- None = 0,
- Full,
- Limited,
- Gamma
- };
+enum class TransferFunctionType : int8_t { None = 0, Full, Limited, Gamma };
- // Opto-electronic conversion function for the sRGB color space
- // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
- static constexpr float OECF_sRGB(float linear) {
- // IEC 61966-2-1:1999
- return linear <= 0.0031308f ?
- linear * 12.92f : (powf(linear, 1.0f / 2.4f) * 1.055f) - 0.055f;
- }
+// Opto-electronic conversion function for the sRGB color space
+// Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+static constexpr float OECF_sRGB(float linear) {
+ // IEC 61966-2-1:1999
+ return linear <= 0.0031308f ? linear * 12.92f : (powf(linear, 1.0f / 2.4f) * 1.055f) - 0.055f;
+}
- // Opto-electronic conversion function for the sRGB color space
- // Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
- // This function returns the input unmodified if linear blending is not enabled
- static constexpr float OECF(float linear) {
+// Opto-electronic conversion function for the sRGB color space
+// Takes a linear sRGB value and converts it to a gamma-encoded sRGB value
+// This function returns the input unmodified if linear blending is not enabled
+static constexpr float OECF(float linear) {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
- return OECF_sRGB(linear);
+ return OECF_sRGB(linear);
#else
- return linear;
+ return linear;
#endif
- }
+}
- // Electro-optical conversion function for the sRGB color space
- // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
- static constexpr float EOCF_sRGB(float srgb) {
- // IEC 61966-2-1:1999
- return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
- }
+// Electro-optical conversion function for the sRGB color space
+// Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+static constexpr float EOCF_sRGB(float srgb) {
+ // IEC 61966-2-1:1999
+ return srgb <= 0.04045f ? srgb / 12.92f : powf((srgb + 0.055f) / 1.055f, 2.4f);
+}
- // Electro-optical conversion function for the sRGB color space
- // Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
- // This function returns the input unmodified if linear blending is not enabled
- static constexpr float EOCF(float srgb) {
+// Electro-optical conversion function for the sRGB color space
+// Takes a gamma-encoded sRGB value and converts it to a linear sRGB value
+// This function returns the input unmodified if linear blending is not enabled
+static constexpr float EOCF(float srgb) {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
- return EOCF_sRGB(srgb);
+ return EOCF_sRGB(srgb);
#else
- return srgb;
+ return srgb;
#endif
- }
+}
- // Returns whether the specified color space's transfer function can be
- // approximated with the native sRGB transfer function. This method
- // returns true for sRGB, gamma 2.2 and Display P3 for instance
- bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
+// Returns whether the specified color space's transfer function can be
+// approximated with the native sRGB transfer function. This method
+// returns true for sRGB, gamma 2.2 and Display P3 for instance
+bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace);
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/FatVector.h b/libs/hwui/utils/FatVector.h
index df8cb076..eafe2f1 100644
--- a/libs/hwui/utils/FatVector.h
+++ b/libs/hwui/utils/FatVector.h
@@ -30,8 +30,8 @@
#include <stddef.h>
#include <stdlib.h>
-#include <type_traits>
#include <utils/Log.h>
+#include <type_traits>
#include <vector>
@@ -43,28 +43,27 @@
public:
struct Allocation {
PREVENT_COPY_AND_ASSIGN(Allocation);
+
public:
- Allocation() {};
+ Allocation(){};
// char array instead of T array, so memory is uninitialized, with no destructors run
char array[sizeof(T) * SIZE];
bool inUse = false;
};
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
- explicit InlineStdAllocator(Allocation& allocation)
- : mAllocation(allocation) {}
- InlineStdAllocator(const InlineStdAllocator& other)
- : mAllocation(other.mAllocation) {}
+ explicit InlineStdAllocator(Allocation& allocation) : mAllocation(allocation) {}
+ InlineStdAllocator(const InlineStdAllocator& other) : mAllocation(other.mAllocation) {}
~InlineStdAllocator() {}
T* allocate(size_t num, const void* = 0) {
if (!mAllocation.inUse && num <= SIZE) {
mAllocation.inUse = true;
- return (T*) mAllocation.array;
+ return (T*)mAllocation.array;
} else {
- return (T*) malloc(num * sizeof(T));
+ return (T*)malloc(num * sizeof(T));
}
}
@@ -88,20 +87,19 @@
template <typename T, size_t SIZE>
class FatVector : public std::vector<T, InlineStdAllocator<T, SIZE>> {
public:
- FatVector() : std::vector<T, InlineStdAllocator<T, SIZE>>(
- InlineStdAllocator<T, SIZE>(mAllocation)) {
+ FatVector()
+ : std::vector<T, InlineStdAllocator<T, SIZE>>(
+ InlineStdAllocator<T, SIZE>(mAllocation)) {
this->reserve(SIZE);
}
- explicit FatVector(size_t capacity) : FatVector() {
- this->resize(capacity);
- }
+ explicit FatVector(size_t capacity) : FatVector() { this->resize(capacity); }
private:
typename InlineStdAllocator<T, SIZE>::Allocation mAllocation;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_FAT_VECTOR_H
+#endif // ANDROID_FAT_VECTOR_H
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
index 33209759..bf27300 100644
--- a/libs/hwui/utils/GLUtils.cpp
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -39,25 +39,25 @@
while ((status = glGetError()) != GL_NO_ERROR) {
errorObserved = true;
switch (status) {
- case GL_INVALID_ENUM:
- ALOGE("GL error: GL_INVALID_ENUM");
- break;
- case GL_INVALID_VALUE:
- ALOGE("GL error: GL_INVALID_VALUE");
- break;
- case GL_INVALID_OPERATION:
- ALOGE("GL error: GL_INVALID_OPERATION");
- break;
- case GL_OUT_OF_MEMORY:
- ALOGE("GL error: Out of memory!");
- break;
- default:
- ALOGE("GL error: 0x%x", status);
+ case GL_INVALID_ENUM:
+ ALOGE("GL error: GL_INVALID_ENUM");
+ break;
+ case GL_INVALID_VALUE:
+ ALOGE("GL error: GL_INVALID_VALUE");
+ break;
+ case GL_INVALID_OPERATION:
+ ALOGE("GL error: GL_INVALID_OPERATION");
+ break;
+ case GL_OUT_OF_MEMORY:
+ ALOGE("GL error: Out of memory!");
+ break;
+ default:
+ ALOGE("GL error: 0x%x", status);
}
}
return errorObserved;
#endif
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index c127478..debfb5d 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -23,13 +23,14 @@
namespace android {
namespace uirenderer {
-
#if DEBUG_OPENGL
-#define GL_CHECKPOINT(LEVEL) \
- do { if (DEBUG_OPENGL >= DEBUG_LEVEL_##LEVEL) {\
- LOG_ALWAYS_FATAL_IF(android::uirenderer::GLUtils::dumpGLErrors(),\
- "GL errors! %s:%d", __FILE__, __LINE__);\
- } } while (0)
+#define GL_CHECKPOINT(LEVEL) \
+ do { \
+ if (DEBUG_OPENGL >= DEBUG_LEVEL_##LEVEL) { \
+ LOG_ALWAYS_FATAL_IF(android::uirenderer::GLUtils::dumpGLErrors(), "GL errors! %s:%d", \
+ __FILE__, __LINE__); \
+ } \
+ } while (0)
#else
#define GL_CHECKPOINT(LEVEL)
#endif
@@ -42,7 +43,7 @@
*/
static bool dumpGLErrors();
-}; // class GLUtils
+}; // class GLUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/LinearAllocator.cpp b/libs/hwui/utils/LinearAllocator.cpp
index d92bc0c..5a59de8 100644
--- a/libs/hwui/utils/LinearAllocator.cpp
+++ b/libs/hwui/utils/LinearAllocator.cpp
@@ -30,10 +30,9 @@
#include <stdlib.h>
#include <utils/Log.h>
-
// The ideal size of a page allocation (these need to be multiples of 8)
-#define INITIAL_PAGE_SIZE ((size_t)512) // 512b
-#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
+#define INITIAL_PAGE_SIZE ((size_t)512) // 512b
+#define MAX_PAGE_SIZE ((size_t)131072) // 128kb
// The maximum amount of wasted space we can have per page
// Allocations exceeding this will have their own dedicated page
@@ -48,7 +47,7 @@
#define ALIGN_SZ (sizeof(int))
#endif
-#define ALIGN(x) (((x) + ALIGN_SZ - 1 ) & ~(ALIGN_SZ - 1))
+#define ALIGN(x) (((x) + ALIGN_SZ - 1) & ~(ALIGN_SZ - 1))
#define ALIGN_PTR(p) ((void*)(ALIGN((size_t)(p))))
#if LOG_NDEBUG
@@ -79,7 +78,7 @@
#define RM_ALLOCATION(size) _addAllocation(-1);
#endif
-#define min(x,y) (((x) < (y)) ? (x) : (y))
+#define min(x, y) (((x) < (y)) ? (x) : (y))
namespace android {
namespace uirenderer {
@@ -89,19 +88,13 @@
Page* next() { return mNextPage; }
void setNext(Page* next) { mNextPage = next; }
- Page()
- : mNextPage(0)
- {}
+ Page() : mNextPage(0) {}
void* operator new(size_t /*size*/, void* buf) { return buf; }
- void* start() {
- return (void*) (((size_t)this) + sizeof(Page));
- }
+ void* start() { return (void*)(((size_t)this) + sizeof(Page)); }
- void* end(int pageSize) {
- return (void*) (((size_t)start()) + pageSize);
- }
+ void* end(int pageSize) { return (void*)(((size_t)start()) + pageSize); }
private:
Page(const Page& /*other*/) {}
@@ -109,15 +102,15 @@
};
LinearAllocator::LinearAllocator()
- : mPageSize(INITIAL_PAGE_SIZE)
- , mMaxAllocSize(INITIAL_PAGE_SIZE * MAX_WASTE_RATIO)
- , mNext(0)
- , mCurrentPage(0)
- , mPages(0)
- , mTotalAllocated(0)
- , mWastedSpace(0)
- , mPageCount(0)
- , mDedicatedPageCount(0) {}
+ : mPageSize(INITIAL_PAGE_SIZE)
+ , mMaxAllocSize(INITIAL_PAGE_SIZE * MAX_WASTE_RATIO)
+ , mNext(0)
+ , mCurrentPage(0)
+ , mPages(0)
+ , mTotalAllocated(0)
+ , mWastedSpace(0)
+ , mPageCount(0)
+ , mDedicatedPageCount(0) {}
LinearAllocator::~LinearAllocator(void) {
while (mDtorList) {
@@ -176,8 +169,7 @@
mDedicatedPageCount++;
page->setNext(mPages);
mPages = page;
- if (!mCurrentPage)
- mCurrentPage = mPages;
+ if (!mCurrentPage) mCurrentPage = mPages;
return start(page);
}
ensureNext(size);
@@ -225,8 +217,8 @@
runDestructorFor(ptr);
// Don't bother rewinding across pages
allocSize = ALIGN(allocSize);
- if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage)
- && ptr == ((char*)mNext - allocSize)) {
+ if (ptr >= start(mCurrentPage) && ptr < end(mCurrentPage) &&
+ ptr == ((char*)mNext - allocSize)) {
mWastedSpace += allocSize;
mNext = ptr;
}
@@ -261,9 +253,9 @@
ALOGD("%sTotal allocated: %.2f%s", prefix, prettySize, prettySuffix);
prettySuffix = toSize(mWastedSpace, prettySize);
ALOGD("%sWasted space: %.2f%s (%.1f%%)", prefix, prettySize, prettySuffix,
- (float) mWastedSpace / (float) mTotalAllocated * 100.0f);
+ (float)mWastedSpace / (float)mTotalAllocated * 100.0f);
ALOGD("%sPages %zu (dedicated %zu)", prefix, mPageCount, mDedicatedPageCount);
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index f95a6fe..03f685e 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -56,10 +56,10 @@
* Note that unlike create, for alloc the type is purely for compile-time error
* checking and does not affect size.
*/
- template<class T>
+ template <class T>
void* alloc(size_t size) {
static_assert(std::is_trivially_destructible<T>::value,
- "Error, type is non-trivial! did you mean to use create()?");
+ "Error, type is non-trivial! did you mean to use create()?");
return allocImpl(size);
}
@@ -67,7 +67,7 @@
* Allocates an instance of the template type with the given construction parameters
* and adds it to the automatic destruction list.
*/
- template<class T, typename... Params>
+ template <class T, typename... Params>
T* create(Params&&... params) {
T* ret = new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
if (!std::is_trivially_destructible<T>::value) {
@@ -77,17 +77,17 @@
return ret;
}
- template<class T, typename... Params>
+ template <class T, typename... Params>
T* create_trivial(Params&&... params) {
static_assert(std::is_trivially_destructible<T>::value,
- "Error, called create_trivial on a non-trivial type");
+ "Error, called create_trivial on a non-trivial type");
return new (allocImpl(sizeof(T))) T(std::forward<Params>(params)...);
}
- template<class T>
+ template <class T>
T* create_trivial_array(int count) {
static_assert(std::is_trivially_destructible<T>::value,
- "Error, called create_trivial_array on a non-trivial type");
+ "Error, called create_trivial_array on a non-trivial type");
return reinterpret_cast<T*>(allocImpl(sizeof(T) * count));
}
@@ -100,7 +100,7 @@
/**
* Same as rewindIfLastAlloc(void*, size_t)
*/
- template<class T>
+ template <class T>
void rewindIfLastAlloc(T* ptr) {
rewindIfLastAlloc((void*)ptr, sizeof(T));
}
@@ -134,7 +134,7 @@
Page* newPage(size_t pageSize);
bool fitsInCurrentPage(size_t size);
void ensureNext(size_t size);
- void* start(Page *p);
+ void* start(Page* p);
void* end(Page* p);
size_t mPageSize;
@@ -154,13 +154,11 @@
template <class T>
class LinearStdAllocator {
public:
- typedef T value_type; // needed to implement std::allocator
- typedef T* pointer; // needed to implement std::allocator
+ typedef T value_type; // needed to implement std::allocator
+ typedef T* pointer; // needed to implement std::allocator
- explicit LinearStdAllocator(LinearAllocator& allocator)
- : linearAllocator(allocator) {}
- LinearStdAllocator(const LinearStdAllocator& other)
- : linearAllocator(other.linearAllocator) {}
+ explicit LinearStdAllocator(LinearAllocator& allocator) : linearAllocator(allocator) {}
+ LinearStdAllocator(const LinearStdAllocator& other) : linearAllocator(other.linearAllocator) {}
~LinearStdAllocator() {}
// rebind marks that allocators can be rebound to different types
@@ -188,9 +186,13 @@
// return that all specializations of LinearStdAllocator are interchangeable
template <class T1, class T2>
-bool operator== (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return true; }
+bool operator==(const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
+ return true;
+}
template <class T1, class T2>
-bool operator!= (const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) { return false; }
+bool operator!=(const LinearStdAllocator<T1>&, const LinearStdAllocator<T2>&) {
+ return false;
+}
template <class T>
class LsaVector : public std::vector<T, LinearStdAllocator<T>> {
@@ -199,7 +201,7 @@
: std::vector<T, LinearStdAllocator<T>>(allocator) {}
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
-#endif // ANDROID_LINEARALLOCATOR_H
+#endif // ANDROID_LINEARALLOCATOR_H
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 7212897b..d758f29 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -19,21 +19,19 @@
#include <type_traits>
#define PREVENT_COPY_AND_ASSIGN(Type) \
- private: \
- Type(const Type&) = delete; \
- void operator=(const Type&) = delete
+private: \
+ Type(const Type&) = delete; \
+ void operator=(const Type&) = delete
-#define HASHABLE_TYPE(Type) \
- bool operator==(const Type& other) const; \
- hash_t hash() const; \
- bool operator!=(const Type& other) const { return !(*this == other); } \
- friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
+#define HASHABLE_TYPE(Type) \
+ bool operator==(const Type& other) const; \
+ hash_t hash() const; \
+ bool operator!=(const Type& other) const { return !(*this == other); } \
+ friend inline hash_t hash_type(const Type& entry) { return entry.hash(); }
#define REQUIRE_COMPATIBLE_LAYOUT(Type) \
- static_assert(std::is_standard_layout<Type>::value, \
- #Type " must have standard layout")
+ static_assert(std::is_standard_layout<Type>::value, #Type " must have standard layout")
-#define WARN_UNUSED_RESULT \
- __attribute__((warn_unused_result))
+#define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#endif /* MACROS_H */
diff --git a/libs/hwui/utils/MathUtils.h b/libs/hwui/utils/MathUtils.h
index 8d20f21..5475898 100644
--- a/libs/hwui/utils/MathUtils.h
+++ b/libs/hwui/utils/MathUtils.h
@@ -16,8 +16,8 @@
#ifndef MATHUTILS_H
#define MATHUTILS_H
-#include <algorithm>
#include <math.h>
+#include <algorithm>
namespace android {
namespace uirenderer {
@@ -34,9 +34,7 @@
return (value >= -NON_ZERO_EPSILON) && (value <= NON_ZERO_EPSILON);
}
- inline static bool isPositive(float value) {
- return value >= NON_ZERO_EPSILON;
- }
+ inline static bool isPositive(float value) { return value >= NON_ZERO_EPSILON; }
/**
* Clamps alpha value, and snaps when very near 0 or 1
@@ -69,28 +67,24 @@
* Returns the number of points (beyond two, the start and end) needed to form a polygonal
* approximation of an arc, with a given threshold value.
*/
- inline static int divisionsNeededToApproximateArc(float radius,
- float angleInRads, float threshold) {
+ inline static int divisionsNeededToApproximateArc(float radius, float angleInRads,
+ float threshold) {
const float errConst = (-threshold / radius + 1);
const float targetCosVal = 2 * errConst * errConst - 1;
// needed divisions are rounded up from approximation
- return (int)(ceilf(angleInRads / acos(targetCosVal)/2)) * 2;
+ return (int)(ceilf(angleInRads / acos(targetCosVal) / 2)) * 2;
}
- inline static bool areEqual(float valueA, float valueB) {
- return isZero(valueA - valueB);
- }
+ inline static bool areEqual(float valueA, float valueB) { return isZero(valueA - valueB); }
- template<typename T>
+ template <typename T>
static inline T clamp(T a, T minValue, T maxValue) {
return std::min(std::max(a, minValue), maxValue);
}
- inline static float lerp(float v1, float v2, float t) {
- return v1 + ((v2 - v1) * t);
- }
-}; // class MathUtils
+ inline static float lerp(float v1, float v2, float t) { return v1 + ((v2 - v1) * t); }
+}; // class MathUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/PaintUtils.h b/libs/hwui/utils/PaintUtils.h
index 2673be1c..233adae 100644
--- a/libs/hwui/utils/PaintUtils.h
+++ b/libs/hwui/utils/PaintUtils.h
@@ -31,7 +31,6 @@
*/
class PaintUtils {
public:
-
static inline GLenum getFilter(const SkPaint* paint) {
if (!paint || paint->getFilterQuality() != kNone_SkFilterQuality) {
return GL_LINEAR;
@@ -40,18 +39,16 @@
}
static bool isOpaquePaint(const SkPaint* paint) {
- if (!paint) return true; // default (paintless) behavior is SrcOver, black
+ if (!paint) return true; // default (paintless) behavior is SrcOver, black
- if (paint->getAlpha() != 0xFF
- || PaintUtils::isBlendedShader(paint->getShader())
- || PaintUtils::isBlendedColorFilter(paint->getColorFilter())) {
+ if (paint->getAlpha() != 0xFF || PaintUtils::isBlendedShader(paint->getShader()) ||
+ PaintUtils::isBlendedColorFilter(paint->getColorFilter())) {
return false;
}
// Only let simple srcOver / src blending modes declare opaque, since behavior is clear.
SkBlendMode mode = paint->getBlendMode();
- return mode == SkBlendMode::kSrcOver
- || mode == SkBlendMode::kSrc;
+ return mode == SkBlendMode::kSrcOver || mode == SkBlendMode::kSrc;
}
static bool isBlendedShader(const SkShader* shader) {
@@ -89,9 +86,7 @@
return false;
}
- static inline bool hasTextShadow(const SkPaint* paint) {
- return getTextShadow(paint, nullptr);
- }
+ static inline bool hasTextShadow(const SkPaint* paint) { return getTextShadow(paint, nullptr); }
static inline SkBlendMode getBlendModeDirect(const SkPaint* paint) {
return paint ? paint->getBlendMode() : SkBlendMode::kSrcOver;
@@ -101,7 +96,7 @@
return paint ? paint->getAlpha() : 255;
}
-}; // class PaintUtils
+}; // class PaintUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/Pair.h b/libs/hwui/utils/Pair.h
index 0db3aa3..4bcd576 100644
--- a/libs/hwui/utils/Pair.h
+++ b/libs/hwui/utils/Pair.h
@@ -27,34 +27,34 @@
F first;
S second;
- Pair() { }
- Pair(const Pair& o) : first(o.first), second(o.second) { }
- Pair(const F& f, const S& s) : first(f), second(s) { }
+ Pair() {}
+ Pair(const Pair& o) : first(o.first), second(o.second) {}
+ Pair(const F& f, const S& s) : first(f), second(s) {}
- inline const F& getFirst() const {
- return first;
- }
+ inline const F& getFirst() const { return first; }
- inline const S& getSecond() const {
- return second;
- }
+ inline const S& getSecond() const { return second; }
};
-}; // namespace uirenderer
+}; // namespace uirenderer
template <typename F, typename S>
-struct trait_trivial_ctor< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_ctor }; };
+struct trait_trivial_ctor<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_ctor };
+};
template <typename F, typename S>
-struct trait_trivial_dtor< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_dtor }; };
+struct trait_trivial_dtor<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_dtor };
+};
template <typename F, typename S>
-struct trait_trivial_copy< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_copy }; };
+struct trait_trivial_copy<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_copy };
+};
template <typename F, typename S>
-struct trait_trivial_move< uirenderer::Pair<F, S> >
-{ enum { value = aggregate_traits<F, S>::has_trivial_move }; };
+struct trait_trivial_move<uirenderer::Pair<F, S> > {
+ enum { value = aggregate_traits<F, S>::has_trivial_move };
+};
-}; // namespace android
+}; // namespace android
-#endif // ANDROID_HWUI_PAIR_H
+#endif // ANDROID_HWUI_PAIR_H
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
index 06bcdcd..b3e8931 100644
--- a/libs/hwui/utils/RingBuffer.h
+++ b/libs/hwui/utils/RingBuffer.h
@@ -23,7 +23,7 @@
namespace android {
namespace uirenderer {
-template<class T, size_t SIZE>
+template <class T, size_t SIZE>
class RingBuffer {
PREVENT_COPY_AND_ASSIGN(RingBuffer);
@@ -42,21 +42,13 @@
return mBuffer[mHead];
}
- T& front() {
- return (*this)[0];
- }
+ T& front() { return (*this)[0]; }
- T& back() {
- return (*this)[size() - 1];
- }
+ T& back() { return (*this)[size() - 1]; }
- T& operator[](size_t index) {
- return mBuffer[(mHead + index + 1) % mCount];
- }
+ T& operator[](size_t index) { return mBuffer[(mHead + index + 1) % mCount]; }
- const T& operator[](size_t index) const {
- return mBuffer[(mHead + index + 1) % mCount];
- }
+ const T& operator[](size_t index) const { return mBuffer[(mHead + index + 1) % mCount]; }
void clear() {
mCount = 0;
@@ -69,7 +61,7 @@
size_t mCount = 0;
};
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
#endif /* RINGBUFFER_H_ */
diff --git a/libs/hwui/utils/StringUtils.cpp b/libs/hwui/utils/StringUtils.cpp
index 64a5970..5304b76 100644
--- a/libs/hwui/utils/StringUtils.cpp
+++ b/libs/hwui/utils/StringUtils.cpp
@@ -34,5 +34,5 @@
return set;
}
-}; // namespace uirenderer
-}; // namespace android
+}; // namespace uirenderer
+}; // namespace android
diff --git a/libs/hwui/utils/StringUtils.h b/libs/hwui/utils/StringUtils.h
index af5d10f..a10610a 100644
--- a/libs/hwui/utils/StringUtils.h
+++ b/libs/hwui/utils/StringUtils.h
@@ -30,9 +30,7 @@
class unordered_string_set : public std::unordered_set<std::string> {
public:
- bool has(const char* str) {
- return find(std::string(str)) != end();
- }
+ bool has(const char* str) { return find(std::string(str)) != end(); }
};
class StringUtils {
@@ -55,8 +53,8 @@
}
};
-class LogcatStream: public std::ostream {
- class LogcatStreamBuf: public std::stringbuf {
+class LogcatStream : public std::ostream {
+ class LogcatStreamBuf : public std::stringbuf {
virtual int sync() {
ALOGD("%s", str().c_str());
str("");
@@ -65,10 +63,9 @@
};
LogcatStreamBuf buffer;
+
public:
- LogcatStream()
- :std::ostream(&buffer) {
- }
+ LogcatStream() : std::ostream(&buffer) {}
};
} /* namespace uirenderer */
diff --git a/libs/hwui/utils/TestWindowContext.cpp b/libs/hwui/utils/TestWindowContext.cpp
index 492ca7fe..700d3b3 100644
--- a/libs/hwui/utils/TestWindowContext.cpp
+++ b/libs/hwui/utils/TestWindowContext.cpp
@@ -36,13 +36,13 @@
*/
class ContextFactory : public android::uirenderer::IContextFactory {
public:
- android::uirenderer::AnimationContext* createAnimationContext
- (android::uirenderer::renderthread::TimeLord& clock) override {
+ android::uirenderer::AnimationContext* createAnimationContext(
+ android::uirenderer::renderthread::TimeLord& clock) override {
return new android::uirenderer::AnimationContext(clock);
}
};
-} // anonymous namespace
+} // anonymous namespace
namespace android {
namespace uirenderer {
@@ -54,45 +54,38 @@
*/
class TestWindowContext::TestWindowData {
-
public:
-
explicit TestWindowData(SkISize size) : mSize(size) {
android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
mCpuConsumer->setName(android::String8("TestWindowContext"));
mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
mAndroidSurface = new android::Surface(mProducer);
- native_window_set_buffers_dimensions(mAndroidSurface.get(),
- mSize.width(), mSize.height());
- native_window_set_buffers_format(mAndroidSurface.get(),
- android::PIXEL_FORMAT_RGBA_8888);
- native_window_set_usage(mAndroidSurface.get(),
- GRALLOC_USAGE_SW_READ_OFTEN |
- GRALLOC_USAGE_SW_WRITE_NEVER |
- GRALLOC_USAGE_HW_RENDER);
+ native_window_set_buffers_dimensions(mAndroidSurface.get(), mSize.width(), mSize.height());
+ native_window_set_buffers_format(mAndroidSurface.get(), android::PIXEL_FORMAT_RGBA_8888);
+ native_window_set_usage(mAndroidSurface.get(), GRALLOC_USAGE_SW_READ_OFTEN |
+ GRALLOC_USAGE_SW_WRITE_NEVER |
+ GRALLOC_USAGE_HW_RENDER);
mRootNode.reset(new android::uirenderer::RenderNode());
mRootNode->incStrong(nullptr);
- mRootNode->mutateStagingProperties().setLeftTopRightBottom
- (0, 0, mSize.width(), mSize.height());
+ mRootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, mSize.width(),
+ mSize.height());
mRootNode->mutateStagingProperties().setClipToBounds(false);
mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
ContextFactory factory;
- mProxy.reset
- (new android::uirenderer::renderthread::RenderProxy(false,
- mRootNode.get(),
- &factory));
+ mProxy.reset(new android::uirenderer::renderthread::RenderProxy(false, mRootNode.get(),
+ &factory));
mProxy->loadSystemProperties();
mProxy->initialize(mAndroidSurface.get());
float lightX = mSize.width() / 2.0f;
- android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
+ android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f};
mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
mProxy->setLightCenter(lightVector);
mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
}
SkCanvas* prepareToDraw() {
- //mCanvas->reset(mSize.width(), mSize.height());
+ // mCanvas->reset(mSize.width(), mSize.height());
mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
return mCanvas->asSkCanvas();
}
@@ -104,17 +97,15 @@
// the timings we record.
}
- void fence() {
- mProxy->fence();
- }
+ void fence() { mProxy->fence(); }
bool capturePixels(SkBitmap* bmp) {
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
SkImageInfo destinationConfig =
- SkImageInfo::Make(mSize.width(), mSize.height(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
+ SkImageInfo::Make(mSize.width(), mSize.height(), kRGBA_8888_SkColorType,
+ kPremul_SkAlphaType, colorSpace);
bmp->allocPixels(destinationConfig);
- android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
+ android_memset32((uint32_t*)bmp->getPixels(), SK_ColorRED,
mSize.width() * mSize.height() * 4);
android::CpuConsumer::LockedBuffer nativeBuffer;
@@ -135,14 +126,13 @@
LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
"Native buffer not RGBA!");
- SkImageInfo nativeConfig =
- SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
- kRGBA_8888_SkColorType, kPremul_SkAlphaType);
+ SkImageInfo nativeConfig = SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType);
// Android stride is in pixels, Skia stride is in bytes
SkBitmap nativeWrapper;
- bool success =
- nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
+ bool success = nativeWrapper.installPixels(nativeConfig, nativeBuffer.data,
+ nativeBuffer.stride * 4);
if (!success) {
SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
return false;
@@ -150,8 +140,8 @@
LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
"Destination buffer not RGBA!");
- success =
- nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
+ success = nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0,
+ 0);
if (!success) {
SkDebugf("Failed to extract pixels from HWUI buffer");
return false;
@@ -163,7 +153,6 @@
}
private:
-
std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
@@ -174,15 +163,13 @@
SkISize mSize;
};
-
-TestWindowContext::TestWindowContext() :
- mData (nullptr) { }
+TestWindowContext::TestWindowContext() : mData(nullptr) {}
TestWindowContext::~TestWindowContext() {
delete mData;
}
-void TestWindowContext::initialize(int width, int height) {
+void TestWindowContext::initialize(int width, int height) {
mData = new TestWindowData(SkISize::Make(width, height));
}
@@ -206,6 +193,5 @@
return mData ? mData->capturePixels(bmp) : false;
}
-} // namespace uirenderer
-} // namespace android
-
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/utils/TestWindowContext.h b/libs/hwui/utils/TestWindowContext.h
index 48ec952..17ad1e3 100644
--- a/libs/hwui/utils/TestWindowContext.h
+++ b/libs/hwui/utils/TestWindowContext.h
@@ -31,9 +31,7 @@
*/
class ANDROID_API TestWindowContext {
-
public:
-
TestWindowContext();
~TestWindowContext();
@@ -58,11 +56,9 @@
class TestWindowData;
TestWindowData* mData;
-
};
} // namespace uirenderer
} // namespace android
#endif // TESTWINDOWCONTEXT_H_
-
diff --git a/libs/hwui/utils/TimeUtils.h b/libs/hwui/utils/TimeUtils.h
index ce181b7..f66edea 100644
--- a/libs/hwui/utils/TimeUtils.h
+++ b/libs/hwui/utils/TimeUtils.h
@@ -21,15 +21,15 @@
namespace android {
namespace uirenderer {
-constexpr nsecs_t operator"" _s (unsigned long long s) {
+constexpr nsecs_t operator"" _s(unsigned long long s) {
return seconds_to_nanoseconds(s);
}
-constexpr nsecs_t operator"" _ms (unsigned long long ms) {
+constexpr nsecs_t operator"" _ms(unsigned long long ms) {
return milliseconds_to_nanoseconds(ms);
}
-constexpr nsecs_t operator"" _us (unsigned long long us) {
+constexpr nsecs_t operator"" _us(unsigned long long us) {
return microseconds_to_nanoseconds(us);
}
diff --git a/libs/hwui/utils/Timing.h b/libs/hwui/utils/Timing.h
index 4b1fabe..978c7bc 100644
--- a/libs/hwui/utils/Timing.h
+++ b/libs/hwui/utils/Timing.h
@@ -22,18 +22,16 @@
#define TIME_METHOD() MethodTimer __method_timer(__func__)
class MethodTimer {
public:
- explicit MethodTimer(const char* name)
- : mMethodName(name) {
- gettimeofday(&mStart, nullptr);
- }
+ explicit MethodTimer(const char* name) : mMethodName(name) { gettimeofday(&mStart, nullptr); }
~MethodTimer() {
struct timeval stop;
gettimeofday(&stop, nullptr);
- long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000)
- + (stop.tv_usec - mStart.tv_usec);
+ long long elapsed = (stop.tv_sec * 1000000) - (mStart.tv_sec * 1000000) +
+ (stop.tv_usec - mStart.tv_usec);
ALOGD("%s took %.2fms", mMethodName, elapsed / 1000.0);
}
+
private:
const char* mMethodName;
struct timeval mStart;
diff --git a/libs/hwui/utils/TraceUtils.h b/libs/hwui/utils/TraceUtils.h
index ddc272c..1869d00 100644
--- a/libs/hwui/utils/TraceUtils.h
+++ b/libs/hwui/utils/TraceUtils.h
@@ -18,11 +18,11 @@
#include <utils/Trace.h>
-#define ATRACE_FORMAT(fmt, ...) \
- TraceUtils::TraceEnder __traceEnder = (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
+#define ATRACE_FORMAT(fmt, ...) \
+ TraceUtils::TraceEnder __traceEnder = \
+ (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
-#define ATRACE_FORMAT_BEGIN(fmt, ...) \
- TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
+#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
namespace android {
namespace uirenderer {
@@ -48,7 +48,7 @@
ATRACE_BEGIN(buf);
}
-}; // class TraceUtils
+}; // class TraceUtils
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/utils/VectorDrawableUtils.cpp b/libs/hwui/utils/VectorDrawableUtils.cpp
index 6f0c96d..1931d64 100644
--- a/libs/hwui/utils/VectorDrawableUtils.cpp
+++ b/libs/hwui/utils/VectorDrawableUtils.cpp
@@ -32,8 +32,8 @@
float ctrlPointY = 0;
float currentSegmentStartX = 0;
float currentSegmentStartY = 0;
- void addCommand(SkPath* outPath, char previousCmd,
- char cmd, const std::vector<float>* points, size_t start, size_t end);
+ void addCommand(SkPath* outPath, char previousCmd, char cmd, const std::vector<float>* points,
+ size_t start, size_t end);
};
bool VectorDrawableUtils::canMorph(const PathData& morphFrom, const PathData& morphTo) {
@@ -42,8 +42,8 @@
}
for (unsigned int i = 0; i < morphFrom.verbs.size(); i++) {
- if (morphFrom.verbs[i] != morphTo.verbs[i]
- || morphFrom.verbSizes[i] != morphTo.verbSizes[i]) {
+ if (morphFrom.verbs[i] != morphTo.verbs[i] ||
+ morphFrom.verbSizes[i] != morphTo.verbSizes[i]) {
return false;
}
}
@@ -51,7 +51,7 @@
}
bool VectorDrawableUtils::interpolatePathData(PathData* outData, const PathData& morphFrom,
- const PathData& morphTo, float fraction) {
+ const PathData& morphTo, float fraction) {
if (!canMorph(morphFrom, morphTo)) {
return false;
}
@@ -59,9 +59,9 @@
return true;
}
- /**
- * Convert an array of PathVerb to Path.
- */
+/**
+* Convert an array of PathVerb to Path.
+*/
void VectorDrawableUtils::verbsToPath(SkPath* outPath, const PathData& data) {
PathResolver resolver;
char previousCommand = 'm';
@@ -70,7 +70,7 @@
for (unsigned int i = 0; i < data.verbs.size(); i++) {
size_t verbSize = data.verbSizes[i];
resolver.addCommand(outPath, previousCommand, data.verbs[i], &data.points, start,
- start + verbSize);
+ start + verbSize);
previousCommand = data.verbs[i];
start += verbSize;
}
@@ -85,8 +85,8 @@
* @param nodeTo The end value as a PathVerb
* @param fraction The fraction to interpolate.
*/
-void VectorDrawableUtils::interpolatePaths(PathData* outData,
- const PathData& from, const PathData& to, float fraction) {
+void VectorDrawableUtils::interpolatePaths(PathData* outData, const PathData& from,
+ const PathData& to, float fraction) {
outData->points.resize(from.points.size());
outData->verbSizes = from.verbSizes;
outData->verbs = from.verbs;
@@ -110,16 +110,8 @@
* @param start The start angle of the arc on the ellipse
* @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
*/
-static void arcToBezier(SkPath* p,
- double cx,
- double cy,
- double a,
- double b,
- double e1x,
- double e1y,
- double theta,
- double start,
- double sweep) {
+static void arcToBezier(SkPath* p, double cx, double cy, double a, double b, double e1x, double e1y,
+ double theta, double start, double sweep) {
// Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
// and http://www.spaceroots.org/documents/ellipse/node22.html
@@ -144,19 +136,13 @@
double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
double tanDiff2 = tan((eta2 - eta1) / 2);
- double alpha =
- sin(eta2 - eta1) * (sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
+ double alpha = sin(eta2 - eta1) * (sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
double q1x = e1x + alpha * ep1x;
double q1y = e1y + alpha * ep1y;
double q2x = e2x - alpha * ep2x;
double q2y = e2y - alpha * ep2y;
- p->cubicTo((float) q1x,
- (float) q1y,
- (float) q2x,
- (float) q2y,
- (float) e2x,
- (float) e2y);
+ p->cubicTo((float)q1x, (float)q1y, (float)q2x, (float)q2y, (float)e2x, (float)e2y);
eta1 = eta2;
e1x = e2x;
e1y = e2y;
@@ -165,19 +151,12 @@
}
}
-inline double toRadians(float theta) { return theta * M_PI / 180;}
+inline double toRadians(float theta) {
+ return theta * M_PI / 180;
+}
-static void drawArc(SkPath* p,
- float x0,
- float y0,
- float x1,
- float y1,
- float a,
- float b,
- float theta,
- bool isMoreThanHalf,
- bool isPositiveArc) {
-
+static void drawArc(SkPath* p, float x0, float y0, float x1, float y1, float a, float b,
+ float theta, bool isMoreThanHalf, bool isPositiveArc) {
/* Convert rotation angle from degrees to radians */
double thetaD = toRadians(theta);
/* Pre-compute rotation matrix entries */
@@ -204,9 +183,8 @@
double disc = 1.0 / dsq - 1.0 / 4.0;
if (disc < 0.0) {
VECTOR_DRAWABLE_LOGD("Points are too far apart %f", dsq);
- float adjust = (float) (sqrt(dsq) / 1.99999);
- drawArc(p, x0, y0, x1, y1, a * adjust,
- b * adjust, theta, isMoreThanHalf, isPositiveArc);
+ float adjust = (float)(sqrt(dsq) / 1.99999);
+ drawArc(p, x0, y0, x1, y1, a * adjust, b * adjust, theta, isMoreThanHalf, isPositiveArc);
return; /* Points are too far apart */
}
double s = sqrt(disc);
@@ -244,248 +222,232 @@
arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
}
-
-
// Use the given verb, and points in the range [start, end) to insert a command into the SkPath.
-void PathResolver::addCommand(SkPath* outPath, char previousCmd,
- char cmd, const std::vector<float>* points, size_t start, size_t end) {
-
+void PathResolver::addCommand(SkPath* outPath, char previousCmd, char cmd,
+ const std::vector<float>* points, size_t start, size_t end) {
int incr = 2;
float reflectiveCtrlPointX;
float reflectiveCtrlPointY;
switch (cmd) {
- case 'z':
- case 'Z':
- outPath->close();
- // Path is closed here, but we need to move the pen to the
- // closed position. So we cache the segment's starting position,
- // and restore it here.
- currentX = currentSegmentStartX;
- currentY = currentSegmentStartY;
- ctrlPointX = currentSegmentStartX;
- ctrlPointY = currentSegmentStartY;
- outPath->moveTo(currentX, currentY);
- break;
- case 'm':
- case 'M':
- case 'l':
- case 'L':
- case 't':
- case 'T':
- incr = 2;
- break;
- case 'h':
- case 'H':
- case 'v':
- case 'V':
- incr = 1;
- break;
- case 'c':
- case 'C':
- incr = 6;
- break;
- case 's':
- case 'S':
- case 'q':
- case 'Q':
- incr = 4;
- break;
- case 'a':
- case 'A':
- incr = 7;
- break;
+ case 'z':
+ case 'Z':
+ outPath->close();
+ // Path is closed here, but we need to move the pen to the
+ // closed position. So we cache the segment's starting position,
+ // and restore it here.
+ currentX = currentSegmentStartX;
+ currentY = currentSegmentStartY;
+ ctrlPointX = currentSegmentStartX;
+ ctrlPointY = currentSegmentStartY;
+ outPath->moveTo(currentX, currentY);
+ break;
+ case 'm':
+ case 'M':
+ case 'l':
+ case 'L':
+ case 't':
+ case 'T':
+ incr = 2;
+ break;
+ case 'h':
+ case 'H':
+ case 'v':
+ case 'V':
+ incr = 1;
+ break;
+ case 'c':
+ case 'C':
+ incr = 6;
+ break;
+ case 's':
+ case 'S':
+ case 'q':
+ case 'Q':
+ incr = 4;
+ break;
+ case 'a':
+ case 'A':
+ incr = 7;
+ break;
}
for (unsigned int k = start; k < end; k += incr) {
switch (cmd) {
- case 'm': // moveto - Start a new sub-path (relative)
- currentX += points->at(k + 0);
- currentY += points->at(k + 1);
- if (k > start) {
- // According to the spec, if a moveto is followed by multiple
- // pairs of coordinates, the subsequent pairs are treated as
- // implicit lineto commands.
+ case 'm': // moveto - Start a new sub-path (relative)
+ currentX += points->at(k + 0);
+ currentY += points->at(k + 1);
+ if (k > start) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ outPath->rLineTo(points->at(k + 0), points->at(k + 1));
+ } else {
+ outPath->rMoveTo(points->at(k + 0), points->at(k + 1));
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ }
+ break;
+ case 'M': // moveto - Start a new sub-path
+ currentX = points->at(k + 0);
+ currentY = points->at(k + 1);
+ if (k > start) {
+ // According to the spec, if a moveto is followed by multiple
+ // pairs of coordinates, the subsequent pairs are treated as
+ // implicit lineto commands.
+ outPath->lineTo(points->at(k + 0), points->at(k + 1));
+ } else {
+ outPath->moveTo(points->at(k + 0), points->at(k + 1));
+ currentSegmentStartX = currentX;
+ currentSegmentStartY = currentY;
+ }
+ break;
+ case 'l': // lineto - Draw a line from the current point (relative)
outPath->rLineTo(points->at(k + 0), points->at(k + 1));
- } else {
- outPath->rMoveTo(points->at(k + 0), points->at(k + 1));
- currentSegmentStartX = currentX;
- currentSegmentStartY = currentY;
- }
- break;
- case 'M': // moveto - Start a new sub-path
- currentX = points->at(k + 0);
- currentY = points->at(k + 1);
- if (k > start) {
- // According to the spec, if a moveto is followed by multiple
- // pairs of coordinates, the subsequent pairs are treated as
- // implicit lineto commands.
+ currentX += points->at(k + 0);
+ currentY += points->at(k + 1);
+ break;
+ case 'L': // lineto - Draw a line from the current point
outPath->lineTo(points->at(k + 0), points->at(k + 1));
- } else {
- outPath->moveTo(points->at(k + 0), points->at(k + 1));
- currentSegmentStartX = currentX;
- currentSegmentStartY = currentY;
- }
- break;
- case 'l': // lineto - Draw a line from the current point (relative)
- outPath->rLineTo(points->at(k + 0), points->at(k + 1));
- currentX += points->at(k + 0);
- currentY += points->at(k + 1);
- break;
- case 'L': // lineto - Draw a line from the current point
- outPath->lineTo(points->at(k + 0), points->at(k + 1));
- currentX = points->at(k + 0);
- currentY = points->at(k + 1);
- break;
- case 'h': // horizontal lineto - Draws a horizontal line (relative)
- outPath->rLineTo(points->at(k + 0), 0);
- currentX += points->at(k + 0);
- break;
- case 'H': // horizontal lineto - Draws a horizontal line
- outPath->lineTo(points->at(k + 0), currentY);
- currentX = points->at(k + 0);
- break;
- case 'v': // vertical lineto - Draws a vertical line from the current point (r)
- outPath->rLineTo(0, points->at(k + 0));
- currentY += points->at(k + 0);
- break;
- case 'V': // vertical lineto - Draws a vertical line from the current point
- outPath->lineTo(currentX, points->at(k + 0));
- currentY = points->at(k + 0);
- break;
- case 'c': // curveto - Draws a cubic Bézier curve (relative)
- outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3),
- points->at(k + 4), points->at(k + 5));
+ currentX = points->at(k + 0);
+ currentY = points->at(k + 1);
+ break;
+ case 'h': // horizontal lineto - Draws a horizontal line (relative)
+ outPath->rLineTo(points->at(k + 0), 0);
+ currentX += points->at(k + 0);
+ break;
+ case 'H': // horizontal lineto - Draws a horizontal line
+ outPath->lineTo(points->at(k + 0), currentY);
+ currentX = points->at(k + 0);
+ break;
+ case 'v': // vertical lineto - Draws a vertical line from the current point (r)
+ outPath->rLineTo(0, points->at(k + 0));
+ currentY += points->at(k + 0);
+ break;
+ case 'V': // vertical lineto - Draws a vertical line from the current point
+ outPath->lineTo(currentX, points->at(k + 0));
+ currentY = points->at(k + 0);
+ break;
+ case 'c': // curveto - Draws a cubic Bézier curve (relative)
+ outPath->rCubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3), points->at(k + 4), points->at(k + 5));
- ctrlPointX = currentX + points->at(k + 2);
- ctrlPointY = currentY + points->at(k + 3);
- currentX += points->at(k + 4);
- currentY += points->at(k + 5);
+ ctrlPointX = currentX + points->at(k + 2);
+ ctrlPointY = currentY + points->at(k + 3);
+ currentX += points->at(k + 4);
+ currentY += points->at(k + 5);
- break;
- case 'C': // curveto - Draws a cubic Bézier curve
- outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3),
- points->at(k + 4), points->at(k + 5));
- currentX = points->at(k + 4);
- currentY = points->at(k + 5);
- ctrlPointX = points->at(k + 2);
- ctrlPointY = points->at(k + 3);
- break;
- case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
- reflectiveCtrlPointX = 0;
- reflectiveCtrlPointY = 0;
- if (previousCmd == 'c' || previousCmd == 's'
- || previousCmd == 'C' || previousCmd == 'S') {
- reflectiveCtrlPointX = currentX - ctrlPointX;
- reflectiveCtrlPointY = currentY - ctrlPointY;
- }
- outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1),
- points->at(k + 2), points->at(k + 3));
- ctrlPointX = currentX + points->at(k + 0);
- ctrlPointY = currentY + points->at(k + 1);
- currentX += points->at(k + 2);
- currentY += points->at(k + 3);
- break;
- case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
- reflectiveCtrlPointX = currentX;
- reflectiveCtrlPointY = currentY;
- if (previousCmd == 'c' || previousCmd == 's'
- || previousCmd == 'C' || previousCmd == 'S') {
- reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
- reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
- }
- outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3));
- ctrlPointX = points->at(k + 0);
- ctrlPointY = points->at(k + 1);
- currentX = points->at(k + 2);
- currentY = points->at(k + 3);
- break;
- case 'q': // Draws a quadratic Bézier (relative)
- outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3));
- ctrlPointX = currentX + points->at(k + 0);
- ctrlPointY = currentY + points->at(k + 1);
- currentX += points->at(k + 2);
- currentY += points->at(k + 3);
- break;
- case 'Q': // Draws a quadratic Bézier
- outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2), points->at(k + 3));
- ctrlPointX = points->at(k + 0);
- ctrlPointY = points->at(k + 1);
- currentX = points->at(k + 2);
- currentY = points->at(k + 3);
- break;
- case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
- reflectiveCtrlPointX = 0;
- reflectiveCtrlPointY = 0;
- if (previousCmd == 'q' || previousCmd == 't'
- || previousCmd == 'Q' || previousCmd == 'T') {
- reflectiveCtrlPointX = currentX - ctrlPointX;
- reflectiveCtrlPointY = currentY - ctrlPointY;
- }
- outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1));
- ctrlPointX = currentX + reflectiveCtrlPointX;
- ctrlPointY = currentY + reflectiveCtrlPointY;
- currentX += points->at(k + 0);
- currentY += points->at(k + 1);
- break;
- case 'T': // Draws a quadratic Bézier curve (reflective control point)
- reflectiveCtrlPointX = currentX;
- reflectiveCtrlPointY = currentY;
- if (previousCmd == 'q' || previousCmd == 't'
- || previousCmd == 'Q' || previousCmd == 'T') {
- reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
- reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
- }
- outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- points->at(k + 0), points->at(k + 1));
- ctrlPointX = reflectiveCtrlPointX;
- ctrlPointY = reflectiveCtrlPointY;
- currentX = points->at(k + 0);
- currentY = points->at(k + 1);
- break;
- case 'a': // Draws an elliptical arc
- // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
- drawArc(outPath,
- currentX,
- currentY,
- points->at(k + 5) + currentX,
- points->at(k + 6) + currentY,
- points->at(k + 0),
- points->at(k + 1),
- points->at(k + 2),
- points->at(k + 3) != 0,
- points->at(k + 4) != 0);
- currentX += points->at(k + 5);
- currentY += points->at(k + 6);
- ctrlPointX = currentX;
- ctrlPointY = currentY;
- break;
- case 'A': // Draws an elliptical arc
- drawArc(outPath,
- currentX,
- currentY,
- points->at(k + 5),
- points->at(k + 6),
- points->at(k + 0),
- points->at(k + 1),
- points->at(k + 2),
- points->at(k + 3) != 0,
- points->at(k + 4) != 0);
- currentX = points->at(k + 5);
- currentY = points->at(k + 6);
- ctrlPointX = currentX;
- ctrlPointY = currentY;
- break;
- default:
- LOG_ALWAYS_FATAL("Unsupported command: %c", cmd);
- break;
+ break;
+ case 'C': // curveto - Draws a cubic Bézier curve
+ outPath->cubicTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3), points->at(k + 4), points->at(k + 5));
+ currentX = points->at(k + 4);
+ currentY = points->at(k + 5);
+ ctrlPointX = points->at(k + 2);
+ ctrlPointY = points->at(k + 3);
+ break;
+ case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'c' || previousCmd == 's' || previousCmd == 'C' ||
+ previousCmd == 'S') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ outPath->rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1), points->at(k + 2), points->at(k + 3));
+ ctrlPointX = currentX + points->at(k + 0);
+ ctrlPointY = currentY + points->at(k + 1);
+ currentX += points->at(k + 2);
+ currentY += points->at(k + 3);
+ break;
+ case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'c' || previousCmd == 's' || previousCmd == 'C' ||
+ previousCmd == 'S') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ outPath->cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1), points->at(k + 2), points->at(k + 3));
+ ctrlPointX = points->at(k + 0);
+ ctrlPointY = points->at(k + 1);
+ currentX = points->at(k + 2);
+ currentY = points->at(k + 3);
+ break;
+ case 'q': // Draws a quadratic Bézier (relative)
+ outPath->rQuadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3));
+ ctrlPointX = currentX + points->at(k + 0);
+ ctrlPointY = currentY + points->at(k + 1);
+ currentX += points->at(k + 2);
+ currentY += points->at(k + 3);
+ break;
+ case 'Q': // Draws a quadratic Bézier
+ outPath->quadTo(points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3));
+ ctrlPointX = points->at(k + 0);
+ ctrlPointY = points->at(k + 1);
+ currentX = points->at(k + 2);
+ currentY = points->at(k + 3);
+ break;
+ case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
+ reflectiveCtrlPointX = 0;
+ reflectiveCtrlPointY = 0;
+ if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' ||
+ previousCmd == 'T') {
+ reflectiveCtrlPointX = currentX - ctrlPointX;
+ reflectiveCtrlPointY = currentY - ctrlPointY;
+ }
+ outPath->rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1));
+ ctrlPointX = currentX + reflectiveCtrlPointX;
+ ctrlPointY = currentY + reflectiveCtrlPointY;
+ currentX += points->at(k + 0);
+ currentY += points->at(k + 1);
+ break;
+ case 'T': // Draws a quadratic Bézier curve (reflective control point)
+ reflectiveCtrlPointX = currentX;
+ reflectiveCtrlPointY = currentY;
+ if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' ||
+ previousCmd == 'T') {
+ reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+ reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+ }
+ outPath->quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY, points->at(k + 0),
+ points->at(k + 1));
+ ctrlPointX = reflectiveCtrlPointX;
+ ctrlPointY = reflectiveCtrlPointY;
+ currentX = points->at(k + 0);
+ currentY = points->at(k + 1);
+ break;
+ case 'a': // Draws an elliptical arc
+ // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
+ drawArc(outPath, currentX, currentY, points->at(k + 5) + currentX,
+ points->at(k + 6) + currentY, points->at(k + 0), points->at(k + 1),
+ points->at(k + 2), points->at(k + 3) != 0, points->at(k + 4) != 0);
+ currentX += points->at(k + 5);
+ currentY += points->at(k + 6);
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
+ break;
+ case 'A': // Draws an elliptical arc
+ drawArc(outPath, currentX, currentY, points->at(k + 5), points->at(k + 6),
+ points->at(k + 0), points->at(k + 1), points->at(k + 2),
+ points->at(k + 3) != 0, points->at(k + 4) != 0);
+ currentX = points->at(k + 5);
+ currentY = points->at(k + 6);
+ ctrlPointX = currentX;
+ ctrlPointY = currentY;
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unsupported command: %c", cmd);
+ break;
}
previousCmd = cmd;
}
}
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/utils/VectorDrawableUtils.h b/libs/hwui/utils/VectorDrawableUtils.h
index b5ef510..4be48fb 100644
--- a/libs/hwui/utils/VectorDrawableUtils.h
+++ b/libs/hwui/utils/VectorDrawableUtils.h
@@ -20,8 +20,8 @@
#include "VectorDrawable.h"
#include <cutils/compiler.h>
-#include "SkPath.h"
#include <vector>
+#include "SkPath.h"
namespace android {
namespace uirenderer {
@@ -30,11 +30,11 @@
public:
ANDROID_API static bool canMorph(const PathData& morphFrom, const PathData& morphTo);
ANDROID_API static bool interpolatePathData(PathData* outData, const PathData& morphFrom,
- const PathData& morphTo, float fraction);
+ const PathData& morphTo, float fraction);
ANDROID_API static void verbsToPath(SkPath* outPath, const PathData& data);
static void interpolatePaths(PathData* outPathData, const PathData& from, const PathData& to,
- float fraction);
+ float fraction);
};
-} // namespace uirenderer
-} // namespace android
+} // namespace uirenderer
+} // namespace android
#endif /* ANDROID_HWUI_VECTORDRAWABLE_UTILS_H*/
diff --git a/libs/protoutil/Android.bp b/libs/protoutil/Android.bp
new file mode 100644
index 0000000..4f1d2d5
--- /dev/null
+++ b/libs/protoutil/Android.bp
@@ -0,0 +1,39 @@
+//
+// 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.
+
+cc_library {
+ name: "libprotoutil",
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wno-missing-field-initializers",
+ "-Wno-unused-variable",
+ "-Wunused-parameter",
+ ],
+
+ srcs: [
+ "src/EncodedBuffer.cpp",
+ "src/ProtoOutputStream.cpp",
+ "src/protobuf.cpp",
+ ],
+
+ export_include_dirs: ["include"],
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+}
diff --git a/libs/protoutil/Android.mk b/libs/protoutil/Android.mk
deleted file mode 100644
index 2a2b087..0000000
--- a/libs/protoutil/Android.mk
+++ /dev/null
@@ -1,39 +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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libprotoutil
-
-LOCAL_CFLAGS := \
- -Wall -Werror -Wno-missing-field-initializers -Wno-unused-variable -Wunused-parameter
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
-
-LOCAL_C_INCLUDES := \
- $(LOCAL_PATH)/include
-
-LOCAL_SRC_FILES := \
- src/EncodedBuffer.cpp \
- src/ProtoOutputStream.cpp \
- src/protobuf.cpp \
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-include $(BUILD_SHARED_LIBRARY)
-
diff --git a/libs/protoutil/include/android/util/ProtoOutputStream.h b/libs/protoutil/include/android/util/ProtoOutputStream.h
index b8415b2..ce41849 100644
--- a/libs/protoutil/include/android/util/ProtoOutputStream.h
+++ b/libs/protoutil/include/android/util/ProtoOutputStream.h
@@ -19,13 +19,63 @@
#include <android/util/EncodedBuffer.h>
-#include <stdint.h>
#include <string>
namespace android {
namespace util {
/**
+ * Position of the field type in a (long long) fieldId.
+ */
+const uint64_t FIELD_TYPE_SHIFT = 32;
+
+/**
+ * Mask for the field types stored in a fieldId. Leaves a whole
+ * byte for future expansion, even though there are currently only 17 types.
+ */
+const uint64_t FIELD_TYPE_MASK = 0x0ffULL << FIELD_TYPE_SHIFT;
+
+/**
+ * The types are copied from external/protobuf/src/google/protobuf/descriptor.h directly,
+ * so no extra mapping needs to be maintained in this case.
+ */
+const uint64_t FIELD_TYPE_UNKNOWN = 0;
+const uint64_t FIELD_TYPE_DOUBLE = 1ULL << FIELD_TYPE_SHIFT; // double, exactly eight bytes on the wire.
+const uint64_t FIELD_TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT; // float, exactly four bytes on the wire.
+const uint64_t FIELD_TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT; // int64, varint on the wire. Negative numbers
+ // take 10 bytes. Use TYPE_SINT64 if negative
+ // values are likely.
+const uint64_t FIELD_TYPE_UINT64 = 4ULL << FIELD_TYPE_SHIFT; // uint64, varint on the wire.
+const uint64_t FIELD_TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT; // int32, varint on the wire. Negative numbers
+ // take 10 bytes. Use TYPE_SINT32 if negative
+ // values are likely.
+const uint64_t FIELD_TYPE_FIXED64 = 6ULL << FIELD_TYPE_SHIFT; // uint64, exactly eight bytes on the wire.
+const uint64_t FIELD_TYPE_FIXED32 = 7ULL << FIELD_TYPE_SHIFT; // uint32, exactly four bytes on the wire.
+const uint64_t FIELD_TYPE_BOOL = 8ULL << FIELD_TYPE_SHIFT; // bool, varint on the wire.
+const uint64_t FIELD_TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT; // UTF-8 text.
+// const uint64_t FIELD_TYPE_GROUP = 10ULL << FIELD_TYPE_SHIFT; // Tag-delimited message. Deprecated.
+const uint64_t FIELD_TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT; // Length-delimited message.
+
+const uint64_t FIELD_TYPE_BYTES = 12ULL << FIELD_TYPE_SHIFT; // Arbitrary byte array.
+const uint64_t FIELD_TYPE_UINT32 = 13ULL << FIELD_TYPE_SHIFT; // uint32, varint on the wire
+const uint64_t FIELD_TYPE_ENUM = 14ULL << FIELD_TYPE_SHIFT; // Enum, varint on the wire
+const uint64_t FIELD_TYPE_SFIXED32 = 15ULL << FIELD_TYPE_SHIFT; // int32, exactly four bytes on the wire
+const uint64_t FIELD_TYPE_SFIXED64 = 16ULL << FIELD_TYPE_SHIFT; // int64, exactly eight bytes on the wire
+const uint64_t FIELD_TYPE_SINT32 = 17ULL << FIELD_TYPE_SHIFT; // int32, ZigZag-encoded varint on the wire
+const uint64_t FIELD_TYPE_SINT64 = 18ULL << FIELD_TYPE_SHIFT; // int64, ZigZag-encoded varint on the wire
+
+//
+// FieldId flags for whether the field is single, repeated or packed.
+// TODO: packed is not supported yet.
+//
+const uint64_t FIELD_COUNT_SHIFT = 40;
+const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_UNKNOWN = 0;
+const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
+
+/**
* Class to write to a protobuf stream.
*
* Each write method takes an ID code from the protoc generated classes
@@ -60,11 +110,12 @@
void end(long long token);
/**
- * Flushes the protobuf data out to given fd.
+ * Flushes the protobuf data out to given fd. When the following functions are called,
+ * it is not able to write to ProtoOutputStream any more since the data is compact.
*/
- size_t size();
- EncodedBuffer::iterator data();
- bool flush(int fd);
+ size_t size(); // Get the size of the serialized protobuf.
+ EncodedBuffer::iterator data(); // Get the reader apis of the data.
+ bool flush(int fd); // Flush data directly to a file descriptor.
// Please don't use the following functions to dump protos unless you are familiar with protobuf encoding.
void writeRawVarint(uint64_t varint);
diff --git a/libs/protoutil/src/ProtoOutputStream.cpp b/libs/protoutil/src/ProtoOutputStream.cpp
index b91e3db0..9d8ee729 100644
--- a/libs/protoutil/src/ProtoOutputStream.cpp
+++ b/libs/protoutil/src/ProtoOutputStream.cpp
@@ -18,58 +18,10 @@
#include <android/util/protobuf.h>
#include <android/util/ProtoOutputStream.h>
#include <cutils/log.h>
-#include <cstring>
namespace android {
namespace util {
-/**
- * Position of the field type in a (long long) fieldId.
- */
-const uint64_t FIELD_TYPE_SHIFT = 32;
-
-/**
- * Mask for the field types stored in a fieldId. Leaves a whole
- * byte for future expansion, even though there are currently only 17 types.
- */
-const uint64_t FIELD_TYPE_MASK = 0x0ffULL << FIELD_TYPE_SHIFT;
-
-const uint64_t FIELD_TYPE_UNKNOWN = 0;
-const uint64_t TYPE_DOUBLE = 1ULL << FIELD_TYPE_SHIFT; // double, exactly eight bytes on the wire.
-const uint64_t TYPE_FLOAT = 2ULL << FIELD_TYPE_SHIFT; // float, exactly four bytes on the wire.
-const uint64_t TYPE_INT64 = 3ULL << FIELD_TYPE_SHIFT; // int64, varint on the wire. Negative numbers
- // take 10 bytes. Use TYPE_SINT64 if negative
- // values are likely.
-const uint64_t TYPE_UINT64 = 4ULL << FIELD_TYPE_SHIFT; // uint64, varint on the wire.
-const uint64_t TYPE_INT32 = 5ULL << FIELD_TYPE_SHIFT; // int32, varint on the wire. Negative numbers
- // take 10 bytes. Use TYPE_SINT32 if negative
- // values are likely.
-const uint64_t TYPE_FIXED64 = 6ULL << FIELD_TYPE_SHIFT; // uint64, exactly eight bytes on the wire.
-const uint64_t TYPE_FIXED32 = 7ULL << FIELD_TYPE_SHIFT; // uint32, exactly four bytes on the wire.
-const uint64_t TYPE_BOOL = 8ULL << FIELD_TYPE_SHIFT; // bool, varint on the wire.
-const uint64_t TYPE_STRING = 9ULL << FIELD_TYPE_SHIFT; // UTF-8 text.
-const uint64_t TYPE_GROUP = 10ULL << FIELD_TYPE_SHIFT; // Tag-delimited message. Deprecated.
-const uint64_t TYPE_MESSAGE = 11ULL << FIELD_TYPE_SHIFT; // Length-delimited message.
-
-const uint64_t TYPE_BYTES = 12ULL << FIELD_TYPE_SHIFT; // Arbitrary byte array.
-const uint64_t TYPE_UINT32 = 13ULL << FIELD_TYPE_SHIFT; // uint32, varint on the wire
-const uint64_t TYPE_ENUM = 14ULL << FIELD_TYPE_SHIFT; // Enum, varint on the wire
-const uint64_t TYPE_SFIXED32 = 15ULL << FIELD_TYPE_SHIFT; // int32, exactly four bytes on the wire
-const uint64_t TYPE_SFIXED64 = 16ULL << FIELD_TYPE_SHIFT; // int64, exactly eight bytes on the wire
-const uint64_t TYPE_SINT32 = 17ULL << FIELD_TYPE_SHIFT; // int32, ZigZag-encoded varint on the wire
-const uint64_t TYPE_SINT64 = 18ULL << FIELD_TYPE_SHIFT; // int64, ZigZag-encoded varint on the wire
-
-//
-// FieldId flags for whether the field is single, repeated or packed.
-// TODO: packed is not supported yet.
-//
-const uint64_t FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_UNKNOWN = 0;
-const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
-
ProtoOutputStream::ProtoOutputStream()
:mBuffer(),
mCopyBegin(0),
@@ -90,18 +42,18 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
- case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
- case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
- case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
- case TYPE_INT32: writeInt32Impl(id, (int)val); break;
- case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
- case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
- case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
- case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
- case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
- case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
- case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
+ case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
+ case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
+ case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
+ case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
default:
ALOGW("Field type %d is not supported when writing double val.",
(int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
@@ -116,18 +68,18 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
- case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
- case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
- case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
- case TYPE_INT32: writeInt32Impl(id, (int)val); break;
- case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
- case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
- case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
- case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
- case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
- case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
- case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
+ case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
+ case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
+ case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
+ case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
default:
ALOGW("Field type %d is not supported when writing float val.",
(int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
@@ -142,20 +94,20 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
- case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
- case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
- case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
- case TYPE_INT32: writeInt32Impl(id, (int)val); break;
- case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
- case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
- case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
- case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
- case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
- case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
- case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
- case TYPE_ENUM: writeEnumImpl(id, (int)val); break;
- case TYPE_BOOL: writeBoolImpl(id, val != 0); break;
+ case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
+ case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
+ case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
+ case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
+ case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
+ case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
default:
ALOGW("Field type %d is not supported when writing int val.",
(int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
@@ -170,20 +122,20 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
- case TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
- case TYPE_INT64: writeInt64Impl(id, (long long)val); break;
- case TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
- case TYPE_INT32: writeInt32Impl(id, (int)val); break;
- case TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
- case TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
- case TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
- case TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
- case TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
- case TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
- case TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
- case TYPE_ENUM: writeEnumImpl(id, (int)val); break;
- case TYPE_BOOL: writeBoolImpl(id, val != 0); break;
+ case FIELD_TYPE_DOUBLE: writeDoubleImpl(id, (double)val); break;
+ case FIELD_TYPE_FLOAT: writeFloatImpl(id, (float)val); break;
+ case FIELD_TYPE_INT64: writeInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_UINT64: writeUint64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_INT32: writeInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_FIXED64: writeFixed64Impl(id, (uint64_t)val); break;
+ case FIELD_TYPE_FIXED32: writeFixed32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_UINT32: writeUint32Impl(id, (uint32_t)val); break;
+ case FIELD_TYPE_SFIXED32: writeSFixed32Impl(id, (int)val); break;
+ case FIELD_TYPE_SFIXED64: writeSFixed64Impl(id, (long long)val); break;
+ case FIELD_TYPE_SINT32: writeZigzagInt32Impl(id, (int)val); break;
+ case FIELD_TYPE_SINT64: writeZigzagInt64Impl(id, (long long)val); break;
+ case FIELD_TYPE_ENUM: writeEnumImpl(id, (int)val); break;
+ case FIELD_TYPE_BOOL: writeBoolImpl(id, val != 0); break;
default:
ALOGW("Field type %d is not supported when writing long long val.",
(int)((fieldId & FIELD_TYPE_MASK) >> FIELD_TYPE_SHIFT));
@@ -198,7 +150,7 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_BOOL:
+ case FIELD_TYPE_BOOL:
writeBoolImpl(id, val);
return true;
default:
@@ -214,7 +166,7 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_STRING:
+ case FIELD_TYPE_STRING:
writeUtf8StringImpl(id, val.c_str(), val.size());
return true;
default:
@@ -230,11 +182,11 @@
if (mCompact) return false;
const uint32_t id = (uint32_t)fieldId;
switch (fieldId & FIELD_TYPE_MASK) {
- case TYPE_STRING:
- case TYPE_BYTES:
+ case FIELD_TYPE_STRING:
+ case FIELD_TYPE_BYTES:
writeUtf8StringImpl(id, val, size);
return true;
- case TYPE_MESSAGE:
+ case FIELD_TYPE_MESSAGE:
// can directly write valid format of message bytes into ProtoOutputStream without calling start/end
writeMessageBytesImpl(id, val, size);
return true;
@@ -291,7 +243,7 @@
long long
ProtoOutputStream::start(uint64_t fieldId)
{
- if ((fieldId & FIELD_TYPE_MASK) != TYPE_MESSAGE) {
+ if ((fieldId & FIELD_TYPE_MASK) != FIELD_TYPE_MESSAGE) {
ALOGE("Can't call start for non-message type field: 0x%llx", (long long)fieldId);
return 0;
}
@@ -564,7 +516,6 @@
inline void
ProtoOutputStream::writeDoubleImpl(uint32_t id, double val)
{
- if (val == 0.0) return;
mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
mBuffer.writeRawFixed64(bit_cast<double, uint64_t>(val));
}
@@ -572,7 +523,6 @@
inline void
ProtoOutputStream::writeFloatImpl(uint32_t id, float val)
{
- if (val == 0.0) return;
mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
mBuffer.writeRawFixed32(bit_cast<float, uint32_t>(val));
}
@@ -580,7 +530,6 @@
inline void
ProtoOutputStream::writeInt64Impl(uint32_t id, long long val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint64((uint64_t)val);
}
@@ -588,7 +537,6 @@
inline void
ProtoOutputStream::writeInt32Impl(uint32_t id, int val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint32((uint32_t)val);
}
@@ -596,7 +544,6 @@
inline void
ProtoOutputStream::writeUint64Impl(uint32_t id, uint64_t val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint64(val);
}
@@ -604,7 +551,6 @@
inline void
ProtoOutputStream::writeUint32Impl(uint32_t id, uint32_t val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint32(val);
}
@@ -612,7 +558,6 @@
inline void
ProtoOutputStream::writeFixed64Impl(uint32_t id, uint64_t val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
mBuffer.writeRawFixed64(val);
}
@@ -620,7 +565,6 @@
inline void
ProtoOutputStream::writeFixed32Impl(uint32_t id, uint32_t val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
mBuffer.writeRawFixed32(val);
}
@@ -628,7 +572,6 @@
inline void
ProtoOutputStream::writeSFixed64Impl(uint32_t id, long long val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_FIXED64);
mBuffer.writeRawFixed64((uint64_t)val);
}
@@ -636,7 +579,6 @@
inline void
ProtoOutputStream::writeSFixed32Impl(uint32_t id, int val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_FIXED32);
mBuffer.writeRawFixed32((uint32_t)val);
}
@@ -644,7 +586,6 @@
inline void
ProtoOutputStream::writeZigzagInt64Impl(uint32_t id, long long val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint64((val << 1) ^ (val >> 63));
}
@@ -652,7 +593,6 @@
inline void
ProtoOutputStream::writeZigzagInt32Impl(uint32_t id, int val)
{
- if (val == 0) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint32((val << 1) ^ (val >> 31));
}
@@ -667,7 +607,6 @@
inline void
ProtoOutputStream::writeBoolImpl(uint32_t id, bool val)
{
- if (!val) return;
mBuffer.writeHeader(id, WIRE_TYPE_VARINT);
mBuffer.writeRawVarint32(val ? 1 : 0);
}
@@ -675,7 +614,7 @@
inline void
ProtoOutputStream::writeUtf8StringImpl(uint32_t id, const char* val, size_t size)
{
- if (val == NULL || size == 0) return;
+ if (val == NULL) return;
writeLengthDelimitedHeader(id, size);
for (size_t i=0; i<size; i++) {
mBuffer.writeRawByte((uint8_t)val[i]);
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index e7f903e..c9d2f7f 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -821,7 +821,7 @@
* considered 1 standard deviation.
*
* <p>For example, if {@link #getAltitude()} returns 150, and
- * {@link #getVerticalAccuracyMeters()} ()} returns 20 then there is a 68% probability
+ * {@link #getVerticalAccuracyMeters()} returns 20 then there is a 68% probability
* of the true altitude being between 130 and 170 meters.
*
* <p>If this location does not have a vertical accuracy, then 0.0 is returned.
@@ -933,7 +933,7 @@
* considered 1 standard deviation.
*
* <p>For example, if {@link #getBearing()} returns 60, and
- * {@link #getBearingAccuracyDegrees()} ()} returns 10, then there is a 68% probability of the
+ * {@link #getBearingAccuracyDegrees()} returns 10, then there is a 68% probability of the
* true bearing being between 50 and 70 degrees.
*
* <p>If this location does not have a bearing accuracy, then 0.0 is returned.
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index ba41a7b..9175416 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -2564,51 +2564,66 @@
});
}
+ String hasImage = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE);
String hasVideo = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
- final String METADATA_HAS_VIDEO_VALUE_YES = "yes";
- if (METADATA_HAS_VIDEO_VALUE_YES.equals(hasVideo)) {
- String width = retriever.extractMetadata(
+ String width = null;
+ String height = null;
+ String rotation = null;
+ final String METADATA_VALUE_YES = "yes";
+ // If the file has both image and video, prefer image info over video info.
+ // App querying ExifInterface is most likely using the bitmap path which
+ // picks the image first.
+ if (METADATA_VALUE_YES.equals(hasImage)) {
+ width = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH);
+ height = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT);
+ rotation = retriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION);
+ } else if (METADATA_VALUE_YES.equals(hasVideo)) {
+ width = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH);
- String height = retriever.extractMetadata(
+ height = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT);
-
- if (width != null) {
- mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH,
- ExifAttribute.createUShort(Integer.parseInt(width), mExifByteOrder));
- }
-
- if (height != null) {
- mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH,
- ExifAttribute.createUShort(Integer.parseInt(height), mExifByteOrder));
- }
-
- String rotation = retriever.extractMetadata(
+ rotation = retriever.extractMetadata(
MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION);
- if (rotation != null) {
- int orientation = ExifInterface.ORIENTATION_NORMAL;
+ }
- // all rotation angles in CW
- switch (Integer.parseInt(rotation)) {
- case 90:
- orientation = ExifInterface.ORIENTATION_ROTATE_90;
- break;
- case 180:
- orientation = ExifInterface.ORIENTATION_ROTATE_180;
- break;
- case 270:
- orientation = ExifInterface.ORIENTATION_ROTATE_270;
- break;
- }
+ if (width != null) {
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_WIDTH,
+ ExifAttribute.createUShort(Integer.parseInt(width), mExifByteOrder));
+ }
- mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION,
- ExifAttribute.createUShort(orientation, mExifByteOrder));
+ if (height != null) {
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_IMAGE_LENGTH,
+ ExifAttribute.createUShort(Integer.parseInt(height), mExifByteOrder));
+ }
+
+ if (rotation != null) {
+ int orientation = ExifInterface.ORIENTATION_NORMAL;
+
+ // all rotation angles in CW
+ switch (Integer.parseInt(rotation)) {
+ case 90:
+ orientation = ExifInterface.ORIENTATION_ROTATE_90;
+ break;
+ case 180:
+ orientation = ExifInterface.ORIENTATION_ROTATE_180;
+ break;
+ case 270:
+ orientation = ExifInterface.ORIENTATION_ROTATE_270;
+ break;
}
- if (DEBUG) {
- Log.d(TAG, "Heif meta: " + width + "x" + height + ", rotation " + rotation);
- }
+ mAttributes[IFD_TYPE_PRIMARY].put(TAG_ORIENTATION,
+ ExifAttribute.createUShort(orientation, mExifByteOrder));
+ }
+
+ if (DEBUG) {
+ Log.d(TAG, "Heif meta: " + width + "x" + height + ", rotation " + rotation);
}
} finally {
retriever.release();
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
index 88b1c5f..1feea89 100644
--- a/media/java/android/media/MediaDrm.java
+++ b/media/java/android/media/MediaDrm.java
@@ -994,7 +994,6 @@
* {@link #PROPERTY_VENDOR}, {@link #PROPERTY_VERSION},
* {@link #PROPERTY_DESCRIPTION}, {@link #PROPERTY_ALGORITHMS}
*/
- /* FIXME this throws IllegalStateException for invalid property names */
@NonNull
public native String getPropertyString(@NonNull @StringProperty String propertyName);
@@ -1002,7 +1001,6 @@
* Byte array property name: the device unique identifier is established during
* device provisioning and provides a means of uniquely identifying each device.
*/
- /* FIXME this throws IllegalStateException for invalid property names */
public static final String PROPERTY_DEVICE_UNIQUE_ID = "deviceUniqueId";
/** @hide */
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 62757e2..17af44b 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -43,6 +43,7 @@
import android.system.OsConstants;
import android.util.Log;
import android.util.Pair;
+import android.util.ArrayMap;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.widget.VideoView;
@@ -58,6 +59,7 @@
import android.media.SubtitleTrack.RenderingWidget;
import android.media.SyncParams;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import libcore.io.IoBridge;
@@ -577,6 +579,7 @@
public class MediaPlayer extends PlayerBase
implements SubtitleController.Listener
, VolumeAutomation
+ , AudioRouting
{
/**
Constant to retrieve only the new metadata since the last
@@ -1417,6 +1420,155 @@
private native @Nullable VolumeShaper.State native_getVolumeShaperState(int id);
+ //--------------------------------------------------------------------------
+ // Explicit Routing
+ //--------------------
+ private AudioDeviceInfo mPreferredDevice = null;
+
+ /**
+ * Specifies an audio device (via an {@link AudioDeviceInfo} object) to route
+ * the output from this MediaPlayer.
+ * @param deviceInfo The {@link AudioDeviceInfo} specifying the audio sink or source.
+ * If deviceInfo is null, default routing is restored.
+ * @return true if succesful, false if the specified {@link AudioDeviceInfo} is non-null and
+ * does not correspond to a valid audio device.
+ */
+ @Override
+ public boolean setPreferredDevice(AudioDeviceInfo deviceInfo) {
+ if (deviceInfo != null && !deviceInfo.isSink()) {
+ return false;
+ }
+ int preferredDeviceId = deviceInfo != null ? deviceInfo.getId() : 0;
+ boolean status = native_setOutputDevice(preferredDeviceId);
+ if (status == true) {
+ synchronized (this) {
+ mPreferredDevice = deviceInfo;
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Returns the selected output specified by {@link #setPreferredDevice}. Note that this
+ * is not guaranteed to correspond to the actual device being used for playback.
+ */
+ @Override
+ public AudioDeviceInfo getPreferredDevice() {
+ synchronized (this) {
+ return mPreferredDevice;
+ }
+ }
+
+ /**
+ * Returns an {@link AudioDeviceInfo} identifying the current routing of this MediaPlayer
+ * Note: The query is only valid if the MediaPlayer is currently playing.
+ * If the player is not playing, the returned device can be null or correspond to previously
+ * selected device when the player was last active.
+ */
+ @Override
+ public AudioDeviceInfo getRoutedDevice() {
+ int deviceId = native_getRoutedDeviceId();
+ if (deviceId == 0) {
+ return null;
+ }
+ AudioDeviceInfo[] devices =
+ AudioManager.getDevicesStatic(AudioManager.GET_DEVICES_OUTPUTS);
+ for (int i = 0; i < devices.length; i++) {
+ if (devices[i].getId() == deviceId) {
+ return devices[i];
+ }
+ }
+ return null;
+ }
+
+ /*
+ * Call BEFORE adding a routing callback handler or AFTER removing a routing callback handler.
+ */
+ private void enableNativeRoutingCallbacksLocked(boolean enabled) {
+ if (mRoutingChangeListeners.size() == 0) {
+ native_enableDeviceCallback(enabled);
+ }
+ }
+
+ /**
+ * The list of AudioRouting.OnRoutingChangedListener interfaces added (with
+ * {@link #addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, Handler)}
+ * by an app to receive (re)routing notifications.
+ */
+ @GuardedBy("mRoutingChangeListeners")
+ private ArrayMap<AudioRouting.OnRoutingChangedListener,
+ NativeRoutingEventHandlerDelegate> mRoutingChangeListeners = new ArrayMap<>();
+
+ /**
+ * Adds an {@link AudioRouting.OnRoutingChangedListener} to receive notifications of routing
+ * changes on this MediaPlayer.
+ * @param listener The {@link AudioRouting.OnRoutingChangedListener} interface to receive
+ * notifications of rerouting events.
+ * @param handler Specifies the {@link Handler} object for the thread on which to execute
+ * the callback. If <code>null</code>, the handler on the main looper will be used.
+ */
+ @Override
+ public void addOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener,
+ Handler handler) {
+ synchronized (mRoutingChangeListeners) {
+ if (listener != null && !mRoutingChangeListeners.containsKey(listener)) {
+ enableNativeRoutingCallbacksLocked(true);
+ mRoutingChangeListeners.put(
+ listener, new NativeRoutingEventHandlerDelegate(this, listener, handler));
+ }
+ }
+ }
+
+ /**
+ * Removes an {@link AudioRouting.OnRoutingChangedListener} which has been previously added
+ * to receive rerouting notifications.
+ * @param listener The previously added {@link AudioRouting.OnRoutingChangedListener} interface
+ * to remove.
+ */
+ @Override
+ public void removeOnRoutingChangedListener(AudioRouting.OnRoutingChangedListener listener) {
+ synchronized (mRoutingChangeListeners) {
+ if (mRoutingChangeListeners.containsKey(listener)) {
+ mRoutingChangeListeners.remove(listener);
+ enableNativeRoutingCallbacksLocked(false);
+ }
+ }
+ }
+
+ /**
+ * Helper class to handle the forwarding of native events to the appropriate listener
+ * (potentially) handled in a different thread
+ */
+ private class NativeRoutingEventHandlerDelegate {
+ private MediaPlayer mMediaPlayer;
+ private AudioRouting.OnRoutingChangedListener mOnRoutingChangedListener;
+ private Handler mHandler;
+
+ NativeRoutingEventHandlerDelegate(final MediaPlayer mediaPlayer,
+ final AudioRouting.OnRoutingChangedListener listener, Handler handler) {
+ mMediaPlayer = mediaPlayer;
+ mOnRoutingChangedListener = listener;
+ mHandler = handler != null ? handler : mEventHandler;
+ }
+
+ void notifyClient() {
+ if (mHandler != null) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mOnRoutingChangedListener != null) {
+ mOnRoutingChangedListener.onRoutingChanged(mMediaPlayer);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ private native final boolean native_setOutputDevice(int deviceId);
+ private native final int native_getRoutedDeviceId();
+ private native final void native_enableDeviceCallback(boolean enabled);
+
/**
* Set the low-level power management behavior for this MediaPlayer. This
* can be used when the MediaPlayer is not playing through a SurfaceHolder
@@ -3176,6 +3328,7 @@
private static final int MEDIA_SUBTITLE_DATA = 201;
private static final int MEDIA_META_DATA = 202;
private static final int MEDIA_DRM_INFO = 210;
+ private static final int MEDIA_AUDIO_ROUTING_CHANGED = 10000;
private TimeProvider mTimeProvider;
@@ -3414,6 +3567,16 @@
case MEDIA_NOP: // interface test message - ignore
break;
+ case MEDIA_AUDIO_ROUTING_CHANGED:
+ AudioManager.resetAudioPortGeneration();
+ synchronized (mRoutingChangeListeners) {
+ for (NativeRoutingEventHandlerDelegate delegate
+ : mRoutingChangeListeners.values()) {
+ delegate.notifyClient();
+ }
+ }
+ return;
+
default:
Log.e(TAG, "Unknown message type " + msg.what);
return;
diff --git a/media/jni/Android.bp b/media/jni/Android.bp
index 1d85c972..597336b 100644
--- a/media/jni/Android.bp
+++ b/media/jni/Android.bp
@@ -35,6 +35,7 @@
"libutils",
"libbinder",
"libmedia",
+ "libmedia_omx",
"libmediametrics",
"libmediadrm",
"libmidi",
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index d0c2aea..51c9e5f 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -282,7 +282,7 @@
drmMessage = "Decrypt error";
break;
case ERROR_DRM_CANNOT_HANDLE:
- drmMessage = "Unsupported scheme or data format";
+ drmMessage = "Invalid parameter or data format";
break;
case ERROR_DRM_TAMPER_DETECTED:
drmMessage = "Invalid state";
@@ -297,7 +297,7 @@
drmMessage = vendorMessage.string();
}
- if (err == BAD_VALUE) {
+ if (err == BAD_VALUE || err == ERROR_DRM_CANNOT_HANDLE) {
jniThrowException(env, "java/lang/IllegalArgumentException", msg);
return true;
} else if (err == ERROR_DRM_NOT_PROVISIONED) {
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index 28827e6..cfa3cc36 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1387,6 +1387,44 @@
// Modular DRM end
// ----------------------------------------------------------------------------
+/////////////////////////////////////////////////////////////////////////////////////
+// AudioRouting begin
+static jboolean android_media_MediaPlayer_setOutputDevice(JNIEnv *env, jobject thiz, jint device_id)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return false;
+ }
+ return mp->setOutputDevice(device_id) == NO_ERROR;
+}
+
+static jint android_media_MediaPlayer_getRoutedDeviceId(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return mp->getRoutedDeviceId();
+}
+
+static void android_media_MediaPlayer_enableDeviceCallback(
+ JNIEnv* env, jobject thiz, jboolean enabled)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ return;
+ }
+
+ status_t status = mp->enableAudioDeviceCallback(enabled);
+ if (status != NO_ERROR) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ ALOGE("enable device callback failed: %d", status);
+ }
+}
+
+// AudioRouting end
+// ----------------------------------------------------------------------------
+
static const JNINativeMethod gMethods[] = {
{
"nativeSetDataSource",
@@ -1448,6 +1486,11 @@
// Modular DRM
{ "_prepareDrm", "([B[B)V", (void *)android_media_MediaPlayer_prepareDrm },
{ "_releaseDrm", "()V", (void *)android_media_MediaPlayer_releaseDrm },
+
+ // AudioRouting
+ {"native_setOutputDevice", "(I)Z", (void *)android_media_MediaPlayer_setOutputDevice},
+ {"native_getRoutedDeviceId", "()I", (void *)android_media_MediaPlayer_getRoutedDeviceId},
+ {"native_enableDeviceCallback", "(Z)V", (void *)android_media_MediaPlayer_enableDeviceCallback},
};
// This function only registers the native methods
diff --git a/packages/MtpDocumentsProvider/res/values-mr/strings.xml b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
index 89a9d14..d581e10 100644
--- a/packages/MtpDocumentsProvider/res/values-mr/strings.xml
+++ b/packages/MtpDocumentsProvider/res/values-mr/strings.xml
@@ -19,7 +19,7 @@
<string name="app_label" msgid="6271216747302322594">"MTP होस्ट"</string>
<string name="downloads_app_label" msgid="7120690641874849726">"डाउनलोड"</string>
<string name="root_name" msgid="5819495383921089536">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> <xliff:g id="STORAGE_NAME">%2$s</xliff:g>"</string>
- <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> मधून फायलींंमध्ये प्रवेश करीत आहे"</string>
+ <string name="accessing_notification_title" msgid="3030133609230917944">"<xliff:g id="DEVICE_MODEL">%1$s</xliff:g> मधून फायलींंमध्ये प्रवेश करत आहे"</string>
<string name="error_busy_device" msgid="3997316850357386589">"दुसरे डिव्हाइस व्यस्त आहे. ते उपलब्ध होईपर्यंत तुम्ही फायली ट्रांसफर करू शकत नाही."</string>
<string name="error_locked_device" msgid="7557872102188356147">"कोणत्याही फायली आढळल्या नाहीत. दुसरे डिव्हाइस कदाचित बंद असू शकते. तसे असल्यास, ते अनलॉक करा आणि पुन्हा प्रयत्न करा."</string>
</resources>
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index 05eb853..862d193 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -34,7 +34,7 @@
<string name="print_preview" msgid="8010217796057763343">"मुद्रण पूर्वावलोकन"</string>
<string name="install_for_print_preview" msgid="6366303997385509332">"पूर्वावलोकनासाठी पीडीएफ व्ह्यूअर इंस्टॉल करा"</string>
<string name="printing_app_crashed" msgid="854477616686566398">"प्रिंटिंग अॅप क्रॅश झाले"</string>
- <string name="generating_print_job" msgid="3119608742651698916">"मुद्रण कार्य व्युत्पन्न करीत आहे"</string>
+ <string name="generating_print_job" msgid="3119608742651698916">"मुद्रण कार्य व्युत्पन्न करत आहे"</string>
<string name="save_as_pdf" msgid="5718454119847596853">"पीडीएफ म्हणून सेव्ह करा"</string>
<string name="all_printers" msgid="5018829726861876202">"सर्व प्रिंटर..."</string>
<string name="print_dialog" msgid="32628687461331979">"मुद्रण संवाद"</string>
@@ -79,8 +79,8 @@
<item quantity="one"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item>
<item quantity="other"><xliff:g id="COUNT_1">%1$s</xliff:g> प्रिंटर शोधण्यासाठी इंस्टॉल करा</item>
</plurals>
- <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करीत आहे"</string>
- <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करीत आहे"</string>
+ <string name="printing_notification_title_template" msgid="295903957762447362">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> मुद्रण करत आहे"</string>
+ <string name="cancelling_notification_title_template" msgid="1821759594704703197">"<xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> रद्द करत आहे"</string>
<string name="failed_notification_title_template" msgid="2256217208186530973">"प्रिंटर एरर <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g>"</string>
<string name="blocked_notification_title_template" msgid="1175435827331588646">"प्रिंटरने <xliff:g id="PRINT_JOB_NAME">%1$s</xliff:g> अवरोधित केले"</string>
<string name="cancel" msgid="4373674107267141885">"रद्द करा"</string>
diff --git a/packages/SettingsLib/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml
index c2167f3..4658924 100644
--- a/packages/SettingsLib/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_two_target.xml
@@ -33,19 +33,17 @@
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:clipToPadding="false"
- android:layout_marginStart="4dp"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
<LinearLayout
android:id="@+id/icon_frame"
- style="@style/preference_icon_frame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="start|center_vertical"
+ android:minWidth="56dp"
android:orientation="horizontal"
android:clipToPadding="false"
- android:paddingEnd="12dp"
android:paddingTop="4dp"
android:paddingBottom="4dp">
<android.support.v7.internal.widget.PreferenceImageView
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index a3430fc..2a4983a 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"Couldn\'t pair with <xliff:g id="DEVICE_NAME">%1$s</xliff:g> because of an incorrect PIN or passkey."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"Can\'t communicate with <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Pairing rejected by <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computer"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Headset"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Phone"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imaging"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Headphone"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Input Peripheral"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wifi off."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wifi disconnected."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Wifi one bar."</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index ea62383..f351e70 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"No se pudo sincronizar con <xliff:g id="DEVICE_NAME">%1$s</xliff:g> debido a que el PIN o la clave de acceso son incorrectos."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"No se puede establecer la comunicación con <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"Vínculo rechazado por <xliff:g id="DEVICE_NAME">%1$s</xliff:g>"</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"Computadora"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"Auriculares"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"Teléfono"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"Imágenes"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"Auriculares"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"Periférico de entrada"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"Bluetooth"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"Wi-Fi inhabilitado"</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"Wi-Fi desconectado"</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"Una barra de Wi-Fi"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 42ee581..17d7191 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -22,7 +22,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="wifi_fail_to_scan" msgid="1265540342578081461">"नेटवर्कसाठी स्कॅन करू शकत नाही"</string>
<string name="wifi_security_none" msgid="7985461072596594400">"काहीही नाही"</string>
- <string name="wifi_remembered" msgid="4955746899347821096">"जतन केले"</string>
+ <string name="wifi_remembered" msgid="4955746899347821096">"सेव्ह केले"</string>
<string name="wifi_disabled_generic" msgid="4259794910584943386">"अक्षम"</string>
<string name="wifi_disabled_network_failure" msgid="2364951338436007124">"IP कॉन्फिगरेशन अयशस्वी"</string>
<string name="wifi_disabled_by_recommendation_provider" msgid="5168315140978066096">"कमी दर्जाच्या नेटवर्कमुळे कनेक्ट केलेले नाही"</string>
@@ -34,7 +34,7 @@
<string name="wifi_not_in_range" msgid="1136191511238508967">"परिक्षेत्रामध्ये नाही"</string>
<string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"स्वयंचलितपणे कनेक्ट करणार नाही"</string>
<string name="wifi_no_internet" msgid="3880396223819116454">"इंटरनेट अॅक्सेस नाही"</string>
- <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे जतन केले"</string>
+ <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे सेव्ह केले"</string>
<string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s द्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_network_scorer_default" msgid="7867260222020343104">"नेटवर्क रेटिंग प्रदात्याद्वारे स्वयंचलितपणे कनेक्ट केले"</string>
<string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s द्वारे कनेक्ट केले"</string>
@@ -52,7 +52,7 @@
<string name="preference_summary_default_combination" msgid="8532964268242666060">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="6557104142667339895">"डिस्कनेक्ट केले"</string>
<string name="bluetooth_disconnecting" msgid="8913264760027764974">"डिस्कनेक्ट करत आहे..."</string>
- <string name="bluetooth_connecting" msgid="8555009514614320497">"कनेक्ट करीत आहे..."</string>
+ <string name="bluetooth_connecting" msgid="8555009514614320497">"कनेक्ट करत आहे..."</string>
<string name="bluetooth_connected" msgid="6038755206916626419">"कनेक्ट केले"</string>
<string name="bluetooth_pairing" msgid="1426882272690346242">"जोडत आहे…"</string>
<string name="bluetooth_connected_no_headset" msgid="2866994875046035609">"कनेक्ट केले (फोन नाही)"</string>
@@ -99,6 +99,13 @@
<string name="bluetooth_pairing_pin_error_message" msgid="8337234855188925274">"अयोग्य पिन किंवा पासकीमुळे <xliff:g id="DEVICE_NAME">%1$s</xliff:g> सह जोडू शकलो नाही."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="7870998403045801381">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> शी संप्रेषण करू शकत नाही."</string>
<string name="bluetooth_pairing_rejected_error_message" msgid="1648157108520832454">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g> द्वारे पेअरींग नाकारले."</string>
+ <string name="bluetooth_talkback_computer" msgid="4875089335641234463">"संगणक"</string>
+ <string name="bluetooth_talkback_headset" msgid="5140152177885220949">"हेडसेट"</string>
+ <string name="bluetooth_talkback_phone" msgid="4260255181240622896">"फोन"</string>
+ <string name="bluetooth_talkback_imaging" msgid="551146170554589119">"इमेज"</string>
+ <string name="bluetooth_talkback_headphone" msgid="26580326066627664">"हेडफोन"</string>
+ <string name="bluetooth_talkback_input_peripheral" msgid="5165842622743212268">"इनपुट परिधीय"</string>
+ <string name="bluetooth_talkback_bluetooth" msgid="5615463912185280812">"ब्लूटूथ"</string>
<string name="accessibility_wifi_off" msgid="1166761729660614716">"वाय फाय बंद."</string>
<string name="accessibility_no_wifi" msgid="8834610636137374508">"वाय फाय डिस्कनेक्ट झाले."</string>
<string name="accessibility_wifi_one_bar" msgid="4869376278894301820">"वाय फाय एक बार."</string>
@@ -135,7 +142,7 @@
<string name="tts_play_example_summary" msgid="8029071615047894486">"उच्चार संश्लेषणाचे एक छोटेसे प्रात्यक्षिक प्ले करा"</string>
<string name="tts_install_data_title" msgid="4264378440508149986">"व्हॉइस डेटा इंस्टॉल करा"</string>
<string name="tts_install_data_summary" msgid="5742135732511822589">"उच्चार संश्लेषणासाठी आवश्यक आवाज डेटा इंस्टॉल करा"</string>
- <string name="tts_engine_security_warning" msgid="8786238102020223650">"हे उच्चार संश्लेषण इंजिन संकेतशब्द आणि क्रेडिट कार्ड नंबर यासारख्या वैयक्तिक मजकुरासह, बोलला जाणारा सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. हे <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> इंजिनवरून येते. या उच्चार संश्लेषण इंजिनचा वापर सक्षम करायचा?"</string>
+ <string name="tts_engine_security_warning" msgid="8786238102020223650">"हे उच्चार संश्लेषण इंजिन पासवर्ड आणि क्रेडिट कार्ड नंबर यासारख्या वैयक्तिक मजकुरासह, बोलला जाणारा सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. हे <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> इंजिनवरून येते. या उच्चार संश्लेषण इंजिनचा वापर सक्षम करायचा?"</string>
<string name="tts_engine_network_required" msgid="1190837151485314743">"या भाषेस टेक्स्ट टू स्पीचसाठी एका नेटवर्क कनेक्शनची आवश्यकता आहे."</string>
<string name="tts_default_sample_string" msgid="4040835213373086322">"हे उच्चार संश्लेषणाचे एक उदाहरण आहे"</string>
<string name="tts_status_title" msgid="7268566550242584413">"डीफॉल्ट भाषा स्थिती"</string>
@@ -245,7 +252,7 @@
<string name="debug_debugging_category" msgid="6781250159513471316">"डीबग करणे"</string>
<string name="debug_app" msgid="8349591734751384446">"डीबग अॅप निवडा"</string>
<string name="debug_app_not_set" msgid="718752499586403499">"कोणतेही डीबग अॅप्लिकेशन सेट नाही"</string>
- <string name="debug_app_set" msgid="2063077997870280017">"अॅप्लिकेशन डीबग करीत आहे: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="debug_app_set" msgid="2063077997870280017">"अॅप्लिकेशन डीबग करत आहे: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="select_application" msgid="5156029161289091703">"अॅप्लिकेशन निवडा"</string>
<string name="no_application" msgid="2813387563129153880">"काहीही नाही"</string>
<string name="wait_for_debugger" msgid="1202370874528893091">"डीबगरची प्रतीक्षा करा"</string>
@@ -303,11 +310,11 @@
<string name="force_resizable_activities_summary" msgid="6667493494706124459">"manifest मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा."</string>
<string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
<string name="enable_freeform_support_summary" msgid="8247310463288834487">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करा."</string>
- <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</string>
+ <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप पासवर्ड"</string>
<string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
- <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
+ <string name="local_backup_password_summary_change" msgid="5376206246809190364">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला पासवर्ड बदलण्यासाठी किंवा काढण्यासाठी टॅप करा"</string>
<string name="local_backup_password_toast_success" msgid="582016086228434290">"नवीन बॅक अप पासवर्ड सेट झाला"</string>
- <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नवीन संकेतशब्द आणि पुष्टीकरण जुळत नाही"</string>
+ <string name="local_backup_password_toast_confirmation_mismatch" msgid="7805892532752708288">"नवीन पासवर्ड आणि पुष्टीकरण जुळत नाही"</string>
<string name="local_backup_password_toast_validation_failure" msgid="5646377234895626531">"बॅक अप पासवर्ड सेट करणे अयशस्वी"</string>
<string-array name="color_mode_names">
<item msgid="2425514299220523812">"सशक्त (डीफॉल्ट)"</item>
@@ -382,13 +389,13 @@
<string name="screen_zoom_summary_custom" msgid="5611979864124160447">"सानुकूल करा (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
<string name="help_feedback_label" msgid="6815040660801785649">"मदत आणि अभिप्राय"</string>
<string name="content_description_menu_button" msgid="8182594799812351266">"मेनू"</string>
- <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड प्रविष्ट करा"</string>
+ <string name="retail_demo_reset_message" msgid="118771671364131297">"डेमो मोडमध्ये फॅक्टरी रीसेट करण्यासाठी पासवर्ड एंटर करा"</string>
<string name="retail_demo_reset_next" msgid="8356731459226304963">"पुढील"</string>
- <string name="retail_demo_reset_title" msgid="696589204029930100">"संकेतशब्द आवश्यक"</string>
+ <string name="retail_demo_reset_title" msgid="696589204029930100">"पासवर्ड आवश्यक"</string>
<string name="active_input_method_subtypes" msgid="3596398805424733238">"सक्रिय इनपुट पद्धती"</string>
<string name="use_system_language_to_select_input_method_subtypes" msgid="5747329075020379587">"सिस्टम भाषा वापरा"</string>
<string name="failed_to_open_app_settings_toast" msgid="1251067459298072462">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> साठी सेटिंग्ज उघडण्यात अयशस्वी"</string>
- <string name="ime_security_warning" msgid="4135828934735934248">"ही इनपुट पद्धत संकेतशब्द आणि क्रेडिट कार्ड नंबर यासह, आपण टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> अॅपवरून येते. ही इनपुट पद्धत वापरायची?"</string>
+ <string name="ime_security_warning" msgid="4135828934735934248">"ही इनपुट पद्धत पासवर्ड आणि क्रेडिट कार्ड नंबर यासह, आपण टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> अॅपवरून येते. ही इनपुट पद्धत वापरायची?"</string>
<string name="direct_boot_unaware_dialog_message" msgid="7870273558547549125">"टीप: रीबूट केल्यानंतर, तुम्ही आपला फोन अनलॉक करे पर्यंत हे अॅप सुरू होऊ शकत नाही"</string>
<string name="ims_reg_title" msgid="7609782759207241443">"IMS नोंदणी स्थिती"</string>
<string name="ims_reg_status_registered" msgid="933003316932739188">"नोंदवलेले"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 360848f..4bb16ff 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -546,11 +546,13 @@
<!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
<string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
- <!-- Title of the developer option for DNS over TLS. -->
- <string name="dns_tls">DNS over TLS</string>
- <!-- Summary to explain the developer option for DNS over TLS. This allows the user to
- request that the system attempt TLS with all DNS servers, or none. -->
- <string name="dns_tls_summary">If enabled, attempt DNS over TLS on port 853.</string>
+ <!-- Developer option setting for Private DNS -->
+ <string name="select_private_dns_configuration_title">Private DNS</string>
+ <string name="select_private_dns_configuration_dialog_title">Select Private DNS Mode</string>
+ <string name="private_dns_mode_off">Off</string>
+ <string name="private_dns_mode_opportunistic">Opportunistic</string>
+ <string name="private_dns_mode_provider">Private DNS provider hostname</string>
+ <string name="private_dns_mode_provider_hostname_hint">Enter hostname of DNS provider</string>
<!-- setting Checkbox summary whether to show options for wireless display certification -->
<string name="wifi_display_certification_summary">Show options for wireless display certification</string>
diff --git a/packages/SettingsLib/res/values/styles.xml b/packages/SettingsLib/res/values/styles.xml
index b7ea1d4..3f312f4 100644
--- a/packages/SettingsLib/res/values/styles.xml
+++ b/packages/SettingsLib/res/values/styles.xml
@@ -21,9 +21,4 @@
<style name="TextAppearanceMedium">
<item name="android:textAppearance">?android:attr/textAppearanceMedium</item>
</style>
-
- <style name="preference_icon_frame">
- <item name="android:layout_marginStart">-4dp</item>
- <item name="android:minWidth">60dp</item>
- </style>
</resources>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
index 32e6389..c3a36e9 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
@@ -28,6 +28,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
@@ -343,7 +344,8 @@
}
DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
Context.DEVICE_POLICY_SERVICE);
- if (dpm == null) {
+ PackageManager pm = context.getPackageManager();
+ if (!pm.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN) || dpm == null) {
return null;
}
boolean isAccountTypeDisabled = false;
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index d90386f..21861692 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -94,7 +94,7 @@
public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
final int iconSize = UserIconDrawable.getSizeForList(context);
if (user.isManagedProfile()) {
- Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_icon);
+ Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_badge);
drawable.setBounds(0, 0, iconSize, iconSize);
return drawable;
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
index 38fe879..386c4e0 100644
--- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java
@@ -10,79 +10,89 @@
*/
public abstract class AbstractPreferenceController {
- protected final Context mContext;
+ protected final Context mContext;
- public AbstractPreferenceController(Context context) {
- mContext = context;
- }
+ public AbstractPreferenceController(Context context) {
+ mContext = context;
+ }
- /**
- * Displays preference in this controller.
- */
- public void displayPreference(PreferenceScreen screen) {
- if (isAvailable()) {
- if (this instanceof Preference.OnPreferenceChangeListener) {
- final Preference preference = screen.findPreference(getPreferenceKey());
- preference.setOnPreferenceChangeListener(
- (Preference.OnPreferenceChangeListener) this);
- }
- } else {
- removePreference(screen, getPreferenceKey());
- }
- }
+ /**
+ * Displays preference in this controller.
+ */
+ public void displayPreference(PreferenceScreen screen) {
+ if (isAvailable()) {
+ if (this instanceof Preference.OnPreferenceChangeListener) {
+ final Preference preference = screen.findPreference(getPreferenceKey());
+ preference.setOnPreferenceChangeListener(
+ (Preference.OnPreferenceChangeListener) this);
+ }
+ } else {
+ removePreference(screen, getPreferenceKey());
+ }
+ }
- /**
- * Updates the current status of preference (summary, switch state, etc)
- */
- public void updateState(Preference preference) {
+ /**
+ * Updates the current status of preference (summary, switch state, etc)
+ */
+ public void updateState(Preference preference) {
- }
+ }
- /**
- * Returns true if preference is available (should be displayed)
- */
- public abstract boolean isAvailable();
+ /**
+ * Returns true if preference is available (should be displayed)
+ */
+ public abstract boolean isAvailable();
- /**
- * Handles preference tree click
- *
- * @param preference the preference being clicked
- * @return true if click is handled
- */
- public boolean handlePreferenceTreeClick(Preference preference) {
- return false;
- }
+ /**
+ * Handles preference tree click
+ *
+ * @param preference the preference being clicked
+ * @return true if click is handled
+ */
+ public boolean handlePreferenceTreeClick(Preference preference) {
+ return false;
+ }
- /**
- * Returns the key for this preference.
- */
- public abstract String getPreferenceKey();
+ /**
+ * Returns the key for this preference.
+ */
+ public abstract String getPreferenceKey();
- /**
- * Removes preference from screen.
- */
- protected final void removePreference(PreferenceScreen screen, String key) {
- findAndRemovePreference(screen, key);
- }
+ /**
+ * Removes preference from screen.
+ */
+ protected final void removePreference(PreferenceScreen screen, String key) {
+ findAndRemovePreference(screen, key);
+ }
- // finds the preference recursively and removes it from its parent
- private boolean findAndRemovePreference(PreferenceGroup prefGroup, String key) {
- final int preferenceCount = prefGroup.getPreferenceCount();
- for (int i = 0; i < preferenceCount; i++) {
- final Preference preference = prefGroup.getPreference(i);
- final String curKey = preference.getKey();
+ /**
+ * Show/hide a preference.
+ */
+ protected final void setVisible(PreferenceGroup group, String key, boolean isVisible) {
+ final Preference pref = group.findPreference(key);
+ if (pref != null) {
+ pref.setVisible(isVisible);
+ }
+ }
- if (curKey != null && curKey.equals(key)) {
- return prefGroup.removePreference(preference);
- }
+ // finds the preference recursively and removes it from its parent
+ private boolean findAndRemovePreference(PreferenceGroup prefGroup, String key) {
+ final int preferenceCount = prefGroup.getPreferenceCount();
+ for (int i = 0; i < preferenceCount; i++) {
+ final Preference preference = prefGroup.getPreference(i);
+ final String curKey = preference.getKey();
- if (preference instanceof PreferenceGroup) {
- if (findAndRemovePreference((PreferenceGroup) preference, key)) {
- return true;
- }
- }
- }
- return false;
- }
+ if (curKey != null && curKey.equals(key)) {
+ return prefGroup.removePreference(preference);
+ }
+
+ if (preference instanceof PreferenceGroup) {
+ if (findAndRemovePreference((PreferenceGroup) preference, key)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 1cb255b..a8262c8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -20,6 +20,7 @@
import android.content.res.XmlResourceParser;
import android.icu.text.TimeZoneFormat;
import android.icu.text.TimeZoneNames;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.text.BidiFormatter;
import android.support.v4.text.TextDirectionHeuristicsCompat;
import android.text.SpannableString;
@@ -32,6 +33,8 @@
import com.android.settingslib.R;
+import libcore.util.TimeZoneFinder;
+
import org.xmlpull.v1.XmlPullParserException;
import java.util.ArrayList;
@@ -43,7 +46,6 @@
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
-import libcore.util.TimeZoneFinder;
/**
* ZoneGetter is the utility class to get time zone and zone list, and both of them have display
@@ -350,7 +352,8 @@
return gmtText;
}
- private static final class ZoneGetterData {
+ @VisibleForTesting
+ public static final class ZoneGetterData {
public final String[] olsonIdsToDisplay;
public final CharSequence[] gmtOffsetTexts;
public final TimeZone[] timeZones;
@@ -377,9 +380,13 @@
}
// Create a lookup of local zone IDs.
- List<String> zoneIds =
- TimeZoneFinder.getInstance().lookupTimeZoneIdsByCountry(locale.getCountry());
+ final List<String> zoneIds = lookupTimeZoneIdsByCountry(locale.getCountry());
localZoneIds = new HashSet<>(zoneIds);
}
+
+ @VisibleForTesting
+ public List<String> lookupTimeZoneIdsByCountry(String country) {
+ return TimeZoneFinder.getInstance().lookupTimeZoneIdsByCountry(country);
+ }
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
index 6aae226..3c02f6a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/development/AbstractEnableAdbPreferenceController.java
@@ -16,11 +16,13 @@
package com.android.settingslib.development;
+import android.app.ActivityManager;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
import android.provider.Settings;
+import android.support.annotation.VisibleForTesting;
import android.support.v14.preference.SwitchPreference;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.preference.Preference;
@@ -95,6 +97,10 @@
@Override
public boolean handlePreferenceTreeClick(Preference preference) {
+ if (isUserAMonkey()) {
+ return false;
+ }
+
if (TextUtils.equals(KEY_ENABLE_ADB, preference.getKey())) {
if (!isAdbEnabled()) {
showConfirmationDialog(preference);
@@ -117,4 +123,9 @@
LocalBroadcastManager.getInstance(mContext)
.sendBroadcast(new Intent(ACTION_ENABLE_ADB_STATE_CHANGED));
}
+
+ @VisibleForTesting
+ boolean isUserAMonkey() {
+ return ActivityManager.isUserAMonkey();
+ }
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
index 750601d..b27d823 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/UserAdapter.java
@@ -57,7 +57,7 @@
if (userInfo.isManagedProfile()) {
mName = context.getString(R.string.managed_user_title);
icon = context.getDrawable(
- com.android.internal.R.drawable.ic_corp_icon);
+ com.android.internal.R.drawable.ic_corp_badge);
} else {
mName = userInfo.name;
final int userId = userInfo.id;
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/drawable/UserIconDrawableTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
similarity index 76%
rename from packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java
rename to packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
index 5fdd114..508107c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/drawable/UserIconDrawableTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawable/UserIconDrawableTest.java
@@ -16,22 +16,19 @@
package com.android.settingslib.drawable;
+import static com.google.common.truth.Truth.assertThat;
+
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import com.android.settingslib.R;
-import com.android.settingslib.SettingsLibRobolectricTestRunner;
-import com.android.settingslib.TestConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Config;
-import static com.google.common.truth.Truth.assertThat;
-
-@RunWith(SettingsLibRobolectricTestRunner.class)
-@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+@RunWith(AndroidJUnit4.class)
public class UserIconDrawableTest {
private UserIconDrawable mDrawable;
@@ -39,7 +36,7 @@
@Test
public void getConstantState_shouldNotBeNull() {
final Bitmap b = BitmapFactory.decodeResource(
- RuntimeEnvironment.application.getResources(),
+ InstrumentationRegistry.getTargetContext().getResources(),
R.drawable.home);
mDrawable = new UserIconDrawable(100 /* size */).setIcon(b).bake();
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index ca366ea..64de635 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -33,6 +33,7 @@
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.UserManager;
@@ -56,6 +57,8 @@
private DevicePolicyManager mDevicePolicyManager;
@Mock
private UserManager mUserManager;
+ @Mock
+ private PackageManager mPackageManager;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private RestrictedLockUtils.Proxy mProxy;
@@ -72,11 +75,32 @@
.thenReturn(mDevicePolicyManager);
when(mContext.getSystemService(Context.USER_SERVICE))
.thenReturn(mUserManager);
+ when(mContext.getPackageManager())
+ .thenReturn(mPackageManager);
RestrictedLockUtils.sProxy = mProxy;
}
@Test
+ public void checkIfDevicePolicyServiceDisabled_noEnforceAdminForManagedProfile() {
+ when(mContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(null);
+ final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+ mContext, "account_type", mUserId);
+
+ assertThat(enforcedAdmin).isEqualTo(null);
+ }
+
+ @Test
+ public void checkIfDeviceAdminFeatureDisabled_noEnforceAdminForManagedProfile() {
+ when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN))
+ .thenReturn(false);
+ final EnforcedAdmin enforcedAdmin = RestrictedLockUtils.checkIfAccountManagementDisabled(
+ mContext, "account_type", mUserId);
+
+ assertThat(enforcedAdmin).isEqualTo(null);
+ }
+
+ @Test
public void checkIfKeyguardFeaturesDisabled_noEnforcedAdminForManagedProfile() {
setUpManagedProfile(mUserId, new ComponentName[] {mAdmin1, mAdmin2});
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/core/PreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
similarity index 87%
rename from packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/PreferenceControllerTest.java
rename to packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
index 9d7cd11..c08bc2a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/PreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java
@@ -15,22 +15,7 @@
*/
package com.android.settingslib.core;
-import android.content.Context;
-import android.support.v7.preference.Preference;
-import android.support.v7.preference.PreferenceGroup;
-import android.support.v7.preference.PreferenceManager;
-import android.support.v7.preference.PreferenceScreen;
-import com.android.settingslib.TestConfig;
-import com.android.settingslib.core.AbstractPreferenceController;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.annotation.Config;
-import org.robolectric.shadows.ShadowApplication;
-import org.robolectric.RobolectricTestRunner;
-
+import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -38,22 +23,41 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.content.Context;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceGroup;
+import android.support.v7.preference.PreferenceManager;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settingslib.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadows.ShadowApplication;
+
@RunWith(RobolectricTestRunner.class)
@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
-public class PreferenceControllerTest {
+public class AbstractPreferenceControllerTest {
@Mock
private Context mContext;
@Mock
private PreferenceScreen mScreen;
- @Mock
- private Preference mPreference;
+ private Preference mPreference;
private TestPrefController mTestPrefController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mPreference = new Preference(RuntimeEnvironment.application);
+ mPreference.setKey(TestPrefController.KEY_PREF);
mTestPrefController = new TestPrefController(mContext);
}
@@ -61,7 +65,6 @@
public void removeExistingPref_shouldBeRemoved() {
when(mScreen.getPreferenceCount()).thenReturn(1);
when(mScreen.getPreference(0)).thenReturn(mPreference);
- when(mPreference.getKey()).thenReturn(TestPrefController.KEY_PREF);
mTestPrefController.removePreference(mScreen, TestPrefController.KEY_PREF);
@@ -85,10 +88,25 @@
}
@Test
+ public void setVisible_prefIsVisible_shouldSetToVisible() {
+ when(mScreen.findPreference(TestPrefController.KEY_PREF)).thenReturn(mPreference);
+
+ mTestPrefController.setVisible(mScreen, TestPrefController.KEY_PREF, true /* visible */);
+ assertThat(mPreference.isVisible()).isTrue();
+ }
+
+ @Test
+ public void setVisible_prefNotVisible_shouldSetToInvisible() {
+ when(mScreen.findPreference(TestPrefController.KEY_PREF)).thenReturn(mPreference);
+
+ mTestPrefController.setVisible(mScreen, TestPrefController.KEY_PREF, false /* visible */);
+ assertThat(mPreference.isVisible()).isFalse();
+ }
+
+ @Test
public void doNotDisplayPref_ifNotAvailable() {
when(mScreen.getPreferenceCount()).thenReturn(1);
when(mScreen.getPreference(0)).thenReturn(mPreference);
- when(mPreference.getKey()).thenReturn(TestPrefController.KEY_PREF);
mTestPrefController.isAvailable = false;
mTestPrefController.displayPreference(mScreen);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
index bcabff3..32fa01c 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/development/EnableAdbPreferenceControllerTest.java
@@ -21,6 +21,7 @@
import static org.mockito.Answers.RETURNS_DEEP_STUBS;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -119,6 +120,18 @@
}
@Test
+ public void handlePreferenceTreeClick_isMonkeyUser_shouldBeFalse() {
+ mController = spy(mController);
+ doReturn(true).when(mController).isUserAMonkey();
+ when(mUserManager.isAdminUser()).thenReturn(true);
+ mController.displayPreference(mScreen);
+
+ final boolean handled = mController.handlePreferenceTreeClick(mPreference);
+
+ assertThat(handled).isFalse();
+ }
+
+ @Test
public void updateState_settingsOn_shouldCheck() {
when(mUserManager.isAdminUser()).thenReturn(true);
Settings.Secure.putInt(mContext.getContentResolver(),
@@ -161,6 +174,7 @@
}
@Override
- public void dismissConfirmationDialog() {}
+ public void dismissConfirmationDialog() {
+ }
}
}
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/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7b8d0db..29ecac0 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -120,6 +120,7 @@
<uses-permission android:name="android.permission.TRUST_LISTENER" />
<uses-permission android:name="android.permission.USE_FINGERPRINT" />
<uses-permission android:name="android.permission.RESET_FINGERPRINT_LOCKOUT" />
+ <uses-permission android:name="android.permission.BIND_SLICE" />
<!-- Needed for WallpaperManager.clear in ImageWallpaper.updateWallpaperLocked -->
<uses-permission android:name="android.permission.SET_WALLPAPER"/>
@@ -222,7 +223,7 @@
-->
<service android:name="SystemUIService"
android:exported="true"
- />
+ />
<!-- Recents depends on every user having their own SystemUI process, so on user switch,
ensure that the process is created by starting this service.
@@ -568,6 +569,11 @@
android:resource="@xml/fileprovider" />
</provider>
+ <provider android:name=".keyguard.KeyguardSliceProvider"
+ android:authorities="com.android.systemui.keyguard"
+ android:exported="true">
+ </provider>
+
<receiver
android:name=".statusbar.KeyboardShortcutsReceiver">
<intent-filter>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
index 39cba74..3018a02 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_emergency_carrier_area.xml
@@ -33,8 +33,10 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/Keyguard.TextView"
+ android:singleLine="true"
android:ellipsize="marquee"
android:visibility="gone"
+ android:gravity="center"
androidprv:allCaps="@bool/kg_use_all_caps" />
<com.android.keyguard.EmergencyButton
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index 97c8965..947f27d 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -32,6 +32,7 @@
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:tint="@color/background_protected"
android:src="@drawable/ic_lockscreen_sim"/>
<include layout="@layout/keyguard_message_area"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index d4c5d74..6f270b4 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -33,6 +33,7 @@
android:id="@+id/keyguard_sim"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:tint="@color/background_protected"
android:src="@drawable/ic_lockscreen_sim"/>
<include layout="@layout/keyguard_message_area"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
index 56fb73f..020cfee 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_status_area.xml
@@ -18,34 +18,37 @@
-->
<!-- This is a view that shows general status information in Keyguard. -->
-<LinearLayout
+<com.android.keyguard.KeyguardSliceView
xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
+ android:layout_marginStart="16dp"
+ android:layout_marginEnd="16dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center">
- <com.android.systemui.statusbar.policy.DateView
- android:id="@+id/date_view"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:textColor="?attr/wallpaperTextColor"
- style="@style/widget_label"
- android:letterSpacing="0.05"
- android:gravity="center"
- />
- <TextView android:id="@+id/alarm_status"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawablePadding="6dp"
- android:drawableStart="@drawable/ic_access_alarms_big"
- android:drawableTint="?attr/wallpaperTextColorSecondary"
- android:drawableTintMode="src_in"
- android:textColor="?attr/wallpaperTextColorSecondary"
- android:letterSpacing="0.05"
- style="@style/widget_label"
- android:layout_marginStart="6dp"
- android:gravity="center"
- android:visibility="gone"
- />
-</LinearLayout>
+ android:layout_marginTop="@dimen/date_owner_info_margin"
+ android:layout_gravity="center_horizontal"
+ android:paddingTop="4dp"
+ android:clipToPadding="false"
+ android:orientation="vertical"
+ android:layout_centerHorizontal="true">
+ <TextView android:id="@+id/title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:gravity="center"
+ android:textSize="22sp"
+ android:textColor="?attr/wallpaperTextColor"
+ />
+ <TextView android:id="@+id/text"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:gravity="center"
+ android:visibility="gone"
+ android:textSize="16sp"
+ android:textColor="?attr/wallpaperTextColor"
+ android:layout_marginTop="4dp"
+ android:ellipsize="end"
+ />
+</com.android.keyguard.KeyguardSliceView>
\ No newline at end of file
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/values/config.xml b/packages/SystemUI/res/values/config.xml
index f54115b..cf79238 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -45,6 +45,9 @@
interface. This name is in the ComponentName flattened format (package/class) -->
<string name="config_statusBarComponent" translatable="false">com.android.systemui.statusbar.phone.StatusBar</string>
+ <!-- Component name of launcher service for overview to connect to -->
+ <string name="config_overviewServiceComponent" translateable="false">com.android.launcher3/com.android.quickstep.TouchInteractionService</string>
+
<!-- Whether or not we show the number in the bar. -->
<bool name="config_statusBarShowNumber">false</bool>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 9901f6f..c678111f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -95,6 +95,10 @@
<!-- Height of a heads up notification in the status bar -->
<dimen name="notification_max_heads_up_height_increased">188dp</dimen>
+ <!-- Height of a messaging notifications with actions at least. Not that this is an upper bound
+ and the notification won't use this much, but is measured with wrap_content -->
+ <dimen name="notification_messaging_actions_min_height">196dp</dimen>
+
<!-- a threshold in dp per second that is considered fast scrolling -->
<dimen name="scroll_fast_threshold">1500dp</dimen>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index e5f8029..cfd95b4 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -66,9 +66,6 @@
<!-- For notification icons for which targetSdk < L, this caches whether the icon is grayscale -->
<item type="id" name="icon_is_grayscale" />
- <item type="id" name="clip_children_tag" />
- <item type="id" name="clip_children_set_tag" />
- <item type="id" name="clip_to_padding_tag" />
<item type="id" name="image_icon_tag" />
<item type="id" name="contains_transformed_view" />
<item type="id" name="is_clicked_heads_up_tag" />
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/shared/Android.mk b/packages/SystemUI/shared/Android.mk
index 88a89bc..e177d1d 100644
--- a/packages/SystemUI/shared/Android.mk
+++ b/packages/SystemUI/shared/Android.mk
@@ -21,7 +21,7 @@
LOCAL_MODULE := SystemUISharedLib
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-Iaidl-files-under, src)
LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
LOCAL_JAR_EXCLUDE_FILES := none
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
similarity index 65%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
index e28e1b3..173a90a 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/IOverviewProxy.aidl
@@ -11,16 +11,15 @@
* 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
+ * limitations under the License.
*/
-package android.telephony.ims.feature;
+package com.android.systemui.shared.recents;
-/**
- * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
- * in the framework.
- * @hide
- */
+import android.view.MotionEvent;
+import com.android.systemui.shared.recents.ISystemUiProxy;
-public interface IRcsFeature {
+oneway interface IOverviewProxy {
+ void onBind(in ISystemUiProxy sysUiProxy);
+ void onMotionEvent(in MotionEvent event);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
new file mode 100644
index 0000000..d82b010
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.shared.recents;
+
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+
+/**
+ * Temporary callbacks into SystemUI.
+ */
+interface ISystemUiProxy {
+
+ /**
+ * Proxies SurfaceControl.screenshot().
+ */
+ Bitmap screenshot(in Rect sourceCrop, int width, int height,
+ int minLayer, int maxLayer, boolean useIdentityTransform,
+ int rotation);
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
index 806a073..f92509d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoadPlan.java
@@ -70,21 +70,6 @@
}
/**
- * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
- * to most-recent order.
- *
- * Note: Do not lock, callers should synchronize on the loader before making this call.
- */
- void preloadRawTasks() {
- int currentUserId = ActivityManagerWrapper.getInstance().getCurrentUserId();
- mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
- ActivityManager.getMaxRecentTasksStatic(), currentUserId);
-
- // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
- Collections.reverse(mRawTasks);
- }
-
- /**
* Preloads the list of recent tasks from the system. After this call, the TaskStack will
* have a list of all the recent tasks with their metadata, not including icons or
* thumbnails which were not cached and have to be loaded.
@@ -95,11 +80,15 @@
* Note: Do not lock, since this can be calling back to the loader, which separately also drives
* this call (callers should synchronize on the loader before making this call).
*/
- void preloadPlan(RecentsTaskLoader loader, int runningTaskId) {
+ public void preloadPlan(RecentsTaskLoader loader, int runningTaskId, int currentUserId) {
Resources res = mContext.getResources();
ArrayList<Task> allTasks = new ArrayList<>();
if (mRawTasks == null) {
- preloadRawTasks();
+ mRawTasks = ActivityManagerWrapper.getInstance().getRecentTasks(
+ ActivityManager.getMaxRecentTasksStatic(), currentUserId);
+
+ // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
+ Collections.reverse(mRawTasks);
}
int taskCount = mRawTasks.size();
@@ -160,7 +149,7 @@
* Note: Do not lock, since this can be calling back to the loader, which separately also drives
* this call (callers should synchronize on the loader before making this call).
*/
- void executePlan(Options opts, RecentsTaskLoader loader) {
+ public void executePlan(Options opts, RecentsTaskLoader loader) {
Resources res = mContext.getResources();
// Iterate through each of the tasks and load them according to the load conditions.
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
index de4c72c..9a991cf 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/RecentsTaskLoader.java
@@ -147,9 +147,15 @@
/** Preloads recents tasks using the specified plan to store the output. */
public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId) {
+ preloadTasks(plan, runningTaskId, ActivityManagerWrapper.getInstance().getCurrentUserId());
+ }
+
+ /** Preloads recents tasks using the specified plan to store the output. */
+ public synchronized void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
+ int currentUserId) {
try {
Trace.beginSection("preloadPlan");
- plan.preloadPlan(this, runningTaskId);
+ plan.preloadPlan(this, runningTaskId, currentUserId);
} finally {
Trace.endSection();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
index 9a1ff54..5f3dcd1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/model/TaskFilter.java
@@ -21,7 +21,7 @@
/**
* An interface for a task filter to query whether a particular task should show in a stack.
*/
-interface TaskFilter {
+public interface TaskFilter {
/** Returns whether the filter accepts the specified task */
boolean acceptTask(SparseArray<Task> taskIdMap, Task t, int index);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
new file mode 100644
index 0000000..7a24071
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/AppTransitionAnimationSpecsFuture.java
@@ -0,0 +1,87 @@
+/*
+ * 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.shared.recents.view;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.view.AppTransitionAnimationSpec;
+import android.view.IAppTransitionAnimationSpecsFuture;
+
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+/**
+ * To be implemented by a particular animation to asynchronously provide the animation specs for a
+ * particular transition.
+ */
+public abstract class AppTransitionAnimationSpecsFuture {
+
+ private final Handler mHandler;
+ private FutureTask<List<AppTransitionAnimationSpec>> mComposeTask = new FutureTask<>(
+ new Callable<List<AppTransitionAnimationSpec>>() {
+ @Override
+ public List<AppTransitionAnimationSpec> call() throws Exception {
+ return composeSpecs();
+ }
+ });
+
+ private final IAppTransitionAnimationSpecsFuture mFuture =
+ new IAppTransitionAnimationSpecsFuture.Stub() {
+ @Override
+ public AppTransitionAnimationSpec[] get() throws RemoteException {
+ try {
+ if (!mComposeTask.isDone()) {
+ mHandler.post(mComposeTask);
+ }
+ List<AppTransitionAnimationSpec> specs = mComposeTask.get();
+ if (specs == null) {
+ return null;
+ }
+
+ AppTransitionAnimationSpec[] arr = new AppTransitionAnimationSpec[specs.size()];
+ specs.toArray(arr);
+ return arr;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ };
+
+ public AppTransitionAnimationSpecsFuture(Handler handler) {
+ mHandler = handler;
+ }
+
+ /**
+ * Returns the future to handle the call from window manager.
+ */
+ public final IAppTransitionAnimationSpecsFuture getFuture() {
+ return mFuture;
+ }
+
+ /**
+ * Called ahead of the future callback to compose the specs to be returned in the future.
+ */
+ public final void composeSpecsSynchronous() {
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ throw new RuntimeException("composeSpecsSynchronous() called from wrong looper");
+ }
+ mComposeTask.run();
+ }
+
+ public abstract List<AppTransitionAnimationSpec> composeSpecs();
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
new file mode 100644
index 0000000..f8f86f0
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/view/RecentsTransition.java
@@ -0,0 +1,125 @@
+/*
+ * 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.shared.recents.view;
+
+import android.app.ActivityOptions;
+import android.app.ActivityOptions.OnAnimationStartedListener;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.GraphicBuffer;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
+import android.view.ThreadedRenderer;
+import android.view.View;
+
+import java.util.function.Consumer;
+
+/**
+ * A helper class to create transitions to/from an App to Recents.
+ */
+public class RecentsTransition {
+
+ /**
+ * Creates a new transition aspect scaled transition activity options.
+ */
+ public static ActivityOptions createAspectScaleAnimation(Context context, Handler handler,
+ boolean scaleUp, AppTransitionAnimationSpecsFuture animationSpecsFuture,
+ final OnAnimationStartedListener animationStartCallback) {
+ final OnAnimationStartedListener animStartedListener = new OnAnimationStartedListener() {
+ private boolean mHandled;
+
+ @Override
+ public void onAnimationStarted() {
+ // OnAnimationStartedListener can be called numerous times, so debounce here to
+ // prevent multiple callbacks
+ if (mHandled) {
+ return;
+ }
+ mHandled = true;
+
+ if (animationStartCallback != null) {
+ animationStartCallback.onAnimationStarted();
+ }
+ }
+ };
+ final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(
+ context, handler,
+ animationSpecsFuture != null ? animationSpecsFuture.getFuture() : null,
+ animStartedListener, scaleUp);
+ return opts;
+ }
+
+ /**
+ * Wraps a animation-start callback in a binder that can be called from window manager.
+ */
+ public static IRemoteCallback wrapStartedListener(final Handler handler,
+ final OnAnimationStartedListener listener) {
+ if (listener == null) {
+ return null;
+ }
+ return new IRemoteCallback.Stub() {
+ @Override
+ public void sendResult(Bundle data) throws RemoteException {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ listener.onAnimationStarted();
+ }
+ });
+ }
+ };
+ }
+
+ /**
+ * @return a {@link GraphicBuffer} with the {@param view} drawn into it. Result can be null if
+ * we were unable to allocate a hardware bitmap.
+ */
+ public static GraphicBuffer drawViewIntoGraphicBuffer(int width, int height, final View view,
+ final float scale, final int eraseColor) {
+ final Bitmap hwBitmap = createHardwareBitmap(width, height, new Consumer<Canvas>() {
+ @Override
+ public void accept(Canvas c) {
+ c.scale(scale, scale);
+ if (eraseColor != 0) {
+ c.drawColor(eraseColor);
+ }
+ if (view != null) {
+ view.draw(c);
+ }
+ }
+ });
+ return hwBitmap != null ? hwBitmap.createGraphicBufferHandle() : null;
+ }
+
+ /**
+ * @return a hardware {@link Bitmap} after being drawn with the {@param consumer}. Result can be
+ * null if we were unable to allocate a hardware bitmap.
+ */
+ public static Bitmap createHardwareBitmap(int width, int height, Consumer<Canvas> consumer) {
+ RenderNode node = RenderNode.create("RecentsTransition", null);
+ node.setLeftTopRightBottom(0, 0, width, height);
+ node.setClipToBounds(false);
+ DisplayListCanvas c = node.start(width, height);
+ consumer.accept(c);
+ node.end(c);
+ return ThreadedRenderer.createHardwareBitmap(node, width, height);
+ }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
index 3f93f76..db1583a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java
@@ -17,10 +17,17 @@
package com.android.systemui.shared.system;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManager.RecentTaskInfo;
+import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -32,15 +39,19 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.IconDrawableFactory;
import android.util.Log;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.ArrayList;
import java.util.List;
+import java.util.function.Consumer;
public class ActivityManagerWrapper {
@@ -50,11 +61,13 @@
private final PackageManager mPackageManager;
private final IconDrawableFactory mDrawableFactory;
+ private final BackgroundExecutor mBackgroundExecutor;
private ActivityManagerWrapper() {
final Context context = AppGlobals.getInitialApplication();
mPackageManager = context.getPackageManager();
mDrawableFactory = IconDrawableFactory.newInstance(context);
+ mBackgroundExecutor = BackgroundExecutor.get();
}
public static ActivityManagerWrapper getInstance() {
@@ -75,6 +88,25 @@
}
/**
+ * @return the top running task (can be {@code null}).
+ */
+ public ActivityManager.RunningTaskInfo getRunningTask() {
+ // Note: The set of running tasks from the system is ordered by recency
+ try {
+ List<ActivityManager.RunningTaskInfo> tasks =
+ ActivityManager.getService().getFilteredTasks(1,
+ ACTIVITY_TYPE_RECENTS /* ignoreActivityType */,
+ WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
+ if (tasks.isEmpty()) {
+ return null;
+ }
+ return tasks.get(0);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* @return a list of the recents tasks.
*/
public List<RecentTaskInfo> getRecentTasks(int numTasks, int userId) {
@@ -198,4 +230,106 @@
}
return label;
}
+
+ /**
+ * Starts a task from Recents.
+ *
+ * @see {@link #startActivityFromRecents(TaskKey, ActivityOptions, int, int, Consumer, Handler)}
+ */
+ public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+ Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
+ startActivityFromRecents(taskKey, options, WINDOWING_MODE_UNDEFINED,
+ ACTIVITY_TYPE_UNDEFINED, resultCallback, resultCallbackHandler);
+ }
+
+ /**
+ * Starts a task from Recents.
+ *
+ * @param resultCallback The result success callback
+ * @param resultCallbackHandler The handler to receive the result callback
+ */
+ public void startActivityFromRecents(Task.TaskKey taskKey, ActivityOptions options,
+ int windowingMode, int activityType, Consumer<Boolean> resultCallback,
+ Handler resultCallbackHandler) {
+ if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ // We show non-visible docked tasks in Recents, but we always want to launch
+ // them in the fullscreen stack.
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ } else if (windowingMode != WINDOWING_MODE_UNDEFINED
+ || activityType != ACTIVITY_TYPE_UNDEFINED) {
+ if (options == null) {
+ options = ActivityOptions.makeBasic();
+ }
+ options.setLaunchWindowingMode(windowingMode);
+ options.setLaunchActivityType(activityType);
+ }
+ final ActivityOptions finalOptions = options;
+
+ // Execute this from another thread such that we can do other things (like caching the
+ // bitmap for the thumbnail) while AM is busy starting our activity.
+ mBackgroundExecutor.submit(() -> {
+ try {
+ ActivityManager.getService().startActivityFromRecents(taskKey.id,
+ finalOptions == null ? null : finalOptions.toBundle());
+ if (resultCallback != null) {
+ resultCallbackHandler.post(() -> resultCallback.accept(true));
+ }
+ } catch (Exception e) {
+ if (resultCallback != null) {
+ resultCallbackHandler.post(() -> resultCallback.accept(false));
+ }
+ }
+ });
+ }
+
+ /**
+ * Requests that the system close any open system windows (including other SystemUI).
+ */
+ public void closeSystemWindows(String reason) {
+ mBackgroundExecutor.submit(() -> {
+ try {
+ ActivityManager.getService().closeSystemDialogs(reason);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to close system windows", e);
+ }
+ });
+ }
+
+ /**
+ * Removes a task by id.
+ */
+ public void removeTask(int taskId) {
+ mBackgroundExecutor.submit(() -> {
+ try {
+ ActivityManager.getService().removeTask(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to remove task=" + taskId, e);
+ }
+ });
+ }
+
+ /**
+ * Cancels the current window transtion to/from Recents for the given task id.
+ */
+ public void cancelWindowTransition(int taskId) {
+ try {
+ ActivityManager.getService().cancelTaskWindowTransition(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
+ }
+ }
+
+ /**
+ * Cancels the current thumbnail transtion to/from Recents for the given task id.
+ */
+ public void cancelThumbnailTransition(int taskId) {
+ try {
+ ActivityManager.getService().cancelTaskThumbnailTransition(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to cancel window transition for task=" + taskId, e);
+ }
+ }
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
new file mode 100644
index 0000000..26e1813
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/BackgroundExecutor.java
@@ -0,0 +1,45 @@
+/*
+ * 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.shared.system;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * Offloads work from other threads by running it in a background thread.
+ */
+public class BackgroundExecutor {
+
+ private static final BackgroundExecutor sInstance = new BackgroundExecutor();
+
+ private final ExecutorService mExecutorService = Executors.newFixedThreadPool(2);
+
+ /**
+ * @return the static instance of the background executor.
+ */
+ public static BackgroundExecutor get() {
+ return sInstance;
+ }
+
+ /**
+ * Runs the given {@param runnable} on one of the background executor threads.
+ */
+ public Future<?> submit(Runnable runnable) {
+ return mExecutorService.submit(runnable);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListener.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
similarity index 68%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListener.java
rename to packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
index 6d0952a..36310f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListener.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListener.java
@@ -14,24 +14,22 @@
* limitations under the License.
*/
-package com.android.systemui.recents.misc;
+package com.android.systemui.shared.system;
import android.app.ActivityManager.TaskSnapshot;
-import android.content.Context;
import android.os.UserHandle;
import android.util.Log;
/**
- * An abstract class to track task stack changes.
- * Classes should implement this instead of {@link android.app.ITaskStackListener}
- * to reduce IPC calls from system services. These callbacks will be called on the main thread.
+ * An interface to track task stack changes. Classes should implement this instead of
+ * {@link android.app.ITaskStackListener} to reduce IPC calls from system services.
*/
public abstract class TaskStackChangeListener {
- /**
- * NOTE: This call is made of the thread that the binder call comes in on.
- */
+ // Binder thread callbacks
public void onTaskStackChangedBackground() { }
+
+ // Main thread callbacks
public void onTaskStackChanged() { }
public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) { }
@@ -45,17 +43,16 @@
public void onTaskProfileLocked(int taskId, int userId) { }
/**
- * Checks that the current user matches the user's SystemUI process. Since
+ * Checks that the current user matches the process. Since
* {@link android.app.ITaskStackListener} is not multi-user aware, handlers of
- * TaskStackChangeListener should make this call to verify that we don't act on events from other
- * user's processes.
+ * {@link TaskStackChangeListener} should make this call to verify that we don't act on events
+ * originating from another user's interactions.
*/
- protected final boolean checkCurrentUserId(Context context, boolean debug) {
+ protected final boolean checkCurrentUserId(int currentUserId, boolean debug) {
int processUserId = UserHandle.myUserId();
- int currentUserId = SystemServicesProxy.getInstance(context).getCurrentUser();
if (processUserId != currentUserId) {
if (debug) {
- Log.d(SystemServicesProxy.TAG, "UID mismatch. SystemUI is running uid=" + processUserId
+ Log.d("TaskStackChangeListener", "UID mismatch. Process is uid=" + processUserId
+ " and the current user is uid=" + currentUserId);
}
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListeners.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
similarity index 99%
rename from packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListeners.java
rename to packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
index 8eb70f0..95fc96f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/TaskStackChangeListeners.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/TaskStackChangeListeners.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.systemui.recents.misc;
+package com.android.systemui.shared.system;
import android.app.ActivityManager.TaskSnapshot;
import android.app.IActivityManager;
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
new file mode 100644
index 0000000..c18f9b6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -0,0 +1,160 @@
+/*
+ * 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.keyguard;
+
+import android.app.PendingIntent;
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Handler;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.R;
+import com.android.systemui.keyguard.KeyguardSliceProvider;
+
+/**
+ * View visible under the clock on the lock screen and AoD.
+ */
+public class KeyguardSliceView extends LinearLayout {
+
+ private final Uri mKeyguardSliceUri;
+ private TextView mTitle;
+ private TextView mText;
+ private Slice mSlice;
+ private PendingIntent mSliceAction;
+ private int mTextColor;
+ private float mDarkAmount = 0;
+
+ private final ContentObserver mObserver;
+
+ public KeyguardSliceView(Context context) {
+ this(context, null, 0);
+ }
+
+ public KeyguardSliceView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public KeyguardSliceView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ mObserver = new KeyguardSliceObserver(new Handler());
+ mKeyguardSliceUri = Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI);;
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTitle = findViewById(R.id.title);
+ mText = findViewById(R.id.text);
+ mTextColor = mTitle.getCurrentTextColor();
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+
+ // Set initial content
+ showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri));
+
+ // Make sure we always have the most current slice
+ getContext().getContentResolver().registerContentObserver(mKeyguardSliceUri,
+ false /* notifyDescendants */, mObserver);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ getContext().getContentResolver().unregisterContentObserver(mObserver);
+ }
+
+ private void showSlice(Slice slice) {
+ // Items will be wrapped into an action when they have tap targets.
+ SliceItem actionSlice = SliceQuery.find(slice, SliceItem.TYPE_ACTION);
+ if (actionSlice != null) {
+ mSlice = actionSlice.getSlice();
+ mSliceAction = actionSlice.getAction();
+ } else {
+ mSlice = slice;
+ mSliceAction = null;
+ }
+
+ if (mSlice == null) {
+ setVisibility(GONE);
+ return;
+ }
+
+ SliceItem title = SliceQuery.find(mSlice, SliceItem.TYPE_TEXT, Slice.HINT_TITLE, null);
+ if (title == null) {
+ mTitle.setVisibility(GONE);
+ } else {
+ mTitle.setVisibility(VISIBLE);
+ mTitle.setText(title.getText());
+ }
+
+ SliceItem text = SliceQuery.find(mSlice, SliceItem.TYPE_TEXT, null, Slice.HINT_TITLE);
+ if (text == null) {
+ mText.setVisibility(GONE);
+ } else {
+ mText.setVisibility(VISIBLE);
+ mText.setText(text.getText());
+ }
+
+ final int visibility = title == null && text == null ? GONE : VISIBLE;
+ if (visibility != getVisibility()) {
+ setVisibility(visibility);
+ }
+ }
+
+ public void setDark(float darkAmount) {
+ mDarkAmount = darkAmount;
+ updateTextColors();
+ }
+
+ public void setTextColor(int textColor) {
+ mTextColor = textColor;
+ }
+
+ private void updateTextColors() {
+ final int blendedColor = ColorUtils.blendARGB(mTextColor, Color.WHITE, mDarkAmount);
+ mTitle.setTextColor(blendedColor);
+ mText.setTextColor(blendedColor);
+ }
+
+ private class KeyguardSliceObserver extends ContentObserver {
+ KeyguardSliceObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ this.onChange(selfChange, null);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ showSlice(Slice.bindSlice(getContext().getContentResolver(), mKeyguardSliceUri));
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index bc2a59d..78cf2b9 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -19,11 +19,9 @@
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Color;
-import android.graphics.PorterDuff;
import android.os.Handler;
import android.os.Looper;
import android.os.UserHandle;
@@ -42,8 +40,8 @@
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.LockPatternUtils;
+import com.android.settingslib.Utils;
import com.android.systemui.ChargingView;
-import com.android.systemui.statusbar.policy.DateView;
import java.util.Locale;
@@ -55,13 +53,11 @@
private final LockPatternUtils mLockPatternUtils;
private final AlarmManager mAlarmManager;
- private TextView mAlarmStatusView;
- private DateView mDateView;
private TextClock mClockView;
private TextView mOwnerInfo;
private ViewGroup mClockContainer;
private ChargingView mBatteryDoze;
- private View mKeyguardStatusArea;
+ private KeyguardSliceView mKeyguardSlice;
private Runnable mPendingMarqueeStart;
private Handler mHandler;
@@ -69,8 +65,6 @@
private boolean mPulsing;
private float mDarkAmount = 0;
private int mTextColor;
- private int mDateTextColor;
- private int mAlarmTextColor;
private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -141,7 +135,6 @@
private void setEnableMarqueeImpl(boolean enabled) {
if (DEBUG) Log.v(TAG, (enabled ? "Enable" : "Disable") + " transport text marquee");
- if (mAlarmStatusView != null) mAlarmStatusView.setSelected(enabled);
if (mOwnerInfo != null) mOwnerInfo.setSelected(enabled);
}
@@ -149,8 +142,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
mClockContainer = findViewById(R.id.keyguard_clock_container);
- mAlarmStatusView = findViewById(R.id.alarm_status);
- mDateView = findViewById(R.id.date_view);
mClockView = findViewById(R.id.clock_view);
mClockView.setShowCurrentUserTime(true);
if (KeyguardClockAccessibilityDelegate.isNeeded(mContext)) {
@@ -158,11 +149,9 @@
}
mOwnerInfo = findViewById(R.id.owner_info);
mBatteryDoze = findViewById(R.id.battery_doze);
- mKeyguardStatusArea = findViewById(R.id.keyguard_status_area);
- mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardStatusArea};
+ mKeyguardSlice = findViewById(R.id.keyguard_status_area);
+ mVisibleInDoze = new View[]{mBatteryDoze, mClockView, mKeyguardSlice};
mTextColor = mClockView.getCurrentTextColor();
- mDateTextColor = mDateView.getCurrentTextColor();
- mAlarmTextColor = mAlarmStatusView.getCurrentTextColor();
boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
setEnableMarquee(shouldMarquee);
@@ -184,8 +173,6 @@
layoutParams.bottomMargin = getResources().getDimensionPixelSize(
R.dimen.bottom_text_spacing_digital);
mClockView.setLayoutParams(layoutParams);
- mDateView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
- getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
if (mOwnerInfo != null) {
mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
getResources().getDimensionPixelSize(R.dimen.widget_label_font_size));
@@ -193,8 +180,6 @@
}
public void refreshTime() {
- mDateView.setDatePattern(Patterns.dateViewSkel);
-
mClockView.setFormat12Hour(Patterns.clockView12);
mClockView.setFormat24Hour(Patterns.clockView24);
}
@@ -205,23 +190,11 @@
Patterns.update(mContext, nextAlarm != null);
refreshTime();
- refreshAlarmStatus(nextAlarm);
- }
-
- void refreshAlarmStatus(AlarmManager.AlarmClockInfo nextAlarm) {
- if (nextAlarm != null) {
- String alarm = formatNextAlarm(mContext, nextAlarm);
- mAlarmStatusView.setText(alarm);
- mAlarmStatusView.setContentDescription(
- getResources().getString(R.string.keyguard_accessibility_next_alarm, alarm));
- mAlarmStatusView.setVisibility(View.VISIBLE);
- } else {
- mAlarmStatusView.setVisibility(View.GONE);
- }
}
public int getClockBottom() {
- return mKeyguardStatusArea.getBottom();
+ return mKeyguardSlice.getVisibility() == VISIBLE ? mKeyguardSlice.getBottom()
+ : mClockView.getBottom();
}
public float getClockTextSize() {
@@ -341,11 +314,8 @@
updateDozeVisibleViews();
mBatteryDoze.setDark(dark);
+ mKeyguardSlice.setDark(darkAmount);
mClockView.setTextColor(ColorUtils.blendARGB(mTextColor, Color.WHITE, darkAmount));
- mDateView.setTextColor(ColorUtils.blendARGB(mDateTextColor, Color.WHITE, darkAmount));
- int blendedAlarmColor = ColorUtils.blendARGB(mAlarmTextColor, Color.WHITE, darkAmount);
- mAlarmStatusView.setTextColor(blendedAlarmColor);
- mAlarmStatusView.setCompoundDrawableTintList(ColorStateList.valueOf(blendedAlarmColor));
}
public void setPulsing(boolean pulsing) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 282a71b..623fe53 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -76,8 +76,8 @@
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.widget.LockPatternUtils;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
import com.google.android.collect.Lists;
@@ -1776,7 +1776,8 @@
}
}
- private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ private final SysUiTaskStackChangeListener
+ mTaskStackListener = new SysUiTaskStackChangeListener() {
@Override
public void onTaskStackChangedBackground() {
try {
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index d8a47c5..62a9319 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -308,6 +308,8 @@
mProviders.put(IWindowManager.class, () -> WindowManagerGlobal.getWindowManagerService());
+ mProviders.put(OverviewProxyService.class, () -> new OverviewProxyService(mContext));
+
// Put all dependencies above here so the factory can override them if it wants.
SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
}
diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
new file mode 100644
index 0000000..9d960a1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.SurfaceControl;
+
+import com.android.systemui.shared.recents.IOverviewProxy;
+import com.android.systemui.shared.recents.ISystemUiProxy;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController;
+import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
+
+/**
+ * Class to send information from overview to launcher with a binder.
+ */
+public class OverviewProxyService {
+
+ private static final String TAG = "OverviewProxyService";
+ private static final long BACKOFF_MILLIS = 5000;
+
+ private final Context mContext;
+ private final Handler mHandler;
+ private final Runnable mConnectionRunnable = this::startConnectionToCurrentUser;
+ private final DeviceProvisionedController mDeviceProvisionedController
+ = Dependency.get(DeviceProvisionedController.class);
+
+ private IOverviewProxy mOverviewProxy;
+ private int mConnectionBackoffAttempts;
+
+ private ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
+ public Bitmap screenshot(Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
+ boolean useIdentityTransform, int rotation) {
+ long token = Binder.clearCallingIdentity();
+ try {
+ return SurfaceControl.screenshot(sourceCrop, width, height, minLayer, maxLayer,
+ useIdentityTransform, rotation);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+ };
+
+ private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (service != null) {
+ mConnectionBackoffAttempts = 0;
+ mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
+ // Listen for launcher's death
+ try {
+ service.linkToDeath(mOverviewServiceDeathRcpt, 0);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Lost connection to launcher service", e);
+ }
+ try {
+ mOverviewProxy.onBind(mSysUiProxy);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to call onBind()", e);
+ }
+ }
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ // Do nothing
+ }
+ };
+
+ private final DeviceProvisionedListener mDeviceProvisionedCallback =
+ new DeviceProvisionedListener() {
+ @Override
+ public void onUserSetupChanged() {
+ if (mDeviceProvisionedController.isCurrentUserSetup()) {
+ startConnectionToCurrentUser();
+ }
+ }
+
+ @Override
+ public void onUserSwitched() {
+ mConnectionBackoffAttempts = 0;
+ startConnectionToCurrentUser();
+ }
+ };
+
+ // This is the death handler for the binder from the launcher service
+ private final IBinder.DeathRecipient mOverviewServiceDeathRcpt = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ mOverviewProxy = null;
+ }
+ };
+
+ public OverviewProxyService(Context context) {
+ mContext = context;
+ mHandler = new Handler();
+ mConnectionBackoffAttempts = 0;
+ mDeviceProvisionedController.addCallback(mDeviceProvisionedCallback);
+ }
+
+ public void startConnectionToCurrentUser() {
+ disconnectFromLauncherService();
+
+ // If user has not setup yet or already connected, do not try to connect
+ if (!mDeviceProvisionedController.isCurrentUserSetup()) {
+ return;
+ }
+ mHandler.removeCallbacks(mConnectionRunnable);
+ Intent launcherServiceIntent = new Intent();
+ launcherServiceIntent.setComponent(ComponentName.unflattenFromString(
+ mContext.getString(R.string.config_overviewServiceComponent)));
+ boolean bound = mContext.bindServiceAsUser(launcherServiceIntent,
+ mOverviewServiceConnection, Context.BIND_AUTO_CREATE,
+ UserHandle.getUserHandleForUid(mDeviceProvisionedController.getCurrentUser()));
+ if (!bound) {
+ // Retry after exponential backoff timeout
+ final long timeoutMs = (long) Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts);
+ mHandler.postDelayed(mConnectionRunnable, timeoutMs);
+ mConnectionBackoffAttempts++;
+ }
+ }
+
+ public IOverviewProxy getProxy() {
+ return mOverviewProxy;
+ }
+
+ private void disconnectFromLauncherService() {
+ if (mOverviewProxy != null) {
+ mContext.unbindService(mOverviewServiceConnection);
+ mOverviewProxy = null;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
index 5d0a9d7..03b0082 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenStatePreventingAdapter.java
@@ -33,8 +33,10 @@
@Override
public void setDozeScreenState(int state) {
- if (state == Display.STATE_DOZE || state == Display.STATE_DOZE_SUSPEND) {
+ if (state == Display.STATE_DOZE) {
state = Display.STATE_ON;
+ } else if (state == Display.STATE_DOZE_SUSPEND) {
+ state = Display.STATE_ON_SUSPEND;
}
super.setDozeScreenState(state);
}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 98b1106..6650cc6 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -92,6 +92,7 @@
@Override
protected void dumpOnHandler(FileDescriptor fd, PrintWriter pw, String[] args) {
+ super.dumpOnHandler(fd, pw, args);
if (mDozeMachine != null) {
mDozeMachine.dump(pw);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
new file mode 100644
index 0000000..03018f7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -0,0 +1,159 @@
+/*
+ * 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.keyguard;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.icu.text.DateFormat;
+import android.icu.text.DisplayContext;
+import android.net.Uri;
+import android.os.Handler;
+import android.app.slice.Slice;
+import android.app.slice.SliceProvider;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+
+import java.util.Date;
+import java.util.Locale;
+
+/**
+ * Simple Slice provider that shows the current date.
+ */
+public class KeyguardSliceProvider extends SliceProvider {
+
+ public static final String KEYGUARD_SLICE_URI = "content://com.android.systemui.keyguard/main";
+
+ private final Date mCurrentTime = new Date();
+ protected final Uri mSliceUri;
+ private final Handler mHandler;
+ private String mDatePattern;
+ private DateFormat mDateFormat;
+ private String mLastText;
+ private boolean mRegistered;
+ private boolean mRegisteredEveryMinute;
+
+ /**
+ * Receiver responsible for time ticking and updating the date format.
+ */
+ @VisibleForTesting
+ final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (Intent.ACTION_TIME_TICK.equals(action)
+ || Intent.ACTION_DATE_CHANGED.equals(action)
+ || Intent.ACTION_TIME_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)
+ || Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ if (Intent.ACTION_LOCALE_CHANGED.equals(action)
+ || Intent.ACTION_TIMEZONE_CHANGED.equals(action)) {
+ // need to get a fresh date format
+ mHandler.post(KeyguardSliceProvider.this::cleanDateFormat);
+ }
+ mHandler.post(KeyguardSliceProvider.this::updateClock);
+ }
+ }
+ };
+
+ public KeyguardSliceProvider() {
+ this(new Handler());
+ }
+
+ @VisibleForTesting
+ KeyguardSliceProvider(Handler handler) {
+ mHandler = handler;
+ mSliceUri = Uri.parse(KEYGUARD_SLICE_URI);
+ }
+
+ @Override
+ public Slice onBindSlice(Uri sliceUri) {
+ return new Slice.Builder(sliceUri).addText(mLastText, Slice.HINT_TITLE).build();
+ }
+
+ @Override
+ public boolean onCreate() {
+
+ mDatePattern = getContext().getString(R.string.system_ui_date_pattern);
+
+ registerClockUpdate(false /* everyMinute */);
+ updateClock();
+ return true;
+ }
+
+ protected void registerClockUpdate(boolean everyMinute) {
+ if (mRegistered) {
+ if (mRegisteredEveryMinute == everyMinute) {
+ return;
+ } else {
+ unregisterClockUpdate();
+ }
+ }
+
+ IntentFilter filter = new IntentFilter();
+ if (everyMinute) {
+ filter.addAction(Intent.ACTION_TIME_TICK);
+ }
+ filter.addAction(Intent.ACTION_DATE_CHANGED);
+ filter.addAction(Intent.ACTION_TIME_CHANGED);
+ filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ getContext().registerReceiver(mIntentReceiver, filter, null /* permission*/,
+ null /* scheduler */);
+ mRegistered = true;
+ mRegisteredEveryMinute = everyMinute;
+ }
+
+ protected void unregisterClockUpdate() {
+ if (!mRegistered) {
+ return;
+ }
+ getContext().unregisterReceiver(mIntentReceiver);
+ mRegistered = false;
+ }
+
+ @VisibleForTesting
+ boolean isRegistered() {
+ return mRegistered;
+ }
+
+ protected void updateClock() {
+ final String text = getFormattedDate();
+ if (!text.equals(mLastText)) {
+ mLastText = text;
+ getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */);
+ }
+ }
+
+ protected String getFormattedDate() {
+ if (mDateFormat == null) {
+ final Locale l = Locale.getDefault();
+ DateFormat format = DateFormat.getInstanceForSkeleton(mDatePattern, l);
+ format.setContext(DisplayContext.CAPITALIZATION_FOR_STANDALONE);
+ mDateFormat = format;
+ }
+ mCurrentTime.setTime(System.currentTimeMillis());
+ return mDateFormat.format(mCurrentTime);
+ }
+
+ @VisibleForTesting
+ void cleanDateFormat() {
+ mDateFormat = null;
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 4c3d5ba..4119ec0 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -26,14 +26,16 @@
import android.os.Bundle;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
public class WorkLockActivityController {
+ private static final String TAG = WorkLockActivityController.class.getSimpleName();
+
private final Context mContext;
- private final SystemServicesProxy mSsp;
private final IActivityManager mIam;
public WorkLockActivityController(Context context) {
@@ -43,17 +45,22 @@
@VisibleForTesting
WorkLockActivityController(Context context, SystemServicesProxy ssp, IActivityManager am) {
mContext = context;
- mSsp = ssp;
mIam = am;
- mSsp.registerTaskStackListener(mLockListener);
+ ssp.registerTaskStackListener(mLockListener);
}
private void startWorkChallengeInTask(int taskId, int userId) {
+ ActivityManager.TaskDescription taskDescription = null;
+ try {
+ taskDescription = mIam.getTaskDescription(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get description for task=" + taskId);
+ }
Intent intent = new Intent(KeyguardManager.ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER)
.setComponent(new ComponentName(mContext, WorkLockActivity.class))
.putExtra(Intent.EXTRA_USER_ID, userId)
- .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, mSsp.getTaskDescription(taskId))
+ .putExtra(WorkLockActivity.EXTRA_TASK_DESCRIPTION, taskDescription)
.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
| Intent.FLAG_ACTIVITY_CLEAR_TOP);
@@ -67,7 +74,11 @@
} else {
// Starting the activity inside the task failed. We can't be sure why, so to be
// safe just remove the whole task if it still exists.
- mSsp.removeTask(taskId);
+ try {
+ mIam.removeTask(taskId);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to get description for task=" + taskId);
+ }
}
}
@@ -96,7 +107,7 @@
}
}
- private final TaskStackChangeListener mLockListener = new TaskStackChangeListener() {
+ private final SysUiTaskStackChangeListener mLockListener = new SysUiTaskStackChangeListener() {
@Override
public void onTaskProfileLocked(int taskId, int userId) {
startWorkChallengeInTask(taskId, userId);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index 7e87666..7ef0f15 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -40,8 +40,9 @@
import com.android.systemui.pip.BasePipManager;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.component.ExpandPipEvent;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.io.PrintWriter;
@@ -69,7 +70,7 @@
/**
* Handler for system task stack changes.
*/
- TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() {
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
mTouchHandler.onActivityPinned();
@@ -202,9 +203,9 @@
StackInfo stackInfo = mActivityManager.getStackInfo(
WINDOWING_MODE_PINNED, ACTIVITY_TYPE_UNDEFINED);
if (stackInfo != null && stackInfo.taskIds != null) {
- SystemServicesProxy ssp = SystemServicesProxy.getInstance(mContext);
+ ActivityManagerWrapper am = ActivityManagerWrapper.getInstance();
for (int taskId : stackInfo.taskIds) {
- ssp.cancelThumbnailTransition(taskId);
+ am.cancelThumbnailTransition(taskId);
}
}
} catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index c92562b..5a91def 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -45,8 +45,8 @@
import com.android.systemui.R;
import com.android.systemui.pip.BasePipManager;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -620,7 +620,7 @@
return false;
}
- private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
+ private SysUiTaskStackChangeListener mTaskStackListener = new SysUiTaskStackChangeListener() {
@Override
public void onTaskStackChanged() {
if (DEBUG) Log.d(TAG, "onTaskStackChanged()");
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/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 2250e41..5b62c7d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -63,6 +63,7 @@
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
@@ -246,7 +247,7 @@
return;
}
- sSystemServicesProxy.sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
int recentsGrowTarget = getComponent(Divider.class).getView().growsRecents();
int currentUser = sSystemServicesProxy.getCurrentUser();
if (sSystemServicesProxy.isSystemUser(currentUser)) {
@@ -410,12 +411,12 @@
}
int currentUser = sSystemServicesProxy.getCurrentUser();
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
final int activityType = runningTask != null
? runningTask.configuration.windowConfiguration.getActivityType()
: ACTIVITY_TYPE_UNDEFINED;
- boolean screenPinningActive = ssp.isScreenPinningActive();
+ boolean screenPinningActive = sSystemServicesProxy.isScreenPinningActive();
boolean isRunningTaskInHomeOrRecentsStack =
activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS;
if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b75a142..c666d57 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -16,6 +16,9 @@
package com.android.systemui.recents;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
+
import android.app.Activity;
import android.app.ActivityOptions;
import android.app.TaskStackBuilder;
@@ -92,6 +95,7 @@
import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.recents.views.RecentsView;
import com.android.systemui.recents.views.SystemBarScrimViews;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.phone.StatusBar;
import java.io.FileDescriptor;
@@ -280,8 +284,7 @@
new DismissRecentsToHomeAnimationStarted(animateTaskViews);
dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent,
overrideAnimation));
- Recents.getSystemServices().sendCloseSystemWindows(
- StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+ ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
EventBus.getDefault().send(dismissEvent);
}
@@ -706,9 +709,9 @@
int launchToTaskId = launchState.launchedToTaskId;
if (launchToTaskId != -1 &&
(event.launchTask == null || launchToTaskId != event.launchTask.key.id)) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.cancelWindowTransition(launchState.launchedToTaskId);
- ssp.cancelThumbnailTransition(getTaskId());
+ ActivityManagerWrapper am = ActivityManagerWrapper.getInstance();
+ am.cancelWindowTransition(launchState.launchedToTaskId);
+ am.cancelThumbnailTransition(getTaskId());
}
}
@@ -755,8 +758,7 @@
loader.deleteTaskData(event.task, false);
// Remove the task from activity manager
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.removeTask(event.task.key.id);
+ ActivityManagerWrapper.getInstance().removeTask(event.task.key.id);
}
public final void onBusEvent(TaskViewDismissedEvent event) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 1533e0a..0b816b5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -20,6 +20,8 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
import static android.view.View.MeasureSpec;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
+
import android.app.ActivityManager;
import android.app.ActivityManager.TaskSnapshot;
import android.app.ActivityOptions;
@@ -70,26 +72,28 @@
import com.android.systemui.recents.misc.DozeTrigger;
import com.android.systemui.recents.misc.ForegroundThread;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.recents.views.RecentsTransitionHelper;
-import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm.VisibilityReport;
import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskViewHeader;
import com.android.systemui.recents.views.TaskViewTransform;
import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
+import com.android.systemui.shared.recents.view.RecentsTransition;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.DividerView;
import com.android.systemui.statusbar.phone.NavigationBarGestureHelper;
import com.android.systemui.statusbar.phone.StatusBar;
import java.util.ArrayList;
+import java.util.List;
/**
* An implementation of the Recents component for the current user. For secondary users, this can
@@ -113,10 +117,10 @@
public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity";
/**
- * An implementation of TaskStackChangeListener, that allows us to listen for changes to the system
+ * An implementation of SysUiTaskStackChangeListener, that allows us to listen for changes to the system
* task stacks and update recents accordingly.
*/
- class TaskStackListenerImpl extends TaskStackChangeListener {
+ class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
@Override
public void onTaskStackChangedBackground() {
@@ -134,8 +138,8 @@
}
// Load the next task only if we aren't svelte
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTaskInfo =
+ ActivityManagerWrapper.getInstance().getRunningTask();
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan plan = new RecentsTaskLoadPlan(mContext);
loader.preloadTasks(plan, -1);
@@ -349,7 +353,8 @@
boolean forceVisible = launchedWhileDockingTask || draggingInRecents;
MutableBoolean isHomeStackVisible = new MutableBoolean(forceVisible);
if (forceVisible || !ssp.isRecentsActivityVisible(isHomeStackVisible)) {
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
startRecentsActivity(runningTask, isHomeStackVisible.value || fromHome, animate,
growTarget);
}
@@ -440,12 +445,14 @@
}
// Otherwise, start the recents activity
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
growTarget);
// Only close the other system windows if we are actually showing recents
- ssp.sendCloseSystemWindows(StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
+ ActivityManagerWrapper.getInstance().closeSystemWindows(
+ SYSTEM_DIALOG_REASON_RECENT_APPS);
mLastToggleTime = SystemClock.elapsedRealtime();
}
} catch (ActivityNotFoundException e) {
@@ -465,7 +472,8 @@
// don't block the touch feedback on the nav bar button which triggers this.
mHandler.post(() -> {
if (!ssp.isRecentsActivityVisible(null)) {
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
if (runningTask == null) {
return;
}
@@ -519,7 +527,8 @@
if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
// Return early if there is no running task
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
if (runningTask == null) return;
// Find the task in the recents list
@@ -556,8 +565,8 @@
}
// Launch the task
- ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+ null /* resultCallback */, null /* resultCallbackHandler */);
}
/**
@@ -574,7 +583,8 @@
if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
// Return early if there is no running task (can't determine affiliated tasks in this case)
- ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTask =
+ ActivityManagerWrapper.getInstance().getRunningTask();
final int activityType = runningTask.configuration.windowConfiguration.getActivityType();
if (runningTask == null) return;
// Return early if the running task is in the home/recents stack (optimization)
@@ -625,8 +635,8 @@
MetricsLogger.count(mContext, "overview_affiliated_task_launch", 1);
// Launch the task
- ssp.startActivityFromRecents(
- mContext, toTask.key, toTask.title, launchOpts, null /* resultListener */);
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(toTask.key, launchOpts,
+ null /* resultListener */, null /* resultCallbackHandler */);
}
public void showNextAffiliatedTask() {
@@ -864,22 +874,22 @@
windowOverrideRect);
RectF toTaskRect = toTransform.rect;
- AppTransitionAnimationSpecsFuture future =
- new RecentsTransitionHelper(mContext).getAppTransitionFuture(
- () -> {
- Rect rect = new Rect();
- toTaskRect.round(rect);
- GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(toTask,
- toTransform);
- return Lists.newArrayList(new AppTransitionAnimationSpec(
- toTask.key.id, thumbnail, rect));
- });
+ AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(mHandler) {
+ @Override
+ public List<AppTransitionAnimationSpec> composeSpecs() {
+ Rect rect = new Rect();
+ toTaskRect.round(rect);
+ GraphicBuffer thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform);
+ return Lists.newArrayList(new AppTransitionAnimationSpec(toTask.key.id, thumbnail,
+ rect));
+ }
+ };
// For low end ram devices, wait for transition flag is reset when Recents entrance
// animation is complete instead of when the transition animation starts
- return new Pair<>(ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
- mHandler, future.getFuture(), isLowRamDevice ? null : mResetToggleFlagListener,
- false /* scaleUp */), future);
+ return new Pair<>(RecentsTransition.createAspectScaleAnimation(mContext, mHandler,
+ false /* scaleUp */, future, isLowRamDevice ? null : mResetToggleFlagListener),
+ future);
}
/**
@@ -919,7 +929,7 @@
boolean disabledInSafeMode = !toTask.isSystemApp && ssp.isInSafeMode();
mHeaderBar.onTaskViewSizeChanged(width, height);
if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- return RecentsTransitionHelper.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
+ return RecentsTransition.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
null, 1f, 0xFFff0000);
} else {
// Workaround for b/27815919, reset the callback so that we do not trigger an
@@ -932,7 +942,7 @@
disabledInSafeMode);
mHeaderBar.onTaskDataLoaded();
mHeaderBar.setDimAlpha(toTransform.dimAlpha);
- return RecentsTransitionHelper.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
+ return RecentsTransition.drawViewIntoGraphicBuffer(width, mTaskBarHeight,
mHeaderBar, 1f, 0);
}
}
@@ -1047,7 +1057,7 @@
Recents.getSystemServices().startActivityAsUserAsync(intent, opts);
EventBus.getDefault().send(new RecentsActivityStartingEvent());
if (future != null) {
- future.precacheSpecs();
+ future.composeSpecsSynchronous();
}
});
EventBus.getDefault().send(hideMenuEvent);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java
new file mode 100644
index 0000000..5d7f1ba
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SysUiTaskStackChangeListener.java
@@ -0,0 +1,35 @@
+/*
+ * 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.misc;
+
+import android.content.Context;
+
+import com.android.systemui.shared.system.TaskStackChangeListener;
+
+/**
+ * An implementation of {@link TaskStackChangeListener}.
+ */
+public abstract class SysUiTaskStackChangeListener extends TaskStackChangeListener {
+
+ /**
+ * Checks that the current user matches the user's SystemUI process.
+ */
+ protected final boolean checkCurrentUserId(Context context, boolean debug) {
+ int currentUserId = SystemServicesProxy.getInstance(context).getCurrentUser();
+ return checkCurrentUserId(currentUserId, debug);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index c4ac52b..a436e17 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -79,9 +79,11 @@
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.systemui.statusbar.policy.UserInfoController;
import java.util.List;
+import java.util.function.Consumer;
/**
* Acts as a shim around the real system services that we need to access data from, and provides
@@ -122,7 +124,6 @@
Paint mBgProtectionPaint;
Canvas mBgProtectionCanvas;
- private final Handler mHandler = new Handler();
private final Runnable mGcRunnable = new Runnable() {
@Override
public void run() {
@@ -196,24 +197,6 @@
}
/**
- * Returns the top running task.
- */
- public ActivityManager.RunningTaskInfo getRunningTask() {
- // Note: The set of running tasks from the system is ordered by recency
- try {
- List<ActivityManager.RunningTaskInfo> tasks = mIam.getFilteredTasks(1,
- ACTIVITY_TYPE_RECENTS /* ignoreActivityType */,
- WINDOWING_MODE_PINNED /* ignoreWindowingMode */);
- if (tasks.isEmpty()) {
- return null;
- }
- return tasks.get(0);
- } catch (RemoteException e) {
- return null;
- }
- }
-
- /**
* Returns whether the recents activity is currently visible.
*/
public boolean isRecentsActivityVisible() {
@@ -364,32 +347,6 @@
return insets.right > 0;
}
- /**
- * Cancels the current window transtion to/from Recents for the given task id.
- */
- public void cancelWindowTransition(int taskId) {
- if (mIam == null) return;
-
- try {
- mIam.cancelTaskWindowTransition(taskId);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
- /**
- * Cancels the current thumbnail transtion to/from Recents for the given task id.
- */
- public void cancelThumbnailTransition(int taskId) {
- if (mIam == null) return;
-
- try {
- mIam.cancelTaskThumbnailTransition(taskId);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- }
-
/** Set the task's windowing mode. */
public void setTaskWindowingMode(int taskId, int windowingMode) {
if (mIam == null) return;
@@ -401,40 +358,6 @@
}
}
- /** Removes the task */
- public void removeTask(final int taskId) {
- if (mAm == null) return;
-
- // Remove the task.
- mUiOffloadThread.submit(() -> {
- try {
- mIam.removeTask(taskId);
- } catch (RemoteException e) {
- e.printStackTrace();
- }
- });
- }
-
- /**
- * Sends a message to close other system windows.
- */
- public void sendCloseSystemWindows(String reason) {
- mUiOffloadThread.submit(() -> {
- try {
- mIam.closeSystemDialogs(reason);
- } catch (RemoteException e) {
- }
- });
- }
-
- public ActivityManager.TaskDescription getTaskDescription(int taskId) {
- try {
- return mIam.getTaskDescription(taskId);
- } catch (RemoteException e) {
- return null;
- }
- }
-
/**
* Returns whether the provided {@param userId} represents the system user.
*/
@@ -557,56 +480,6 @@
opts != null ? opts.toBundle() : null, UserHandle.CURRENT));
}
- public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
- ActivityOptions options,
- @Nullable final StartActivityFromRecentsResultListener resultListener) {
- startActivityFromRecents(context, taskKey, taskName, options,
- WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_UNDEFINED, resultListener);
- }
-
- /** Starts an activity from recents. */
- public void startActivityFromRecents(Context context, Task.TaskKey taskKey, String taskName,
- ActivityOptions options, int windowingMode, int activityType,
- @Nullable final StartActivityFromRecentsResultListener resultListener) {
- if (mIam == null) {
- return;
- }
- if (taskKey.windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
- // We show non-visible docked tasks in Recents, but we always want to launch
- // them in the fullscreen stack.
- if (options == null) {
- options = ActivityOptions.makeBasic();
- }
- options.setLaunchWindowingMode(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
- } else if (windowingMode != WINDOWING_MODE_UNDEFINED
- || activityType != ACTIVITY_TYPE_UNDEFINED) {
- if (options == null) {
- options = ActivityOptions.makeBasic();
- }
- options.setLaunchWindowingMode(windowingMode);
- options.setLaunchActivityType(activityType);
- }
- final ActivityOptions finalOptions = options;
-
- // Execute this from another thread such that we can do other things (like caching the
- // bitmap for the thumbnail) while AM is busy starting our activity.
- mUiOffloadThread.submit(() -> {
- try {
- mIam.startActivityFromRecents(
- taskKey.id, finalOptions == null ? null : finalOptions.toBundle());
- if (resultListener != null) {
- mHandler.post(() -> resultListener.onStartActivityResult(true));
- }
- } catch (Exception e) {
- Log.e(TAG, context.getString(
- R.string.recents_launch_error_message, taskName), e);
- if (resultListener != null) {
- mHandler.post(() -> resultListener.onStartActivityResult(false));
- }
- }
- });
- }
-
/** Starts an in-place animation on the front most application windows. */
public void startInPlaceAnimationOnFrontMostApplication(ActivityOptions opts) {
if (mIam == null) return;
@@ -623,7 +496,7 @@
* Registers a task stack listener with the system.
* This should be called on the main thread.
*/
- public void registerTaskStackListener(TaskStackChangeListener listener) {
+ public void registerTaskStackListener(SysUiTaskStackChangeListener listener) {
if (mIam == null) return;
synchronized (mTaskStackChangeListeners) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
new file mode 100644
index 0000000..99390ec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionComposer.java
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2014 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.views;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
+
+import android.content.Context;
+import android.graphics.GraphicBuffer;
+import android.graphics.Rect;
+import android.util.Log;
+import android.view.AppTransitionAnimationSpec;
+
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.RecentsDebugFlags;
+import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.view.RecentsTransition;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A helper class to create the transition app animation specs to/from Recents
+ */
+public class RecentsTransitionComposer {
+
+ private static final String TAG = "RecentsTransitionComposer";
+
+ private Context mContext;
+ private TaskViewTransform mTmpTransform = new TaskViewTransform();
+
+ public RecentsTransitionComposer(Context context) {
+ mContext = context;
+ }
+
+ /**
+ * Composes a single animation spec for the given {@link TaskView}
+ */
+ private static AppTransitionAnimationSpec composeAnimationSpec(TaskStackView stackView,
+ TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
+ GraphicBuffer b = null;
+ if (addHeaderBitmap) {
+ b = composeHeaderBitmap(taskView, transform);
+ if (b == null) {
+ return null;
+ }
+ }
+
+ Rect taskRect = new Rect();
+ transform.rect.round(taskRect);
+ // Disable in for low ram devices because each task does in Recents does not have fullscreen
+ // height (stackView height) and when transitioning to fullscreen app, the code below would
+ // force the task thumbnail to full stackView height immediately causing the transition
+ // jarring.
+ if (!Recents.getConfiguration().isLowRamDevice && taskView.getTask() !=
+ stackView.getStack().getStackFrontMostTask()) {
+ taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
+ }
+ return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
+ }
+
+ /**
+ * Composes the transition spec when docking a task, which includes a full task bitmap.
+ */
+ public List<AppTransitionAnimationSpec> composeDockAnimationSpec(TaskView taskView,
+ Rect bounds) {
+ mTmpTransform.fillIn(taskView);
+ Task task = taskView.getTask();
+ GraphicBuffer buffer = RecentsTransitionComposer.composeTaskBitmap(taskView, mTmpTransform);
+ return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, buffer,
+ bounds));
+ }
+
+ /**
+ * Composes the animation specs for all the tasks in the target stack.
+ */
+ public List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
+ final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) {
+ // Calculate the offscreen task rect (for tasks that are not backed by views)
+ TaskView taskView = stackView.getChildViewForTask(task);
+ TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
+ Rect offscreenTaskRect = new Rect();
+ stackLayout.getFrontOfStackTransform().rect.round(offscreenTaskRect);
+
+ // If this is a full screen stack, the transition will be towards the single, full screen
+ // task. We only need the transition spec for this task.
+
+ // TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
+ // check for INVALID_STACK_ID (now WINDOWING_MODE_UNDEFINED)
+ if (windowingMode == WINDOWING_MODE_FULLSCREEN
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ || activityType == ACTIVITY_TYPE_ASSISTANT
+ || windowingMode == WINDOWING_MODE_UNDEFINED) {
+ List<AppTransitionAnimationSpec> specs = new ArrayList<>();
+ if (taskView == null) {
+ specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
+ } else {
+ mTmpTransform.fillIn(taskView);
+ stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
+ AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
+ mTmpTransform, true /* addHeaderBitmap */);
+ if (spec != null) {
+ specs.add(spec);
+ }
+ }
+ return specs;
+ }
+ return Collections.emptyList();
+ }
+
+ /**
+ * Composes a single animation spec for the given {@link Task}
+ */
+ private static AppTransitionAnimationSpec composeOffscreenAnimationSpec(Task task,
+ Rect taskRect) {
+ return new AppTransitionAnimationSpec(task.key.id, null, taskRect);
+ }
+
+ public static GraphicBuffer composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
+ float scale = transform.scale;
+ int fromWidth = (int) (transform.rect.width() * scale);
+ int fromHeight = (int) (transform.rect.height() * scale);
+ if (fromWidth == 0 || fromHeight == 0) {
+ Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() +
+ " at transform: " + transform);
+
+ return RecentsTransition.drawViewIntoGraphicBuffer(1, 1, null, 1f, 0x00ffffff);
+ } else {
+ if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
+ return RecentsTransition.drawViewIntoGraphicBuffer(fromWidth, fromHeight, null, 1f,
+ 0xFFff0000);
+ } else {
+ return RecentsTransition.drawViewIntoGraphicBuffer(fromWidth, fromHeight, taskView,
+ scale, 0);
+ }
+ }
+ }
+
+ private static GraphicBuffer composeHeaderBitmap(TaskView taskView,
+ TaskViewTransform transform) {
+ float scale = transform.scale;
+ int headerWidth = (int) (transform.rect.width());
+ int headerHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
+ if (headerWidth == 0 || headerHeight == 0) {
+ return null;
+ }
+
+ if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
+ return RecentsTransition.drawViewIntoGraphicBuffer(headerWidth, headerHeight, null, 1f,
+ 0xFFff0000);
+ } else {
+ return RecentsTransition.drawViewIntoGraphicBuffer(headerWidth, headerHeight,
+ taskView.mHeaderView, scale, 0);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
deleted file mode 100644
index 7442904..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Copyright (C) 2014 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.views;
-
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-
-import android.annotation.Nullable;
-import android.app.ActivityOptions;
-import android.app.ActivityOptions.OnAnimationStartedListener;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.GraphicBuffer;
-import android.graphics.Rect;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IRemoteCallback;
-import android.os.RemoteException;
-import android.util.Log;
-import android.view.AppTransitionAnimationSpec;
-import android.view.DisplayListCanvas;
-import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
-import android.view.View;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsDebugFlags;
-import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
-import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
-import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
-import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
-import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
-import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
-import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.model.TaskStack;
-import com.android.systemui.statusbar.phone.StatusBar;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A helper class to create transitions to/from Recents
- */
-public class RecentsTransitionHelper {
-
- private static final String TAG = "RecentsTransitionHelper";
- private static final boolean DEBUG = false;
-
- /**
- * Special value for {@link #mAppTransitionAnimationSpecs}: Indicate that we are currently
- * waiting for the specs to be retrieved.
- */
- private static final List<AppTransitionAnimationSpec> SPECS_WAITING = new ArrayList<>();
-
- @GuardedBy("this")
- private List<AppTransitionAnimationSpec> mAppTransitionAnimationSpecs = SPECS_WAITING;
-
- private Context mContext;
- private Handler mHandler;
- private TaskViewTransform mTmpTransform = new TaskViewTransform();
-
- private class StartScreenPinningRunnableRunnable implements Runnable {
-
- private int taskId = -1;
-
- @Override
- public void run() {
- EventBus.getDefault().send(new ScreenPinningRequestEvent(mContext, taskId));
- }
- }
- private StartScreenPinningRunnableRunnable mStartScreenPinningRunnable
- = new StartScreenPinningRunnableRunnable();
-
- public RecentsTransitionHelper(Context context) {
- mContext = context;
- mHandler = new Handler();
- }
-
- /**
- * Launches the specified {@link Task}.
- */
- public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
- final TaskStackView stackView, final TaskView taskView,
- final boolean screenPinningRequested, final int windowingMode, final int activityType) {
-
- final ActivityOptions.OnAnimationStartedListener animStartedListener;
- final AppTransitionAnimationSpecsFuture transitionFuture;
- if (taskView != null) {
-
- // Fetch window rect here already in order not to be blocked on lock contention in WM
- // when the future calls it.
- final Rect windowRect = Recents.getSystemServices().getWindowRect();
- transitionFuture = getAppTransitionFuture(() -> composeAnimationSpecs(
- task, stackView, windowingMode, activityType, windowRect));
- animStartedListener = new OnAnimationStartedListener() {
- private boolean mHandled;
-
- @Override
- public void onAnimationStarted() {
- if (mHandled) {
- return;
- }
- mHandled = true;
-
- // If we are launching into another task, cancel the previous task's
- // window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
- EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
- stackView.cancelAllTaskViewAnimations();
-
- if (screenPinningRequested) {
- // Request screen pinning after the animation runs
- mStartScreenPinningRunnable.taskId = task.key.id;
- mHandler.postDelayed(mStartScreenPinningRunnable, 350);
- }
-
- if (!Recents.getConfiguration().isLowRamDevice) {
- // Reset the state where we are waiting for the transition to start
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
- }
- }
- };
- } else {
- // This is only the case if the task is not on screen (scrolled offscreen for example)
- transitionFuture = null;
- animStartedListener = new OnAnimationStartedListener() {
- private boolean mHandled;
-
- @Override
- public void onAnimationStarted() {
- if (mHandled) {
- return;
- }
- mHandled = true;
-
- // If we are launching into another task, cancel the previous task's
- // window transition
- EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
- EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
- stackView.cancelAllTaskViewAnimations();
-
- if (!Recents.getConfiguration().isLowRamDevice) {
- // Reset the state where we are waiting for the transition to start
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
- }
- }
- };
- }
-
- EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(true));
- final ActivityOptions opts = ActivityOptions.makeMultiThumbFutureAspectScaleAnimation(mContext,
- mHandler, transitionFuture != null ? transitionFuture.future : null,
- animStartedListener, true /* scaleUp */);
- if (taskView == null) {
- // If there is no task view, then we do not need to worry about animating out occluding
- // task views, and we can launch immediately
- startTaskActivity(stack, task, taskView, opts, transitionFuture,
- windowingMode, activityType);
- } else {
- LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
- screenPinningRequested);
- EventBus.getDefault().send(launchStartedEvent);
- startTaskActivity(stack, task, taskView, opts, transitionFuture, windowingMode,
- activityType);
- }
- Recents.getSystemServices().sendCloseSystemWindows(
- StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
- }
-
- public IRemoteCallback wrapStartedListener(final OnAnimationStartedListener listener) {
- if (listener == null) {
- return null;
- }
- return new IRemoteCallback.Stub() {
- @Override
- public void sendResult(Bundle data) throws RemoteException {
- mHandler.post(new Runnable() {
- @Override
- public void run() {
- listener.onAnimationStarted();
- }
- });
- }
- };
- }
-
- /**
- * Starts the activity for the launch task.
- *
- * @param taskView this is the {@link TaskView} that we are launching from. This can be null if
- * we are toggling recents and the launch-to task is now offscreen.
- */
- private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
- ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
- int windowingMode, int activityType) {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ssp.startActivityFromRecents(mContext, task.key, task.title, opts, windowingMode,
- activityType,
- succeeded -> {
- if (succeeded) {
- // Keep track of the index of the task launch
- int taskIndexFromFront = 0;
- int taskIndex = stack.indexOfStackTask(task);
- if (taskIndex > -1) {
- taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
- }
- EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
- } else {
- // Dismiss the task if we fail to launch it
- if (taskView != null) {
- taskView.dismissTask();
- }
-
- // Keep track of failed launches
- EventBus.getDefault().send(new LaunchTaskFailedEvent());
- }
- });
- if (transitionFuture != null) {
- mHandler.post(transitionFuture::precacheSpecs);
- }
- }
-
- /**
- * Creates a future which will later be queried for animation specs for this current transition.
- *
- * @param composer The implementation that composes the specs on the UI thread.
- */
- public AppTransitionAnimationSpecsFuture getAppTransitionFuture(
- final AnimationSpecComposer composer) {
- synchronized (this) {
- mAppTransitionAnimationSpecs = SPECS_WAITING;
- }
- IAppTransitionAnimationSpecsFuture future = new IAppTransitionAnimationSpecsFuture.Stub() {
- @Override
- public AppTransitionAnimationSpec[] get() throws RemoteException {
- mHandler.post(() -> {
- synchronized (RecentsTransitionHelper.this) {
- mAppTransitionAnimationSpecs = composer.composeSpecs();
- RecentsTransitionHelper.this.notifyAll();
- }
- });
- synchronized (RecentsTransitionHelper.this) {
- while (mAppTransitionAnimationSpecs == SPECS_WAITING) {
- try {
- RecentsTransitionHelper.this.wait();
- } catch (InterruptedException e) {}
- }
- if (mAppTransitionAnimationSpecs == null) {
- return null;
- }
- AppTransitionAnimationSpec[] specs
- = new AppTransitionAnimationSpec[mAppTransitionAnimationSpecs.size()];
- mAppTransitionAnimationSpecs.toArray(specs);
- mAppTransitionAnimationSpecs = SPECS_WAITING;
- return specs;
- }
- }
- };
- return new AppTransitionAnimationSpecsFuture(composer, future);
- }
-
- /**
- * Composes the transition spec when docking a task, which includes a full task bitmap.
- */
- public List<AppTransitionAnimationSpec> composeDockAnimationSpec(TaskView taskView,
- Rect bounds) {
- mTmpTransform.fillIn(taskView);
- Task task = taskView.getTask();
- GraphicBuffer buffer = RecentsTransitionHelper.composeTaskBitmap(taskView, mTmpTransform);
- return Collections.singletonList(new AppTransitionAnimationSpec(task.key.id, buffer,
- bounds));
- }
-
- /**
- * Composes the animation specs for all the tasks in the target stack.
- */
- private List<AppTransitionAnimationSpec> composeAnimationSpecs(final Task task,
- final TaskStackView stackView, int windowingMode, int activityType, Rect windowRect) {
- // Calculate the offscreen task rect (for tasks that are not backed by views)
- TaskView taskView = stackView.getChildViewForTask(task);
- TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
- Rect offscreenTaskRect = new Rect();
- stackLayout.getFrontOfStackTransform().rect.round(offscreenTaskRect);
-
- // If this is a full screen stack, the transition will be towards the single, full screen
- // task. We only need the transition spec for this task.
-
- // TODO: Sometimes targetStackId is not initialized after reboot, so we also have to
- // check for INVALID_STACK_ID (now WINDOWING_MODE_UNDEFINED)
- if (windowingMode == WINDOWING_MODE_FULLSCREEN
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
- || windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
- || activityType == ACTIVITY_TYPE_ASSISTANT
- || windowingMode == WINDOWING_MODE_UNDEFINED) {
- List<AppTransitionAnimationSpec> specs = new ArrayList<>();
- if (taskView == null) {
- specs.add(composeOffscreenAnimationSpec(task, offscreenTaskRect));
- } else {
- mTmpTransform.fillIn(taskView);
- stackLayout.transformToScreenCoordinates(mTmpTransform, windowRect);
- AppTransitionAnimationSpec spec = composeAnimationSpec(stackView, taskView,
- mTmpTransform, true /* addHeaderBitmap */);
- if (spec != null) {
- specs.add(spec);
- }
- }
- return specs;
- }
- return Collections.emptyList();
- }
-
- /**
- * Composes a single animation spec for the given {@link Task}
- */
- private static AppTransitionAnimationSpec composeOffscreenAnimationSpec(Task task,
- Rect taskRect) {
- return new AppTransitionAnimationSpec(task.key.id, null, taskRect);
- }
-
- public static GraphicBuffer composeTaskBitmap(TaskView taskView, TaskViewTransform transform) {
- float scale = transform.scale;
- int fromWidth = (int) (transform.rect.width() * scale);
- int fromHeight = (int) (transform.rect.height() * scale);
- if (fromWidth == 0 || fromHeight == 0) {
- Log.e(TAG, "Could not compose thumbnail for task: " + taskView.getTask() +
- " at transform: " + transform);
-
- return drawViewIntoGraphicBuffer(1, 1, null, 1f, 0x00ffffff);
- } else {
- if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- return drawViewIntoGraphicBuffer(fromWidth, fromHeight, null, 1f, 0xFFff0000);
- } else {
- return drawViewIntoGraphicBuffer(fromWidth, fromHeight, taskView, scale, 0);
- }
- }
- }
-
- private static GraphicBuffer composeHeaderBitmap(TaskView taskView,
- TaskViewTransform transform) {
- float scale = transform.scale;
- int headerWidth = (int) (transform.rect.width());
- int headerHeight = (int) (taskView.mHeaderView.getMeasuredHeight() * scale);
- if (headerWidth == 0 || headerHeight == 0) {
- return null;
- }
-
- if (RecentsDebugFlags.Static.EnableTransitionThumbnailDebugMode) {
- return drawViewIntoGraphicBuffer(headerWidth, headerHeight, null, 1f, 0xFFff0000);
- } else {
- return drawViewIntoGraphicBuffer(headerWidth, headerHeight, taskView.mHeaderView,
- scale, 0);
- }
- }
-
- public static GraphicBuffer drawViewIntoGraphicBuffer(int bufferWidth, int bufferHeight,
- View view, float scale, int eraseColor) {
- RenderNode node = RenderNode.create("RecentsTransition", null);
- node.setLeftTopRightBottom(0, 0, bufferWidth, bufferHeight);
- node.setClipToBounds(false);
- DisplayListCanvas c = node.start(bufferWidth, bufferHeight);
- c.scale(scale, scale);
- if (eraseColor != 0) {
- c.drawColor(eraseColor);
- }
- if (view != null) {
- view.draw(c);
- }
- node.end(c);
- Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, bufferWidth, bufferHeight);
- return hwBitmap.createGraphicBufferHandle();
- }
-
- /**
- * Composes a single animation spec for the given {@link TaskView}
- */
- private static AppTransitionAnimationSpec composeAnimationSpec(TaskStackView stackView,
- TaskView taskView, TaskViewTransform transform, boolean addHeaderBitmap) {
- GraphicBuffer b = null;
- if (addHeaderBitmap) {
- b = composeHeaderBitmap(taskView, transform);
- if (b == null) {
- return null;
- }
- }
-
- Rect taskRect = new Rect();
- transform.rect.round(taskRect);
- // Disable in for low ram devices because each task does in Recents does not have fullscreen
- // height (stackView height) and when transitioning to fullscreen app, the code below would
- // force the task thumbnail to full stackView height immediately causing the transition
- // jarring.
- if (!Recents.getConfiguration().isLowRamDevice && taskView.getTask() !=
- stackView.getStack().getStackFrontMostTask()) {
- taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
- }
- return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
- }
-
- public interface AnimationSpecComposer {
- List<AppTransitionAnimationSpec> composeSpecs();
- }
-
- /**
- * Class to be returned from {@link #composeAnimationSpec} that gives access to both the future
- * and the anonymous class used for composing.
- */
- public class AppTransitionAnimationSpecsFuture {
-
- private final AnimationSpecComposer composer;
- private final IAppTransitionAnimationSpecsFuture future;
-
- private AppTransitionAnimationSpecsFuture(AnimationSpecComposer composer,
- IAppTransitionAnimationSpecsFuture future) {
- this.composer = composer;
- this.future = future;
- }
-
- public IAppTransitionAnimationSpecsFuture getFuture() {
- return future;
- }
-
- /**
- * Manually generates and caches the spec such that they are already available when the
- * future needs.
- */
- public void precacheSpecs() {
- synchronized (RecentsTransitionHelper.this) {
- mAppTransitionAnimationSpecs = composer.composeSpecs();
- }
- }
- }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 5f12a04..b82f15e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -16,8 +16,13 @@
package com.android.systemui.recents.views;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_HOME_KEY;
+import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS;
+
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.Nullable;
+import android.app.ActivityOptions;
import android.app.ActivityOptions.OnAnimationStartedListener;
import android.content.Context;
import android.content.res.ColorStateList;
@@ -28,8 +33,10 @@
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Handler;
import android.util.ArraySet;
import android.util.AttributeSet;
+import android.util.Log;
import android.util.MathUtils;
import android.view.AppTransitionAnimationSpec;
import android.view.LayoutInflater;
@@ -54,15 +61,22 @@
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
+import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
import com.android.systemui.recents.events.activity.HideStackActionButtonEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
+import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
import com.android.systemui.recents.events.activity.ShowEmptyViewEvent;
import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
import com.android.systemui.recents.events.component.ExpandPipEvent;
+import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
+import com.android.systemui.recents.events.component.SetWaitingForTransitionStartEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
@@ -76,8 +90,9 @@
import com.android.systemui.shared.recents.utilities.Utilities;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.TaskStack;
-import com.android.systemui.recents.views.RecentsTransitionHelper.AnimationSpecComposer;
-import com.android.systemui.recents.views.RecentsTransitionHelper.AppTransitionAnimationSpecsFuture;
+import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
+import com.android.systemui.shared.recents.view.RecentsTransition;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.stackdivider.WindowManagerProxy;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -101,6 +116,7 @@
private static final int BUSY_RECENTS_TASK_COUNT = 3;
+ private Handler mHandler;
private TaskStackView mTaskStackView;
private TextView mStackActionButton;
private TextView mEmptyView;
@@ -126,7 +142,7 @@
mMultiWindowBackgroundScrim.setAlpha(alpha);
};
- private RecentsTransitionHelper mTransitionHelper;
+ private RecentsTransitionComposer mTransitionHelper;
@ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
private RecentsViewTouchHandler mTouchHandler;
private final FlingAnimationUtils mFlingAnimationUtils;
@@ -148,7 +164,8 @@
setWillNotDraw(false);
SystemServicesProxy ssp = Recents.getSystemServices();
- mTransitionHelper = new RecentsTransitionHelper(getContext());
+ mHandler = new Handler();
+ mTransitionHelper = new RecentsTransitionComposer(getContext());
mDividerSize = ssp.getDockedDividerSize(context);
mTouchHandler = new RecentsViewTouchHandler(this);
mFlingAnimationUtils = new FlingAnimationUtils(context, 0.3f);
@@ -518,9 +535,8 @@
/**** EventBus Events ****/
public final void onBusEvent(LaunchTaskEvent event) {
- mTransitionHelper.launchTaskFromRecents(getStack(), event.task, mTaskStackView,
- event.taskView, event.screenPinningRequested, event.targetWindowingMode,
- event.targetActivityType);
+ launchTaskFromRecents(getStack(), event.task, mTaskStackView, event.taskView,
+ event.screenPinningRequested, event.targetWindowingMode, event.targetActivityType);
if (Recents.getConfiguration().isLowRamDevice) {
EventBus.getDefault().send(new HideStackActionButtonEvent(false /* translate */));
}
@@ -607,17 +623,15 @@
};
final Rect taskRect = getTaskRect(event.taskView);
- AppTransitionAnimationSpecsFuture future =
- mTransitionHelper.getAppTransitionFuture(
- new AnimationSpecComposer() {
- @Override
- public List<AppTransitionAnimationSpec> composeSpecs() {
- return mTransitionHelper.composeDockAnimationSpec(
- event.taskView, taskRect);
- }
- });
+ AppTransitionAnimationSpecsFuture future = new AppTransitionAnimationSpecsFuture(
+ getHandler()) {
+ @Override
+ public List<AppTransitionAnimationSpec> composeSpecs() {
+ return mTransitionHelper.composeDockAnimationSpec(event.taskView, taskRect);
+ }
+ };
ssp.overridePendingAppTransitionMultiThumbFuture(future.getFuture(),
- mTransitionHelper.wrapStartedListener(startedListener),
+ RecentsTransition.wrapStartedListener(getHandler(), startedListener),
true /* scaleUp */);
MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
@@ -881,7 +895,8 @@
* @return the bounds of the stack action button.
*/
Rect getStackActionButtonBoundsFromStackLayout() {
- Rect actionButtonRect = new Rect(mTaskStackView.mLayoutAlgorithm.getStackActionButtonRect());
+ Rect actionButtonRect = new Rect(
+ mTaskStackView.mLayoutAlgorithm.getStackActionButtonRect());
int left, top;
if (Recents.getConfiguration().isLowRamDevice) {
Rect windowRect = Recents.getSystemServices().getWindowRect();
@@ -906,6 +921,141 @@
return mStackActionButton;
}
+ /**
+ * Launches the specified {@link Task}.
+ */
+ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
+ final TaskStackView stackView, final TaskView taskView,
+ final boolean screenPinningRequested, final int windowingMode, final int activityType) {
+
+ final ActivityOptions.OnAnimationStartedListener animStartedListener;
+ final AppTransitionAnimationSpecsFuture transitionFuture;
+ if (taskView != null) {
+
+ // Fetch window rect here already in order not to be blocked on lock contention in WM
+ // when the future calls it.
+ final Rect windowRect = Recents.getSystemServices().getWindowRect();
+ transitionFuture = new AppTransitionAnimationSpecsFuture(stackView.getHandler()) {
+ @Override
+ public List<AppTransitionAnimationSpec> composeSpecs() {
+ return mTransitionHelper.composeAnimationSpecs(task, stackView, windowingMode,
+ activityType, windowRect);
+ }
+ };
+ animStartedListener = new OnAnimationStartedListener() {
+ private boolean mHandled;
+
+ @Override
+ public void onAnimationStarted() {
+ if (mHandled) {
+ return;
+ }
+ mHandled = true;
+
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ stackView.cancelAllTaskViewAnimations();
+
+ if (screenPinningRequested) {
+ // Request screen pinning after the animation runs
+ mHandler.postDelayed(() -> {
+ EventBus.getDefault().send(new ScreenPinningRequestEvent(mContext,
+ task.key.id));
+ }, 350);
+ }
+
+ if (!Recents.getConfiguration().isLowRamDevice) {
+ // Reset the state where we are waiting for the transition to start
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ }
+ }
+ };
+ } else {
+ // This is only the case if the task is not on screen (scrolled offscreen for example)
+ transitionFuture = null;
+ animStartedListener = new OnAnimationStartedListener() {
+ private boolean mHandled;
+
+ @Override
+ public void onAnimationStarted() {
+ if (mHandled) {
+ return;
+ }
+ mHandled = true;
+
+ // If we are launching into another task, cancel the previous task's
+ // window transition
+ EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ stackView.cancelAllTaskViewAnimations();
+
+ if (!Recents.getConfiguration().isLowRamDevice) {
+ // Reset the state where we are waiting for the transition to start
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(false));
+ }
+ }
+ };
+ }
+
+ EventBus.getDefault().send(new SetWaitingForTransitionStartEvent(true));
+ final ActivityOptions opts = RecentsTransition.createAspectScaleAnimation(mContext,
+ mHandler, true /* scaleUp */, transitionFuture != null ? transitionFuture : null,
+ animStartedListener);
+ if (taskView == null) {
+ // If there is no task view, then we do not need to worry about animating out occluding
+ // task views, and we can launch immediately
+ startTaskActivity(stack, task, taskView, opts, transitionFuture,
+ windowingMode, activityType);
+ } else {
+ LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView,
+ screenPinningRequested);
+ EventBus.getDefault().send(launchStartedEvent);
+ startTaskActivity(stack, task, taskView, opts, transitionFuture, windowingMode,
+ activityType);
+ }
+ ActivityManagerWrapper.getInstance().closeSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS);
+ }
+
+ /**
+ * Starts the activity for the launch task.
+ *
+ * @param taskView this is the {@link TaskView} that we are launching from. This can be null if
+ * we are toggling recents and the launch-to task is now offscreen.
+ */
+ private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskView taskView,
+ ActivityOptions opts, AppTransitionAnimationSpecsFuture transitionFuture,
+ int windowingMode, int activityType) {
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key, opts, windowingMode,
+ activityType, succeeded -> {
+ if (succeeded) {
+ // Keep track of the index of the task launch
+ int taskIndexFromFront = 0;
+ int taskIndex = stack.indexOfStackTask(task);
+ if (taskIndex > -1) {
+ taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+ }
+ EventBus.getDefault().send(new LaunchTaskSucceededEvent(
+ taskIndexFromFront));
+ } else {
+ Log.e(TAG, mContext.getString(R.string.recents_launch_error_message,
+ task.title));
+
+ // Dismiss the task if we fail to launch it
+ if (taskView != null) {
+ taskView.dismissTask();
+ }
+
+ // Keep track of failed launches
+ EventBus.getDefault().send(new LaunchTaskFailedEvent());
+ }
+ }, getHandler());
+ if (transitionFuture != null) {
+ mHandler.post(transitionFuture::composeSpecsSynchronous);
+ }
+ }
+
@Override
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
super.requestDisallowInterceptTouchEvent(disallowIntercept);
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 7bcef57..1596d12 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -439,7 +439,7 @@
if (mMinimizedSnapAlgorithm == null) {
mMinimizedSnapAlgorithm = new DividerSnapAlgorithm(getContext().getResources(),
mDisplayWidth, mDisplayHeight, mDividerSize, isHorizontalDivision(),
- mStableInsets, mDockedStackMinimized && mHomeStackResizable);
+ mStableInsets, mDockSide, mDockedStackMinimized && mHomeStackResizable);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
index 0997983..b2bbe30 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/ForcedResizableInfoActivityController.java
@@ -31,8 +31,8 @@
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.AppTransitionFinishedEvent;
import com.android.systemui.recents.events.component.ShowUserToastEvent;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
import com.android.systemui.stackdivider.events.StartedDragingEvent;
import com.android.systemui.stackdivider.events.StoppedDragingEvent;
@@ -76,7 +76,7 @@
mContext = context;
EventBus.getDefault().register(this);
SystemServicesProxy.getInstance(context).registerTaskStackListener(
- new TaskStackChangeListener() {
+ new SysUiTaskStackChangeListener() {
@Override
public void onActivityForcedResizable(String packageName, int taskId,
int reason) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6c5f4b2..8ff950e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -69,6 +69,7 @@
import com.android.systemui.statusbar.notification.HybridNotificationView;
import com.android.systemui.statusbar.notification.NotificationInflater;
import com.android.systemui.statusbar.notification.NotificationUtils;
+import com.android.systemui.statusbar.notification.NotificationViewWrapper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.StatusBar;
@@ -453,6 +454,11 @@
} else {
headsUpheight = mMaxHeadsUpHeight;
}
+ NotificationViewWrapper headsUpWrapper = layout.getVisibleWrapper(
+ NotificationContentView.VISIBLE_TYPE_HEADSUP);
+ if (headsUpWrapper != null) {
+ headsUpheight = Math.max(headsUpheight, headsUpWrapper.getMinLayoutHeight());
+ }
layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
mNotificationAmbientHeight);
}
@@ -1256,16 +1262,21 @@
}
private void initDimens() {
- mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
- mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
- mNotificationMinHeightLarge = getFontScaledHeight(
+ mNotificationMinHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_min_height_legacy);
+ mNotificationMinHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_min_height);
+ mNotificationMinHeightLarge = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_min_height_increased);
- mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
- mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
- mMaxHeadsUpHeightLegacy = getFontScaledHeight(
+ mNotificationMaxHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_max_height);
+ mNotificationAmbientHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_ambient_height);
+ mMaxHeadsUpHeightLegacy = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height_legacy);
- mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
- mMaxHeadsUpHeightIncreased = getFontScaledHeight(
+ mMaxHeadsUpHeight = NotificationUtils.getFontScaledHeight(mContext,
+ R.dimen.notification_max_heads_up_height);
+ mMaxHeadsUpHeightIncreased = NotificationUtils.getFontScaledHeight(mContext,
R.dimen.notification_max_heads_up_height_increased);
Resources res = getResources();
@@ -1280,17 +1291,6 @@
}
/**
- * @param dimenId the dimen to look up
- * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
- */
- private int getFontScaledHeight(int dimenId) {
- int dimensionPixelSize = getResources().getDimensionPixelSize(dimenId);
- float factor = Math.max(1.0f, getResources().getDisplayMetrics().scaledDensity /
- getResources().getDisplayMetrics().density);
- return (int) (dimensionPixelSize * factor);
- }
-
- /**
* Resets this view so it can be re-used for an updated notification.
*/
public void reset() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
index 5353005..09b11c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
@@ -35,7 +35,8 @@
/**
* A view that can be transformed to and from.
*/
-public class ViewTransformationHelper implements TransformableView {
+public class ViewTransformationHelper implements TransformableView,
+ TransformState.TransformInfo {
private static final int TAG_CONTAINS_TRANSFORMED_VIEW = R.id.contains_transformed_view;
@@ -59,7 +60,7 @@
public TransformState getCurrentState(int fadingView) {
View view = mTransformedViews.get(fadingView);
if (view != null && view.getVisibility() != View.GONE) {
- return TransformState.createFrom(view);
+ return TransformState.createFrom(view, this);
}
return null;
}
@@ -88,6 +89,7 @@
endRunnable.run();
}
setVisible(false);
+ mViewTransformationAnimation = null;
} else {
abortTransformations();
}
@@ -245,7 +247,7 @@
}
public void resetTransformedView(View view) {
- TransformState state = TransformState.createFrom(view);
+ TransformState state = TransformState.createFrom(view, this);
state.setVisible(true /* visible */, true /* force */);
state.recycle();
}
@@ -257,6 +259,11 @@
return new ArraySet<>(mTransformedViews.values());
}
+ @Override
+ public boolean isAnimating() {
+ return mViewTransformationAnimation != null && mViewTransformationAnimation.isRunning();
+ }
+
public static abstract class CustomTransformation {
/**
* Transform a state to the given view
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index fed2ebe..41cae6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -45,8 +45,9 @@
import com.android.systemui.classifier.FalsingManager;
import com.android.systemui.fragments.FragmentHostManager;
import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
@@ -305,14 +306,14 @@
}
/**
- * An implementation of TaskStackChangeListener, that listens for changes in the system task
+ * An implementation of SysUiTaskStackChangeListener, that listens for changes in the system task
* stack and notifies the navigation bar.
*/
- private class TaskStackListenerImpl extends TaskStackChangeListener {
+ private class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
@Override
public void onTaskStackChanged() {
- SystemServicesProxy ssp = Recents.getSystemServices();
- ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
+ ActivityManager.RunningTaskInfo runningTaskInfo =
+ ActivityManagerWrapper.getInstance().getRunningTask();
if (runningTaskInfo != null && runningTaskInfo.baseActivity != null) {
mController.taskChanged(runningTaskInfo.baseActivity.getPackageName(),
runningTaskInfo);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
index 92f26d6..8227b77 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageTransformState.java
@@ -39,8 +39,8 @@
private Icon mIcon;
@Override
- public void initFrom(View view) {
- super.initFrom(view);
+ public void initFrom(View view, TransformInfo transformInfo) {
+ super.initFrom(view, transformInfo);
if (view instanceof ImageView) {
mIcon = (Icon) view.getTag(ICON_TAG);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
new file mode 100644
index 0000000..4c2a2f5
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MessagingLayoutTransformState.java
@@ -0,0 +1,405 @@
+/*
+ * 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.statusbar.notification;
+
+import android.content.res.Resources;
+import android.util.Pools;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.internal.widget.MessagingGroup;
+import com.android.internal.widget.MessagingLayout;
+import com.android.internal.widget.MessagingLinearLayout;
+import com.android.internal.widget.MessagingMessage;
+import com.android.internal.widget.MessagingPropertyAnimator;
+import com.android.internal.widget.ViewClippingUtil;
+import com.android.systemui.Interpolators;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * A transform state of the action list
+*/
+public class MessagingLayoutTransformState extends TransformState {
+
+ private static Pools.SimplePool<MessagingLayoutTransformState> sInstancePool
+ = new Pools.SimplePool<>(40);
+ private MessagingLinearLayout mMessageContainer;
+ private MessagingLayout mMessagingLayout;
+ private HashMap<MessagingGroup, MessagingGroup> mGroupMap = new HashMap<>();
+ private float mRelativeTranslationOffset;
+
+ public static MessagingLayoutTransformState obtain() {
+ MessagingLayoutTransformState instance = sInstancePool.acquire();
+ if (instance != null) {
+ return instance;
+ }
+ return new MessagingLayoutTransformState();
+ }
+
+ @Override
+ public void initFrom(View view, TransformInfo transformInfo) {
+ super.initFrom(view, transformInfo);
+ if (mTransformedView instanceof MessagingLinearLayout) {
+ mMessageContainer = (MessagingLinearLayout) mTransformedView;
+ mMessagingLayout = mMessageContainer.getMessagingLayout();
+ Resources resources = view.getContext().getResources();
+ mRelativeTranslationOffset = resources.getDisplayMetrics().density * 8;
+ }
+ }
+
+ @Override
+ public boolean transformViewTo(TransformState otherState, float transformationAmount) {
+ if (otherState instanceof MessagingLayoutTransformState) {
+ // It's a party! Let's transform between these two layouts!
+ transformViewInternal((MessagingLayoutTransformState) otherState, transformationAmount,
+ true /* to */);
+ return true;
+ } else {
+ return super.transformViewTo(otherState, transformationAmount);
+ }
+ }
+
+ @Override
+ public void transformViewFrom(TransformState otherState, float transformationAmount) {
+ if (otherState instanceof MessagingLayoutTransformState) {
+ // It's a party! Let's transform between these two layouts!
+ transformViewInternal((MessagingLayoutTransformState) otherState, transformationAmount,
+ false /* to */);
+ } else {
+ super.transformViewFrom(otherState, transformationAmount);
+ }
+ }
+
+ private void transformViewInternal(MessagingLayoutTransformState mlt,
+ float transformationAmount, boolean to) {
+ ArrayList<MessagingGroup> ownGroups = filterHiddenGroups(
+ mMessagingLayout.getMessagingGroups());
+ ArrayList<MessagingGroup> otherGroups = filterHiddenGroups(
+ mlt.mMessagingLayout.getMessagingGroups());
+ HashMap<MessagingGroup, MessagingGroup> pairs = findPairs(ownGroups, otherGroups);
+ MessagingGroup lastPairedGroup = null;
+ float currentTranslation = 0;
+ float transformationDistanceRemaining = 0;
+ for (int i = ownGroups.size() - 1; i >= 0; i--) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ MessagingGroup matchingGroup = pairs.get(ownGroup);
+ if (!isGone(ownGroup)) {
+ if (matchingGroup != null) {
+ transformGroups(ownGroup, matchingGroup, transformationAmount, to);
+ if (lastPairedGroup == null) {
+ lastPairedGroup = ownGroup;
+ if (to){
+ float totalTranslation = ownGroup.getTop() - matchingGroup.getTop();
+ transformationDistanceRemaining
+ = matchingGroup.getAvatar().getTranslationY();
+ currentTranslation = transformationDistanceRemaining - totalTranslation;
+ } else {
+ float totalTranslation = matchingGroup.getTop() - ownGroup.getTop();
+ currentTranslation = ownGroup.getAvatar().getTranslationY();
+ transformationDistanceRemaining = currentTranslation - totalTranslation;
+ }
+ }
+ } else {
+ float groupTransformationAmount = transformationAmount;
+ if (lastPairedGroup != null) {
+ adaptGroupAppear(ownGroup, transformationAmount, currentTranslation,
+ to);
+ int distance = lastPairedGroup.getTop() - ownGroup.getTop();
+ float transformationDistance = mTransformInfo.isAnimating()
+ ? distance
+ : ownGroup.getHeight() * 0.75f;
+ float translationProgress = transformationDistanceRemaining
+ - (distance - transformationDistance);
+ groupTransformationAmount =
+ translationProgress / transformationDistance;
+ groupTransformationAmount = Math.max(0.0f, Math.min(1.0f,
+ groupTransformationAmount));
+ if (to) {
+ groupTransformationAmount = 1.0f - groupTransformationAmount;
+ }
+ }
+ if (to) {
+ disappear(ownGroup, groupTransformationAmount);
+ } else {
+ appear(ownGroup, groupTransformationAmount);
+ }
+ }
+ }
+ }
+ }
+
+ private void appear(MessagingGroup ownGroup, float transformationAmount) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ View child = ownMessages.getChildAt(j);
+ if (isGone(child)) {
+ continue;
+ }
+ appear(child, transformationAmount);
+ setClippingDeactivated(child, true);
+ }
+ appear(ownGroup.getAvatar(), transformationAmount);
+ appear(ownGroup.getSender(), transformationAmount);
+ setClippingDeactivated(ownGroup.getSender(), true);
+ setClippingDeactivated(ownGroup.getAvatar(), true);
+ }
+
+ private void adaptGroupAppear(MessagingGroup ownGroup, float transformationAmount,
+ float overallTranslation, boolean to) {
+ float relativeOffset;
+ if (to) {
+ relativeOffset = transformationAmount * mRelativeTranslationOffset;
+ } else {
+ relativeOffset = (1.0f - transformationAmount) * mRelativeTranslationOffset;
+ }
+ if (ownGroup.getSender().getVisibility() != View.GONE) {
+ relativeOffset *= 0.5f;
+ }
+ ownGroup.getMessageContainer().setTranslationY(relativeOffset);
+ ownGroup.setTranslationY(overallTranslation * 0.85f);
+ }
+
+ private void disappear(MessagingGroup ownGroup, float transformationAmount) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ View child = ownMessages.getChildAt(j);
+ if (isGone(child)) {
+ continue;
+ }
+ disappear(child, transformationAmount);
+ setClippingDeactivated(child, true);
+ }
+ disappear(ownGroup.getAvatar(), transformationAmount);
+ disappear(ownGroup.getSender(), transformationAmount);
+ setClippingDeactivated(ownGroup.getSender(), true);
+ setClippingDeactivated(ownGroup.getAvatar(), true);
+ }
+
+ private void appear(View child, float transformationAmount) {
+ if (child.getVisibility() == View.GONE) {
+ return;
+ }
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.appear(transformationAmount, null);
+ ownState.recycle();
+ }
+
+ private void disappear(View child, float transformationAmount) {
+ if (child.getVisibility() == View.GONE) {
+ return;
+ }
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.disappear(transformationAmount, null);
+ ownState.recycle();
+ }
+
+ private ArrayList<MessagingGroup> filterHiddenGroups(
+ ArrayList<MessagingGroup> groups) {
+ ArrayList<MessagingGroup> result = new ArrayList<>(groups);
+ for (int i = 0; i < result.size(); i++) {
+ MessagingGroup messagingGroup = result.get(i);
+ if (isGone(messagingGroup)) {
+ result.remove(i);
+ i--;
+ }
+ }
+ return result;
+ }
+
+ private void transformGroups(MessagingGroup ownGroup, MessagingGroup otherGroup,
+ float transformationAmount, boolean to) {
+ transformView(transformationAmount, to, ownGroup.getSender(), otherGroup.getSender(),
+ true /* sameAsAny */);
+ transformView(transformationAmount, to, ownGroup.getAvatar(), otherGroup.getAvatar(),
+ true /* sameAsAny */);
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ MessagingLinearLayout otherMessages = otherGroup.getMessageContainer();
+ float previousTranslation = 0;
+ for (int i = 0; i < ownMessages.getChildCount(); i++) {
+ View child = ownMessages.getChildAt(ownMessages.getChildCount() - 1 - i);
+ if (isGone(child)) {
+ continue;
+ }
+ int otherIndex = otherMessages.getChildCount() - 1 - i;
+ View otherChild = null;
+ if (otherIndex >= 0) {
+ otherChild = otherMessages.getChildAt(otherIndex);
+ if (isGone(otherChild)) {
+ otherChild = null;
+ }
+ }
+ if (otherChild == null) {
+ float distanceToTop = child.getTop() + child.getHeight() + previousTranslation;
+ transformationAmount = distanceToTop / child.getHeight();
+ transformationAmount = Math.max(0.0f, Math.min(1.0f, transformationAmount));
+ if (to) {
+ transformationAmount = 1.0f - transformationAmount;
+ }
+ }
+ transformView(transformationAmount, to, child, otherChild, false /* sameAsAny */);
+ if (otherChild == null) {
+ child.setTranslationY(previousTranslation);
+ setClippingDeactivated(child, true);
+ } else if (to) {
+ float totalTranslation = child.getTop() + ownGroup.getTop()
+ - otherChild.getTop() - otherChild.getTop();
+ previousTranslation = otherChild.getTranslationY() - totalTranslation;
+ } else {
+ previousTranslation = child.getTranslationY();
+ }
+ }
+ }
+
+ private void transformView(float transformationAmount, boolean to, View ownView,
+ View otherView, boolean sameAsAny) {
+ TransformState ownState = TransformState.createFrom(ownView, mTransformInfo);
+ if (!mTransformInfo.isAnimating()) {
+ ownState.setDefaultInterpolator(Interpolators.LINEAR);
+ }
+ ownState.setIsSameAsAnyView(sameAsAny);
+ if (to) {
+ if (otherView != null) {
+ TransformState otherState = TransformState.createFrom(otherView, mTransformInfo);
+ ownState.transformViewTo(otherState, transformationAmount);
+ otherState.recycle();
+ } else {
+ ownState.disappear(transformationAmount, null);
+ }
+ } else {
+ if (otherView != null) {
+ TransformState otherState = TransformState.createFrom(otherView, mTransformInfo);
+ ownState.transformViewFrom(otherState, transformationAmount);
+ otherState.recycle();
+ } else {
+ ownState.appear(transformationAmount, null);
+ }
+ }
+ ownState.recycle();
+ }
+
+ private HashMap<MessagingGroup, MessagingGroup> findPairs(ArrayList<MessagingGroup> ownGroups,
+ ArrayList<MessagingGroup> otherGroups) {
+ mGroupMap.clear();
+ int lastMatch = Integer.MAX_VALUE;
+ for (int i = ownGroups.size() - 1; i >= 0; i--) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ MessagingGroup bestMatch = null;
+ int bestCompatibility = 0;
+ for (int j = Math.min(otherGroups.size(), lastMatch) - 1; j >= 0; j--) {
+ MessagingGroup otherGroup = otherGroups.get(j);
+ int compatibility = ownGroup.calculateGroupCompatibility(otherGroup);
+ if (compatibility > bestCompatibility) {
+ bestCompatibility = compatibility;
+ bestMatch = otherGroup;
+ lastMatch = j;
+ }
+ }
+ if (bestMatch != null) {
+ mGroupMap.put(ownGroup, bestMatch);
+ }
+ }
+ return mGroupMap;
+ }
+
+ private boolean isGone(View view) {
+ if (view.getVisibility() == View.GONE) {
+ return true;
+ }
+ final ViewGroup.LayoutParams lp = view.getLayoutParams();
+ if (lp instanceof MessagingLinearLayout.LayoutParams
+ && ((MessagingLinearLayout.LayoutParams) lp).hide) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void setVisible(boolean visible, boolean force) {
+ resetTransformedView();
+ ArrayList<MessagingGroup> ownGroups = mMessagingLayout.getMessagingGroups();
+ for (int i = 0; i < ownGroups.size(); i++) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ if (!isGone(ownGroup)) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ MessagingMessage child = (MessagingMessage) ownMessages.getChildAt(j);
+ setVisible(child, visible, force);
+ }
+ setVisible(ownGroup.getAvatar(), visible, force);
+ setVisible(ownGroup.getSender(), visible, force);
+ }
+ }
+ }
+
+ private void setVisible(View child, boolean visible, boolean force) {
+ if (isGone(child) || MessagingPropertyAnimator.isAnimatingAlpha(child)) {
+ return;
+ }
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.setVisible(visible, force);
+ ownState.recycle();
+ }
+
+ @Override
+ protected void resetTransformedView() {
+ super.resetTransformedView();
+ ArrayList<MessagingGroup> ownGroups = mMessagingLayout.getMessagingGroups();
+ for (int i = 0; i < ownGroups.size(); i++) {
+ MessagingGroup ownGroup = ownGroups.get(i);
+ if (!isGone(ownGroup)) {
+ MessagingLinearLayout ownMessages = ownGroup.getMessageContainer();
+ for (int j = 0; j < ownMessages.getChildCount(); j++) {
+ View child = ownMessages.getChildAt(j);
+ if (isGone(child)) {
+ continue;
+ }
+ resetTransformedView(child);
+ setClippingDeactivated(child, false);
+ }
+ resetTransformedView(ownGroup.getAvatar());
+ resetTransformedView(ownGroup.getSender());
+ setClippingDeactivated(ownGroup.getAvatar(), false);
+ setClippingDeactivated(ownGroup.getSender(), false);
+ ownGroup.setTranslationY(0);
+ ownGroup.getMessageContainer().setTranslationY(0);
+ }
+ }
+ }
+
+ private void resetTransformedView(View child) {
+ TransformState ownState = TransformState.createFrom(child, mTransformInfo);
+ ownState.resetTransformedView();
+ ownState.recycle();
+ }
+
+ @Override
+ protected void reset() {
+ super.reset();
+ mMessageContainer = null;
+ mMessagingLayout = null;
+ }
+
+ @Override
+ public void recycle() {
+ super.recycle();
+ mGroupMap.clear();;
+ sInstancePool.release(this);
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
index f6ee1ca..fb5644f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMessagingTemplateViewWrapper.java
@@ -16,7 +16,9 @@
package com.android.systemui.statusbar.notification;
+import com.android.internal.widget.MessagingLayout;
import com.android.internal.widget.MessagingLinearLayout;
+import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.TransformableView;
@@ -32,41 +34,20 @@
*/
public class NotificationMessagingTemplateViewWrapper extends NotificationTemplateViewWrapper {
- private View mContractedMessage;
- private ArrayList<View> mHistoricMessages = new ArrayList<View>();
+ private final int mMinHeightWithActions;
+ private MessagingLayout mMessagingLayout;
+ private MessagingLinearLayout mMessagingLinearLayout;
protected NotificationMessagingTemplateViewWrapper(Context ctx, View view,
ExpandableNotificationRow row) {
super(ctx, view, row);
+ mMessagingLayout = (MessagingLayout) view;
+ mMinHeightWithActions = NotificationUtils.getFontScaledHeight(ctx,
+ R.dimen.notification_messaging_actions_min_height);
}
private void resolveViews() {
- mContractedMessage = null;
-
- View container = mView.findViewById(com.android.internal.R.id.notification_messaging);
- if (container instanceof MessagingLinearLayout
- && ((MessagingLinearLayout) container).getChildCount() > 0) {
- MessagingLinearLayout messagingContainer = (MessagingLinearLayout) container;
-
- int childCount = messagingContainer.getChildCount();
- for (int i = 0; i < childCount; i++) {
- View child = messagingContainer.getChildAt(i);
-
- if (child.getVisibility() == View.GONE
- && child instanceof TextView
- && !TextUtils.isEmpty(((TextView) child).getText())) {
- mHistoricMessages.add(child);
- }
-
- // Only consider the first visible child - transforming to a position other than the
- // first looks bad because we have to move across other messages that are fading in.
- if (child.getId() == messagingContainer.getContractedChildId()) {
- mContractedMessage = child;
- } else if (child.getVisibility() == View.VISIBLE) {
- break;
- }
- }
- }
+ mMessagingLinearLayout = mMessagingLayout.getMessagingLinearLayout();
}
@Override
@@ -81,16 +62,22 @@
protected void updateTransformedTypes() {
// This also clears the existing types
super.updateTransformedTypes();
- if (mContractedMessage != null) {
- mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
- mContractedMessage);
+ if (mMessagingLinearLayout != null) {
+ mTransformationHelper.addTransformedView(mMessagingLinearLayout.getId(),
+ mMessagingLinearLayout);
}
}
@Override
public void setRemoteInputVisible(boolean visible) {
- for (int i = 0; i < mHistoricMessages.size(); i++) {
- mHistoricMessages.get(i).setVisibility(visible ? View.VISIBLE : View.GONE);
+ mMessagingLayout.showHistoricMessages(visible);
+ }
+
+ @Override
+ public int getMinLayoutHeight() {
+ if (mActionsContainer != null && mActionsContainer.getVisibility() != View.GONE) {
+ return mMinHeightWithActions;
}
+ return super.getMinLayoutHeight();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index bb979eb..fd085d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -41,7 +41,7 @@
private ProgressBar mProgressBar;
private TextView mTitle;
private TextView mText;
- private View mActionsContainer;
+ protected View mActionsContainer;
private View mReplyAction;
private Rect mTmpRect = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
index 3115361..af393c9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationUtils.java
@@ -66,4 +66,14 @@
Settings.System.HAPTIC_FEEDBACK_ENABLED, 0, UserHandle.USER_CURRENT) == 0;
}
+ /**
+ * @param dimenId the dimen to look up
+ * @return the font scaled dimen as if it were in sp but doesn't shrink sizes below dp
+ */
+ public static int getFontScaledHeight(Context context, int dimenId) {
+ int dimensionPixelSize = context.getResources().getDimensionPixelSize(dimenId);
+ float factor = Math.max(1.0f, context.getResources().getDisplayMetrics().scaledDensity /
+ context.getResources().getDisplayMetrics().density);
+ return (int) (dimensionPixelSize * factor);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index 5200d69..1cd5f15 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -190,4 +190,8 @@
public boolean disallowSingleClick(float x, float y) {
return false;
}
+
+ public int getMinLayoutHeight() {
+ return 0;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
index c4aabe4..178c813 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
@@ -33,8 +33,8 @@
private TextView mText;
@Override
- public void initFrom(View view) {
- super.initFrom(view);
+ public void initFrom(View view, TransformInfo transformInfo) {
+ super.initFrom(view, transformInfo);
if (view instanceof TextView) {
mText = (TextView) view;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index bafedff..ad07af0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -26,6 +26,8 @@
import android.widget.ProgressBar;
import android.widget.TextView;
+import com.android.internal.widget.MessagingPropertyAnimator;
+import com.android.internal.widget.ViewClippingUtil;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
import com.android.systemui.statusbar.CrossFadeHelper;
@@ -43,23 +45,46 @@
public static final int TRANSFORM_ALL = TRANSFORM_X | TRANSFORM_Y;
private static final float UNDEFINED = -1f;
- private static final int CLIP_CLIPPING_SET = R.id.clip_children_set_tag;
- private static final int CLIP_CHILDREN_TAG = R.id.clip_children_tag;
- private static final int CLIP_TO_PADDING = R.id.clip_to_padding_tag;
private static final int TRANSFORMATION_START_X = R.id.transformation_start_x_tag;
private static final int TRANSFORMATION_START_Y = R.id.transformation_start_y_tag;
private static final int TRANSFORMATION_START_SCLALE_X = R.id.transformation_start_scale_x_tag;
private static final int TRANSFORMATION_START_SCLALE_Y = R.id.transformation_start_scale_y_tag;
private static Pools.SimplePool<TransformState> sInstancePool = new Pools.SimplePool<>(40);
+ private static ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS
+ = new ViewClippingUtil.ClippingParameters() {
+ @Override
+ public boolean shouldFinish(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ return !row.isChildInGroup();
+ }
+ return false;
+ }
+
+ @Override
+ public void onClippingStateChanged(View view, boolean isClipping) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ if (isClipping) {
+ row.setClipToActualHeight(true);
+ } else if (row.isChildInGroup()) {
+ row.setClipToActualHeight(false);
+ }
+ }
+ }
+ };
protected View mTransformedView;
+ protected TransformInfo mTransformInfo;
private int[] mOwnPosition = new int[2];
private boolean mSameAsAny;
private float mTransformationEndY = UNDEFINED;
private float mTransformationEndX = UNDEFINED;
+ private Interpolator mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
- public void initFrom(View view) {
+ public void initFrom(View view, TransformInfo transformInfo) {
mTransformedView = view;
+ mTransformInfo = transformInfo;
}
/**
@@ -108,13 +133,16 @@
final View transformedView = mTransformedView;
boolean transformX = (transformationFlags & TRANSFORM_X) != 0;
boolean transformY = (transformationFlags & TRANSFORM_Y) != 0;
- boolean transformScale = transformScale(otherState);
+ boolean differentHeight = otherState.getViewHeight() != getViewHeight();
+ boolean differentWidth = otherState.getViewWidth() != getViewWidth();
+ boolean transformScale = transformScale(otherState) && (differentHeight || differentWidth);
// lets animate the positions correctly
if (transformationAmount == 0.0f
|| transformX && getTransformationStartX() == UNDEFINED
|| transformY && getTransformationStartY() == UNDEFINED
- || transformScale && getTransformationStartScaleX() == UNDEFINED
- || transformScale && getTransformationStartScaleY() == UNDEFINED) {
+ || transformScale && getTransformationStartScaleX() == UNDEFINED && differentWidth
+ || transformScale && getTransformationStartScaleY() == UNDEFINED
+ && differentHeight) {
int[] otherPosition;
if (transformationAmount != 0.0f) {
otherPosition = otherState.getLaidOutLocationOnScreen();
@@ -132,14 +160,14 @@
}
// we also want to animate the scale if we're the same
View otherView = otherState.getTransformedView();
- if (transformScale && otherState.getViewWidth() != getViewWidth()) {
+ if (transformScale && differentWidth) {
setTransformationStartScaleX(otherState.getViewWidth() * otherView.getScaleX()
/ (float) getViewWidth());
transformedView.setPivotX(0);
} else {
setTransformationStartScaleX(UNDEFINED);
}
- if (transformScale && otherState.getViewHeight() != getViewHeight()) {
+ if (transformScale && differentHeight) {
setTransformationStartScaleY(otherState.getViewHeight() * otherView.getScaleY()
/ (float) getViewHeight());
transformedView.setPivotY(0);
@@ -159,7 +187,7 @@
}
setClippingDeactivated(transformedView, true);
}
- float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ float interpolatedValue = mDefaultInterpolator.getInterpolation(
transformationAmount);
if (transformX) {
float interpolation = interpolatedValue;
@@ -297,7 +325,7 @@
}
setClippingDeactivated(transformedView, true);
}
- float interpolatedValue = Interpolators.FAST_OUT_SLOW_IN.getInterpolation(
+ float interpolatedValue = mDefaultInterpolator.getInterpolation(
transformationAmount);
int[] otherStablePosition = otherState.getLaidOutLocationOnScreen();
int[] ownPosition = getLaidOutLocationOnScreen();
@@ -354,59 +382,8 @@
}
}
- public static void setClippingDeactivated(final View transformedView, boolean deactivated) {
- if (!(transformedView.getParent() instanceof ViewGroup)) {
- return;
- }
- ViewGroup view = (ViewGroup) transformedView.getParent();
- while (true) {
- ArraySet<View> clipSet = (ArraySet<View>) view.getTag(CLIP_CLIPPING_SET);
- if (clipSet == null) {
- clipSet = new ArraySet<>();
- view.setTag(CLIP_CLIPPING_SET, clipSet);
- }
- Boolean clipChildren = (Boolean) view.getTag(CLIP_CHILDREN_TAG);
- if (clipChildren == null) {
- clipChildren = view.getClipChildren();
- view.setTag(CLIP_CHILDREN_TAG, clipChildren);
- }
- Boolean clipToPadding = (Boolean) view.getTag(CLIP_TO_PADDING);
- if (clipToPadding == null) {
- clipToPadding = view.getClipToPadding();
- view.setTag(CLIP_TO_PADDING, clipToPadding);
- }
- ExpandableNotificationRow row = view instanceof ExpandableNotificationRow
- ? (ExpandableNotificationRow) view
- : null;
- if (!deactivated) {
- clipSet.remove(transformedView);
- if (clipSet.isEmpty()) {
- view.setClipChildren(clipChildren);
- view.setClipToPadding(clipToPadding);
- view.setTag(CLIP_CLIPPING_SET, null);
- if (row != null) {
- row.setClipToActualHeight(true);
- }
- }
- } else {
- clipSet.add(transformedView);
- view.setClipChildren(false);
- view.setClipToPadding(false);
- if (row != null && row.isChildInGroup()) {
- // We still want to clip to the parent's height
- row.setClipToActualHeight(false);
- }
- }
- if (row != null && !row.isChildInGroup()) {
- return;
- }
- final ViewParent parent = view.getParent();
- if (parent instanceof ViewGroup) {
- view = (ViewGroup) parent;
- } else {
- return;
- }
- }
+ protected void setClippingDeactivated(final View transformedView, boolean deactivated) {
+ ViewClippingUtil.setClippingDeactivated(transformedView, deactivated, CLIPPING_PARAMETERS);
}
public int[] getLaidOutLocationOnScreen() {
@@ -423,6 +400,9 @@
// remove scale
mOwnPosition[0] -= (1.0f - mTransformedView.getScaleX()) * mTransformedView.getPivotX();
mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
+
+ // Remove local translations
+ mOwnPosition[1] -= MessagingPropertyAnimator.getLocalTranslationY(mTransformedView);
return mOwnPosition;
}
@@ -444,20 +424,26 @@
CrossFadeHelper.fadeOut(mTransformedView, transformationAmount);
}
- public static TransformState createFrom(View view) {
+ public static TransformState createFrom(View view,
+ TransformInfo transformInfo) {
if (view instanceof TextView) {
TextViewTransformState result = TextViewTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
return result;
}
if (view.getId() == com.android.internal.R.id.actions_container) {
ActionListTransformState result = ActionListTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
+ return result;
+ }
+ if (view.getId() == com.android.internal.R.id.notification_messaging) {
+ MessagingLayoutTransformState result = MessagingLayoutTransformState.obtain();
+ result.initFrom(view, transformInfo);
return result;
}
if (view instanceof ImageView) {
ImageTransformState result = ImageTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
if (view.getId() == com.android.internal.R.id.reply_icon_action) {
((TransformState) result).setIsSameAsAnyView(true);
}
@@ -465,15 +451,15 @@
}
if (view instanceof ProgressBar) {
ProgressTransformState result = ProgressTransformState.obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
return result;
}
TransformState result = obtain();
- result.initFrom(view);
+ result.initFrom(view, transformInfo);
return result;
}
- private void setIsSameAsAnyView(boolean sameAsAny) {
+ public void setIsSameAsAnyView(boolean sameAsAny) {
mSameAsAny = sameAsAny;
}
@@ -533,6 +519,7 @@
mSameAsAny = false;
mTransformationEndX = UNDEFINED;
mTransformationEndY = UNDEFINED;
+ mDefaultInterpolator = Interpolators.FAST_OUT_SLOW_IN;
}
public void setVisible(boolean visible, boolean force) {
@@ -578,4 +565,12 @@
public View getTransformedView() {
return mTransformedView;
}
+
+ public void setDefaultInterpolator(Interpolator interpolator) {
+ mDefaultInterpolator = interpolator;
+ }
+
+ public interface TransformInfo {
+ boolean isAnimating();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index d226fed..1c361ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -175,9 +175,8 @@
private boolean isLight(int vis, int barMode, int flag) {
boolean isTransparentBar = (barMode == MODE_TRANSPARENT
|| barMode == MODE_LIGHTS_OUT_TRANSPARENT);
- boolean allowLight = isTransparentBar && !mBatteryController.isPowerSave();
boolean light = (vis & flag) != 0;
- return allowLight && light;
+ return isTransparentBar && light;
}
private boolean animateChange() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 8e0a506..717699b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -20,6 +20,8 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
@@ -29,9 +31,11 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.policy.DividerSnapAlgorithm.SnapTarget;
import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper;
+import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.tuner.TunerService;
@@ -45,6 +49,7 @@
public class NavigationBarGestureHelper extends GestureDetector.SimpleOnGestureListener
implements TunerService.Tunable, GestureHelper {
+ private static final String TAG = "NavBarGestureHelper";
private static final String KEY_DOCK_WINDOW_GESTURE = "overview_nav_bar_gesture";
/**
* When dragging from the navigation bar, we drag in recents.
@@ -75,6 +80,7 @@
private int mTouchDownY;
private boolean mDownOnRecents;
private VelocityTracker mVelocityTracker;
+ private OverviewProxyService mOverviewEventSender = Dependency.get(OverviewProxyService.class);
private boolean mDockWindowEnabled;
private boolean mDockWindowTouchSlopExceeded;
@@ -107,6 +113,16 @@
}
public boolean onInterceptTouchEvent(MotionEvent event) {
+ final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
+ if (overviewProxy != null) {
+ mNavigationBarView.requestUnbufferedDispatch(event);
+ try {
+ overviewProxy.onMotionEvent(event);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Callback failed", e);
+ }
+ }
+
// If we move more than a fixed amount, then start capturing for the
// task switcher detector
mTaskSwitcherDetector.onTouchEvent(event);
@@ -122,9 +138,8 @@
int y = (int) event.getY();
int xDiff = Math.abs(x - mTouchDownX);
int yDiff = Math.abs(y - mTouchDownY);
- boolean exceededTouchSlop = !mIsVertical
- ? xDiff > mScrollTouchSlop && xDiff > yDiff
- : yDiff > mScrollTouchSlop && yDiff > xDiff;
+ boolean exceededTouchSlop = xDiff > mScrollTouchSlop && xDiff > yDiff
+ || yDiff > mScrollTouchSlop && yDiff > xDiff;
if (exceededTouchSlop) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index b876286b..ba4ff58 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -65,8 +65,8 @@
import com.android.systemui.UiOffloadThread;
import com.android.systemui.qs.tiles.DndTile;
import com.android.systemui.qs.tiles.RotationLockTile;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CommandQueue.Callbacks;
import com.android.systemui.statusbar.policy.BluetoothController;
@@ -768,7 +768,7 @@
mIconController.setIconVisibility(mSlotDataSaver, isDataSaving);
}
- private final TaskStackChangeListener mTaskListener = new TaskStackChangeListener() {
+ private final SysUiTaskStackChangeListener mTaskListener = new SysUiTaskStackChangeListener() {
@Override
public void onTaskStackChanged() {
// Listen for changes to stacks and then check which instant apps are foreground.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index fa2b8e8..46e3aa1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static android.app.StatusBarManager.DISABLE2_NOTIFICATION_SHADE;
import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.StatusBarManager.windowStateToString;
@@ -145,6 +146,8 @@
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.util.NotificationMessagingUtil;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.MessagingGroup;
+import com.android.internal.widget.MessagingMessage;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -157,6 +160,7 @@
import com.android.systemui.EventLogTags;
import com.android.systemui.ForegroundServiceController;
import com.android.systemui.Interpolators;
+import com.android.systemui.OverviewProxyService;
import com.android.systemui.Prefs;
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
@@ -271,7 +275,7 @@
public static final boolean ENABLE_CHILD_NOTIFICATIONS
= SystemProperties.getBoolean("debug.child_notifs", true);
public static final boolean FORCE_REMOTE_INPUT_HISTORY =
- SystemProperties.getBoolean("debug.force_remoteinput_history", false);
+ SystemProperties.getBoolean("debug.force_remoteinput_history", true);
private static final boolean ENABLE_LOCK_SCREEN_ALLOW_REMOTE_INPUT = false;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
@@ -874,6 +878,7 @@
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_PRESENT);
+ filter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiver(mBaseBroadcastReceiver, filter);
IntentFilter internalFilter = new IntentFilter();
@@ -1229,6 +1234,8 @@
}
public void onDensityOrFontScaleChanged() {
+ MessagingMessage.dropCache();
+ MessagingGroup.dropCache();
// start old BaseStatusBar.onDensityOrFontScaleChanged().
if (!KeyguardUpdateMonitor.getInstance(mContext).isSwitchingUser()) {
updateNotificationsOnDensityOrFontScaleChanged();
@@ -1682,8 +1689,9 @@
clearCurrentMediaNotification();
updateMediaMetaData(true, true);
}
- if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)) {
- Entry entry = mNotificationData.get(key);
+ Entry entry = mNotificationData.get(key);
+ if (FORCE_REMOTE_INPUT_HISTORY && mRemoteInputController.isSpinning(key)
+ && entry.row != null && !entry.row.isDismissed()) {
StatusBarNotification sbn = entry.notification;
Notification.Builder b = Notification.Builder
@@ -1719,6 +1727,7 @@
deferRemoval = false;
}
if (updated) {
+ Log.w(TAG, "Keeping notification around after sending remote input "+ entry.key);
mKeysKeptForRemoteInput.add(entry.key);
return;
}
@@ -1728,7 +1737,6 @@
mHeadsUpEntriesToRemoveOnSwitch.add(mHeadsUpManager.getEntry(key));
return;
}
- Entry entry = mNotificationData.get(key);
if (entry != null && mRemoteInputController.isRemoteInputActive(entry)
&& (entry.row != null && !entry.row.isDismissed())) {
@@ -3275,12 +3283,8 @@
}
void checkBarMode(int mode, int windowState, BarTransitions transitions) {
- final boolean powerSave = mBatteryController.isPowerSave();
final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
- && windowState != WINDOW_STATE_HIDDEN && !powerSave;
- if (powerSave && getBarState() == StatusBarState.SHADE) {
- mode = MODE_WARNING;
- }
+ && windowState != WINDOW_STATE_HIDDEN;
transitions.transitionTo(mode, anim);
}
@@ -5265,7 +5269,8 @@
boolean isCameraAllowedByAdmin() {
if (mDevicePolicyManager.getCameraDisabled(null, mCurrentUserId)) {
return false;
- } else if (isKeyguardShowing() && isKeyguardSecure()) {
+ } else if (mStatusBarKeyguardViewManager == null ||
+ (isKeyguardShowing() && isKeyguardSecure())) {
// Check if the admin has disabled the camera specifically for the keyguard
return (mDevicePolicyManager.getKeyguardDisabledFeatures(null, mCurrentUserId)
& DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA) == 0;
@@ -5882,6 +5887,9 @@
userSwitched(mCurrentUserId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
updateCurrentProfilesCache();
+ } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+ // Start the overview connection to the launcher service
+ Dependency.get(OverviewProxyService.class).startConnectionToCurrentUser();
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
List<ActivityManager.RecentTaskInfo> recentTask = null;
try {
@@ -7096,7 +7104,9 @@
}
public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
- return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
+ return mShowLockscreenNotifications
+ && ((mDisabled2 & DISABLE2_NOTIFICATION_SHADE) == 0)
+ && !mNotificationData.isAmbient(sbn.getKey());
}
// extended in StatusBar
@@ -7108,7 +7118,7 @@
mAllowLockscreenRemoteInput = allowLockscreenRemoteInput;
}
- private void updateLockscreenNotificationSetting() {
+ protected void updateLockscreenNotificationSetting() {
final boolean show = Settings.Secure.getIntForUser(mContext.getContentResolver(),
Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS,
1,
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/doze/DozeScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
index 720e9f0..a17a95f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStatePreventingAdapterTest.java
@@ -70,7 +70,7 @@
@Test
public void forwards_setDozeScreenState_doze_suspend() throws Exception {
mWrapper.setDozeScreenState(Display.STATE_DOZE_SUSPEND);
- verify(mInner).setDozeScreenState(Display.STATE_ON);
+ verify(mInner).setDozeScreenState(Display.STATE_ON_SUSPEND);
}
@Test
@@ -95,4 +95,4 @@
assertSame(mInner, DozeScreenStatePreventingAdapter.wrapIfNeeded(mInner, params));
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
index d78e739..ed93561 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuspendScreenStatePreventingAdapterTest.java
@@ -74,6 +74,12 @@
}
@Test
+ public void forwards_setDozeScreenState_on_suspend() throws Exception {
+ mWrapper.setDozeScreenState(Display.STATE_ON_SUSPEND);
+ verify(mInner).setDozeScreenState(Display.STATE_ON_SUSPEND);
+ }
+
+ @Test
public void forwards_requestWakeUp() throws Exception {
mWrapper.requestWakeUp();
verify(mInner).requestWakeUp();
@@ -95,4 +101,4 @@
assertSame(mInner, DozeSuspendScreenStatePreventingAdapter.wrapIfNeeded(mInner, params));
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
new file mode 100644
index 0000000..4437aac
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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.keyguard;
+
+import android.app.slice.Slice;
+import android.app.slice.SliceItem;
+import android.app.slice.SliceQuery;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Handler;
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
+public class KeyguardSliceProviderTest extends SysuiTestCase {
+
+ private TestableKeyguardSliceProvider mProvider;
+
+ @Before
+ public void setup() {
+ mProvider = new TestableKeyguardSliceProvider();
+ mProvider.attachInfo(getContext(), null);
+ }
+
+ @Test
+ public void registersClockUpdate() {
+ Assert.assertTrue("registerClockUpdate should have been called during initialization.",
+ mProvider.isRegistered());
+ }
+
+ @Test
+ public void unregisterClockUpdate() {
+ mProvider.unregisterClockUpdate();
+ Assert.assertFalse("Clock updates should have been unregistered.",
+ mProvider.isRegistered());
+ }
+
+ @Test
+ public void returnsValidSlice() {
+ Slice slice = mProvider.onBindSlice(Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI));
+ SliceItem text = SliceQuery.find(slice, SliceItem.TYPE_TEXT, Slice.HINT_TITLE,
+ null /* nonHints */);
+ Assert.assertNotNull("Slice must provide a title.", text);
+ }
+
+ @Test
+ public void cleansDateFormat() {
+ mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIMEZONE_CHANGED));
+ TestableLooper.get(this).processAllMessages();
+ Assert.assertEquals("Date format should have been cleaned.", 1 /* expected */,
+ mProvider.mCleanDateFormatInvokations);
+ }
+
+ @Test
+ public void updatesClock() {
+ mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK));
+ TestableLooper.get(this).processAllMessages();
+ Assert.assertEquals("Clock should have been updated.", 2 /* expected */,
+ mProvider.mUpdateClockInvokations);
+ }
+
+ private class TestableKeyguardSliceProvider extends KeyguardSliceProvider {
+ int mCleanDateFormatInvokations;
+ int mUpdateClockInvokations;
+
+ TestableKeyguardSliceProvider() {
+ super(new Handler(TestableLooper.get(KeyguardSliceProviderTest.this).getLooper()));
+ }
+
+ @Override
+ void cleanDateFormat() {
+ super.cleanDateFormat();
+ mCleanDateFormatInvokations++;
+ }
+
+ @Override
+ protected void updateClock() {
+ super.updateClock();
+ mUpdateClockInvokations++;
+ }
+ }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
index b86fc21..d758314 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/WorkLockActivityControllerTest.java
@@ -20,7 +20,6 @@
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.argThat;
@@ -41,10 +40,8 @@
import android.support.test.runner.AndroidJUnit4;
import com.android.systemui.SysuiTestCase;
-import com.android.systemui.keyguard.WorkLockActivity;
-import com.android.systemui.keyguard.WorkLockActivityController;
+import com.android.systemui.recents.misc.SysUiTaskStackChangeListener;
import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.TaskStackChangeListener;
import org.junit.Before;
import org.junit.Test;
@@ -68,7 +65,7 @@
private @Mock IActivityManager mIActivityManager;
private WorkLockActivityController mController;
- private TaskStackChangeListener mTaskStackListener;
+ private SysUiTaskStackChangeListener mTaskStackListener;
@Before
public void setUp() throws Exception {
@@ -78,8 +75,8 @@
doReturn("com.example.test").when(mContext).getPackageName();
// Construct controller. Save the TaskStackListener for injecting events.
- final ArgumentCaptor<TaskStackChangeListener> listenerCaptor =
- ArgumentCaptor.forClass(TaskStackChangeListener.class);
+ final ArgumentCaptor<SysUiTaskStackChangeListener> listenerCaptor =
+ ArgumentCaptor.forClass(SysUiTaskStackChangeListener.class);
mController =
new WorkLockActivityController(mContext, mSystemServicesProxy, mIActivityManager);
@@ -97,7 +94,7 @@
// The overlay should start and the task the activity started in should not be removed.
verifyStartActivity(TASK_ID, true /*taskOverlay*/);
- verify(mSystemServicesProxy, never()).removeTask(anyInt() /*taskId*/);
+ verify(mIActivityManager, never()).removeTask(anyInt() /*taskId*/);
}
@Test
@@ -111,7 +108,7 @@
// The task the activity started in should be removed to prevent the locked task from
// being shown.
verifyStartActivity(TASK_ID, true /*taskOverlay*/);
- verify(mSystemServicesProxy).removeTask(TASK_ID);
+ verify(mIActivityManager).removeTask(TASK_ID);
}
// End of tests, start of helpers
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/proto/src/ipconnectivity.proto b/proto/src/ipconnectivity.proto
index 437da8f..327f17d 100644
--- a/proto/src/ipconnectivity.proto
+++ b/proto/src/ipconnectivity.proto
@@ -50,9 +50,10 @@
optional int32 value = 2;
};
-// An event record when the system default network disconnects or the system
-// switches to a new default network.
-// Next tag: 10.
+// An event recorded when the system default network disconnects or the system
+// switches to a new default network. An event is also recorded to cover gaps
+// without a default network.
+// Next tag: 12
message DefaultNetworkEvent {
// Reason why this network stopped being the default.
@@ -72,26 +73,34 @@
};
// Duration in milliseconds when this network was the default.
- // Since version 4
+ // Since P.
optional int64 default_network_duration_ms = 5;
- // Duration in milliseconds without a default network before this network
- // became the default.
- // Since version 4
- optional int64 no_default_network_duration_ms = 6;
+ // Duration in milliseconds when this default network Internet access was
+ // validated. This field is equal to 0 for DefaultNetworkEvents representing
+ // lack of a default network.
+ // Since P.
+ optional int64 validation_duration_ms = 11;
// Network score of this network when it became the default network.
- // Since version 4
+ // Or 0 if this event represents a period without a default network.
+ // Since P.
optional int64 initial_score = 7;
// Network score of this network when it stopped being the default network.
- // Since version 4
+ // Or 0 if this event represents a period without a default network.
+ // Since P.
optional int64 final_score = 8;
// Best available information about IP support of this default network.
- // Since version 4
+ // Or NONE if this event represents a period without a default network.
+ // Since P.
optional IPSupport ip_support = 9;
+ // LinkLayer of the previous default network. Ignores any previous period
+ // without a default network.
+ // Since P
+ optional LinkLayer previous_default_network_link_layer = 10;
// Deprecated fields
@@ -112,6 +121,11 @@
// TRANSPORT_* constants as defined in NetworkCapabilities.
// Deprecated since version 3. Replaced by top-level transports field.
repeated int32 transport_types = 4 [deprecated = true];
+
+ // Duration in milliseconds without a default network. This field is non-zero
+ // only for DefaultNetworkEvents representing lack of a default network.
+ // Since P.
+ optional int64 no_default_network_duration_ms = 6 [deprecated = true];
};
// Logs IpReachabilityMonitor probe events and NUD_FAILED events.
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 2e0f394..d3dcf5a 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -2799,420 +2799,316 @@
// OS: O
TEXT_LONGPRESS = 629;
- // ACTION: An app requested an unknown permission
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_UNKNOWN = 630;
- // ACTION: An app was granted an unknown permission
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_UNKNOWN = 631;
- // ACTION: An app requested an unknown permission and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_UNKNOWN = 632;
- // ACTION: An unknown permission was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_UNKNOWN = 633;
- // ACTION: An app requested the permission READ_CALENDAR
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_CALENDAR = 634;
- // ACTION: An app was granted the permission READ_CALENDAR
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CALENDAR = 635;
- // ACTION: An app requested the permission READ_CALENDAR and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CALENDAR = 636;
- // ACTION: The permission READ_CALENDAR was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CALENDAR = 637;
- // ACTION: An app requested the permission WRITE_CALENDAR
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CALENDAR = 638;
- // ACTION: An app was granted the permission WRITE_CALENDAR
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CALENDAR = 639;
- // ACTION: An app requested the permission WRITE_CALENDAR and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CALENDAR = 640;
- // ACTION: The permission WRITE_CALENDAR was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CALENDAR = 641;
- // ACTION: An app requested the permission CAMERA
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_CAMERA = 642;
- // ACTION: An app was granted the permission CAMERA
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_CAMERA = 643;
- // ACTION: An app requested the permission CAMERA and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_CAMERA = 644;
- // ACTION: The permission CAMERA was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_CAMERA = 645;
- // ACTION: An app requested the permission READ_CONTACTS
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_READ_CONTACTS = 646;
- // ACTION: An app was granted the permission READ_CONTACTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CONTACTS = 647;
- // ACTION: An app requested the permission READ_CONTACTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CONTACTS = 648;
- // ACTION: The permission READ_CONTACTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CONTACTS = 649;
- // ACTION: An app requested the permission WRITE_CONTACTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CONTACTS = 650;
- // ACTION: An app was granted the permission WRITE_CONTACTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CONTACTS = 651;
- // ACTION: An app requested the permission WRITE_CONTACTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CONTACTS = 652;
- // ACTION: The permission WRITE_CONTACTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CONTACTS = 653;
- // ACTION: An app requested the permission GET_ACCOUNTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_GET_ACCOUNTS = 654;
- // ACTION: An app was granted the permission GET_ACCOUNTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_GET_ACCOUNTS = 655;
- // ACTION: An app requested the permission GET_ACCOUNTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_GET_ACCOUNTS = 656;
- // ACTION: The permission GET_ACCOUNTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_GET_ACCOUNTS = 657;
- // ACTION: An app requested the permission ACCESS_FINE_LOCATION
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_ACCESS_FINE_LOCATION = 658;
- // ACTION: An app was granted the permission ACCESS_FINE_LOCATION
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ACCESS_FINE_LOCATION = 659;
- // ACTION: An app requested the permission ACCESS_FINE_LOCATION and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ACCESS_FINE_LOCATION = 660;
- // ACTION: The permission ACCESS_FINE_LOCATION was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ACCESS_FINE_LOCATION = 661;
- // ACTION: An app requested the permission ACCESS_COARSE_LOCATION
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_ACCESS_COARSE_LOCATION = 662;
- // ACTION: An app was granted the permission ACCESS_COARSE_LOCATION
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ACCESS_COARSE_LOCATION = 663;
- // ACTION: An app requested the permission ACCESS_COARSE_LOCATION and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ACCESS_COARSE_LOCATION = 664;
- // ACTION: The permission ACCESS_COARSE_LOCATION was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ACCESS_COARSE_LOCATION = 665;
- // ACTION: An app requested the permission RECORD_AUDIO
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECORD_AUDIO = 666;
- // ACTION: An app was granted the permission RECORD_AUDIO
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECORD_AUDIO = 667;
- // ACTION: An app requested the permission RECORD_AUDIO and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECORD_AUDIO = 668;
- // ACTION: The permission RECORD_AUDIO was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECORD_AUDIO = 669;
- // ACTION: An app requested the permission READ_PHONE_STATE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_PHONE_STATE = 670;
- // ACTION: An app was granted the permission READ_PHONE_STATE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_PHONE_STATE = 671;
- // ACTION: An app requested the permission READ_PHONE_STATE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_PHONE_STATE = 672;
- // ACTION: The permission READ_PHONE_STATE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_PHONE_STATE = 673;
- // ACTION: An app requested the permission CALL_PHONE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_CALL_PHONE = 674;
- // ACTION: An app was granted the permission CALL_PHONE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_CALL_PHONE = 675;
- // ACTION: An app requested the permission CALL_PHONE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_CALL_PHONE = 676;
- // ACTION: The permission CALL_PHONE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_CALL_PHONE = 677;
- // ACTION: An app requested the permission READ_CALL_LOG
- // PACKAGE: The package name of the app requesting the permission
+ // AOBSOLETE
ACTION_PERMISSION_REQUEST_READ_CALL_LOG = 678;
- // ACTION: An app was granted the permission READ_CALL_LOG
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CALL_LOG = 679;
- // ACTION: An app requested the permission READ_CALL_LOG and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CALL_LOG = 680;
- // ACTION: The permission READ_CALL_LOG was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CALL_LOG = 681;
- // ACTION: An app requested the permission WRITE_CALL_LOG
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_CALL_LOG = 682;
- // ACTION: An app was granted the permission WRITE_CALL_LOG
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_CALL_LOG = 683;
- // ACTION: An app requested the permission WRITE_CALL_LOG and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_CALL_LOG = 684;
- // ACTION: The permission WRITE_CALL_LOG was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_CALL_LOG = 685;
- // ACTION: An app requested the permission ADD_VOICEMAIL
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_ADD_VOICEMAIL = 686;
- // ACTION: An app was granted the permission ADD_VOICEMAIL
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_ADD_VOICEMAIL = 687;
- // ACTION: An app requested the permission ADD_VOICEMAIL and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_ADD_VOICEMAIL = 688;
- // ACTION: The permission ADD_VOICEMAIL was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_ADD_VOICEMAIL = 689;
- // ACTION: An app requested the permission USE_SIP
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_USE_SIP = 690;
- // ACTION: An app was granted the permission USE_SIP
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_USE_SIP = 691;
- // ACTION: An app requested the permission USE_SIP and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_USE_SIP = 692;
- // ACTION: The permission USE_SIP was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_USE_SIP = 693;
- // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_PROCESS_OUTGOING_CALLS = 694;
- // ACTION: An app was granted the permission PROCESS_OUTGOING_CALLS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_PROCESS_OUTGOING_CALLS = 695;
- // ACTION: An app requested the permission PROCESS_OUTGOING_CALLS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_PROCESS_OUTGOING_CALLS = 696;
- // ACTION: The permission PROCESS_OUTGOING_CALLS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_PROCESS_OUTGOING_CALLS = 697;
- // ACTION: An app requested the permission READ_CELL_BROADCASTS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_CELL_BROADCASTS = 698;
- // ACTION: An app was granted the permission READ_CELL_BROADCASTS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_CELL_BROADCASTS = 699;
- // ACTION: An app requested the permission READ_CELL_BROADCASTS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_CELL_BROADCASTS = 700;
- // ACTION: The permission READ_CELL_BROADCASTS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_CELL_BROADCASTS = 701;
- // ACTION: An app requested the permission BODY_SENSORS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_BODY_SENSORS = 702;
- // ACTION: An app was granted the permission BODY_SENSORS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_BODY_SENSORS = 703;
- // ACTION: An app requested the permission BODY_SENSORS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_BODY_SENSORS = 704;
- // ACTION: The permission BODY_SENSORS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_BODY_SENSORS = 705;
- // ACTION: An app requested the permission SEND_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_SEND_SMS = 706;
- // ACTION: An app was granted the permission SEND_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_SEND_SMS = 707;
- // ACTION: An app requested the permission SEND_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_SEND_SMS = 708;
- // ACTION: The permission SEND_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_SEND_SMS = 709;
- // ACTION: An app requested the permission RECEIVE_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_SMS = 710;
- // ACTION: An app was granted the permission RECEIVE_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_SMS = 711;
- // ACTION: An app requested the permission RECEIVE_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_SMS = 712;
- // ACTION: The permission RECEIVE_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_SMS = 713;
- // ACTION: An app requested the permission READ_SMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_SMS = 714;
- // ACTION: An app was granted the permission READ_SMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_SMS = 715;
- // ACTION: An app requested the permission READ_SMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_SMS = 716;
- // ACTION: The permission READ_SMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_SMS = 717;
- // ACTION: An app requested the permission RECEIVE_WAP_PUSH
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_WAP_PUSH = 718;
- // ACTION: An app was granted the permission RECEIVE_WAP_PUSH
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_WAP_PUSH = 719;
- // ACTION: An app requested the permission RECEIVE_WAP_PUSH and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_WAP_PUSH = 720;
- // ACTION: The permission RECEIVE_WAP_PUSH was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_WAP_PUSH = 721;
- // ACTION: An app requested the permission RECEIVE_MMS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_RECEIVE_MMS = 722;
- // ACTION: An app was granted the permission RECEIVE_MMS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_RECEIVE_MMS = 723;
- // ACTION: An app requested the permission RECEIVE_MMS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_RECEIVE_MMS = 724;
- // ACTION: The permission RECEIVE_MMS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_RECEIVE_MMS = 725;
- // ACTION: An app requested the permission READ_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_EXTERNAL_STORAGE = 726;
- // ACTION: An app was granted the permission READ_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_EXTERNAL_STORAGE = 727;
- // ACTION: An app requested the permission READ_EXTERNAL_STORAGE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_EXTERNAL_STORAGE = 728;
- // ACTION: The permission READ_EXTERNAL_STORAGE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_EXTERNAL_STORAGE = 729;
- // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_WRITE_EXTERNAL_STORAGE = 730;
- // ACTION: An app was granted the permission WRITE_EXTERNAL_STORAGE
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_WRITE_EXTERNAL_STORAGE = 731;
- // ACTION: An app requested the permission WRITE_EXTERNAL_STORAGE and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_WRITE_EXTERNAL_STORAGE = 732;
- // ACTION: The permission WRITE_EXTERNAL_STORAGE was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_WRITE_EXTERNAL_STORAGE = 733;
// ACTION: Logged when a provisioning session has started
@@ -3221,20 +3117,16 @@
// ACTION: Logged when a provisioning session has completed
PROVISIONING_SESSION_COMPLETED = 735;
- // ACTION: An app requested the permission READ_PHONE_NUMBERS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_REQUEST_READ_PHONE_NUMBERS = 736;
- // ACTION: An app was granted the permission READ_PHONE_NUMBERS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_PERMISSION_GRANT_READ_PHONE_NUMBERS = 737;
- // ACTION: An app requested the permission READ_PHONE_NUMBERS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_PERMISSION_DENIED_READ_PHONE_NUMBERS = 738;
- // ACTION: The permission READ_PHONE_NUMBERS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_PERMISSION_REVOKE_READ_PHONE_NUMBERS = 739;
// ACTION: QS Brightness Slider (with auto brightness disabled, and VR enabled)
@@ -3726,68 +3618,52 @@
// CATEGORY: SETTINGS
SETTINGS_LOCK_SCREEN_PREFERENCES = 882;
- // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_ACCESS_NOTIFICATIONS = 883;
- // ACTION: An app was granted the app-op permission ACCESS_NOTIFICATIONS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_ACCESS_NOTIFICATIONS = 884;
- // ACTION: An app requested the app-op permission ACCESS_NOTIFICATIONS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_ACCESS_NOTIFICATIONS = 885;
- // ACTION: The app-op permission ACCESS_NOTIFICATIONS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_ACCESS_NOTIFICATIONS = 886;
- // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_SYSTEM_ALERT_WINDOW = 887;
- // ACTION: An app was granted the app-op permission SYSTEM_ALERT_WINDOW
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_SYSTEM_ALERT_WINDOW = 888;
- // ACTION: An app requested the app-op permission SYSTEM_ALERT_WINDOW and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_SYSTEM_ALERT_WINDOW = 889;
- // ACTION: The app-op permission SYSTEM_ALERT_WINDOW was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_SYSTEM_ALERT_WINDOW = 890;
- // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_WRITE_SETTINGS = 891;
- // ACTION: An app was granted the app-op permission REQUEST_WRITE_SETTINGS
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_WRITE_SETTINGS = 892;
- // ACTION: An app requested the app-op permission REQUEST_WRITE_SETTINGS and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_WRITE_SETTINGS = 893;
- // ACTION: The app-op permission REQUEST_WRITE_SETTINGS was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_WRITE_SETTINGS = 894;
- // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_REQUEST_REQUEST_INSTALL_PACKAGES = 895;
- // ACTION: An app was granted the app-op permission REQUEST_INSTALL_PACKAGES
- // PACKAGE: The package name of the app that was granted the permission
+ // OBSOLETE
ACTION_APPOP_GRANT_REQUEST_INSTALL_PACKAGES = 896;
- // ACTION: An app requested the app-op permission REQUEST_INSTALL_PACKAGES and the request was denied
- // PACKAGE: The package name of the app requesting the permission
+ // OBSOLETE
ACTION_APPOP_DENIED_REQUEST_INSTALL_PACKAGES = 897;
- // ACTION: The app-op permission REQUEST_INSTALL_PACKAGES was revoked for an app
- // PACKAGE: The package name of the app the permission was revoked for
+ // OBSOLETE
ACTION_APPOP_REVOKE_REQUEST_INSTALL_PACKAGES = 898;
// ACTION: Phase 1 of instant application resolution occurred
@@ -4567,6 +4443,10 @@
// OS: O MR
COLOR_MODE_SETTINGS = 1143;
+ // Enclosing category for group of APP_TRANSITION_FOO events,
+ // logged when we cancel an app transition.
+ APP_TRANSITION_CANCELLED = 1144;
+
// ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
// OPEN: Settings > Network & Internet > Mobile network
@@ -4754,6 +4634,52 @@
// OS: P
DIALOG_OEM_LOCK_INFO = 1238;
+ // ACTION: Settings > Wi-Fi > Click one network > Auto sign in
+ // CATEGORY: SETTINGS
+ // OS: P
+ ACTION_WIFI_AUTO_SIGN_IN = 1239;
+
+ // Open: Settings > System > About phone > IMEI
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_IMEI_INFO = 1240;
+
+ // In permission action fields tagged like this reference the permission affected
+ FIELD_PERMISSION = 1241;
+
+ // ACTION: An app requested a permission and we asked to user to approve the request
+ // PACKAGE: The package name of the app requesting the permission
+ // Tag FIELD_PERMISSION: Name of the permission requested
+ ACTION_PERMISSION_REQUESTED = 1242;
+
+ // ACTION: An app was granted the a permission. This can happen after a user approved a request
+ // or automatically. In the second case there will not be an
+ // ACTION_PERMISSION_REQUESTED.
+ // PACKAGE: The package name of the app that was granted the permission
+ // Tag FIELD_PERMISSION: Name of the permission granted
+ ACTION_PERMISSION_GRANTED = 1243;
+
+ // ACTION: An app requested the a permission and the request was denied by the user or a device
+ // policy
+ // PACKAGE: The package name of the app requesting the permission
+ // Tag FIELD_PERMISSION: Name of the permission denied
+ ACTION_PERMISSION_DENIED = 1244;
+
+ // ACTION: A permission was revoked
+ // PACKAGE: The package name of the app the permission was revoked for
+ // Tag FIELD_PERMISSION: Name of the permission revoked
+ ACTION_PERMISSION_REVOKED = 1245;
+
+ // OPEN: Settings > System > About Phone > Sim status
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_SIM_STATUS = 1246;
+
+ // OPEN: Settings > System > About Phone > Android Version
+ // CATEGORY: SETTINGS
+ // OS: P
+ DIALOG_FIRMWARE_VERSION = 1247;
+
// Add new aosp constants above this line.
// END OF AOSP CONSTANTS
}
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/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 236fbfd..02a62e1 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -28,6 +28,7 @@
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Objects;
@@ -112,4 +113,12 @@
}
return log;
}
+
+ public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable String text) {
+ if (text == null) {
+ pw.println("null");
+ } else {
+ pw.print(text.length()); pw.println("_chars");
+ }
+ }
}
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/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index 6d3d792..dac4586 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -49,6 +49,8 @@
import com.android.internal.R;
import com.android.server.UiThread;
+import com.android.server.autofill.Helper;
+
import libcore.util.Objects;
import java.io.PrintWriter;
@@ -466,7 +468,8 @@
pw.print(prefix); pw.print("mCallback: "); pw.println(mCallback != null);
pw.print(prefix); pw.print("mListView: "); pw.println(mListView);
pw.print(prefix); pw.print("mAdapter: "); pw.println(mAdapter != null);
- pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText);
+ pw.print(prefix); pw.print("mFilterText: ");
+ Helper.printlnRedactedText(pw, mFilterText);
pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 622b8423..e92a564 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -80,6 +80,7 @@
import android.content.pm.Signature;
import android.database.ContentObserver;
import android.net.Uri;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Binder;
import android.os.Build;
@@ -126,7 +127,6 @@
import com.android.server.SystemConfig;
import com.android.server.SystemService;
import com.android.server.backup.PackageManagerBackupAgent.Metadata;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
diff --git a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
index 20f2369..a45a4f0 100644
--- a/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/RefactoredBackupManagerService.java
@@ -71,6 +71,7 @@
import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Process;
import android.os.RemoteException;
@@ -120,7 +121,6 @@
import com.android.server.backup.utils.BackupManagerMonitorUtils;
import com.android.server.backup.utils.BackupObserverUtils;
import com.android.server.backup.utils.SparseArrayUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import com.google.android.collect.Sets;
diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
index 8d8a013..a08c19e 100644
--- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
+++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java
@@ -158,16 +158,19 @@
MSG_RESTORE_SESSION_TIMEOUT);
long oldId = Binder.clearCallingIdentity();
- backupManagerService.getWakelock().acquire();
- if (MORE_DEBUG) {
- Slog.d(TAG, "restoreAll() kicking off");
+ try {
+ backupManagerService.getWakelock().acquire();
+ if (MORE_DEBUG) {
+ Slog.d(TAG, "restoreAll() kicking off");
+ }
+ Message msg = backupManagerService.getBackupHandler().obtainMessage(
+ MSG_RUN_RESTORE);
+ msg.obj = new RestoreParams(mRestoreTransport, dirName,
+ observer, monitor, token);
+ backupManagerService.getBackupHandler().sendMessage(msg);
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
- Message msg = backupManagerService.getBackupHandler().obtainMessage(
- MSG_RUN_RESTORE);
- msg.obj = new RestoreParams(mRestoreTransport, dirName,
- observer, monitor, token);
- backupManagerService.getBackupHandler().sendMessage(msg);
- Binder.restoreCallingIdentity(oldId);
return 0;
}
}
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index ad30897..ea0ed27 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -38,7 +38,7 @@
import android.content.pm.PackageManager;
import android.hidl.manager.V1_0.IServiceManager;
import android.hidl.manager.V1_0.IServiceNotification;
-import android.hardware.health.V2_0.HealthInfo;
+import android.hardware.health.V1_0.HealthInfo;
import android.hardware.health.V2_0.IHealthInfoCallback;
import android.hardware.health.V2_0.IHealth;
import android.hardware.health.V2_0.Result;
@@ -49,6 +49,7 @@
import android.os.Binder;
import android.os.FileUtils;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.IBatteryPropertiesListener;
import android.os.IBatteryPropertiesRegistrar;
import android.os.IBinder;
@@ -56,6 +57,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Trace;
import android.os.UEventObserver;
import android.os.UserHandle;
import android.provider.Settings;
@@ -74,6 +76,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.concurrent.atomic.AtomicReference;
/**
@@ -175,6 +178,7 @@
private HealthServiceWrapper mHealthServiceWrapper;
private HealthHalCallback mHealthHalCallback;
private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
+ private HandlerThread mHandlerThread;
public BatteryService(Context context) {
super(context);
@@ -246,6 +250,7 @@
}
private void registerHealthCallback() {
+ traceBegin("HealthInitWrapper");
mHealthServiceWrapper = new HealthServiceWrapper();
mHealthHalCallback = new HealthHalCallback();
// IHealth is lazily retrieved.
@@ -259,8 +264,11 @@
} catch (NoSuchElementException ex) {
Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");
throw ex;
+ } finally {
+ traceEnd();
}
+ traceBegin("HealthInitWaitUpdate");
// init register for new service notifications, and IServiceManager should return the
// existing service in a near future. Wait for this.update() to instantiate
// the initial mHealthInfo.
@@ -280,6 +288,7 @@
Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)
+ "ms and received the update.");
+ traceEnd();
}
private void updateBatteryWarningLevelLocked() {
@@ -302,16 +311,16 @@
private boolean isPoweredLocked(int plugTypeSet) {
// assume we are powered if battery state is unknown so
// the "stay on while plugged in" option will work.
- if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
+ if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.legacy.chargerAcOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.chargerAcOnline) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.legacy.chargerUsbOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.chargerUsbOnline) {
return true;
}
- if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.legacy.chargerWirelessOnline) {
+ if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.chargerWirelessOnline) {
return true;
}
return false;
@@ -328,15 +337,15 @@
* (becomes <= mLowBatteryWarningLevel).
*/
return !plugged
- && mHealthInfo.legacy.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
- && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel
+ && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
+ && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel
&& (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
}
private void shutdownIfNoPowerLocked() {
// shut down gracefully if our battery is critically low and we are not powered.
// wait until the system has booted before attempting to display the shutdown dialog.
- if (mHealthInfo.legacy.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+ if (mHealthInfo.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -357,7 +366,7 @@
// shut down gracefully if temperature is too high (> 68.0C by default)
// wait until the system has booted before attempting to display the
// shutdown dialog.
- if (mHealthInfo.legacy.batteryTemperature > mShutdownBatteryTemperature) {
+ if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -375,6 +384,7 @@
}
private void update(HealthInfo info) {
+ traceBegin("HealthInfoUpdate");
synchronized (mLock) {
if (!mUpdatesStopped) {
mHealthInfo = info;
@@ -385,40 +395,38 @@
copy(mLastHealthInfo, info);
}
}
+ traceEnd();
}
private static void copy(HealthInfo dst, HealthInfo src) {
- dst.legacy.chargerAcOnline = src.legacy.chargerAcOnline;
- dst.legacy.chargerUsbOnline = src.legacy.chargerUsbOnline;
- dst.legacy.chargerWirelessOnline = src.legacy.chargerWirelessOnline;
- dst.legacy.maxChargingCurrent = src.legacy.maxChargingCurrent;
- dst.legacy.maxChargingVoltage = src.legacy.maxChargingVoltage;
- dst.legacy.batteryStatus = src.legacy.batteryStatus;
- dst.legacy.batteryHealth = src.legacy.batteryHealth;
- dst.legacy.batteryPresent = src.legacy.batteryPresent;
- dst.legacy.batteryLevel = src.legacy.batteryLevel;
- dst.legacy.batteryVoltage = src.legacy.batteryVoltage;
- dst.legacy.batteryTemperature = src.legacy.batteryTemperature;
- dst.legacy.batteryCurrent = src.legacy.batteryCurrent;
- dst.legacy.batteryCycleCount = src.legacy.batteryCycleCount;
- dst.legacy.batteryFullCharge = src.legacy.batteryFullCharge;
- dst.legacy.batteryChargeCounter = src.legacy.batteryChargeCounter;
- dst.legacy.batteryTechnology = src.legacy.batteryTechnology;
- dst.batteryCurrentAverage = src.batteryCurrentAverage;
- dst.batteryCapacity = src.batteryCapacity;
- dst.energyCounter = src.energyCounter;
+ dst.chargerAcOnline = src.chargerAcOnline;
+ dst.chargerUsbOnline = src.chargerUsbOnline;
+ dst.chargerWirelessOnline = src.chargerWirelessOnline;
+ dst.maxChargingCurrent = src.maxChargingCurrent;
+ dst.maxChargingVoltage = src.maxChargingVoltage;
+ dst.batteryStatus = src.batteryStatus;
+ dst.batteryHealth = src.batteryHealth;
+ dst.batteryPresent = src.batteryPresent;
+ dst.batteryLevel = src.batteryLevel;
+ dst.batteryVoltage = src.batteryVoltage;
+ dst.batteryTemperature = src.batteryTemperature;
+ dst.batteryCurrent = src.batteryCurrent;
+ dst.batteryCycleCount = src.batteryCycleCount;
+ dst.batteryFullCharge = src.batteryFullCharge;
+ dst.batteryChargeCounter = src.batteryChargeCounter;
+ dst.batteryTechnology = src.batteryTechnology;
}
private void processValuesLocked(boolean force) {
boolean logOutlier = false;
long dischargeDuration = 0;
- mBatteryLevelCritical = (mHealthInfo.legacy.batteryLevel <= mCriticalBatteryLevel);
- if (mHealthInfo.legacy.chargerAcOnline) {
+ mBatteryLevelCritical = (mHealthInfo.batteryLevel <= mCriticalBatteryLevel);
+ if (mHealthInfo.chargerAcOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
- } else if (mHealthInfo.legacy.chargerUsbOnline) {
+ } else if (mHealthInfo.chargerUsbOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
- } else if (mHealthInfo.legacy.chargerWirelessOnline) {
+ } else if (mHealthInfo.chargerWirelessOnline) {
mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
} else {
mPlugType = BATTERY_PLUGGED_NONE;
@@ -433,10 +441,10 @@
// Let the battery stats keep track of the current level.
try {
- mBatteryStats.setBatteryState(mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth,
- mPlugType, mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryTemperature,
- mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryChargeCounter,
- mHealthInfo.legacy.batteryFullCharge);
+ mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
+ mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
+ mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
+ mHealthInfo.batteryFullCharge);
} catch (RemoteException e) {
// Should never happen.
}
@@ -444,16 +452,16 @@
shutdownIfNoPowerLocked();
shutdownIfOverTempLocked();
- if (force || (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
- mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
- mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
- mHealthInfo.legacy.batteryLevel != mLastBatteryLevel ||
+ if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||
+ mHealthInfo.batteryHealth != mLastBatteryHealth ||
+ mHealthInfo.batteryPresent != mLastBatteryPresent ||
+ mHealthInfo.batteryLevel != mLastBatteryLevel ||
mPlugType != mLastPlugType ||
- mHealthInfo.legacy.batteryVoltage != mLastBatteryVoltage ||
- mHealthInfo.legacy.batteryTemperature != mLastBatteryTemperature ||
- mHealthInfo.legacy.maxChargingCurrent != mLastMaxChargingCurrent ||
- mHealthInfo.legacy.maxChargingVoltage != mLastMaxChargingVoltage ||
- mHealthInfo.legacy.batteryChargeCounter != mLastChargeCounter ||
+ mHealthInfo.batteryVoltage != mLastBatteryVoltage ||
+ mHealthInfo.batteryTemperature != mLastBatteryTemperature ||
+ mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||
+ mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||
+ mHealthInfo.batteryChargeCounter != mLastChargeCounter ||
mInvalidCharger != mLastInvalidCharger)) {
if (mPlugType != mLastPlugType) {
@@ -462,33 +470,33 @@
// There's no value in this data unless we've discharged at least once and the
// battery level has changed; so don't log until it does.
- if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.legacy.batteryLevel) {
+ if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.batteryLevel) {
dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
logOutlier = true;
EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
- mDischargeStartLevel, mHealthInfo.legacy.batteryLevel);
+ mDischargeStartLevel, mHealthInfo.batteryLevel);
// make sure we see a discharge event before logging again
mDischargeStartTime = 0;
}
} else if (mPlugType == BATTERY_PLUGGED_NONE) {
// charging -> discharging or we just powered up
mDischargeStartTime = SystemClock.elapsedRealtime();
- mDischargeStartLevel = mHealthInfo.legacy.batteryLevel;
+ mDischargeStartLevel = mHealthInfo.batteryLevel;
}
}
- if (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
- mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
- mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
+ if (mHealthInfo.batteryStatus != mLastBatteryStatus ||
+ mHealthInfo.batteryHealth != mLastBatteryHealth ||
+ mHealthInfo.batteryPresent != mLastBatteryPresent ||
mPlugType != mLastPlugType) {
EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
- mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth, mHealthInfo.legacy.batteryPresent ? 1 : 0,
- mPlugType, mHealthInfo.legacy.batteryTechnology);
+ mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0,
+ mPlugType, mHealthInfo.batteryTechnology);
}
- if (mHealthInfo.legacy.batteryLevel != mLastBatteryLevel) {
+ if (mHealthInfo.batteryLevel != mLastBatteryLevel) {
// Don't do this just from voltage or temperature changes, that is
// too noisy.
EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
- mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryTemperature);
+ mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);
}
if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
mPlugType == BATTERY_PLUGGED_NONE) {
@@ -501,16 +509,16 @@
if (!mBatteryLevelLow) {
// Should we now switch in to low battery mode?
if (mPlugType == BATTERY_PLUGGED_NONE
- && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel) {
+ && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) {
mBatteryLevelLow = true;
}
} else {
// Should we now switch out of low battery mode?
if (mPlugType != BATTERY_PLUGGED_NONE) {
mBatteryLevelLow = false;
- } else if (mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
+ } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
mBatteryLevelLow = false;
- } else if (force && mHealthInfo.legacy.batteryLevel >= mLowBatteryWarningLevel) {
+ } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) {
// If being forced, the previous state doesn't matter, we will just
// absolutely check to see if we are now above the warning level.
mBatteryLevelLow = false;
@@ -557,7 +565,7 @@
}
});
} else if (mSentLowBatteryBroadcast &&
- mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
+ mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
mSentLowBatteryBroadcast = false;
final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
@@ -583,16 +591,16 @@
logOutlierLocked(dischargeDuration);
}
- mLastBatteryStatus = mHealthInfo.legacy.batteryStatus;
- mLastBatteryHealth = mHealthInfo.legacy.batteryHealth;
- mLastBatteryPresent = mHealthInfo.legacy.batteryPresent;
- mLastBatteryLevel = mHealthInfo.legacy.batteryLevel;
+ mLastBatteryStatus = mHealthInfo.batteryStatus;
+ mLastBatteryHealth = mHealthInfo.batteryHealth;
+ mLastBatteryPresent = mHealthInfo.batteryPresent;
+ mLastBatteryLevel = mHealthInfo.batteryLevel;
mLastPlugType = mPlugType;
- mLastBatteryVoltage = mHealthInfo.legacy.batteryVoltage;
- mLastBatteryTemperature = mHealthInfo.legacy.batteryTemperature;
- mLastMaxChargingCurrent = mHealthInfo.legacy.maxChargingCurrent;
- mLastMaxChargingVoltage = mHealthInfo.legacy.maxChargingVoltage;
- mLastChargeCounter = mHealthInfo.legacy.batteryChargeCounter;
+ mLastBatteryVoltage = mHealthInfo.batteryVoltage;
+ mLastBatteryTemperature = mHealthInfo.batteryTemperature;
+ mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;
+ mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;
+ mLastChargeCounter = mHealthInfo.batteryChargeCounter;
mLastBatteryLevelCritical = mBatteryLevelCritical;
mLastInvalidCharger = mInvalidCharger;
}
@@ -604,23 +612,23 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
| Intent.FLAG_RECEIVER_REPLACE_PENDING);
- int icon = getIconLocked(mHealthInfo.legacy.batteryLevel);
+ int icon = getIconLocked(mHealthInfo.batteryLevel);
intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
- intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.legacy.batteryStatus);
- intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.legacy.batteryHealth);
- intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.legacy.batteryPresent);
- intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.legacy.batteryLevel);
+ intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
+ intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
+ intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
+ intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
- intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.legacy.batteryVoltage);
- intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
- intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
+ intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
+ intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
+ intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);
intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
- intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
- intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
+ intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
+ intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
+ intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
if (DEBUG) {
Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
+ ", info:" + mHealthInfo.toString());
@@ -684,14 +692,14 @@
long durationThreshold = Long.parseLong(durationThresholdString);
int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
if (duration <= durationThreshold &&
- mDischargeStartLevel - mHealthInfo.legacy.batteryLevel >= dischargeThreshold) {
+ mDischargeStartLevel - mHealthInfo.batteryLevel >= dischargeThreshold) {
// If the discharge cycle is bad enough we want to know about it.
logBatteryStatsLocked();
}
if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
" discharge threshold: " + dischargeThreshold);
if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
- (mDischargeStartLevel - mHealthInfo.legacy.batteryLevel));
+ (mDischargeStartLevel - mHealthInfo.batteryLevel));
} catch (NumberFormatException e) {
Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
durationThresholdString + " or " + dischargeThresholdString);
@@ -700,14 +708,14 @@
}
private int getIconLocked(int level) {
- if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
+ if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
- } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
+ } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
return com.android.internal.R.drawable.stat_sys_battery;
- } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
- || mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
+ } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
+ || mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
- && mHealthInfo.legacy.batteryLevel >= 100) {
+ && mHealthInfo.batteryLevel >= 100) {
return com.android.internal.R.drawable.stat_sys_battery_charge;
} else {
return com.android.internal.R.drawable.stat_sys_battery;
@@ -771,9 +779,9 @@
if (!mUpdatesStopped) {
copy(mLastHealthInfo, mHealthInfo);
}
- mHealthInfo.legacy.chargerAcOnline = false;
- mHealthInfo.legacy.chargerUsbOnline = false;
- mHealthInfo.legacy.chargerWirelessOnline = false;
+ mHealthInfo.chargerAcOnline = false;
+ mHealthInfo.chargerUsbOnline = false;
+ mHealthInfo.chargerWirelessOnline = false;
long ident = Binder.clearCallingIdentity();
try {
mUpdatesStopped = true;
@@ -805,25 +813,25 @@
boolean update = true;
switch (key) {
case "present":
- mHealthInfo.legacy.batteryPresent = Integer.parseInt(value) != 0;
+ mHealthInfo.batteryPresent = Integer.parseInt(value) != 0;
break;
case "ac":
- mHealthInfo.legacy.chargerAcOnline = Integer.parseInt(value) != 0;
+ mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0;
break;
case "usb":
- mHealthInfo.legacy.chargerUsbOnline = Integer.parseInt(value) != 0;
+ mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0;
break;
case "wireless":
- mHealthInfo.legacy.chargerWirelessOnline = Integer.parseInt(value) != 0;
+ mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0;
break;
case "status":
- mHealthInfo.legacy.batteryStatus = Integer.parseInt(value);
+ mHealthInfo.batteryStatus = Integer.parseInt(value);
break;
case "level":
- mHealthInfo.legacy.batteryLevel = Integer.parseInt(value);
+ mHealthInfo.batteryLevel = Integer.parseInt(value);
break;
case "temp":
- mHealthInfo.legacy.batteryTemperature = Integer.parseInt(value);
+ mHealthInfo.batteryTemperature = Integer.parseInt(value);
break;
case "invalid":
mInvalidCharger = Integer.parseInt(value);
@@ -882,20 +890,20 @@
if (mUpdatesStopped) {
pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
}
- pw.println(" AC powered: " + mHealthInfo.legacy.chargerAcOnline);
- pw.println(" USB powered: " + mHealthInfo.legacy.chargerUsbOnline);
- pw.println(" Wireless powered: " + mHealthInfo.legacy.chargerWirelessOnline);
- pw.println(" Max charging current: " + mHealthInfo.legacy.maxChargingCurrent);
- pw.println(" Max charging voltage: " + mHealthInfo.legacy.maxChargingVoltage);
- pw.println(" Charge counter: " + mHealthInfo.legacy.batteryChargeCounter);
- pw.println(" status: " + mHealthInfo.legacy.batteryStatus);
- pw.println(" health: " + mHealthInfo.legacy.batteryHealth);
- pw.println(" present: " + mHealthInfo.legacy.batteryPresent);
- pw.println(" level: " + mHealthInfo.legacy.batteryLevel);
+ pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
+ pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
+ pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
+ pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
+ pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
+ pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
+ pw.println(" status: " + mHealthInfo.batteryStatus);
+ pw.println(" health: " + mHealthInfo.batteryHealth);
+ pw.println(" present: " + mHealthInfo.batteryPresent);
+ pw.println(" level: " + mHealthInfo.batteryLevel);
pw.println(" scale: " + BATTERY_SCALE);
- pw.println(" voltage: " + mHealthInfo.legacy.batteryVoltage);
- pw.println(" temperature: " + mHealthInfo.legacy.batteryTemperature);
- pw.println(" technology: " + mHealthInfo.legacy.batteryTechnology);
+ pw.println(" voltage: " + mHealthInfo.batteryVoltage);
+ pw.println(" temperature: " + mHealthInfo.batteryTemperature);
+ pw.println(" technology: " + mHealthInfo.batteryTechnology);
} else {
Shell shell = new Shell();
shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
@@ -909,29 +917,37 @@
synchronized (mLock) {
proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
int batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_NONE;
- if (mHealthInfo.legacy.chargerAcOnline) {
+ if (mHealthInfo.chargerAcOnline) {
batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_AC;
- } else if (mHealthInfo.legacy.chargerUsbOnline) {
+ } else if (mHealthInfo.chargerUsbOnline) {
batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_USB;
- } else if (mHealthInfo.legacy.chargerWirelessOnline) {
+ } else if (mHealthInfo.chargerWirelessOnline) {
batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_WIRELESS;
}
proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
- proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
- proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
- proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.legacy.batteryStatus);
- proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.legacy.batteryHealth);
- proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.legacy.batteryPresent);
- proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.legacy.batteryLevel);
+ proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
+ proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
+ proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
+ proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus);
+ proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth);
+ proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent);
+ proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel);
proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
- proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.legacy.batteryVoltage);
- proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
- proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
+ proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage);
+ proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature);
+ proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology);
}
proto.flush();
}
+ private static void traceBegin(String name) {
+ Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
+ }
+
+ private static void traceEnd() {
+ Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+ }
+
private final class Led {
private final Light mBatteryLight;
@@ -960,8 +976,8 @@
* Synchronize on BatteryService.
*/
public void updateLightsLocked() {
- final int level = mHealthInfo.legacy.batteryLevel;
- final int status = mHealthInfo.legacy.batteryStatus;
+ final int level = mHealthInfo.batteryLevel;
+ final int status = mHealthInfo.batteryStatus;
if (level < mLowBatteryWarningLevel) {
if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
// Solid red when battery is charging
@@ -997,6 +1013,7 @@
String instance) {
if (newService == null) return;
+ traceBegin("HealthUnregisterCallback");
try {
if (oldService != null) {
int r = oldService.unregisterCallback(this);
@@ -1008,8 +1025,11 @@
} catch (RemoteException ex) {
Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
+ ex.getMessage());
+ } finally {
+ traceEnd();
}
+ traceBegin("HealthRegisterCallback");
try {
int r = newService.registerCallback(this);
if (r != Result.SUCCESS) {
@@ -1022,6 +1042,8 @@
} catch (RemoteException ex) {
Slog.e(TAG, "health: cannot register callback (transaction error): "
+ ex.getMessage());
+ } finally {
+ traceEnd();
}
}
}
@@ -1054,53 +1076,63 @@
Slog.e(TAG, "health: must not call unregisterListener on battery properties");
}
public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) throw new RemoteException("no health service");
- final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
- switch(id) {
- case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
- service.getChargeCounter((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
- service.getCurrentNow((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
- service.getCurrentAverage((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_CAPACITY:
- service.getCapacity((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_STATUS:
- service.getChargeStatus((int result, int value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
- case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
- service.getEnergyCounter((int result, long value) -> {
- outResult.value = result;
- if (result == Result.SUCCESS) prop.setLong(value);
- });
- break;
+ traceBegin("HealthGetProperty");
+ try {
+ IHealth service = mHealthServiceWrapper.getLastService();
+ if (service == null) throw new RemoteException("no health service");
+ final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
+ switch(id) {
+ case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
+ service.getChargeCounter((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
+ service.getCurrentNow((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
+ service.getCurrentAverage((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_CAPACITY:
+ service.getCapacity((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_STATUS:
+ service.getChargeStatus((int result, int value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
+ service.getEnergyCounter((int result, long value) -> {
+ outResult.value = result;
+ if (result == Result.SUCCESS) prop.setLong(value);
+ });
+ break;
+ }
+ return outResult.value;
+ } finally {
+ traceEnd();
}
- return outResult.value;
}
public void scheduleUpdate() throws RemoteException {
- IHealth service = mHealthServiceWrapper.getLastService();
- if (service == null) throw new RemoteException("no health service");
- service.update();
+ traceBegin("HealthScheduleUpdate");
+ try {
+ IHealth service = mHealthServiceWrapper.getLastService();
+ if (service == null) throw new RemoteException("no health service");
+ service.update();
+ } finally {
+ traceEnd();
+ }
}
}
@@ -1122,7 +1154,7 @@
@Override
public int getBatteryLevel() {
synchronized (mLock) {
- return mHealthInfo.legacy.batteryLevel;
+ return mHealthInfo.batteryLevel;
}
}
@@ -1163,14 +1195,13 @@
Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
private final IServiceNotification mNotification = new Notification();
+ private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceRefresh");
// These variables are fixed after init.
private Callback mCallback;
private IHealthSupplier mHealthSupplier;
private String mInstanceName;
- private final Object mLastServiceSetLock = new Object();
// Last IHealth service received.
- // set must be also be guarded with mLastServiceSetLock to ensure ordering.
private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
/**
@@ -1188,6 +1219,10 @@
* Start monitoring registration of new IHealth services. Only instances that are in
* {@code sAllInstances} and in device / framework manifest are used. This function should
* only be called once.
+ *
+ * mCallback.onRegistration() is called synchronously (aka in init thread) before
+ * this method returns.
+ *
* @throws RemoteException transaction error when talking to IServiceManager
* @throws NoSuchElementException if one of the following cases:
* - No service manager;
@@ -1203,28 +1238,53 @@
if (callback == null || managerSupplier == null || healthSupplier == null)
throw new NullPointerException();
+ IServiceManager manager;
+
mCallback = callback;
mHealthSupplier = healthSupplier;
- IServiceManager manager = managerSupplier.get();
+ // Initialize mLastService and call callback for the first time (in init thread)
+ IHealth newService = null;
for (String name : sAllInstances) {
- if (manager.getTransport(IHealth.kInterfaceName, name) !=
- IServiceManager.Transport.EMPTY) {
+ traceBegin("HealthInitGetService_" + name);
+ try {
+ newService = healthSupplier.get(name);
+ } catch (NoSuchElementException ex) {
+ /* ignored, handled below */
+ } finally {
+ traceEnd();
+ }
+ if (newService != null) {
mInstanceName = name;
+ mLastService.set(newService);
break;
}
}
- if (mInstanceName == null) {
+ if (mInstanceName == null || newService == null) {
throw new NoSuchElementException(String.format(
"No IHealth service instance among %s is available. Perhaps no permission?",
sAllInstances.toString()));
}
+ mCallback.onRegistration(null, newService, mInstanceName);
- manager.registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
+ // Register for future service registrations
+ traceBegin("HealthInitRegisterNotification");
+ mHandlerThread.start();
+ try {
+ managerSupplier.get().registerForNotifications(
+ IHealth.kInterfaceName, mInstanceName, mNotification);
+ } finally {
+ traceEnd();
+ }
Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
}
+ @VisibleForTesting
+ HandlerThread getHandlerThread() {
+ return mHandlerThread;
+ }
+
interface Callback {
/**
* This function is invoked asynchronously when a new and related IServiceNotification
@@ -1253,7 +1313,7 @@
*/
interface IHealthSupplier {
default IHealth get(String name) throws NoSuchElementException, RemoteException {
- return IHealth.getService(name);
+ return IHealth.getService(name, true /* retry */);
}
}
@@ -1263,18 +1323,27 @@
boolean preexisting) {
if (!IHealth.kInterfaceName.equals(interfaceName)) return;
if (!mInstanceName.equals(instanceName)) return;
- try {
- // ensures the order of multiple onRegistration on different threads.
- synchronized (mLastServiceSetLock) {
- IHealth newService = mHealthSupplier.get(instanceName);
- IHealth oldService = mLastService.getAndSet(newService);
- Slog.i(TAG, "health: new instance registered " + instanceName);
- mCallback.onRegistration(oldService, newService, instanceName);
+
+ // This runnable only runs on mHandlerThread and ordering is ensured, hence
+ // no locking is needed inside the runnable.
+ mHandlerThread.getThreadHandler().post(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ IHealth newService = mHealthSupplier.get(mInstanceName);
+ IHealth oldService = mLastService.getAndSet(newService);
+
+ // preexisting may be inaccurate (race). Check for equality here.
+ if (Objects.equals(newService, oldService)) return;
+
+ Slog.i(TAG, "health: new instance registered " + mInstanceName);
+ mCallback.onRegistration(oldService, newService, mInstanceName);
+ } catch (NoSuchElementException | RemoteException ex) {
+ Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
+ + "': " + ex.getMessage() + ". Perhaps no permission?");
+ }
}
- } catch (NoSuchElementException | RemoteException ex) {
- Slog.e(TAG, "health: Cannot get instance '" + instanceName + "': " +
- ex.getMessage() + ". Perhaps no permission?");
- }
+ });
}
}
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7e65d36..3e40dfd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,7 +29,10 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
@@ -70,6 +73,7 @@
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
+import android.net.VpnService;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.util.MultinetworkPolicyTracker;
@@ -2119,9 +2123,14 @@
final boolean valid =
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
final boolean wasValidated = nai.lastValidated;
+ final boolean wasDefault = isDefaultNetwork(nai);
if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
(msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
if (valid != nai.lastValidated) {
+ if (wasDefault) {
+ metricsLogger().defaultNetworkMetrics().logDefaultNetworkValidity(
+ SystemClock.elapsedRealtime(), valid);
+ }
final int oldScore = nai.getCurrentScore();
nai.lastValidated = valid;
nai.everValidated |= valid;
@@ -2293,7 +2302,8 @@
// Let rematchAllNetworksAndRequests() below record a new default network event
// if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
// whose timestamps tell how long it takes to recover a default network.
- metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(null, nai);
+ long now = SystemClock.elapsedRealtime();
+ metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
}
notifyIfacesChangedForNetworkStats();
// TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
@@ -4675,10 +4685,12 @@
}
}
- final NetworkCapabilities prevNc = nai.networkCapabilities;
+ final NetworkCapabilities prevNc;
synchronized (nai) {
+ prevNc = nai.networkCapabilities;
nai.networkCapabilities = networkCapabilities;
}
+
if (nai.getCurrentScore() == oldScore &&
networkCapabilities.equalRequestableCapabilities(prevNc)) {
// If the requestable capabilities haven't changed, and the score hasn't changed, then
@@ -4692,6 +4704,28 @@
rematchAllNetworksAndRequests(nai, oldScore);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+
+ // Report changes that are interesting for network statistics tracking.
+ if (prevNc != null) {
+ final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) !=
+ networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED);
+ final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
+ networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ if (meteredChanged || roamingChanged) {
+ notifyIfacesChangedForNetworkStats();
+ }
+ }
+
+ if (!networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+ // Tell VPNs about updated capabilities, since they may need to
+ // bubble those changes through.
+ synchronized (mVpns) {
+ for (int i = 0; i < mVpns.size(); i++) {
+ final Vpn vpn = mVpns.valueAt(i);
+ vpn.updateCapabilities();
+ }
+ }
+ }
}
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
@@ -5024,7 +5058,7 @@
makeDefault(newNetwork);
// Log 0 -> X and Y -> X default network transitions, where X is the new default.
metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
- newNetwork, oldDefaultNetwork);
+ now, newNetwork, oldDefaultNetwork);
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
}
@@ -5225,14 +5259,6 @@
}
notifyLockdownVpn(networkAgent);
- if (oldInfo != null && oldInfo.getState() == state) {
- if (oldInfo.isRoaming() != newInfo.isRoaming()) {
- if (VDBG) log("roaming status changed, notifying NetworkStatsService");
- notifyIfacesChangedForNetworkStats();
- } else if (VDBG) log("ignoring duplicate network state non-change");
- // In either case, no further work should be needed.
- return;
- }
if (DBG) {
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
(oldInfo == null ? "null" : oldInfo.getState()) +
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index c60d7b0..8a15ded 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -20,6 +20,9 @@
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.NETWORK_STACK;
import static android.Manifest.permission.SHUTDOWN;
+import static android.net.ConnectivityManager.PRIVATE_DNS_DEFAULT_MODE;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC;
+import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
@@ -92,6 +95,7 @@
import android.telephony.PhoneStateListener;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -1946,9 +1950,9 @@
public void setDnsConfigurationForNetwork(int netId, String[] servers, String domains) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
- ContentResolver resolver = mContext.getContentResolver();
+ final ContentResolver cr = mContext.getContentResolver();
- int sampleValidity = Settings.Global.getInt(resolver,
+ int sampleValidity = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_SAMPLE_VALIDITY_SECONDS,
DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS);
if (sampleValidity < 0 || sampleValidity > 65535) {
@@ -1957,7 +1961,7 @@
sampleValidity = DNS_RESOLVER_DEFAULT_SAMPLE_VALIDITY_SECONDS;
}
- int successThreshold = Settings.Global.getInt(resolver,
+ int successThreshold = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_SUCCESS_THRESHOLD_PERCENT,
DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT);
if (successThreshold < 0 || successThreshold > 100) {
@@ -1966,9 +1970,9 @@
successThreshold = DNS_RESOLVER_DEFAULT_SUCCESS_THRESHOLD_PERCENT;
}
- int minSamples = Settings.Global.getInt(resolver,
+ int minSamples = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_MIN_SAMPLES, DNS_RESOLVER_DEFAULT_MIN_SAMPLES);
- int maxSamples = Settings.Global.getInt(resolver,
+ int maxSamples = Settings.Global.getInt(cr,
Settings.Global.DNS_RESOLVER_MAX_SAMPLES, DNS_RESOLVER_DEFAULT_MAX_SAMPLES);
if (minSamples < 0 || minSamples > maxSamples || maxSamples > 64) {
Slog.w(TAG, "Invalid sample count (min, max)=(" + minSamples + ", " + maxSamples +
@@ -1980,8 +1984,24 @@
final String[] domainStrs = domains == null ? new String[0] : domains.split(" ");
final int[] params = { sampleValidity, successThreshold, minSamples, maxSamples };
- final boolean useTls = Settings.Global.getInt(resolver,
- Settings.Global.DNS_TLS_DISABLED, 0) == 0;
+ final boolean useTls = shouldUseTls(cr);
+ // TODO: Populate tlsHostname once it's decided how the hostname's IP
+ // addresses will be resolved:
+ //
+ // [1] network-provided DNS servers are included here with the
+ // hostname and netd will use the network-provided servers to
+ // resolve the hostname and fix up its internal structures, or
+ //
+ // [2] network-provided DNS servers are included here without the
+ // hostname, the ConnectivityService layer resolves the given
+ // hostname, and then reconfigures netd with this information.
+ //
+ // In practice, there will always be a need for ConnectivityService or
+ // the captive portal app to use the network-provided services to make
+ // some queries. This argues in favor of [1], in concert with another
+ // mechanism, perhaps setting a high bit in the netid, to indicate
+ // via existing DNS APIs which set of servers (network-provided or
+ // non-network-provided private DNS) should be queried.
final String tlsHostname = "";
final String[] tlsFingerprints = new String[0];
try {
@@ -1992,6 +2012,15 @@
}
}
+ private static boolean shouldUseTls(ContentResolver cr) {
+ String privateDns = Settings.Global.getString(cr, Settings.Global.PRIVATE_DNS_MODE);
+ if (TextUtils.isEmpty(privateDns)) {
+ privateDns = PRIVATE_DNS_DEFAULT_MODE;
+ }
+ return privateDns.equals(PRIVATE_DNS_MODE_OPPORTUNISTIC) ||
+ privateDns.startsWith(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ }
+
@Override
public void addVpnUidRanges(int netId, UidRange[] ranges) {
mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index 1924a86..a9f190c 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -16,6 +16,8 @@
package com.android.server;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+
import android.content.ContentResolver;
import android.content.Context;
import android.os.Build;
@@ -146,7 +148,7 @@
SystemProperties.set(PROP_RESCUE_LEVEL, Integer.toString(level));
EventLogTags.writeRescueLevel(level, triggerUid);
- PackageManagerService.logCriticalInfo(Log.WARN, "Incremented rescue level to "
+ logCriticalInfo(Log.WARN, "Incremented rescue level to "
+ levelToString(level) + " triggered by UID " + triggerUid);
}
@@ -166,12 +168,12 @@
try {
executeRescueLevelInternal(context, level);
EventLogTags.writeRescueSuccess(level);
- PackageManagerService.logCriticalInfo(Log.DEBUG,
+ logCriticalInfo(Log.DEBUG,
"Finished rescue level " + levelToString(level));
} catch (Throwable t) {
final String msg = ExceptionUtils.getCompleteMessage(t);
EventLogTags.writeRescueFailure(level, msg);
- PackageManagerService.logCriticalInfo(Log.ERROR,
+ logCriticalInfo(Log.ERROR,
"Failed rescue level " + levelToString(level) + ": " + msg);
}
}
diff --git a/services/core/java/com/android/server/ServiceThread.java b/services/core/java/com/android/server/ServiceThread.java
index bce64af..26703c5 100644
--- a/services/core/java/com/android/server/ServiceThread.java
+++ b/services/core/java/com/android/server/ServiceThread.java
@@ -19,7 +19,6 @@
import android.os.HandlerThread;
import android.os.Process;
import android.os.StrictMode;
-import android.util.Slog;
/**
* Special handler thread that we create for system services that require their own loopers.
@@ -38,11 +37,10 @@
public void run() {
Process.setCanSelfBackground(false);
- // For debug builds, log event loop stalls to dropbox for analysis.
- if (!mAllowIo && StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode logging for " + getName() + " looper.");
+ if (!mAllowIo) {
+ StrictMode.initThreadDefaults(null);
}
super.run();
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index bfbce40..75e8000 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -56,6 +56,7 @@
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
+import android.os.IProgressListener;
import android.os.IStoraged;
import android.os.IVold;
import android.os.IVoldListener;
@@ -570,7 +571,7 @@
}
// TODO: Reintroduce shouldBenchmark() test
- fstrim(0);
+ fstrim(0, null);
// invoke the completion callback, if any
// TODO: fstrim is non-blocking, so remove this useless callback
@@ -1576,21 +1577,19 @@
}
@Override
- public long benchmark(String volId) {
+ public void benchmark(String volId, IVoldTaskListener listener) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
- // TODO: refactor for callers to provide a listener
try {
- final CompletableFuture<PersistableBundle> result = new CompletableFuture<>();
mVold.benchmark(volId, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
- // Not currently used
+ dispatchOnStatus(listener, status, extras);
}
@Override
public void onFinished(int status, PersistableBundle extras) {
- result.complete(extras);
+ dispatchOnFinished(listener, status, extras);
final String path = extras.getString("path");
final String ident = extras.getString("ident");
@@ -1611,10 +1610,8 @@
}
}
});
- return result.get(3, TimeUnit.MINUTES).getLong("run", Long.MAX_VALUE);
- } catch (Exception e) {
- Slog.wtf(TAG, e);
- return Long.MAX_VALUE;
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
}
@@ -1742,13 +1739,15 @@
}
@Override
- public void fstrim(int flags) {
+ public void fstrim(int flags, IVoldTaskListener listener) {
enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
try {
mVold.fstrim(flags, new IVoldTaskListener.Stub() {
@Override
public void onStatus(int status, PersistableBundle extras) {
+ dispatchOnStatus(listener, status, extras);
+
// Ignore trim failures
if (status != 0) return;
@@ -1770,12 +1769,13 @@
@Override
public void onFinished(int status, PersistableBundle extras) {
- // Not currently used
+ dispatchOnFinished(listener, status, extras);
+
// TODO: benchmark when desired
}
});
- } catch (Exception e) {
- Slog.wtf(TAG, e);
+ } catch (RemoteException e) {
+ throw e.rethrowAsRuntimeException();
}
}
@@ -3239,6 +3239,26 @@
}
}
+ private void dispatchOnStatus(IVoldTaskListener listener, int status,
+ PersistableBundle extras) {
+ if (listener != null) {
+ try {
+ listener.onStatus(status, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ private void dispatchOnFinished(IVoldTaskListener listener, int status,
+ PersistableBundle extras) {
+ if (listener != null) {
+ try {
+ listener.onFinished(status, extras);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
private static class Callbacks extends Handler {
private static final int MSG_STORAGE_STATE_CHANGED = 1;
private static final int MSG_VOLUME_STATE_CHANGED = 2;
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 8b79b9d..0e51fda 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -27,6 +27,7 @@
import android.hardware.input.InputManager;
import android.hardware.vibrator.V1_0.Constants.EffectStrength;
import android.media.AudioManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Handler;
@@ -56,7 +57,6 @@
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 8d46d1e..35f83e4 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -60,9 +60,6 @@
// Set this to true to use debug default values.
static final boolean DB = false;
- // Set this to true to have the watchdog record kernel thread stacks when it fires
- static final boolean RECORD_KERNEL_THREADS = true;
-
// Note 1: Do not lower this value below thirty seconds without tightening the invoke-with
// timeout in com.android.internal.os.ZygoteConnection, or wrapped applications
// can trigger the watchdog.
@@ -509,11 +506,6 @@
// The system's been hanging for a minute, another second or two won't hurt much.
SystemClock.sleep(2000);
- // Pull our own kernel thread stacks as well if we're configured for that
- if (RECORD_KERNEL_THREADS) {
- dumpKernelStackTraces();
- }
-
// Trigger the kernel to dump all blocked threads, and backtraces on all CPUs to the kernel log
doSysRq('w');
doSysRq('l');
@@ -591,18 +583,6 @@
}
}
- private File dumpKernelStackTraces() {
- String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
- if (tracesPath == null || tracesPath.length() == 0) {
- return null;
- }
-
- native_dumpKernelStacks(tracesPath);
- return new File(tracesPath);
- }
-
- private native void native_dumpKernelStacks(String tracesPath);
-
public static final class OpenFdMonitor {
/**
* Number of FDs below the soft limit that we trigger a runtime restart at. This was
diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java
index c04ddf8..ea7b443 100644
--- a/services/core/java/com/android/server/am/ActivityDisplay.java
+++ b/services/core/java/com/android/server/am/ActivityDisplay.java
@@ -404,8 +404,8 @@
if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
|| windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY) {
- return supportsSplitScreen && WindowConfiguration.supportSplitScreenWindowingMode(
- windowingMode, activityType);
+ return supportsSplitScreen
+ && WindowConfiguration.supportSplitScreenWindowingMode(activityType);
}
if (!supportsFreeform && windowingMode == WINDOWING_MODE_FREEFORM) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
index ceb2ad6..0a7d3fd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
+++ b/services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
@@ -92,6 +92,7 @@
static final boolean DEBUG_USAGE_STATS = DEBUG_ALL || false;
static final boolean DEBUG_PERMISSIONS_REVIEW = DEBUG_ALL || false;
static final boolean DEBUG_WHITELISTS = DEBUG_ALL || false;
+ static final boolean DEBUG_METRICS = DEBUG_ALL || false;
static final String POSTFIX_ADD_REMOVE = (APPEND_CATEGORY_NAME) ? "_AddRemove" : "";
static final String POSTFIX_APP = (APPEND_CATEGORY_NAME) ? "_App" : "";
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e98bb1a..842a5b8 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -401,6 +401,7 @@
import com.android.server.AttributeCache;
import com.android.server.DeviceIdleController;
import com.android.server.IntentResolver;
+import com.android.server.IoThread;
import com.android.server.LocalServices;
import com.android.server.LockGuard;
import com.android.server.NetworkManagementInternal;
@@ -1011,15 +1012,6 @@
private static final int MAX_DUP_SUPPRESSED_STACKS = 5000;
/**
- * Strict Mode background batched logging state.
- *
- * The string buffer is guarded by itself, and its lock is also
- * used to determine if another batched write is already
- * in-flight.
- */
- private final StringBuilder mStrictModeBuffer = new StringBuilder();
-
- /**
* Keeps track of all IIntentReceivers that have been registered for broadcasts.
* Hash keys are the receiver IBinder, hash value is a ReceiverList.
*/
@@ -4043,10 +4035,14 @@
if (DEBUG_SWITCH) Slog.d(TAG_SWITCH,
"updateUsageStats: comp=" + component + "res=" + resumed);
final BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
+ StatsLog.write(StatsLog.ACTIVITY_FOREGROUND_STATE_CHANGED,
+ component.userId, component.realActivity.getPackageName(),
+ component.realActivity.getShortClassName(), resumed ? 1 : 0);
if (resumed) {
if (mUsageStatsService != null) {
mUsageStatsService.reportEvent(component.realActivity, component.userId,
UsageEvents.Event.MOVE_TO_FOREGROUND);
+
}
synchronized (stats) {
stats.noteActivityResumedLocked(component.app.uid);
@@ -4737,7 +4733,9 @@
mWindowManager, appOpsManager, proxy, this,
OP_ASSIST_STRUCTURE, OP_NONE);
requester.requestAssistData(mStackSupervisor.getTopVisibleActivities(),
- true, false /* fetchScreenshots */, recentsUid, recentsPackage);
+ true /* fetchData */, false /* fetchScreenshots */,
+ true /* allowFetchData */, false /* alloweFetchScreenshots */,
+ recentsUid, recentsPackage);
}
final Intent intent = new Intent();
@@ -14267,10 +14265,9 @@
IBinder app,
int violationMask,
StrictMode.ViolationInfo info) {
- ProcessRecord r = findAppProcess(app, "StrictMode");
- if (r == null) {
- return;
- }
+ // We're okay if the ProcessRecord is missing; it probably means that
+ // we're reporting a violation from the system process itself.
+ final ProcessRecord r = findAppProcess(app, "StrictMode");
if ((violationMask & StrictMode.PENALTY_DROPBOX) != 0) {
Integer stackFingerprint = info.hashCode();
@@ -14332,18 +14329,15 @@
(process.info.flags & (ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0;
final String processName = process == null ? "unknown" : process.processName;
- final String dropboxTag = isSystemApp ? "system_app_strictmode" : "data_app_strictmode";
final DropBoxManager dbox = (DropBoxManager)
mContext.getSystemService(Context.DROPBOX_SERVICE);
// Exit early if the dropbox isn't configured to accept this report type.
+ final String dropboxTag = processClass(process) + "_strictmode";
if (dbox == null || !dbox.isTagEnabled(dropboxTag)) return;
- boolean bufferWasEmpty;
- boolean needsFlush;
- final StringBuilder sb = isSystemApp ? mStrictModeBuffer : new StringBuilder(1024);
+ final StringBuilder sb = new StringBuilder(1024);
synchronized (sb) {
- bufferWasEmpty = sb.length() == 0;
appendDropBoxProcessHeaders(process, processName, sb);
sb.append("Build: ").append(Build.FINGERPRINT).append("\n");
sb.append("System-App: ").append(isSystemApp).append("\n");
@@ -14369,75 +14363,18 @@
}
}
sb.append("\n");
- if (info.hasStackTrace()) {
- sb.append(info.getStackTrace());
- sb.append("\n");
- }
+ sb.append(info.getStackTrace());
+ sb.append("\n");
if (info.getViolationDetails() != null) {
sb.append(info.getViolationDetails());
sb.append("\n");
}
-
- // Only buffer up to ~64k. Various logging bits truncate
- // things at 128k.
- needsFlush = (sb.length() > 64 * 1024);
}
- // Flush immediately if the buffer's grown too large, or this
- // is a non-system app. Non-system apps are isolated with a
- // different tag & policy and not batched.
- //
- // Batching is useful during internal testing with
- // StrictMode settings turned up high. Without batching,
- // thousands of separate files could be created on boot.
- if (!isSystemApp || needsFlush) {
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- String report;
- synchronized (sb) {
- report = sb.toString();
- sb.delete(0, sb.length());
- sb.trimToSize();
- }
- if (report.length() != 0) {
- dbox.addText(dropboxTag, report);
- }
- }
- }.start();
- return;
- }
-
- // System app batching:
- if (!bufferWasEmpty) {
- // An existing dropbox-writing thread is outstanding, so
- // we don't need to start it up. The existing thread will
- // catch the buffer appends we just did.
- return;
- }
-
- // Worker thread to both batch writes and to avoid blocking the caller on I/O.
- // (After this point, we shouldn't access AMS internal data structures.)
- new Thread("Error dump: " + dropboxTag) {
- @Override
- public void run() {
- // 5 second sleep to let stacks arrive and be batched together
- try {
- Thread.sleep(5000); // 5 seconds
- } catch (InterruptedException e) {}
-
- String errorReport;
- synchronized (mStrictModeBuffer) {
- errorReport = mStrictModeBuffer.toString();
- if (errorReport.length() == 0) {
- return;
- }
- mStrictModeBuffer.delete(0, mStrictModeBuffer.length());
- mStrictModeBuffer.trimToSize();
- }
- dbox.addText(dropboxTag, errorReport);
- }
- }.start();
+ final String res = sb.toString();
+ IoThread.getHandler().post(() -> {
+ dbox.addText(dropboxTag, res);
+ });
}
/**
@@ -14704,7 +14641,12 @@
if (process == null) {
// If process is null, we are being called from some internal code
// and may be about to die -- run this synchronously.
- worker.run();
+ final int oldMask = StrictMode.allowThreadDiskWritesMask();
+ try {
+ worker.run();
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
} else {
worker.start();
}
@@ -20775,9 +20717,10 @@
// the current [or imminent] receiver on.
private boolean isReceivingBroadcastLocked(ProcessRecord app,
ArraySet<BroadcastQueue> receivingQueues) {
- if (!app.curReceivers.isEmpty()) {
- for (BroadcastRecord r : app.curReceivers) {
- receivingQueues.add(r.queue);
+ final int N = app.curReceivers.size();
+ if (N > 0) {
+ for (int i = 0; i < N; i++) {
+ receivingQueues.add(app.curReceivers.valueAt(i).queue);
}
return true;
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index d6bd2b31..7eb922c 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -2476,7 +2476,10 @@
pw.println(" -e <NAME> <VALUE>: set argument <NAME> to <VALUE>. For test runners a");
pw.println(" common form is [-e <testrunner_flag> <value>[,<value>...]].");
pw.println(" -p <FILE>: write profiling data to <FILE>");
- pw.println(" -m: Write output as protobuf (machine readable)");
+ pw.println(" -m: Write output as protobuf to stdout (machine readable)");
+ pw.println(" -f <Optional PATH/TO/FILE>: Write output as protobuf to a file (machine");
+ pw.println(" readable). If path is not specified, default directory and file name will");
+ pw.println(" be used: /sdcard/instrument-logs/log-yyyyMMdd-hhmmss-SSS.instrumentation_data_proto");
pw.println(" -w: wait for instrumentation to finish before returning. Required for");
pw.println(" test runners.");
pw.println(" --user <USER_ID> | current: Specify user instrumentation runs in;");
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 93c0f77..eb022b7 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -13,6 +13,7 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CANCELLED;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_IS_EPHEMERAL;
@@ -28,16 +29,22 @@
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_NO_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_REPORTED_DRAWN_WITH_BUNDLE;
import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_TRANSITION_WARM_LAUNCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_METRICS;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.content.Context;
import android.metrics.LogMaker;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
import android.os.SystemClock;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseIntArray;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.os.SomeArgs;
import java.util.ArrayList;
@@ -58,6 +65,8 @@
private static final long INVALID_START_TIME = -1;
+ private static final int MSG_CHECK_VISIBILITY = 0;
+
// Preallocated strings we are sending to tron, so we don't have to allocate a new one every
// time we log.
private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
@@ -78,6 +87,23 @@
private final SparseArray<StackTransitionInfo> mStackTransitionInfo = new SparseArray<>();
private final SparseArray<StackTransitionInfo> mLastStackTransitionInfo = new SparseArray<>();
+ private final H mHandler;
+ private final class H extends Handler {
+
+ public H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_CHECK_VISIBILITY:
+ final SomeArgs args = (SomeArgs) msg.obj;
+ checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2);
+ break;
+ }
+ }
+ };
private final class StackTransitionInfo {
private ActivityRecord launchedActivity;
@@ -91,10 +117,11 @@
private boolean loggedStartingWindowDrawn;
}
- ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context) {
+ ActivityMetricsLogger(ActivityStackSupervisor supervisor, Context context, Looper looper) {
mLastLogTimeSecs = SystemClock.elapsedRealtime() / 1000;
mSupervisor = supervisor;
mContext = context;
+ mHandler = new H(looper);
}
void logWindowState() {
@@ -145,6 +172,7 @@
*/
void notifyActivityLaunching() {
if (!isAnyTransitionActive()) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunching");
mCurrentTransitionStartTime = SystemClock.uptimeMillis();
mLastTransitionStartTime = mCurrentTransitionStartTime;
}
@@ -202,6 +230,12 @@
private void notifyActivityLaunched(int resultCode, ActivityRecord launchedActivity,
boolean processRunning, boolean processSwitch) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched"
+ + " resultCode=" + resultCode
+ + " launchedActivity=" + launchedActivity
+ + " processRunning=" + processRunning
+ + " processSwitch=" + processSwitch);
+
// If we are already in an existing transition, only update the activity name, but not the
// other attributes.
final int stackId = launchedActivity != null && launchedActivity.getStack() != null
@@ -230,6 +264,8 @@
return;
}
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyActivityLaunched successful");
+
final StackTransitionInfo newInfo = new StackTransitionInfo();
newInfo.launchedActivity = launchedActivity;
newInfo.currentTransitionProcessRunning = processRunning;
@@ -243,6 +279,8 @@
* Notifies the tracker that all windows of the app have been drawn.
*/
void notifyWindowsDrawn(int stackId, long timestamp) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyWindowsDrawn stackId=" + stackId);
+
final StackTransitionInfo info = mStackTransitionInfo.get(stackId);
if (info == null || info.loggedWindowsDrawn) {
return;
@@ -276,6 +314,7 @@
if (!isAnyTransitionActive() || mLoggedTransitionStarting) {
return;
}
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyTransitionStarting");
mCurrentTransitionDelayMs = calculateDelay(timestamp);
mLoggedTransitionStarting = true;
for (int index = stackIdReasons.size() - 1; index >= 0; index--) {
@@ -295,17 +334,37 @@
* Notifies the tracker that the visibility of an app is changing.
*
* @param activityRecord the app that is changing its visibility
- * @param visible whether it's going to be visible or not
*/
- void notifyVisibilityChanged(ActivityRecord activityRecord, boolean visible) {
+ void notifyVisibilityChanged(ActivityRecord activityRecord) {
final StackTransitionInfo info = mStackTransitionInfo.get(activityRecord.getStackId());
+ if (info == null) {
+ return;
+ }
+ if (info.launchedActivity != activityRecord) {
+ return;
+ }
+ final TaskRecord t = activityRecord.getTask();
+ final SomeArgs args = SomeArgs.obtain();
+ args.arg1 = t;
+ args.arg2 = activityRecord;
+ mHandler.obtainMessage(MSG_CHECK_VISIBILITY, args).sendToTarget();
+ }
- // If we have an active transition that's waiting on a certain activity that will be
- // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
- if (info != null && !visible && info.launchedActivity == activityRecord) {
- mStackTransitionInfo.remove(activityRecord.getStackId());
- if (mStackTransitionInfo.size() == 0) {
- reset(true /* abort */);
+ private void checkVisibility(TaskRecord t, ActivityRecord r) {
+ synchronized (mSupervisor.mService) {
+
+ final StackTransitionInfo info = mStackTransitionInfo.get(r.getStackId());
+
+ // If we have an active transition that's waiting on a certain activity that will be
+ // invisible now, we'll never get onWindowsDrawn, so abort the transition if necessary.
+ if (info != null && !t.isVisible()) {
+ if (DEBUG_METRICS) Slog.i(TAG, "notifyVisibilityChanged to invisible"
+ + " activity=" + r);
+ logAppTransitionCancel(info);
+ mStackTransitionInfo.remove(r.getStackId());
+ if (mStackTransitionInfo.size() == 0) {
+ reset(true /* abort */);
+ }
}
}
}
@@ -341,6 +400,7 @@
}
private void reset(boolean abort) {
+ if (DEBUG_METRICS) Slog.i(TAG, "reset abort=" + abort);
if (!abort && isAnyTransitionActive()) {
logAppTransitionMultiEvents();
}
@@ -361,7 +421,20 @@
return (int) (timestamp - mCurrentTransitionStartTime);
}
+ private void logAppTransitionCancel(StackTransitionInfo info) {
+ final int type = getTransitionType(info);
+ if (type == -1) {
+ return;
+ }
+ final LogMaker builder = new LogMaker(APP_TRANSITION_CANCELLED);
+ builder.setPackageName(info.launchedActivity.packageName);
+ builder.setType(type);
+ builder.addTaggedData(FIELD_CLASS_NAME, info.launchedActivity.info.name);
+ mMetricsLogger.write(builder);
+ }
+
private void logAppTransitionMultiEvents() {
+ if (DEBUG_METRICS) Slog.i(TAG, "logging transition events");
for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
final StackTransitionInfo info = mStackTransitionInfo.valueAt(index);
final int type = getTransitionType(info);
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 2f0b649..b2308d5 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -77,7 +77,6 @@
import static android.content.res.Configuration.UI_MODE_TYPE_VR_HEADSET;
import static android.os.Build.VERSION_CODES.HONEYCOMB;
import static android.os.Build.VERSION_CODES.O;
-import static android.os.Build.VERSION_CODES.O_MR1;
import static android.os.Process.SYSTEM_UID;
import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.WindowManagerPolicy.NAV_BAR_LEFT;
@@ -202,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;
@@ -886,6 +887,7 @@
Entry ent = AttributeCache.instance().get(packageName,
realTheme, com.android.internal.R.styleable.Window, userId);
+
if (ent != null) {
fullscreen = !ActivityInfo.isTranslucentOrFloating(ent.array);
hasWallpaper = ent.array.getBoolean(R.styleable.Window_windowShowWallpaper, false);
@@ -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)) {
@@ -1526,7 +1529,7 @@
void setVisibility(boolean visible) {
mWindowContainerController.setVisibility(visible, mDeferHidingClient);
- mStackSupervisor.mActivityMetricsLogger.notifyVisibilityChanged(this, visible);
+ mStackSupervisor.mActivityMetricsLogger.notifyVisibilityChanged(this);
}
// TODO: Look into merging with #setVisibility()
@@ -2119,11 +2122,6 @@
}
void setRequestedOrientation(int requestedOrientation) {
- if (ActivityInfo.isFixedOrientation(requestedOrientation) && !fullscreen
- && appInfo.targetSdkVersion >= O_MR1) {
- throw new IllegalStateException("Only fullscreen activities can request orientation");
- }
-
final int displayId = getDisplayId();
final Configuration displayConfig =
mStackSupervisor.getDisplayOverrideConfiguration(displayId);
@@ -2184,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/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 88403fc..1fefbd1 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
@@ -1778,6 +1779,15 @@
return inPinnedWindowingMode();
}
+ /** @return True if the resizing of the primary-split-screen stack affects this stack size. */
+ boolean affectedBySplitScreenResize() {
+ if (!supportsSplitScreenWindowingMode()) {
+ return false;
+ }
+ final int windowingMode = getWindowingMode();
+ return windowingMode != WINDOWING_MODE_FREEFORM && windowingMode != WINDOWING_MODE_PINNED;
+ }
+
/**
* @return the top most visible activity that wants to dismiss Keyguard
*/
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 43a2a9f..062083c 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -575,7 +575,7 @@
mService = service;
mHandler = new ActivityStackSupervisorHandler(looper);
mRunningTasks = createRunningTasks();
- mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
+ mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext, looper);
mKeyguardController = new KeyguardController(service, this);
mLaunchingBoundsController = new LaunchingBoundsController();
@@ -2441,7 +2441,7 @@
Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stack.mStackId);
mWindowManager.deferSurfaceLayout();
try {
- if (stack.supportsSplitScreenWindowingMode()) {
+ if (stack.affectedBySplitScreenResize()) {
if (bounds == null && stack.inSplitScreenWindowingMode()) {
// null bounds = fullscreen windowing mode...at least for now.
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
@@ -2541,8 +2541,6 @@
null, mTmpOptions, task, task.getActivityType(), onTop);
if (onTop) {
- final int returnToType =
- toDisplay.getTopVisibleStackActivityType(WINDOWING_MODE_PINNED);
final boolean isTopTask = i == (size - 1);
// Defer resume until all the tasks have been moved to the fullscreen stack
task.reparent(toStack, ON_TOP, REPARENT_MOVE_STACK_TO_FRONT,
@@ -2631,7 +2629,7 @@
if (current.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
continue;
}
- if (!current.supportsSplitScreenWindowingMode()) {
+ if (!current.affectedBySplitScreenResize()) {
continue;
}
// Need to set windowing mode here before we try to get the dock bounds.
@@ -4177,8 +4175,8 @@
}
// Handle incorrect launch/move to secondary display if needed.
- final boolean launchOnSecondaryDisplayFailed;
if (isSecondaryDisplayPreferred) {
+ final boolean launchOnSecondaryDisplayFailed;
final int actualDisplayId = task.getStack().mDisplayId;
if (!task.canBeLaunchedOnDisplay(actualDisplayId)) {
// The task landed on an inappropriate display somehow, move it to the default
@@ -4193,34 +4191,34 @@
|| (preferredDisplayId != INVALID_DISPLAY
&& preferredDisplayId != actualDisplayId);
}
- } else {
- // The task wasn't requested to be on a secondary display.
- launchOnSecondaryDisplayFailed = false;
- }
-
- final ActivityRecord topActivity = task.getTopActivity();
- if (launchOnSecondaryDisplayFailed
- || !task.supportsSplitScreenWindowingMode() || forceNonResizable) {
if (launchOnSecondaryDisplayFailed) {
// Display a warning toast that we tried to put a non-resizeable task on a secondary
// display with config different from global config.
mService.mTaskChangeNotificationController
.notifyActivityLaunchOnSecondaryDisplayFailed();
- } else {
- // Display a warning toast that we tried to put a non-dockable task in the docked
- // stack.
- mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
+ return;
}
+ }
+
+ final ActivityRecord topActivity = task.getTopActivity();
+ if (!task.supportsSplitScreenWindowingMode() || forceNonResizable) {
+ // Display a warning toast that we tried to put a non-dockable task in the docked
+ // stack.
+ mService.mTaskChangeNotificationController.notifyActivityDismissingDockedStack();
// Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
// we need to move it to top of fullscreen stack, otherwise it will be covered.
- final ActivityStack dockedStack = task.getStack().getDisplay().getSplitScreenPrimaryStack();
+ final ActivityStack dockedStack =
+ task.getStack().getDisplay().getSplitScreenPrimaryStack();
if (dockedStack != null) {
moveTasksToFullscreenStackLocked(dockedStack, actualStack == dockedStack);
}
- } else if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
- && !topActivity.noDisplay) {
+ return;
+ }
+
+ if (topActivity != null && topActivity.isNonResizableOrForcedResizable()
+ && !topActivity.noDisplay) {
final String packageName = topActivity.appInfo.packageName;
final int reason = isSecondaryDisplayPreferred
? FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY
@@ -4489,9 +4487,12 @@
"startActivityFromRecents: Task " + taskId + " not found.");
}
- // We always want to return to the home activity instead of the recents activity from
- // whatever is started from the recents activity, so move the home stack forward.
- moveHomeStackToFront("startActivityFromRecents");
+ if (windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
+ // We always want to return to the home activity instead of the recents activity
+ // from whatever is started from the recents activity, so move the home stack
+ // forward.
+ moveHomeStackToFront("startActivityFromRecents");
+ }
// If the user must confirm credentials (e.g. when first launching a work app and the
// Work Challenge is present) let startActivityInPackage handle the intercepting.
@@ -4502,9 +4503,13 @@
mService.mActivityStarter.sendPowerHintForLaunchStartIfNeeded(true /* forceSend */,
targetActivity);
mActivityMetricsLogger.notifyActivityLaunching();
- mService.moveTaskToFrontLocked(task.taskId, 0, bOptions, true /* fromRecents */);
- mActivityMetricsLogger.notifyActivityLaunched(ActivityManager.START_TASK_TO_FRONT,
- targetActivity);
+ try {
+ mService.moveTaskToFrontLocked(task.taskId, 0, bOptions,
+ true /* fromRecents */);
+ } finally {
+ mActivityMetricsLogger.notifyActivityLaunched(START_TASK_TO_FRONT,
+ targetActivity);
+ }
// If we are launching the task in the docked stack, put it into resizing mode so
// the window renders full-screen with the background filling the void. Also only
diff --git a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
index 8306731..f22fe37 100644
--- a/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
+++ b/services/core/java/com/android/server/am/AssistDataReceiverProxy.java
@@ -37,17 +37,12 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "AssistDataReceiverProxy" : TAG_AM;
private String mCallerPackage;
- private boolean mBinderDied;
private IAssistDataReceiver mReceiver;
public AssistDataReceiverProxy(IAssistDataReceiver receiver, String callerPackage) {
- try {
- receiver.asBinder().linkToDeath(this, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Could not link to client death", e);
- }
mReceiver = receiver;
mCallerPackage = callerPackage;
+ linkToDeath();
}
@Override
@@ -58,7 +53,7 @@
@Override
public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
- if (!mBinderDied) {
+ if (mReceiver != null) {
try {
mReceiver.onHandleAssistData(data);
} catch (RemoteException e) {
@@ -70,7 +65,7 @@
@Override
public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
- if (!mBinderDied) {
+ if (mReceiver != null) {
try {
mReceiver.onHandleAssistScreenshot(screenshot);
} catch (RemoteException e) {
@@ -81,7 +76,27 @@
}
@Override
+ public void onAssistRequestCompleted() {
+ unlinkToDeath();
+ }
+
+ @Override
public void binderDied() {
- mBinderDied = true;
+ unlinkToDeath();
+ }
+
+ private void linkToDeath() {
+ try {
+ mReceiver.asBinder().linkToDeath(this, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Could not link to client death", e);
+ }
+ }
+
+ private void unlinkToDeath() {
+ if (mReceiver != null) {
+ mReceiver.asBinder().unlinkToDeath(this, 0);
+ }
+ mReceiver = null;
}
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/am/AssistDataRequester.java b/services/core/java/com/android/server/am/AssistDataRequester.java
index e32ff6e..a8f829f 100644
--- a/services/core/java/com/android/server/am/AssistDataRequester.java
+++ b/services/core/java/com/android/server/am/AssistDataRequester.java
@@ -94,6 +94,17 @@
*/
@GuardedBy("mCallbacksLock")
void onAssistScreenshotReceivedLocked(Bitmap screenshot);
+
+ /**
+ * Called when there is no more pending assist data or screenshots for the last request.
+ * If the request was canceled, then this callback will not be made. In addition, the
+ * callback will be made with the {@param mCallbacksLock} held, and only if
+ * {@link #canHandleReceivedAssistDataLocked()} is true.
+ */
+ @GuardedBy("mCallbacksLock")
+ default void onAssistRequestCompleted() {
+ // Do nothing
+ }
}
/**
@@ -131,15 +142,21 @@
* @param fetchScreenshot whether or not to fetch the screenshot, only applies if fetchData is
* true, the caller is allowed to fetch the assist data, and the current activity allows
* assist data to be fetched from it
+ * @param allowFetchData to be joined with other checks, determines whether or not the requester
+ * is allowed to fetch the assist data
+ * @param allowFetchScreenshot to be joined with other checks, determines whether or not the
+ * requester is allowed to fetch the assist screenshot
*/
- public void requestAssistData(List<IBinder> activityTokens, boolean fetchData,
- boolean fetchScreenshot, int callingUid, String callingPackage) {
- // TODO: Better handle the cancel case if a request can be reused
- // TODO: Known issue, if the assist data is not allowed on the current activity, then no
- // assist data is requested for any of the other activities
+ public void requestAssistData(List<IBinder> activityTokens, final boolean fetchData,
+ final boolean fetchScreenshot, boolean allowFetchData, boolean allowFetchScreenshot,
+ int callingUid, String callingPackage) {
+ // TODO(b/34090158): Known issue, if the assist data is not allowed on the current activity,
+ // then no assist data is requested for any of the other activities
// Early exit if there are no activity to fetch for
if (activityTokens.isEmpty()) {
+ // No activities, just dispatch request-complete
+ tryDispatchRequestComplete();
return;
}
@@ -150,8 +167,8 @@
} catch (RemoteException e) {
// Should never happen
}
- fetchData &= isAssistDataAllowed;
- fetchScreenshot &= fetchData && isAssistDataAllowed
+ allowFetchData &= isAssistDataAllowed;
+ allowFetchScreenshot &= fetchData && isAssistDataAllowed
&& (mRequestScreenshotAppOps != OP_NONE);
mCanceled = false;
@@ -162,7 +179,7 @@
if (fetchData) {
if (mAppOpsManager.checkOpNoThrow(mRequestStructureAppOps, callingUid, callingPackage)
- == MODE_ALLOWED) {
+ == MODE_ALLOWED && allowFetchData) {
final int numActivities = activityTokens.size();
for (int i = 0; i < numActivities; i++) {
IBinder topActivity = activityTokens.get(i);
@@ -177,8 +194,12 @@
mPendingDataCount++;
} else if (i == 0) {
// Wasn't allowed... given that, let's not do the screenshot either.
- dispatchAssistDataReceived(null);
- fetchScreenshot = false;
+ if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+ dispatchAssistDataReceived(null);
+ } else {
+ mAssistData.add(null);
+ }
+ allowFetchScreenshot = false;
break;
}
} catch (RemoteException e) {
@@ -187,14 +208,18 @@
}
} else {
// Wasn't allowed... given that, let's not do the screenshot either.
- dispatchAssistDataReceived(null);
- fetchScreenshot = false;
+ if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+ dispatchAssistDataReceived(null);
+ } else {
+ mAssistData.add(null);
+ }
+ allowFetchScreenshot = false;
}
}
if (fetchScreenshot) {
if (mAppOpsManager.checkOpNoThrow(mRequestScreenshotAppOps, callingUid, callingPackage)
- == MODE_ALLOWED) {
+ == MODE_ALLOWED && allowFetchScreenshot) {
try {
MetricsLogger.count(mContext, "assist_with_screen", 1);
mPendingScreenshotCount++;
@@ -203,24 +228,38 @@
// Can't happen
}
} else {
- dispatchAssistScreenshotReceived(null);
+ if (mCallbacks.canHandleReceivedAssistDataLocked()) {
+ dispatchAssistScreenshotReceived(null);
+ } else {
+ mAssistScreenshot.add(null);
+ }
}
}
+ // For the cases where we dispatch null data/screenshot due to permissions, just dispatch
+ // request-complete after those are made
+ tryDispatchRequestComplete();
}
/**
* This call should only be made when the callbacks are capable of handling the received assist
- * data.
+ * data. The owner is also responsible for locking before calling this method.
*/
public void processPendingAssistData() {
+ flushPendingAssistData();
+ tryDispatchRequestComplete();
+ }
+
+ private void flushPendingAssistData() {
final int dataCount = mAssistData.size();
for (int i = 0; i < dataCount; i++) {
dispatchAssistDataReceived(mAssistData.get(i));
}
+ mAssistData.clear();
final int screenshotsCount = mAssistScreenshot.size();
for (int i = 0; i < screenshotsCount; i++) {
dispatchAssistScreenshotReceived(mAssistScreenshot.get(i));
}
+ mAssistScreenshot.clear();
}
public int getPendingDataCount() {
@@ -254,8 +293,9 @@
if (mCallbacks.canHandleReceivedAssistDataLocked()) {
// Process any pending data and dispatch the new data as well
- processPendingAssistData();
+ flushPendingAssistData();
dispatchAssistDataReceived(data);
+ tryDispatchRequestComplete();
} else {
// Queue up the data for processing later
mAssistData.add(data);
@@ -273,8 +313,9 @@
if (mCallbacks.canHandleReceivedAssistDataLocked()) {
// Process any pending data and dispatch the new data as well
- processPendingAssistData();
+ flushPendingAssistData();
dispatchAssistScreenshotReceived(screenshot);
+ tryDispatchRequestComplete();
} else {
// Queue up the data for processing later
mAssistScreenshot.add(screenshot);
@@ -298,6 +339,13 @@
mCallbacks.onAssistScreenshotReceivedLocked(screenshot);
}
+ private void tryDispatchRequestComplete() {
+ if (mPendingDataCount == 0 && mPendingScreenshotCount == 0 &&
+ mAssistData.isEmpty() && mAssistScreenshot.isEmpty()) {
+ mCallbacks.onAssistRequestCompleted();
+ }
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix); pw.print("mPendingDataCount="); pw.println(mPendingDataCount);
pw.print(prefix); pw.print("mAssistData="); pw.println(mAssistData);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index db12ae2..a035bd0 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -21,8 +21,10 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.wifi.WifiActivityEnergyInfo;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
+import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -52,7 +54,6 @@
import com.android.internal.os.RpmStats;
import com.android.internal.util.DumpUtils;
import com.android.server.LocalServices;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import android.util.StatsLog;
import java.io.File;
@@ -177,9 +178,22 @@
}
public void publish() {
+ LocalServices.addService(BatteryStatsInternal.class, new LocalService());
ServiceManager.addService(BatteryStats.SERVICE_NAME, asBinder());
}
+ private final class LocalService extends BatteryStatsInternal {
+ @Override
+ public String[] getWifiIfaces() {
+ return mStats.getWifiIfaces().clone();
+ }
+
+ @Override
+ public String[] getMobileIfaces() {
+ return mStats.getMobileIfaces().clone();
+ }
+ }
+
private static void awaitUninterruptibly(Future<?> future) {
while (true) {
try {
diff --git a/services/core/java/com/android/server/am/RunningTasks.java b/services/core/java/com/android/server/am/RunningTasks.java
index 400b03a..c860df8 100644
--- a/services/core/java/com/android/server/am/RunningTasks.java
+++ b/services/core/java/com/android/server/am/RunningTasks.java
@@ -47,8 +47,10 @@
void getTasks(int maxNum, List<RunningTaskInfo> list, @ActivityType int ignoreActivityType,
@WindowingMode int ignoreWindowingMode, SparseArray<ActivityDisplay> activityDisplays,
int callingUid, boolean allowed) {
- // For each stack on each display, add the tasks into the sorted set and then pull the first
- // {@param maxNum} from the set
+ // Return early if there are no tasks to fetch
+ if (maxNum <= 0) {
+ return;
+ }
// Gather all of the tasks across all of the tasks, and add them to the sorted set
mTmpSortedSet.clear();
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/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 1a4f9d4..c5514fb 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1036,6 +1036,16 @@
return null;
}
+ boolean isVisible() {
+ for (int i = mActivities.size() - 1; i >= 0; --i) {
+ final ActivityRecord r = mActivities.get(i);
+ if (r.visible) {
+ return true;
+ }
+ }
+ return false;
+ }
+
void getAllRunningVisibleActivitiesLocked(ArrayList<ActivityRecord> outActivities) {
if (mStack != null) {
for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 5eb2a8d..3f23737 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -122,6 +122,7 @@
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityManager;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.XmlUtils;
import com.android.server.EventLogTags;
@@ -398,8 +399,9 @@
* {@link AudioManager#RINGER_MODE_SILENT}, or
* {@link AudioManager#RINGER_MODE_VIBRATE}.
*/
- // protected by mSettingsLock
+ @GuardedBy("mSettingsLock")
private int mRingerMode; // internal ringer mode, affects muting of underlying streams
+ @GuardedBy("mSettingsLock")
private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
/** @see System#MODE_RINGER_STREAMS_AFFECTED */
@@ -929,8 +931,11 @@
mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_RECORD, mForcedUseForComm,
"onAudioServerDied"));
AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
- final int forSys = mCameraSoundForced ?
- AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
+ final int forSys;
+ synchronized (mSettingsLock) {
+ forSys = mCameraSoundForced ?
+ AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE;
+ }
mForceUseLogger.log(new ForceUseEvent(AudioSystem.FOR_SYSTEM, forSys,
"onAudioServerDied"));
AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, forSys);
@@ -3797,6 +3802,7 @@
return (mRingerModeMutedStreams & (1 << streamType)) != 0;
}
+ @GuardedBy("mSettingsLock")
private boolean updateRingerModeAffectedStreams() {
int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
Settings.System.MODE_RINGER_STREAMS_AFFECTED,
@@ -3810,12 +3816,10 @@
ringerModeAffectedStreams = mRingerModeDelegate
.getRingerModeAffectedStreams(ringerModeAffectedStreams);
}
- synchronized (mCameraSoundForced) {
- if (mCameraSoundForced) {
- ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- } else {
- ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
- }
+ if (mCameraSoundForced) {
+ ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
+ } else {
+ ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
}
if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
@@ -4185,7 +4189,6 @@
// 2 mSetModeDeathHandlers
// 3 mSettingsLock
// 4 VolumeStreamState.class
- // 5 mCameraSoundForced
public class VolumeStreamState {
private final int mStreamType;
private final int mIndexMin;
@@ -4252,27 +4255,28 @@
}
public void readSettings() {
- synchronized (VolumeStreamState.class) {
- // force maximum volume on all streams if fixed volume property is set
- if (mUseFixedVolume) {
- mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
- return;
- }
- // do not read system stream volume from settings: this stream is always aliased
- // to another stream type and its volume is never persisted. Values in settings can
- // only be stale values
- if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
- (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
- int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
- synchronized (mCameraSoundForced) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ // force maximum volume on all streams if fixed volume property is set
+ if (mUseFixedVolume) {
+ mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
+ return;
+ }
+ // do not read system stream volume from settings: this stream is always aliased
+ // to another stream type and its volume is never persisted. Values in settings can
+ // only be stale values
+ if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
+ (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
+ int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
if (mCameraSoundForced) {
index = mIndexMax;
}
+ mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
+ return;
}
- mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
- return;
}
-
+ }
+ synchronized (VolumeStreamState.class) {
int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
for (int i = 0; remainingDevices != 0; i++) {
@@ -4385,34 +4389,34 @@
public boolean setIndex(int index, int device, String caller) {
boolean changed = false;
int oldIndex;
- synchronized (VolumeStreamState.class) {
- oldIndex = getIndex(device);
- index = getValidIndex(index);
- synchronized (mCameraSoundForced) {
+ synchronized (mSettingsLock) {
+ synchronized (VolumeStreamState.class) {
+ oldIndex = getIndex(device);
+ index = getValidIndex(index);
if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
index = mIndexMax;
}
- }
- mIndexMap.put(device, index);
+ mIndexMap.put(device, index);
- changed = oldIndex != index;
- // Apply change to all streams using this one as alias if:
- // - the index actually changed OR
- // - there is no volume index stored for this device on alias stream.
- // If changing volume of current device, also change volume of current
- // device on aliased stream
- final boolean currentDevice = (device == getDeviceForStream(mStreamType));
- final int numStreamTypes = AudioSystem.getNumStreamTypes();
- for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
- final VolumeStreamState aliasStreamState = mStreamStates[streamType];
- if (streamType != mStreamType &&
- mStreamVolumeAlias[streamType] == mStreamType &&
- (changed || !aliasStreamState.hasIndexForDevice(device))) {
- final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
- aliasStreamState.setIndex(scaledIndex, device, caller);
- if (currentDevice) {
- aliasStreamState.setIndex(scaledIndex,
- getDeviceForStream(streamType), caller);
+ changed = oldIndex != index;
+ // Apply change to all streams using this one as alias if:
+ // - the index actually changed OR
+ // - there is no volume index stored for this device on alias stream.
+ // If changing volume of current device, also change volume of current
+ // device on aliased stream
+ final boolean currentDevice = (device == getDeviceForStream(mStreamType));
+ final int numStreamTypes = AudioSystem.getNumStreamTypes();
+ for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+ final VolumeStreamState aliasStreamState = mStreamStates[streamType];
+ if (streamType != mStreamType &&
+ mStreamVolumeAlias[streamType] == mStreamType &&
+ (changed || !aliasStreamState.hasIndexForDevice(device))) {
+ final int scaledIndex = rescaleIndex(index, mStreamType, streamType);
+ aliasStreamState.setIndex(scaledIndex, device, caller);
+ if (currentDevice) {
+ aliasStreamState.setIndex(scaledIndex,
+ getDeviceForStream(streamType), caller);
+ }
}
}
}
@@ -6022,13 +6026,8 @@
boolean cameraSoundForced = readCameraSoundForced();
synchronized (mSettingsLock) {
- boolean cameraSoundForcedChanged = false;
- synchronized (mCameraSoundForced) {
- if (cameraSoundForced != mCameraSoundForced) {
- mCameraSoundForced = cameraSoundForced;
- cameraSoundForcedChanged = true;
- }
- }
+ final boolean cameraSoundForcedChanged = (cameraSoundForced != mCameraSoundForced);
+ mCameraSoundForced = cameraSoundForced;
if (cameraSoundForcedChanged) {
if (!mIsSingleVolume) {
VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
@@ -6408,11 +6407,12 @@
//==========================================================================================
// cached value of com.android.internal.R.bool.config_camera_sound_forced
- private Boolean mCameraSoundForced;
+ @GuardedBy("mSettingsLock")
+ private boolean mCameraSoundForced;
// called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
public boolean isCameraSoundForced() {
- synchronized (mCameraSoundForced) {
+ synchronized (mSettingsLock) {
return mCameraSoundForced;
}
}
@@ -6734,7 +6734,9 @@
public void setRingerModeDelegate(RingerModeDelegate delegate) {
mRingerModeDelegate = delegate;
if (mRingerModeDelegate != null) {
- updateRingerModeAffectedStreams();
+ synchronized (mSettingsLock) {
+ updateRingerModeAffectedStreams();
+ }
setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
}
}
diff --git a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
index 8981db1..28c3585 100644
--- a/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
+++ b/services/core/java/com/android/server/connectivity/DefaultNetworkMetrics.java
@@ -18,9 +18,11 @@
import android.net.LinkProperties;
import android.net.metrics.DefaultNetworkEvent;
-import android.net.metrics.IpConnectivityLog;
+import android.os.SystemClock;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.BitUtils;
+import com.android.internal.util.RingBuffer;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
import java.io.PrintWriter;
@@ -35,19 +37,49 @@
private static final int ROLLING_LOG_SIZE = 64;
+ public final long creationTimeMs = SystemClock.elapsedRealtime();
+
// Event buffer used for metrics upload. The buffer is cleared when events are collected.
@GuardedBy("this")
private final List<DefaultNetworkEvent> mEvents = new ArrayList<>();
+ // Rolling event buffer used for dumpsys and bugreports.
+ @GuardedBy("this")
+ private final RingBuffer<DefaultNetworkEvent> mEventsLog =
+ new RingBuffer(DefaultNetworkEvent.class, ROLLING_LOG_SIZE);
+
+ // Information about the current status of the default network.
+ @GuardedBy("this")
+ private DefaultNetworkEvent mCurrentDefaultNetwork;
+ @GuardedBy("this")
+ private boolean mIsCurrentlyValid;
+ @GuardedBy("this")
+ private long mLastValidationTimeMs;
+ // Transport information about the last default network.
+ @GuardedBy("this")
+ private int mLastTransports;
+
+ public DefaultNetworkMetrics() {
+ newDefaultNetwork(creationTimeMs, null);
+ }
+
public synchronized void listEvents(PrintWriter pw) {
+ pw.println("default network events:");
long localTimeMs = System.currentTimeMillis();
- for (DefaultNetworkEvent ev : mEvents) {
- pw.println(ev);
+ long timeMs = SystemClock.elapsedRealtime();
+ for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
+ printEvent(localTimeMs, pw, ev);
}
+ mCurrentDefaultNetwork.updateDuration(timeMs);
+ if (mIsCurrentlyValid) {
+ updateValidationTime(timeMs);
+ mLastValidationTimeMs = timeMs;
+ }
+ printEvent(localTimeMs, pw, mCurrentDefaultNetwork);
}
public synchronized void listEventsAsProto(PrintWriter pw) {
- for (DefaultNetworkEvent ev : mEvents) {
+ for (DefaultNetworkEvent ev : mEventsLog.toArray()) {
pw.print(IpConnectivityEventBuilder.toProto(ev));
}
}
@@ -59,20 +91,75 @@
mEvents.clear();
}
- public synchronized void logDefaultNetworkEvent(
- NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
- DefaultNetworkEvent ev = new DefaultNetworkEvent();
- if (newNai != null) {
- ev.netId = newNai.network().netId;
- ev.transportTypes = newNai.networkCapabilities.getTransportTypes();
- }
- if (prevNai != null) {
- ev.prevNetId = prevNai.network().netId;
- final LinkProperties lp = prevNai.linkProperties;
- ev.prevIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
- ev.prevIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+ public synchronized void logDefaultNetworkValidity(long timeMs, boolean isValid) {
+ if (!isValid && mIsCurrentlyValid) {
+ mIsCurrentlyValid = false;
+ updateValidationTime(timeMs);
}
+ if (isValid && !mIsCurrentlyValid) {
+ mIsCurrentlyValid = true;
+ mLastValidationTimeMs = timeMs;
+ }
+ }
+
+ private void updateValidationTime(long timeMs) {
+ mCurrentDefaultNetwork.validatedMs += timeMs - mLastValidationTimeMs;
+ }
+
+ public synchronized void logDefaultNetworkEvent(
+ long timeMs, NetworkAgentInfo newNai, NetworkAgentInfo oldNai) {
+ logCurrentDefaultNetwork(timeMs, oldNai);
+ newDefaultNetwork(timeMs, newNai);
+ }
+
+ private void logCurrentDefaultNetwork(long timeMs, NetworkAgentInfo oldNai) {
+ DefaultNetworkEvent ev = mCurrentDefaultNetwork;
+ ev.updateDuration(timeMs);
+ ev.previousTransports = mLastTransports;
+ // oldNai is null if the system had no default network before the transition.
+ if (oldNai != null) {
+ // The system acquired a new default network.
+ fillLinkInfo(ev, oldNai);
+ ev.finalScore = oldNai.getCurrentScore();
+ ev.validatedMs = ev.durationMs;
+ }
+ // Only change transport of the previous default network if the event currently logged
+ // corresponds to an existing default network, and not to the absence of a default network.
+ // This allows to log pairs of transports for successive default networks regardless of
+ // whether or not the system experienced a period without any default network.
+ if (ev.transports != 0) {
+ mLastTransports = ev.transports;
+ }
mEvents.add(ev);
+ mEventsLog.append(ev);
+ }
+
+ private void newDefaultNetwork(long timeMs, NetworkAgentInfo newNai) {
+ DefaultNetworkEvent ev = new DefaultNetworkEvent(timeMs);
+ ev.durationMs = timeMs;
+ // newNai is null if the system has no default network after the transition.
+ if (newNai != null) {
+ fillLinkInfo(ev, newNai);
+ ev.initialScore = newNai.getCurrentScore();
+ if (newNai.lastValidated) {
+ mIsCurrentlyValid = true;
+ mLastValidationTimeMs = timeMs;
+ }
+ }
+ mCurrentDefaultNetwork = ev;
+ }
+
+ private static void fillLinkInfo(DefaultNetworkEvent ev, NetworkAgentInfo nai) {
+ LinkProperties lp = nai.linkProperties;
+ ev.netId = nai.network().netId;
+ ev.transports |= BitUtils.packBits(nai.networkCapabilities.getTransportTypes());
+ ev.ipv4 |= lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+ ev.ipv6 |= lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+ }
+
+ private static void printEvent(long localTimeMs, PrintWriter pw, DefaultNetworkEvent ev) {
+ long localCreationTimeMs = localTimeMs - ev.durationMs;
+ pw.println(String.format("%tT.%tL: %s", localCreationTimeMs, localCreationTimeMs, ev));
}
}
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
index 3d71ecb..a011692b 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityEventBuilder.java
@@ -25,6 +25,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+import android.net.ConnectivityManager;
import android.net.ConnectivityMetricsEvent;
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.ApfStats;
@@ -135,11 +136,17 @@
public static IpConnectivityEvent toProto(DefaultNetworkEvent in) {
IpConnectivityLogClass.DefaultNetworkEvent ev =
new IpConnectivityLogClass.DefaultNetworkEvent();
- ev.networkId = netIdOf(in.netId);
- ev.previousNetworkId = netIdOf(in.prevNetId);
- ev.transportTypes = in.transportTypes;
- ev.previousNetworkIpSupport = ipSupportOf(in);
- final IpConnectivityEvent out = buildEvent(in.netId, 0, null);
+ ev.finalScore = in.finalScore;
+ ev.initialScore = in.initialScore;
+ ev.ipSupport = ipSupportOf(in);
+ ev.defaultNetworkDurationMs = in.durationMs;
+ ev.validationDurationMs = in.validatedMs;
+ ev.previousDefaultNetworkLinkLayer = transportsToLinkLayer(in.previousTransports);
+ final IpConnectivityEvent out = buildEvent(in.netId, in.transports, null);
+ if (in.transports == 0) {
+ // Set link layer to NONE for events representing the absence of a default network.
+ out.linkLayer = IpConnectivityLogClass.NONE;
+ }
out.setDefaultNetworkEvent(ev);
return out;
}
@@ -321,13 +328,13 @@
}
private static int ipSupportOf(DefaultNetworkEvent in) {
- if (in.prevIPv4 && in.prevIPv6) {
+ if (in.ipv4 && in.ipv6) {
return IpConnectivityLogClass.DefaultNetworkEvent.DUAL;
}
- if (in.prevIPv6) {
+ if (in.ipv6) {
return IpConnectivityLogClass.DefaultNetworkEvent.IPV6;
}
- if (in.prevIPv4) {
+ if (in.ipv4) {
return IpConnectivityLogClass.DefaultNetworkEvent.IPV4;
}
return IpConnectivityLogClass.DefaultNetworkEvent.NONE;
diff --git a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
index 24217e6..f427819 100644
--- a/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
+++ b/services/core/java/com/android/server/connectivity/IpConnectivityMetrics.java
@@ -23,8 +23,6 @@
import android.net.metrics.ApfProgramEvent;
import android.net.metrics.IpConnectivityLog;
import android.os.Binder;
-import android.os.IBinder;
-import android.os.Parcelable;
import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
@@ -45,6 +43,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import java.util.function.ToIntFunction;
@@ -214,86 +213,66 @@
}
/**
- * Clears the event buffer and prints its content as a protobuf serialized byte array
+ * Clear the event buffer and prints its content as a protobuf serialized byte array
* inside a base64 encoded string.
*/
- private void cmdFlush(FileDescriptor fd, PrintWriter pw, String[] args) {
+ private void cmdFlush(PrintWriter pw) {
pw.print(flushEncodedOutput());
}
/**
- * Prints the content of the event buffer, either using the events ASCII representation
- * or using protobuf text format.
+ * Print the content of the rolling event buffer in human readable format.
+ * Also print network dns/connect statistics and recent default network events.
*/
- private void cmdList(FileDescriptor fd, PrintWriter pw, String[] args) {
- final ArrayList<ConnectivityMetricsEvent> events;
- synchronized (mLock) {
- events = new ArrayList(mBuffer);
- }
-
- if (args.length > 1 && args[1].equals("proto")) {
- for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
- pw.print(ev.toString());
- }
- if (mNetdListener != null) {
- mNetdListener.listAsProtos(pw);
- }
- mDefaultNetworkMetrics.listEventsAsProto(pw);
- return;
- }
-
+ private void cmdList(PrintWriter pw) {
+ pw.println("metrics events:");
+ final List<ConnectivityMetricsEvent> events = getEvents();
for (ConnectivityMetricsEvent ev : events) {
pw.println(ev.toString());
}
+ pw.println("");
if (mNetdListener != null) {
mNetdListener.list(pw);
}
+ pw.println("");
mDefaultNetworkMetrics.listEvents(pw);
}
- /**
- * Prints for bug reports the content of the rolling event log and the
- * content of Netd event listener.
+ /*
+ * Print the content of the rolling event buffer in text proto format.
*/
- private void cmdDumpsys(FileDescriptor fd, PrintWriter pw, String[] args) {
- final ConnectivityMetricsEvent[] events;
- synchronized (mLock) {
- events = mEventLog.toArray();
- }
- for (ConnectivityMetricsEvent ev : events) {
- pw.println(ev.toString());
+ private void cmdListAsProto(PrintWriter pw) {
+ final List<ConnectivityMetricsEvent> events = getEvents();
+ for (IpConnectivityEvent ev : IpConnectivityEventBuilder.toProto(events)) {
+ pw.print(ev.toString());
}
if (mNetdListener != null) {
- mNetdListener.list(pw);
+ mNetdListener.listAsProtos(pw);
}
- mDefaultNetworkMetrics.listEvents(pw);
+ mDefaultNetworkMetrics.listEventsAsProto(pw);
}
- private void cmdStats(FileDescriptor fd, PrintWriter pw, String[] args) {
+ /*
+ * Return a copy of metrics events stored in buffer for metrics uploading.
+ */
+ private List<ConnectivityMetricsEvent> getEvents() {
synchronized (mLock) {
- pw.println("Buffered events: " + mBuffer.size());
- pw.println("Buffer capacity: " + mCapacity);
- pw.println("Dropped events: " + mDropped);
+ return Arrays.asList(mEventLog.toArray());
}
- if (mNetdListener != null) {
- mNetdListener.dump(pw);
- }
- }
-
- private void cmdDefault(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (args.length == 0) {
- pw.println("No command");
- return;
- }
- pw.println("Unknown command " + TextUtils.join(" ", args));
}
public final class Impl extends IIpConnectivityMetrics.Stub {
- static final String CMD_FLUSH = "flush";
- static final String CMD_LIST = "list";
- static final String CMD_STATS = "stats";
- static final String CMD_DUMPSYS = "-a"; // dumpsys.cpp dumps services with "-a" as arguments
- static final String CMD_DEFAULT = CMD_STATS;
+ // Dump and flushes the metrics event buffer in base64 encoded serialized proto output.
+ static final String CMD_FLUSH = "flush";
+ // Dump the rolling buffer of metrics event in human readable proto text format.
+ static final String CMD_PROTO = "proto";
+ // Dump the rolling buffer of metrics event and pretty print events using a human readable
+ // format. Also print network dns/connect statistics and default network event time series.
+ static final String CMD_LIST = "list";
+ // By default any other argument will fall into the default case which is remapped to the
+ // "list" command. This includes most notably bug reports collected by dumpsys.cpp with
+ // the "-a" argument.
+ static final String CMD_DEFAULT = CMD_LIST;
@Override
public int logEvent(ConnectivityMetricsEvent event) {
@@ -308,19 +287,15 @@
final String cmd = (args.length > 0) ? args[0] : CMD_DEFAULT;
switch (cmd) {
case CMD_FLUSH:
- cmdFlush(fd, pw, args);
+ cmdFlush(pw);
return;
- case CMD_DUMPSYS:
- cmdDumpsys(fd, pw, args);
+ case CMD_PROTO:
+ cmdListAsProto(pw);
return;
- case CMD_LIST:
- cmdList(fd, pw, args);
- return;
- case CMD_STATS:
- cmdStats(fd, pw, args);
- return;
+ case CMD_LIST: // fallthrough
default:
- cmdDefault(fd, pw, args);
+ cmdList(pw);
+ return;
}
}
@@ -345,22 +320,22 @@
}
@Override
- public boolean registerNetdEventCallback(INetdEventCallback callback) {
+ public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
enforceNetdEventListeningPermission();
if (mNetdListener == null) {
return false;
}
- return mNetdListener.registerNetdEventCallback(callback);
+ return mNetdListener.addNetdEventCallback(callerType, callback);
}
@Override
- public boolean unregisterNetdEventCallback() {
+ public boolean removeNetdEventCallback(int callerType) {
enforceNetdEventListeningPermission();
if (mNetdListener == null) {
// if the service is null, we aren't registered anyway
return true;
}
- return mNetdListener.unregisterNetdEventCallback();
+ return mNetdListener.removeNetdEventCallback(callerType);
}
};
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 05c6e69..af138b93 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -98,21 +98,55 @@
@GuardedBy("this")
private final TokenBucket mConnectTb =
new TokenBucket(CONNECT_LATENCY_FILL_RATE, CONNECT_LATENCY_BURST_LIMIT);
- // Callback should only be registered/unregistered when logging is being enabled/disabled in DPM
- // by the device owner. It's DevicePolicyManager's responsibility to ensure that.
- @GuardedBy("this")
- private INetdEventCallback mNetdEventCallback;
- public synchronized boolean registerNetdEventCallback(INetdEventCallback callback) {
- mNetdEventCallback = callback;
+
+ /**
+ * There are only 2 possible callbacks.
+ *
+ * mNetdEventCallbackList[CALLBACK_CALLER_DEVICE_POLICY].
+ * Callback registered/unregistered when logging is being enabled/disabled in DPM
+ * by the device owner. It's DevicePolicyManager's responsibility to ensure that.
+ *
+ * mNetdEventCallbackList[CALLBACK_CALLER_NETWORK_WATCHLIST]
+ * Callback registered/unregistered by NetworkWatchlistService.
+ */
+ @GuardedBy("this")
+ private static final int[] ALLOWED_CALLBACK_TYPES = {
+ INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY,
+ INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST
+ };
+
+ @GuardedBy("this")
+ private INetdEventCallback[] mNetdEventCallbackList =
+ new INetdEventCallback[ALLOWED_CALLBACK_TYPES.length];
+
+ public synchronized boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+ if (!isValidCallerType(callerType)) {
+ Log.e(TAG, "Invalid caller type: " + callerType);
+ return false;
+ }
+ mNetdEventCallbackList[callerType] = callback;
return true;
}
- public synchronized boolean unregisterNetdEventCallback() {
- mNetdEventCallback = null;
+ public synchronized boolean removeNetdEventCallback(int callerType) {
+ if (!isValidCallerType(callerType)) {
+ Log.e(TAG, "Invalid caller type: " + callerType);
+ return false;
+ }
+ mNetdEventCallbackList[callerType] = null;
return true;
}
+ private static boolean isValidCallerType(int callerType) {
+ for (int i = 0; i < ALLOWED_CALLBACK_TYPES.length; i++) {
+ if (callerType == ALLOWED_CALLBACK_TYPES[i]) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public NetdEventListenerService(Context context) {
this(context.getSystemService(ConnectivityManager.class));
}
@@ -169,8 +203,10 @@
long timestamp = System.currentTimeMillis();
getMetricsForNetwork(timestamp, netId).addDnsResult(eventType, returnCode, latencyMs);
- if (mNetdEventCallback != null) {
- mNetdEventCallback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid);
+ for (INetdEventCallback callback : mNetdEventCallbackList) {
+ if (callback != null) {
+ callback.onDnsEvent(hostname, ipAddresses, ipAddressesCount, timestamp, uid);
+ }
}
}
@@ -184,8 +220,14 @@
long timestamp = System.currentTimeMillis();
getMetricsForNetwork(timestamp, netId).addConnectResult(error, latencyMs, ipAddr);
- if (mNetdEventCallback != null) {
- mNetdEventCallback.onConnectEvent(ipAddr, port, timestamp, uid);
+ for (INetdEventCallback callback : mNetdEventCallbackList) {
+ if (callback != null) {
+ // TODO(rickywai): Remove this checking to collect ip in watchlist.
+ if (callback ==
+ mNetdEventCallbackList[INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY]) {
+ callback.onConnectEvent(ipAddr, port, timestamp, uid);
+ }
+ }
}
}
@@ -243,24 +285,21 @@
mWakeupStats.clear();
}
- public synchronized void dump(PrintWriter writer) {
- IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- pw.println(TAG + ":");
- pw.increaseIndent();
- list(pw);
- pw.decreaseIndent();
- }
-
public synchronized void list(PrintWriter pw) {
+ pw.println("dns/connect events:");
for (int i = 0; i < mNetworkMetrics.size(); i++) {
pw.println(mNetworkMetrics.valueAt(i).connectMetrics);
}
for (int i = 0; i < mNetworkMetrics.size(); i++) {
pw.println(mNetworkMetrics.valueAt(i).dnsMetrics);
}
+ pw.println("");
+ pw.println("network statistics:");
for (NetworkMetricsSnapshot s : getNetworkMetricsSnapshots()) {
pw.println(s);
}
+ pw.println("");
+ pw.println("packet wakeup events:");
for (int i = 0; i < mWakeupStats.size(); i++) {
pw.println(mWakeupStats.valueAt(i));
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a44b18d..7715727 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -90,6 +92,8 @@
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.ConnectivityService;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -245,10 +249,10 @@
}
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
- // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+ updateCapabilities();
loadAlwaysOnPackage();
}
@@ -275,6 +279,62 @@
updateAlwaysOnNotification(detailedState);
}
+ public void updateCapabilities() {
+ final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
+ updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
+ mNetworkCapabilities);
+
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+ }
+
+ @VisibleForTesting
+ public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
+ NetworkCapabilities caps) {
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = false;
+ boolean roaming = false;
+
+ if (ArrayUtils.isEmpty(underlyingNetworks)) {
+ // No idea what the underlying networks are; assume sane defaults
+ metered = true;
+ roaming = false;
+ } else {
+ for (Network underlying : underlyingNetworks) {
+ final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
+
+ // When we have multiple networks, we have to assume the
+ // worst-case link speed and restrictions.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ if (metered) {
+ caps.removeCapability(NET_CAPABILITY_NOT_METERED);
+ } else {
+ caps.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ if (roaming) {
+ caps.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else {
+ caps.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ }
+
/**
* Chooses whether to force all connections to go though VPN.
*
@@ -1344,6 +1404,7 @@
}
}
}
+ updateCapabilities();
return true;
}
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index 6e1c21e..c4e6ff6 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -163,10 +163,6 @@
};
private SyncManager getSyncManager() {
- if (SystemProperties.getBoolean("config.disable_network", false)) {
- return null;
- }
-
synchronized(mSyncManagerLock) {
try {
// Try to create the SyncManager, return null if it fails (e.g. the disk is full).
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index f930b52..600bc42 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -1120,6 +1120,27 @@
// Dismiss the black surface without fanfare.
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
+ } else if (target == Display.STATE_ON_SUSPEND) {
+ // Want screen full-power and suspended.
+ // Wait for brightness animation to complete beforehand unless already
+ // suspended because we may not be able to change it after suspension.
+ if (mScreenBrightnessRampAnimator.isAnimating()
+ && mPowerState.getScreenState() != Display.STATE_ON_SUSPEND) {
+ return;
+ }
+
+ // If not already suspending, temporarily set the state to on until the
+ // screen on is unblocked, then suspend.
+ if (mPowerState.getScreenState() != Display.STATE_ON_SUSPEND) {
+ if (!setScreenState(Display.STATE_ON)) {
+ return;
+ }
+ setScreenState(Display.STATE_ON_SUSPEND);
+ }
+
+ // Dismiss the black surface without fanfare.
+ mPowerState.setColorFadeLevel(1.0f);
+ mPowerState.dismissColorFade();
} else {
// Want screen off.
mPendingScreenOff = true;
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index d61a418..eb9ff58 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -22,6 +22,7 @@
import com.android.server.lights.LightsManager;
import android.content.Context;
+import android.hardware.sidekick.SidekickInternal;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
@@ -35,7 +36,6 @@
import android.view.DisplayEventReceiver;
import android.view.Surface;
import android.view.SurfaceControl;
-
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
@@ -148,6 +148,8 @@
return SurfaceControl.POWER_MODE_DOZE;
case Display.STATE_DOZE_SUSPEND:
return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
+ case Display.STATE_ON_SUSPEND:
+ return SurfaceControl.POWER_MODE_ON_SUSPEND;
default:
return SurfaceControl.POWER_MODE_NORMAL;
}
@@ -170,6 +172,8 @@
private int mActiveColorMode;
private boolean mActiveColorModeInvalid;
private Display.HdrCapabilities mHdrCapabilities;
+ private boolean mSidekickActive;
+ private SidekickInternal mSidekickInternal;
private SurfaceControl.PhysicalDisplayInfo mDisplayInfos[];
@@ -181,6 +185,7 @@
updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
colorModes, activeColorMode);
updateColorModesLocked(colorModes, activeColorMode);
+ mSidekickInternal = LocalServices.getService(SidekickInternal.class);
if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
LightsManager lights = LocalServices.getService(LightsManager.class);
mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
@@ -467,6 +472,10 @@
|| oldState == Display.STATE_DOZE_SUSPEND) {
setDisplayState(Display.STATE_DOZE);
currentState = Display.STATE_DOZE;
+ } else if (state == Display.STATE_ON_SUSPEND
+ || oldState == Display.STATE_ON_SUSPEND) {
+ setDisplayState(Display.STATE_ON);
+ currentState = Display.STATE_ON;
} else {
return; // old state and new state is off
}
@@ -510,16 +519,40 @@
+ ", state=" + Display.stateToString(state) + ")");
}
+ // We must tell sidekick to stop controlling the display before we
+ // can change its power mode, so do that first.
+ if (mSidekickActive) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER,
+ "SidekickInternal#endDisplayControl");
+ try {
+ mSidekickInternal.endDisplayControl();
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ mSidekickActive = false;
+ }
+ final int mode = getPowerModeForState(state);
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
+ "id=" + displayId
+ ", state=" + Display.stateToString(state) + ")");
try {
- final int mode = getPowerModeForState(state);
SurfaceControl.setDisplayPowerMode(token, mode);
Trace.traceCounter(Trace.TRACE_TAG_POWER, "DisplayPowerMode", mode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
+ // If we're entering a suspended (but not OFF) power state and we
+ // have a sidekick available, tell it now that it can take control.
+ if (Display.isSuspendedState(state) && state != Display.STATE_OFF
+ && mSidekickInternal != null && !mSidekickActive) {
+ Trace.traceBegin(Trace.TRACE_TAG_POWER,
+ "SidekickInternal#startDisplayControl");
+ try {
+ mSidekickActive = mSidekickInternal.startDisplayControl(state);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_POWER);
+ }
+ }
}
private void setDisplayBrightness(int brightness) {
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 39f2a96..caa8522 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -174,7 +174,7 @@
private final class AppIdleStateChangeListener
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) {
boolean changed = false;
synchronized (mLock) {
if (mAppIdleParoleOn) {
diff --git a/services/core/java/com/android/server/location/GeofenceManager.java b/services/core/java/com/android/server/location/GeofenceManager.java
index 2493dfb..d50ffe9 100644
--- a/services/core/java/com/android/server/location/GeofenceManager.java
+++ b/services/core/java/com/android/server/location/GeofenceManager.java
@@ -145,7 +145,8 @@
*/
private void updateMinInterval() {
mEffectiveMinIntervalMs = Settings.Global.getLong(mResolver,
- Settings.Global.LOCATION_BACKGROUND_THROTTLE_INTERVAL_MS, DEFAULT_MIN_INTERVAL_MS);
+ Settings.Global.LOCATION_BACKGROUND_THROTTLE_PROXIMITY_ALERT_INTERVAL_MS,
+ DEFAULT_MIN_INTERVAL_MS);
}
public void addFence(LocationRequest request, Geofence geofence, PendingIntent intent,
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4cf35bc..beb7486 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -48,6 +48,7 @@
import android.net.NetworkRequest;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.BatteryStats;
import android.os.Binder;
@@ -84,7 +85,6 @@
import com.android.internal.location.ProviderRequest;
import com.android.server.power.BatterySaverPolicy;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
@@ -803,18 +803,6 @@
}
};
mGnssMetrics = new GnssMetrics();
-
- /*
- * A cycle of native_init() and native_cleanup() is needed so that callbacks are registered
- * after bootup even when location is disabled. This will allow Emergency SUPL to work even
- * when location is disabled before device restart.
- * */
- boolean isInitialized = native_init();
- if(!isInitialized) {
- Log.d(TAG, "Failed to initialize at bootup");
- } else {
- native_cleanup();
- }
}
/**
@@ -2272,6 +2260,19 @@
* this handler.
*/
private void handleInitialize() {
+ /*
+ * A cycle of native_init() and native_cleanup() is needed so that callbacks are
+ * registered after bootup even when location is disabled.
+ * This will allow Emergency SUPL to work even when location is disabled before device
+ * restart.
+ */
+ boolean isInitialized = native_init();
+ if(!isInitialized) {
+ Log.w(TAG, "Native initialization failed at bootup");
+ } else {
+ native_cleanup();
+ }
+
// load default GPS configuration
// (this configuration might change in the future based on SIM changes)
reloadGpsProperties(mContext, mProperties);
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
index b7bca1fb..ef94000 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordCrypto.java
@@ -112,7 +112,7 @@
}
}
- public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
+ public static byte[] decryptBlobV1(String keyAlias, byte[] blob, byte[] applicationId) {
try {
KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
keyStore.load(null);
@@ -120,6 +120,20 @@
SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
byte[] intermediate = decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, blob);
return decrypt(decryptionKey, intermediate);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new RuntimeException("Failed to decrypt blob", e);
+ }
+ }
+
+ public static byte[] decryptBlob(String keyAlias, byte[] blob, byte[] applicationId) {
+ try {
+ KeyStore keyStore = KeyStore.getInstance("AndroidKeyStore");
+ keyStore.load(null);
+
+ SecretKey decryptionKey = (SecretKey) keyStore.getKey(keyAlias, null);
+ byte[] intermediate = decrypt(decryptionKey, blob);
+ return decrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
} catch (CertificateException | IOException | BadPaddingException
| IllegalBlockSizeException
| KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
@@ -150,9 +164,8 @@
keyStore.setEntry(keyAlias,
new KeyStore.SecretKeyEntry(secretKey),
builder.build());
- byte[] intermediate = encrypt(secretKey, data);
- return encrypt(applicationId, APPLICATION_ID_PERSONALIZATION, intermediate);
-
+ byte[] intermediate = encrypt(applicationId, APPLICATION_ID_PERSONALIZATION, data);
+ return encrypt(secretKey, intermediate);
} catch (CertificateException | IOException | BadPaddingException
| IllegalBlockSizeException
| KeyStoreException | NoSuchPaddingException | NoSuchAlgorithmException
diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
index 9440f17..ca6c9e7 100644
--- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
+++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java
@@ -101,7 +101,8 @@
private static final byte WEAVER_VERSION = 1;
private static final int INVALID_WEAVER_SLOT = -1;
- private static final byte SYNTHETIC_PASSWORD_VERSION = 1;
+ private static final byte SYNTHETIC_PASSWORD_VERSION_V1 = 1;
+ private static final byte SYNTHETIC_PASSWORD_VERSION = 2;
private static final byte SYNTHETIC_PASSWORD_PASSWORD_BASED = 0;
private static final byte SYNTHETIC_PASSWORD_TOKEN_BASED = 1;
@@ -792,6 +793,7 @@
byte[] pwdToken = computePasswordToken(credential, pwd);
final byte[] applicationId;
+ final long sid;
int weaverSlot = loadWeaverSlot(handle, userId);
if (weaverSlot != INVALID_WEAVER_SLOT) {
// Weaver based user password
@@ -804,6 +806,7 @@
if (result.gkResponse.getResponseCode() != VerifyCredentialResponse.RESPONSE_OK) {
return result;
}
+ sid = GateKeeper.INVALID_SECURE_USER_ID;
applicationId = transformUnderWeaverSecret(pwdToken, result.gkResponse.getPayload());
} else {
byte[] gkPwdToken = passwordTokenToGkInput(pwdToken);
@@ -836,12 +839,13 @@
result.gkResponse = VerifyCredentialResponse.ERROR;
return result;
}
+ sid = sidFromPasswordHandle(pwd.passwordHandle);
applicationId = transformUnderSecdiscardable(pwdToken,
loadSecdiscardable(handle, userId));
}
result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_PASSWORD_BASED,
- applicationId, userId);
+ applicationId, sid, userId);
// Perform verifyChallenge to refresh auth tokens for GK if user password exists.
result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
@@ -877,7 +881,7 @@
}
byte[] applicationId = transformUnderSecdiscardable(token, secdiscardable);
result.authToken = unwrapSyntheticPasswordBlob(handle, SYNTHETIC_PASSWORD_TOKEN_BASED,
- applicationId, userId);
+ applicationId, 0L, userId);
if (result.authToken != null) {
result.gkResponse = verifyChallenge(gatekeeper, result.authToken, 0L, userId);
if (result.gkResponse == null) {
@@ -892,19 +896,26 @@
}
private AuthenticationToken unwrapSyntheticPasswordBlob(long handle, byte type,
- byte[] applicationId, int userId) {
+ byte[] applicationId, long sid, int userId) {
byte[] blob = loadState(SP_BLOB_NAME, handle, userId);
if (blob == null) {
return null;
}
- if (blob[0] != SYNTHETIC_PASSWORD_VERSION) {
+ final byte version = blob[0];
+ if (version != SYNTHETIC_PASSWORD_VERSION && version != SYNTHETIC_PASSWORD_VERSION_V1) {
throw new RuntimeException("Unknown blob version");
}
if (blob[1] != type) {
throw new RuntimeException("Invalid blob type");
}
- byte[] secret = decryptSPBlob(getHandleName(handle),
+ final byte[] secret;
+ if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
+ secret = SyntheticPasswordCrypto.decryptBlobV1(getHandleName(handle),
+ Arrays.copyOfRange(blob, 2, blob.length), applicationId);
+ } else {
+ secret = decryptSPBlob(getHandleName(handle),
Arrays.copyOfRange(blob, 2, blob.length), applicationId);
+ }
if (secret == null) {
Log.e(TAG, "Fail to decrypt SP for user " + userId);
return null;
@@ -919,6 +930,10 @@
} else {
result.syntheticPassword = new String(secret);
}
+ if (version == SYNTHETIC_PASSWORD_VERSION_V1) {
+ Log.i(TAG, "Upgrade v1 SP blob for user " + userId + ", type = " + type);
+ createSyntheticPasswordBlob(handle, type, result, applicationId, sid, userId);
+ }
return result;
}
diff --git a/services/core/java/com/android/server/media/AudioPlaybackMonitor.java b/services/core/java/com/android/server/media/AudioPlaybackMonitor.java
deleted file mode 100644
index 791ee82..0000000
--- a/services/core/java/com/android/server/media/AudioPlaybackMonitor.java
+++ /dev/null
@@ -1,289 +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 com.android.server.media;
-
-import android.content.Context;
-import android.media.AudioManager.AudioPlaybackCallback;
-import android.media.AudioPlaybackConfiguration;
-import android.media.IAudioService;
-import android.media.IPlaybackConfigDispatcher;
-import android.os.Binder;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.util.IntArray;
-import android.util.Log;
-import android.util.SparseArray;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Monitors changes in audio playback, and notify the newly started audio playback through the
- * {@link OnAudioPlaybackStartedListener} and the activeness change through the
- * {@link OnAudioPlaybackActiveStateListener}.
- */
-class AudioPlaybackMonitor extends IPlaybackConfigDispatcher.Stub {
- private static boolean DEBUG = MediaSessionService.DEBUG;
- private static String TAG = "AudioPlaybackMonitor";
-
- private static AudioPlaybackMonitor sInstance;
-
- /**
- * Called when audio playback is started for a given UID.
- */
- interface OnAudioPlaybackStartedListener {
- void onAudioPlaybackStarted(int uid);
- }
-
- /**
- * Called when audio player state is changed.
- */
- interface OnAudioPlayerActiveStateChangedListener {
- void onAudioPlayerActiveStateChanged(int uid, boolean active);
- }
-
- private final Object mLock = new Object();
- private final Context mContext;
- private final List<OnAudioPlaybackStartedListener> mAudioPlaybackStartedListeners
- = new ArrayList<>();
- private final List<OnAudioPlayerActiveStateChangedListener>
- mAudioPlayerActiveStateChangedListeners = new ArrayList<>();
- private final Map<Integer, Integer> mAudioPlaybackStates = new HashMap<>();
- private final Set<Integer> mActiveAudioPlaybackClientUids = new HashSet<>();
-
- // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
- // The UID whose audio playback becomes active at the last comes first.
- // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
- private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
-
- static AudioPlaybackMonitor getInstance(Context context, IAudioService audioService) {
- if (sInstance == null) {
- sInstance = new AudioPlaybackMonitor(context, audioService);
- }
- return sInstance;
- }
-
- private AudioPlaybackMonitor(Context context, IAudioService audioService) {
- mContext = context;
- try {
- audioService.registerPlaybackCallback(this);
- } catch (RemoteException e) {
- Log.wtf(TAG, "Failed to register playback callback", e);
- }
- }
-
- /**
- * Called when the {@link AudioPlaybackConfiguration} is updated.
- * <p>If an app starts audio playback, the app's local media session will be the media button
- * session. If the app has multiple media sessions, the playback active local session will be
- * picked.
- *
- * @param configs List of the current audio playback configuration
- */
- @Override
- public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
- boolean flush) {
- if (flush) {
- Binder.flushPendingCommands();
- }
- final long token = Binder.clearCallingIdentity();
- try {
- List<Integer> newActiveAudioPlaybackClientUids = new ArrayList<>();
- List<OnAudioPlayerActiveStateChangedListener> audioPlayerActiveStateChangedListeners;
- List<OnAudioPlaybackStartedListener> audioPlaybackStartedListeners;
- synchronized (mLock) {
- // Update mActiveAudioPlaybackClientUids and mSortedAudioPlaybackClientUids,
- // and find newly activated audio playbacks.
- mActiveAudioPlaybackClientUids.clear();
- for (AudioPlaybackConfiguration config : configs) {
- // Ignore inactive (i.e. not playing) or PLAYER_TYPE_JAM_SOUNDPOOL
- // (i.e. playback from the SoundPool class which is only for sound effects)
- // playback.
- // Note that we shouldn't ignore PLAYER_TYPE_UNKNOWN because it might be OEM
- // specific audio/video players.
- if (!config.isActive() || config.getPlayerType()
- == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
- continue;
- }
-
- mActiveAudioPlaybackClientUids.add(config.getClientUid());
- Integer oldState = mAudioPlaybackStates.get(config.getPlayerInterfaceId());
- if (!isActiveState(oldState)) {
- if (DEBUG) {
- Log.d(TAG, "Found a new active media playback. " +
- AudioPlaybackConfiguration.toLogFriendlyString(config));
- }
- // New active audio playback.
- newActiveAudioPlaybackClientUids.add(config.getClientUid());
- int index = mSortedAudioPlaybackClientUids.indexOf(config.getClientUid());
- if (index == 0) {
- // It's the lastly played music app already. Skip updating.
- continue;
- } else if (index > 0) {
- mSortedAudioPlaybackClientUids.remove(index);
- }
- mSortedAudioPlaybackClientUids.add(0, config.getClientUid());
- }
- }
- audioPlayerActiveStateChangedListeners = new ArrayList<>(
- mAudioPlayerActiveStateChangedListeners);
- audioPlaybackStartedListeners = new ArrayList<>(mAudioPlaybackStartedListeners);
- }
- // Notify the change of audio playback states.
- for (AudioPlaybackConfiguration config : configs) {
- boolean wasActive = isActiveState(
- mAudioPlaybackStates.get(config.getPlayerInterfaceId()));
- boolean isActive = config.isActive();
- if (wasActive != isActive) {
- for (OnAudioPlayerActiveStateChangedListener listener
- : audioPlayerActiveStateChangedListeners) {
- listener.onAudioPlayerActiveStateChanged(config.getClientUid(),
- isActive);
- }
- }
- }
- // Notify the start of audio playback
- for (int uid : newActiveAudioPlaybackClientUids) {
- for (OnAudioPlaybackStartedListener listener : audioPlaybackStartedListeners) {
- listener.onAudioPlaybackStarted(uid);
- }
- }
- mAudioPlaybackStates.clear();
- for (AudioPlaybackConfiguration config : configs) {
- mAudioPlaybackStates.put(config.getPlayerInterfaceId(), config.getPlayerState());
- }
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- /**
- * Registers OnAudioPlaybackStartedListener.
- */
- public void registerOnAudioPlaybackStartedListener(OnAudioPlaybackStartedListener listener) {
- synchronized (mLock) {
- mAudioPlaybackStartedListeners.add(listener);
- }
- }
-
- /**
- * Unregisters OnAudioPlaybackStartedListener.
- */
- public void unregisterOnAudioPlaybackStartedListener(OnAudioPlaybackStartedListener listener) {
- synchronized (mLock) {
- mAudioPlaybackStartedListeners.remove(listener);
- }
- }
-
- /**
- * Registers OnAudioPlayerActiveStateChangedListener.
- */
- public void registerOnAudioPlayerActiveStateChangedListener(
- OnAudioPlayerActiveStateChangedListener listener) {
- synchronized (mLock) {
- mAudioPlayerActiveStateChangedListeners.add(listener);
- }
- }
-
- /**
- * Unregisters OnAudioPlayerActiveStateChangedListener.
- */
- public void unregisterOnAudioPlayerActiveStateChangedListener(
- OnAudioPlayerActiveStateChangedListener listener) {
- synchronized (mLock) {
- mAudioPlayerActiveStateChangedListeners.remove(listener);
- }
- }
-
- /**
- * Returns the sorted list of UIDs that have had active audio playback. (i.e. playing an
- * audio/video) The UID whose audio playback becomes active at the last comes first.
- */
- public IntArray getSortedAudioPlaybackClientUids() {
- IntArray sortedAudioPlaybackClientUids = new IntArray();
- synchronized (mLock) {
- sortedAudioPlaybackClientUids.addAll(mSortedAudioPlaybackClientUids);
- }
- return sortedAudioPlaybackClientUids;
- }
-
- /**
- * Returns if the audio playback is active for the uid.
- */
- public boolean isPlaybackActive(int uid) {
- synchronized (mLock) {
- return mActiveAudioPlaybackClientUids.contains(uid);
- }
- }
-
- /**
- * Cleans up the sorted list of audio playback client UIDs with given {@param
- * mediaButtonSessionUid}.
- * <p>UIDs whose audio playback started after the media button session's audio playback
- * cannot be the lastly played media app. So they won't needed anymore.
- *
- * @param mediaButtonSessionUid UID of the media button session.
- */
- public void cleanUpAudioPlaybackUids(int mediaButtonSessionUid) {
- synchronized (mLock) {
- int userId = UserHandle.getUserId(mediaButtonSessionUid);
- for (int i = mSortedAudioPlaybackClientUids.size() - 1; i >= 0; i--) {
- if (mSortedAudioPlaybackClientUids.get(i) == mediaButtonSessionUid) {
- break;
- }
- int uid = mSortedAudioPlaybackClientUids.get(i);
- if (userId == UserHandle.getUserId(uid) && !isPlaybackActive(uid)) {
- // Clean up unnecessary UIDs.
- // It doesn't need to be managed profile aware because it's just to prevent
- // the list from increasing indefinitely. The media button session updating
- // shouldn't be affected by cleaning up.
- mSortedAudioPlaybackClientUids.remove(i);
- }
- }
- }
- }
-
- /**
- * Dumps {@link AudioPlaybackMonitor}.
- */
- public void dump(PrintWriter pw, String prefix) {
- synchronized (mLock) {
- pw.println(prefix + "Audio playback (lastly played comes first)");
- String indent = prefix + " ";
- for (int i = 0; i < mSortedAudioPlaybackClientUids.size(); i++) {
- int uid = mSortedAudioPlaybackClientUids.get(i);
- pw.print(indent + "uid=" + uid + " packages=");
- String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
- if (packages != null && packages.length > 0) {
- for (int j = 0; j < packages.length; j++) {
- pw.print(packages[j] + " ");
- }
- }
- pw.println();
- }
- }
- }
-
- private boolean isActiveState(Integer state) {
- return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
- }
-}
diff --git a/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
new file mode 100644
index 0000000..be223f1
--- /dev/null
+++ b/services/core/java/com/android/server/media/AudioPlayerStateMonitor.java
@@ -0,0 +1,327 @@
+/*
+ * 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.server.media;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.media.AudioPlaybackConfiguration;
+import android.media.IAudioService;
+import android.media.IPlaybackConfigDispatcher;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.IntArray;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Monitors the state changes of audio players.
+ */
+class AudioPlayerStateMonitor extends IPlaybackConfigDispatcher.Stub {
+ private static boolean DEBUG = MediaSessionService.DEBUG;
+ private static String TAG = "AudioPlayerStateMonitor";
+
+ private static AudioPlayerStateMonitor sInstance = new AudioPlayerStateMonitor();
+
+ /**
+ * Called when the state of audio player is changed.
+ */
+ interface OnAudioPlayerStateChangedListener {
+ void onAudioPlayerStateChanged(
+ int uid, int prevState, @Nullable AudioPlaybackConfiguration config);
+ }
+
+ private final static class MessageHandler extends Handler {
+ private static final int MSG_AUDIO_PLAYER_STATE_CHANGED = 1;
+
+ private final OnAudioPlayerStateChangedListener mListsner;
+
+ public MessageHandler(Looper looper, OnAudioPlayerStateChangedListener listener) {
+ super(looper);
+ mListsner = listener;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_AUDIO_PLAYER_STATE_CHANGED:
+ mListsner.onAudioPlayerStateChanged(
+ msg.arg1, msg.arg2, (AudioPlaybackConfiguration) msg.obj);
+ break;
+ }
+ }
+
+ public void sendAudioPlayerStateChangedMessage(int uid, int prevState,
+ AudioPlaybackConfiguration config) {
+ obtainMessage(MSG_AUDIO_PLAYER_STATE_CHANGED, uid, prevState, config).sendToTarget();
+ }
+ }
+
+ private final Object mLock = new Object();
+ @GuardedBy("mLock")
+ private final Map<OnAudioPlayerStateChangedListener, MessageHandler> mListenerMap =
+ new HashMap<>();
+ @GuardedBy("mLock")
+ private final Map<Integer, Integer> mAudioPlayerStates = new HashMap<>();
+ @GuardedBy("mLock")
+ private final Map<Integer, HashSet<Integer>> mAudioPlayersForUid = new HashMap<>();
+ // Sorted array of UIDs that had active audio playback. (i.e. playing an audio/video)
+ // The UID whose audio playback becomes active at the last comes first.
+ // TODO(b/35278867): Find and use unique identifier for apps because apps may share the UID.
+ @GuardedBy("mLock")
+ private final IntArray mSortedAudioPlaybackClientUids = new IntArray();
+
+ @GuardedBy("mLock")
+ private boolean mRegisteredToAudioService;
+
+ static AudioPlayerStateMonitor getInstance() {
+ return sInstance;
+ }
+
+ private AudioPlayerStateMonitor() {
+ }
+
+ /**
+ * Called when the {@link AudioPlaybackConfiguration} is updated.
+ * <p>If an app starts audio playback, the app's local media session will be the media button
+ * session. If the app has multiple media sessions, the playback active local session will be
+ * picked.
+ *
+ * @param configs List of the current audio playback configuration
+ */
+ @Override
+ public void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
+ boolean flush) {
+ if (flush) {
+ Binder.flushPendingCommands();
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ final Map<Integer, Integer> prevAudioPlayerStates = new HashMap<>(mAudioPlayerStates);
+ final Map<Integer, HashSet<Integer>> prevAudioPlayersForUid =
+ new HashMap<>(mAudioPlayersForUid);
+ synchronized (mLock) {
+ mAudioPlayerStates.clear();
+ mAudioPlayersForUid.clear();
+ for (AudioPlaybackConfiguration config : configs) {
+ int pii = config.getPlayerInterfaceId();
+ int uid = config.getClientUid();
+ mAudioPlayerStates.put(pii, config.getPlayerState());
+ HashSet<Integer> players = mAudioPlayersForUid.get(uid);
+ if (players == null) {
+ players = new HashSet<Integer>();
+ players.add(pii);
+ mAudioPlayersForUid.put(uid, players);
+ } else {
+ players.add(pii);
+ }
+ }
+ for (AudioPlaybackConfiguration config : configs) {
+ if (!config.isActive()) {
+ continue;
+ }
+
+ int uid = config.getClientUid();
+ if (!isActiveState(prevAudioPlayerStates.get(config.getPlayerInterfaceId()))) {
+ if (DEBUG) {
+ Log.d(TAG, "Found a new active media playback. " +
+ AudioPlaybackConfiguration.toLogFriendlyString(config));
+ }
+ // New active audio playback.
+ int index = mSortedAudioPlaybackClientUids.indexOf(uid);
+ if (index == 0) {
+ // It's the lastly played music app already. Skip updating.
+ continue;
+ } else if (index > 0) {
+ mSortedAudioPlaybackClientUids.remove(index);
+ }
+ mSortedAudioPlaybackClientUids.add(0, uid);
+ }
+ }
+ // Notify the change of audio player states.
+ for (AudioPlaybackConfiguration config : configs) {
+ final Integer prevState = prevAudioPlayerStates.get(config.getPlayerInterfaceId());
+ final int prevStateInt =
+ (prevState == null) ? AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN :
+ prevState.intValue();
+ if (prevStateInt != config.getPlayerState()) {
+ sendAudioPlayerStateChangedMessageLocked(
+ config.getClientUid(), prevStateInt, config);
+ }
+ }
+ for (Integer prevUid : prevAudioPlayersForUid.keySet()) {
+ // If all players for prevUid is removed, notify the prev state was
+ // PLAYER_STATE_STARTED only when there were a player whose state was
+ // PLAYER_STATE_STARTED, otherwise any inactive state is okay to notify.
+ if (!mAudioPlayersForUid.containsKey(prevUid)) {
+ Set<Integer> prevPlayers = prevAudioPlayersForUid.get(prevUid);
+ int prevState = AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN;
+ for (int pii : prevPlayers) {
+ Integer state = prevAudioPlayerStates.get(pii);
+ if (state == null) {
+ continue;
+ }
+ if (state == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ prevState = state;
+ break;
+ } else if (prevState
+ == AudioPlaybackConfiguration.PLAYER_STATE_UNKNOWN) {
+ prevState = state;
+ }
+ }
+ sendAudioPlayerStateChangedMessageLocked(prevUid, prevState, null);
+ }
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ /**
+ * Registers OnAudioPlayerStateChangedListener.
+ */
+ public void registerListener(OnAudioPlayerStateChangedListener listener, Handler handler) {
+ synchronized (mLock) {
+ mListenerMap.put(listener, new MessageHandler((handler == null) ?
+ Looper.myLooper() : handler.getLooper(), listener));
+ }
+ }
+
+ /**
+ * Unregisters OnAudioPlayerStateChangedListener.
+ */
+ public void unregisterListener(OnAudioPlayerStateChangedListener listener) {
+ synchronized (mLock) {
+ mListenerMap.remove(listener);
+ }
+ }
+
+ /**
+ * Returns the sorted list of UIDs that have had active audio playback. (i.e. playing an
+ * audio/video) The UID whose audio playback becomes active at the last comes first.
+ */
+ public IntArray getSortedAudioPlaybackClientUids() {
+ IntArray sortedAudioPlaybackClientUids = new IntArray();
+ synchronized (mLock) {
+ sortedAudioPlaybackClientUids.addAll(mSortedAudioPlaybackClientUids);
+ }
+ return sortedAudioPlaybackClientUids;
+ }
+
+ /**
+ * Returns if the audio playback is active for the uid.
+ */
+ public boolean isPlaybackActive(int uid) {
+ synchronized (mLock) {
+ Set<Integer> players = mAudioPlayersForUid.get(uid);
+ if (players == null) {
+ return false;
+ }
+ for (Integer pii : players) {
+ if (isActiveState(mAudioPlayerStates.get(pii))) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Cleans up the sorted list of audio playback client UIDs with given {@param
+ * mediaButtonSessionUid}.
+ * <p>UIDs whose audio playback are inactive and have started before the media button session's
+ * audio playback cannot be the lastly played media app. So they won't needed anymore.
+ *
+ * @param mediaButtonSessionUid UID of the media button session.
+ */
+ public void cleanUpAudioPlaybackUids(int mediaButtonSessionUid) {
+ synchronized (mLock) {
+ int userId = UserHandle.getUserId(mediaButtonSessionUid);
+ for (int i = mSortedAudioPlaybackClientUids.size() - 1; i >= 0; i--) {
+ if (mSortedAudioPlaybackClientUids.get(i) == mediaButtonSessionUid) {
+ break;
+ }
+ int uid = mSortedAudioPlaybackClientUids.get(i);
+ if (userId == UserHandle.getUserId(uid) && !isPlaybackActive(uid)) {
+ // Clean up unnecessary UIDs.
+ // It doesn't need to be managed profile aware because it's just to prevent
+ // the list from increasing indefinitely. The media button session updating
+ // shouldn't be affected by cleaning up.
+ mSortedAudioPlaybackClientUids.remove(i);
+ }
+ }
+ }
+ }
+
+ /**
+ * Dumps {@link AudioPlayerStateMonitor}.
+ */
+ public void dump(Context context, PrintWriter pw, String prefix) {
+ synchronized (mLock) {
+ pw.println(prefix + "Audio playback (lastly played comes first)");
+ String indent = prefix + " ";
+ for (int i = 0; i < mSortedAudioPlaybackClientUids.size(); i++) {
+ int uid = mSortedAudioPlaybackClientUids.get(i);
+ pw.print(indent + "uid=" + uid + " packages=");
+ String[] packages = context.getPackageManager().getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ for (int j = 0; j < packages.length; j++) {
+ pw.print(packages[j] + " ");
+ }
+ }
+ pw.println();
+ }
+ }
+ }
+
+ public void registerSelfIntoAudioServiceIfNeeded(IAudioService audioService) {
+ synchronized (mLock) {
+ try {
+ if (!mRegisteredToAudioService) {
+ audioService.registerPlaybackCallback(this);
+ mRegisteredToAudioService = true;
+ }
+ } catch (RemoteException e) {
+ Log.wtf(TAG, "Failed to register playback callback", e);
+ mRegisteredToAudioService = false;
+ }
+ }
+ }
+
+ private void sendAudioPlayerStateChangedMessageLocked(
+ final int uid, final int prevState, final AudioPlaybackConfiguration config) {
+ for (MessageHandler messageHandler : mListenerMap.values()) {
+ messageHandler.sendAudioPlayerStateChangedMessage(uid, prevState, config);
+ }
+ }
+
+ private static boolean isActiveState(Integer state) {
+ return state != null && state.equals(AudioPlaybackConfiguration.PLAYER_STATE_STARTED);
+ }
+}
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 1cfd5f0..3c9e1d4 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -19,12 +19,14 @@
import com.android.internal.util.DumpUtils;
import com.android.server.Watchdog;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.media.AudioPlaybackConfiguration;
import android.media.AudioRoutesInfo;
import android.media.AudioSystem;
import android.media.IAudioRoutesObserver;
@@ -96,7 +98,8 @@
private int mCurrentUserId = -1;
private boolean mGlobalBluetoothA2dpOn = false;
private final IAudioService mAudioService;
- private final AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
+ private final Handler mHandler = new Handler();
private final AudioRoutesInfo mCurAudioRoutesInfo = new AudioRoutesInfo();
public MediaRouterService(Context context) {
@@ -106,31 +109,57 @@
mAudioService = IAudioService.Stub.asInterface(
ServiceManager.getService(Context.AUDIO_SERVICE));
- mAudioPlaybackMonitor = AudioPlaybackMonitor.getInstance(context, mAudioService);
- mAudioPlaybackMonitor.registerOnAudioPlayerActiveStateChangedListener(
- new AudioPlaybackMonitor.OnAudioPlayerActiveStateChangedListener() {
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor.registerListener(
+ new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() {
+ static final long WAIT_MS = 500;
+ final Runnable mRestoreBluetoothA2dpRunnable = new Runnable() {
+ @Override
+ public void run() {
+ restoreBluetoothA2dp();
+ }
+ };
+
@Override
- public void onAudioPlayerActiveStateChanged(int uid, boolean active) {
+ public void onAudioPlayerStateChanged(
+ int uid, int prevState, @Nullable AudioPlaybackConfiguration config) {
+ int restoreUid = -1;
+ boolean active = config == null ? false : config.isActive();
if (active) {
- restoreRoute(uid);
+ restoreUid = uid;
+ } else if (prevState != AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+ // Noting to do if the prev state is not an active state.
+ return;
} else {
IntArray sortedAudioPlaybackClientUids =
- mAudioPlaybackMonitor.getSortedAudioPlaybackClientUids();
- boolean restored = false;
- for (int i = 0; i < sortedAudioPlaybackClientUids.size(); i++) {
- if (mAudioPlaybackMonitor.isPlaybackActive(
+ mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
+ for (int i = 0; i < sortedAudioPlaybackClientUids.size(); ++i) {
+ if (mAudioPlayerStateMonitor.isPlaybackActive(
sortedAudioPlaybackClientUids.get(i))) {
- restoreRoute(sortedAudioPlaybackClientUids.get(i));
- restored = true;
+ restoreUid = sortedAudioPlaybackClientUids.get(i);
break;
}
}
- if (!restored) {
- restoreBluetoothA2dp();
+ }
+
+ mHandler.removeCallbacks(mRestoreBluetoothA2dpRunnable);
+ if (restoreUid >= 0) {
+ restoreRoute(restoreUid);
+ if (DEBUG) {
+ Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid
+ + " active " + active + " restoring " + restoreUid);
+ }
+ } else {
+ mHandler.postDelayed(mRestoreBluetoothA2dpRunnable, WAIT_MS);
+ if (DEBUG) {
+ Slog.d(TAG, "onAudioPlayerStateChanged: " + "uid " + uid
+ + " active " + active + " delaying");
}
}
}
- });
+ }, mHandler);
+ mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
+
AudioRoutesInfo audioRoutes = null;
try {
audioRoutes = mAudioService.startWatchingRoutes(new IAudioRoutesObserver.Stub() {
@@ -261,9 +290,14 @@
final long token = Binder.clearCallingIdentity();
try {
+ ClientRecord clientRecord;
synchronized (mLock) {
- return isPlaybackActiveLocked(client);
+ clientRecord = mAllClientRecords.get(client.asBinder());
}
+ if (clientRecord != null) {
+ return mAudioPlayerStateMonitor.isPlaybackActive(clientRecord.mUid);
+ }
+ return false;
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -480,14 +514,6 @@
return null;
}
- private boolean isPlaybackActiveLocked(IMediaRouterClient client) {
- ClientRecord clientRecord = mAllClientRecords.get(client.asBinder());
- if (clientRecord != null) {
- return mAudioPlaybackMonitor.isPlaybackActive(clientRecord.mUid);
- }
- return false;
- }
-
private void setDiscoveryRequestLocked(IMediaRouterClient client,
int routeTypes, boolean activeScan) {
final IBinder binder = client.asBinder();
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index aa65244..f6a81d0 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -16,6 +16,7 @@
package com.android.server.media;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.KeyguardManager;
@@ -31,7 +32,7 @@
import android.content.pm.UserInfo;
import android.database.ContentObserver;
import android.media.AudioManager;
-import android.media.AudioManagerInternal;
+import android.media.AudioPlaybackConfiguration;
import android.media.AudioSystem;
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
@@ -68,7 +69,6 @@
import android.view.ViewConfiguration;
import com.android.internal.util.DumpUtils;
-import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.Watchdog;
import com.android.server.Watchdog.Monitor;
@@ -104,7 +104,6 @@
private KeyguardManager mKeyguardManager;
private IAudioService mAudioService;
- private AudioManagerInternal mAudioManagerInternal;
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
private INotificationManager mNotificationManager;
@@ -114,7 +113,7 @@
// It's always not null after the MediaSessionService is started.
private FullUserRecord mCurrentFullUserRecord;
private MediaSessionRecord mGlobalPrioritySession;
- private AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
// Used to notify system UI when remote volume was changed. TODO find a
// better way to handle this.
@@ -137,11 +136,16 @@
mKeyguardManager =
(KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
mAudioService = getAudioService();
- mAudioPlaybackMonitor = AudioPlaybackMonitor.getInstance(getContext(), mAudioService);
- mAudioPlaybackMonitor.registerOnAudioPlaybackStartedListener(
- new AudioPlaybackMonitor.OnAudioPlaybackStartedListener() {
+ mAudioPlayerStateMonitor = AudioPlayerStateMonitor.getInstance();
+ mAudioPlayerStateMonitor.registerListener(
+ new AudioPlayerStateMonitor.OnAudioPlayerStateChangedListener() {
@Override
- public void onAudioPlaybackStarted(int uid) {
+ public void onAudioPlayerStateChanged(
+ int uid, int prevState, @Nullable AudioPlaybackConfiguration config) {
+ if (config == null || !config.isActive() || config.getPlayerType()
+ == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
+ return;
+ }
synchronized (mLock) {
FullUserRecord user =
getFullUserRecordLocked(UserHandle.getUserId(uid));
@@ -150,8 +154,8 @@
}
}
}
- });
- mAudioManagerInternal = LocalServices.getService(AudioManagerInternal.class);
+ }, null /* handler */);
+ mAudioPlayerStateMonitor.registerSelfIntoAudioServiceIfNeeded(mAudioService);
mContentResolver = getContext().getContentResolver();
mSettingsObserver = new SettingsObserver();
mSettingsObserver.observe();
@@ -650,7 +654,7 @@
public FullUserRecord(int fullUserId) {
mFullUserId = fullUserId;
- mPriorityStack = new MediaSessionStack(mAudioPlaybackMonitor, this);
+ mPriorityStack = new MediaSessionStack(mAudioPlayerStateMonitor, this);
// Restore the remembered media button receiver before the boot.
String mediaButtonReceiver = Settings.Secure.getStringForUser(mContentResolver,
Settings.System.MEDIA_BUTTON_RECEIVER, mFullUserId);
@@ -1309,7 +1313,7 @@
for (int i = 0; i < count; i++) {
mUserRecords.valueAt(i).dumpLocked(pw, "");
}
- mAudioPlaybackMonitor.dump(pw, "");
+ mAudioPlayerStateMonitor.dump(getContext(), pw, "");
}
}
diff --git a/services/core/java/com/android/server/media/MediaSessionStack.java b/services/core/java/com/android/server/media/MediaSessionStack.java
index d9fe72e..719ec36 100644
--- a/services/core/java/com/android/server/media/MediaSessionStack.java
+++ b/services/core/java/com/android/server/media/MediaSessionStack.java
@@ -75,7 +75,7 @@
*/
private final List<MediaSessionRecord> mSessions = new ArrayList<MediaSessionRecord>();
- private final AudioPlaybackMonitor mAudioPlaybackMonitor;
+ private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
private final OnMediaButtonSessionChangedListener mOnMediaButtonSessionChangedListener;
/**
@@ -84,7 +84,6 @@
*/
private MediaSessionRecord mMediaButtonSession;
- private MediaSessionRecord mCachedDefault;
private MediaSessionRecord mCachedVolumeDefault;
/**
@@ -93,8 +92,8 @@
private final SparseArray<ArrayList<MediaSessionRecord>> mCachedActiveLists =
new SparseArray<>();
- MediaSessionStack(AudioPlaybackMonitor monitor, OnMediaButtonSessionChangedListener listener) {
- mAudioPlaybackMonitor = monitor;
+ MediaSessionStack(AudioPlayerStateMonitor monitor, OnMediaButtonSessionChangedListener listener) {
+ mAudioPlayerStateMonitor = monitor;
mOnMediaButtonSessionChangedListener = listener;
}
@@ -187,13 +186,13 @@
if (DEBUG) {
Log.d(TAG, "updateMediaButtonSessionIfNeeded, callers=" + Debug.getCallers(2));
}
- IntArray audioPlaybackUids = mAudioPlaybackMonitor.getSortedAudioPlaybackClientUids();
+ IntArray audioPlaybackUids = mAudioPlayerStateMonitor.getSortedAudioPlaybackClientUids();
for (int i = 0; i < audioPlaybackUids.size(); i++) {
MediaSessionRecord mediaButtonSession =
findMediaButtonSession(audioPlaybackUids.get(i));
if (mediaButtonSession != null) {
// Found the media button session.
- mAudioPlaybackMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
+ mAudioPlayerStateMonitor.cleanUpAudioPlaybackUids(mediaButtonSession.getUid());
if (mMediaButtonSession != mediaButtonSession) {
updateMediaButtonSession(mediaButtonSession);
}
@@ -216,7 +215,7 @@
for (MediaSessionRecord session : mSessions) {
if (uid == session.getUid()) {
if (session.getPlaybackState() != null && session.isPlaybackActive() ==
- mAudioPlaybackMonitor.isPlaybackActive(session.getUid())) {
+ mAudioPlayerStateMonitor.isPlaybackActive(session.getUid())) {
// If there's a media session whose PlaybackState matches
// the audio playback state, return it immediately.
return session;
@@ -376,7 +375,6 @@
}
private void clearCache(int userId) {
- mCachedDefault = null;
mCachedVolumeDefault = null;
mCachedActiveLists.remove(userId);
// mCachedActiveLists may also include the list of sessions for UserHandle.USER_ALL,
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b4056b3..3fa3cd4 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -142,6 +142,7 @@
import android.os.MessageQueue.IdleHandler;
import android.os.PersistableBundle;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
@@ -192,7 +193,6 @@
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.SystemConfig;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import libcore.io.IoUtils;
@@ -3746,7 +3746,7 @@
extends UsageStatsManagerInternal.AppIdleStateChangeListener {
@Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle, int bucket) {
try {
final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
PackageManager.MATCH_UNINSTALLED_PACKAGES, userId);
diff --git a/services/core/java/com/android/server/net/watchlist/DigestUtils.java b/services/core/java/com/android/server/net/watchlist/DigestUtils.java
new file mode 100644
index 0000000..57becb0
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/DigestUtils.java
@@ -0,0 +1,54 @@
+/*
+ * 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.server.net.watchlist;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+/**
+ * Utils for calculating digests.
+ */
+public class DigestUtils {
+
+ private static final int FILE_READ_BUFFER_SIZE = 16 * 1024;
+
+ private DigestUtils() {}
+
+ /** @return SHA256 hash of the provided file */
+ public static byte[] getSha256Hash(File apkFile) throws IOException, NoSuchAlgorithmException {
+ try (InputStream stream = new FileInputStream(apkFile)) {
+ return getSha256Hash(stream);
+ }
+ }
+
+ /** @return SHA256 hash of data read from the provided input stream */
+ public static byte[] getSha256Hash(InputStream stream)
+ throws IOException, NoSuchAlgorithmException {
+ MessageDigest digester = MessageDigest.getInstance("SHA256");
+
+ int bytesRead;
+ byte[] buf = new byte[FILE_READ_BUFFER_SIZE];
+ while ((bytesRead = stream.read(buf)) >= 0) {
+ digester.update(buf, 0, bytesRead);
+ }
+ return digester.digest();
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/net/watchlist/HarmfulDigests.java b/services/core/java/com/android/server/net/watchlist/HarmfulDigests.java
new file mode 100644
index 0000000..27c22ce
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/HarmfulDigests.java
@@ -0,0 +1,55 @@
+/*
+ * 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.server.net.watchlist;
+
+import com.android.internal.util.HexDump;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper class to store all harmful digests in memory.
+ * TODO: Optimize memory usage using byte array with binary search.
+ */
+class HarmfulDigests {
+
+ private final Set<String> mDigestSet;
+
+ HarmfulDigests(List<byte[]> digests) {
+ final HashSet<String> tmpDigestSet = new HashSet<>();
+ final int size = digests.size();
+ for (int i = 0; i < size; i++) {
+ tmpDigestSet.add(HexDump.toHexString(digests.get(i)));
+ }
+ mDigestSet = Collections.unmodifiableSet(tmpDigestSet);
+ }
+
+ public boolean contains(byte[] digest) {
+ return mDigestSet.contains(HexDump.toHexString(digest));
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ for (String digest : mDigestSet) {
+ pw.println(digest);
+ }
+ pw.println("");
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
new file mode 100644
index 0000000..171703a
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/NetworkWatchlistService.java
@@ -0,0 +1,267 @@
+/*
+ * 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.server.net.watchlist;
+
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
+import android.net.NetworkWatchlistManager;
+import android.net.metrics.IpConnectivityLog;
+import android.os.Binder;
+import android.os.Process;
+import android.os.SharedMemory;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.DumpUtils;
+import com.android.internal.net.INetworkWatchlistManager;
+import com.android.server.ServiceThread;
+import com.android.server.SystemService;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Implementation of network watchlist service.
+ */
+public class NetworkWatchlistService extends INetworkWatchlistManager.Stub {
+
+ private static final String TAG = NetworkWatchlistService.class.getSimpleName();
+ static final boolean DEBUG = false;
+
+ private static final String PROPERTY_NETWORK_WATCHLIST_ENABLED =
+ "ro.network_watchlist_enabled";
+
+ private static final int MAX_NUM_OF_WATCHLIST_DIGESTS = 10000;
+
+ public static class Lifecycle extends SystemService {
+ private NetworkWatchlistService mService;
+
+ public Lifecycle(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void onStart() {
+ if (!SystemProperties.getBoolean(PROPERTY_NETWORK_WATCHLIST_ENABLED, false)) {
+ // Watchlist service is disabled
+ return;
+ }
+ mService = new NetworkWatchlistService(getContext());
+ publishBinderService(Context.NETWORK_WATCHLIST_SERVICE, mService);
+ }
+
+ @Override
+ public void onBootPhase(int phase) {
+ if (!SystemProperties.getBoolean(PROPERTY_NETWORK_WATCHLIST_ENABLED, false)) {
+ // Watchlist service is disabled
+ return;
+ }
+ if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
+ try {
+ mService.initIpConnectivityMetrics();
+ mService.startWatchlistLogging();
+ } catch (RemoteException e) {
+ // Should not happen
+ }
+ ReportWatchlistJobService.schedule(getContext());
+ }
+ }
+ }
+
+ private volatile boolean mIsLoggingEnabled = false;
+ private final Object mLoggingSwitchLock = new Object();
+
+ private final WatchlistSettings mSettings;
+ private final Context mContext;
+
+ // Separate thread to handle expensive watchlist logging work.
+ private final ServiceThread mHandlerThread;
+
+ @VisibleForTesting
+ IIpConnectivityMetrics mIpConnectivityMetrics;
+ @VisibleForTesting
+ WatchlistLoggingHandler mNetworkWatchlistHandler;
+
+ public NetworkWatchlistService(Context context) {
+ mContext = context;
+ mSettings = WatchlistSettings.getInstance();
+ mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
+ /* allowIo */ false);
+ mHandlerThread.start();
+ mNetworkWatchlistHandler = new WatchlistLoggingHandler(mContext,
+ mHandlerThread.getLooper());
+ mNetworkWatchlistHandler.reportWatchlistIfNecessary();
+ }
+
+ // For testing only
+ @VisibleForTesting
+ NetworkWatchlistService(Context context, ServiceThread handlerThread,
+ WatchlistLoggingHandler handler, IIpConnectivityMetrics ipConnectivityMetrics) {
+ mContext = context;
+ mSettings = WatchlistSettings.getInstance();
+ mHandlerThread = handlerThread;
+ mNetworkWatchlistHandler = handler;
+ mIpConnectivityMetrics = ipConnectivityMetrics;
+ }
+
+ private void initIpConnectivityMetrics() {
+ mIpConnectivityMetrics = (IIpConnectivityMetrics) IIpConnectivityMetrics.Stub.asInterface(
+ ServiceManager.getService(IpConnectivityLog.SERVICE_NAME));
+ }
+
+ private final INetdEventCallback mNetdEventCallback = new INetdEventCallback.Stub() {
+ @Override
+ public void onDnsEvent(String hostname, String[] ipAddresses, int ipAddressesCount,
+ long timestamp, int uid) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+ mNetworkWatchlistHandler.asyncNetworkEvent(hostname, ipAddresses, uid);
+ }
+
+ @Override
+ public void onConnectEvent(String ipAddr, int port, long timestamp, int uid) {
+ if (!mIsLoggingEnabled) {
+ return;
+ }
+ mNetworkWatchlistHandler.asyncNetworkEvent(null, new String[]{ipAddr}, uid);
+ }
+ };
+
+ @VisibleForTesting
+ protected boolean startWatchlistLoggingImpl() throws RemoteException {
+ if (DEBUG) {
+ Slog.i(TAG, "Starting watchlist logging.");
+ }
+ synchronized (mLoggingSwitchLock) {
+ if (mIsLoggingEnabled) {
+ Slog.w(TAG, "Watchlist logging is already running");
+ return true;
+ }
+ try {
+ if (mIpConnectivityMetrics.addNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST, mNetdEventCallback)) {
+ mIsLoggingEnabled = true;
+ return true;
+ } else {
+ return false;
+ }
+ } catch (RemoteException re) {
+ // Should not happen
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public boolean startWatchlistLogging() throws RemoteException {
+ enforceWatchlistLoggingPermission();
+ return startWatchlistLoggingImpl();
+ }
+
+ @VisibleForTesting
+ protected boolean stopWatchlistLoggingImpl() {
+ if (DEBUG) {
+ Slog.i(TAG, "Stopping watchlist logging");
+ }
+ synchronized (mLoggingSwitchLock) {
+ if (!mIsLoggingEnabled) {
+ Slog.w(TAG, "Watchlist logging is not running");
+ return true;
+ }
+ // stop the logging regardless of whether we fail to unregister listener
+ mIsLoggingEnabled = false;
+
+ try {
+ return mIpConnectivityMetrics.removeNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST);
+ } catch (RemoteException re) {
+ // Should not happen
+ return false;
+ }
+ }
+ }
+
+ @Override
+ public boolean stopWatchlistLogging() throws RemoteException {
+ enforceWatchlistLoggingPermission();
+ return stopWatchlistLoggingImpl();
+ }
+
+ private void enforceWatchlistLoggingPermission() {
+ final int uid = Binder.getCallingUid();
+ if (uid != Process.SYSTEM_UID) {
+ throw new SecurityException(String.format("Uid %d has no permission to change watchlist"
+ + " setting.", uid));
+ }
+ }
+
+ /**
+ * Set a new network watchlist.
+ * This method should be called by ConfigUpdater only.
+ *
+ * @return True if network watchlist is updated.
+ */
+ public boolean setNetworkSecurityWatchlist(List<byte[]> domainsCrc32Digests,
+ List<byte[]> domainsSha256Digests,
+ List<byte[]> ipAddressesCrc32Digests,
+ List<byte[]> ipAddressesSha256Digests) {
+ Slog.i(TAG, "Setting network watchlist");
+ if (domainsCrc32Digests == null || domainsSha256Digests == null
+ || ipAddressesCrc32Digests == null || ipAddressesSha256Digests == null) {
+ Slog.e(TAG, "Parameters cannot be null");
+ return false;
+ }
+ if (domainsCrc32Digests.size() != domainsSha256Digests.size()
+ || ipAddressesCrc32Digests.size() != ipAddressesSha256Digests.size()) {
+ Slog.e(TAG, "Must need to have the same number of CRC32 and SHA256 digests");
+ return false;
+ }
+ if (domainsSha256Digests.size() + ipAddressesSha256Digests.size()
+ > MAX_NUM_OF_WATCHLIST_DIGESTS) {
+ Slog.e(TAG, "Total watchlist size cannot exceed " + MAX_NUM_OF_WATCHLIST_DIGESTS);
+ return false;
+ }
+ mSettings.writeSettingsToDisk(domainsCrc32Digests, domainsSha256Digests,
+ ipAddressesCrc32Digests, ipAddressesSha256Digests);
+ Slog.i(TAG, "Set network watchlist: Success");
+ return true;
+ }
+
+ @Override
+ public void reportWatchlistIfNecessary() {
+ // Allow any apps to trigger report event, as we won't run it if it's too early.
+ mNetworkWatchlistHandler.reportWatchlistIfNecessary();
+ }
+
+ @Override
+ protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ mSettings.dump(fd, pw, args);
+ }
+
+}
diff --git a/services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java b/services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java
new file mode 100644
index 0000000..dfeb1b2
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/ReportWatchlistJobService.java
@@ -0,0 +1,76 @@
+/*
+ * 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.server.net.watchlist;
+
+import android.app.job.JobInfo;
+import android.app.job.JobParameters;
+import android.app.job.JobScheduler;
+import android.app.job.JobService;
+import android.content.ComponentName;
+import android.content.Context;
+import android.net.NetworkWatchlistManager;
+import android.util.Slog;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A job that periodically report watchlist records.
+ */
+public class ReportWatchlistJobService extends JobService {
+
+ private static final boolean DEBUG = NetworkWatchlistService.DEBUG;
+ private static final String TAG = "WatchlistJobService";
+
+ // Unique job id used in system service, other jobs should not use the same value.
+ public static final int REPORT_WATCHLIST_RECORDS_JOB_ID = 0xd7689;
+ public static final long REPORT_WATCHLIST_RECORDS_PERIOD_MILLIS =
+ TimeUnit.HOURS.toMillis(12);
+
+ @Override
+ public boolean onStartJob(final JobParameters jobParameters) {
+ if (jobParameters.getJobId() != REPORT_WATCHLIST_RECORDS_JOB_ID) {
+ return false;
+ }
+ if (DEBUG) Slog.d(TAG, "Start scheduled job.");
+ new NetworkWatchlistManager(this).reportWatchlistIfNecessary();
+ jobFinished(jobParameters, false);
+ return true;
+ }
+
+ @Override
+ public boolean onStopJob(JobParameters jobParameters) {
+ return true; // Reschedule when possible.
+ }
+
+ /**
+ * Schedule the {@link ReportWatchlistJobService} to run periodically.
+ */
+ public static void schedule(Context context) {
+ if (DEBUG) Slog.d(TAG, "Scheduling records aggregator task");
+ final JobScheduler scheduler =
+ (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
+ scheduler.schedule(new JobInfo.Builder(REPORT_WATCHLIST_RECORDS_JOB_ID,
+ new ComponentName(context, ReportWatchlistJobService.class))
+ //.setOverrideDeadline(45 * 1000) // Schedule job soon, for testing.
+ .setPeriodic(REPORT_WATCHLIST_RECORDS_PERIOD_MILLIS)
+ .setRequiresDeviceIdle(true)
+ .setRequiresBatteryNotLow(true)
+ .setPersisted(false)
+ .build());
+ }
+
+}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
new file mode 100644
index 0000000..2247558
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistLoggingHandler.java
@@ -0,0 +1,298 @@
+/*
+ * 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.server.net.watchlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
+import android.os.Bundle;
+import android.os.DropBoxManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A Handler class for network watchlist logging on a background thread.
+ */
+class WatchlistLoggingHandler extends Handler {
+
+ private static final String TAG = WatchlistLoggingHandler.class.getSimpleName();
+ private static final boolean DEBUG = NetworkWatchlistService.DEBUG;
+
+ @VisibleForTesting
+ static final int LOG_WATCHLIST_EVENT_MSG = 1;
+ @VisibleForTesting
+ static final int REPORT_RECORDS_IF_NECESSARY_MSG = 2;
+
+ private static final long ONE_DAY_MS = TimeUnit.DAYS.toMillis(1);
+ private static final String DROPBOX_TAG = "network_watchlist_report";
+
+ private final Context mContext;
+ private final ContentResolver mResolver;
+ private final PackageManager mPm;
+ private final WatchlistReportDbHelper mDbHelper;
+ private final WatchlistSettings mSettings;
+ // A cache for uid and apk digest mapping.
+ // As uid won't be reused until reboot, it's safe to assume uid is unique per signature and app.
+ // TODO: Use more efficient data structure.
+ private final HashMap<Integer, byte[]> mCachedUidDigestMap = new HashMap<>();
+
+ private interface WatchlistEventKeys {
+ String HOST = "host";
+ String IP_ADDRESSES = "ipAddresses";
+ String UID = "uid";
+ String TIMESTAMP = "timestamp";
+ }
+
+ WatchlistLoggingHandler(Context context, Looper looper) {
+ super(looper);
+ mContext = context;
+ mPm = mContext.getPackageManager();
+ mResolver = mContext.getContentResolver();
+ mDbHelper = WatchlistReportDbHelper.getInstance(context);
+ mSettings = WatchlistSettings.getInstance();
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case LOG_WATCHLIST_EVENT_MSG: {
+ final Bundle data = msg.getData();
+ handleNetworkEvent(
+ data.getString(WatchlistEventKeys.HOST),
+ data.getStringArray(WatchlistEventKeys.IP_ADDRESSES),
+ data.getInt(WatchlistEventKeys.UID),
+ data.getLong(WatchlistEventKeys.TIMESTAMP)
+ );
+ break;
+ }
+ case REPORT_RECORDS_IF_NECESSARY_MSG:
+ tryAggregateRecords();
+ break;
+ default: {
+ Slog.d(TAG, "WatchlistLoggingHandler received an unknown of message.");
+ break;
+ }
+ }
+ }
+
+ /**
+ * Report network watchlist records if we collected enough data.
+ */
+ public void reportWatchlistIfNecessary() {
+ final Message msg = obtainMessage(REPORT_RECORDS_IF_NECESSARY_MSG);
+ sendMessage(msg);
+ }
+
+ /**
+ * Insert network traffic event to watchlist async queue processor.
+ */
+ public void asyncNetworkEvent(String host, String[] ipAddresses, int uid) {
+ final Message msg = obtainMessage(LOG_WATCHLIST_EVENT_MSG);
+ final Bundle bundle = new Bundle();
+ bundle.putString(WatchlistEventKeys.HOST, host);
+ bundle.putStringArray(WatchlistEventKeys.IP_ADDRESSES, ipAddresses);
+ bundle.putInt(WatchlistEventKeys.UID, uid);
+ bundle.putLong(WatchlistEventKeys.TIMESTAMP, System.currentTimeMillis());
+ msg.setData(bundle);
+ sendMessage(msg);
+ }
+
+ private void handleNetworkEvent(String hostname, String[] ipAddresses,
+ int uid, long timestamp) {
+ if (DEBUG) {
+ Slog.i(TAG, "handleNetworkEvent with host: " + hostname + ", uid: " + uid);
+ }
+ final String cncDomain = searchAllSubDomainsInWatchlist(hostname);
+ if (cncDomain != null) {
+ insertRecord(getDigestFromUid(uid), cncDomain, timestamp);
+ } else {
+ final String cncIp = searchIpInWatchlist(ipAddresses);
+ if (cncIp != null) {
+ insertRecord(getDigestFromUid(uid), cncIp, timestamp);
+ }
+ }
+ }
+
+ private boolean insertRecord(byte[] digest, String cncHost, long timestamp) {
+ final boolean result = mDbHelper.insertNewRecord(digest, cncHost, timestamp);
+ tryAggregateRecords();
+ return result;
+ }
+
+ private boolean shouldReportNetworkWatchlist() {
+ final long lastReportTime = Settings.Global.getLong(mResolver,
+ Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME, 0L);
+ final long currentTimestamp = System.currentTimeMillis();
+ if (currentTimestamp < lastReportTime) {
+ Slog.i(TAG, "Last report time is larger than current time, reset report");
+ mDbHelper.cleanup();
+ return false;
+ }
+ return currentTimestamp >= lastReportTime + ONE_DAY_MS;
+ }
+
+ private void tryAggregateRecords() {
+ if (shouldReportNetworkWatchlist()) {
+ Slog.i(TAG, "Start aggregating watchlist records.");
+ final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
+ if (dbox != null && !dbox.isTagEnabled(DROPBOX_TAG)) {
+ final WatchlistReportDbHelper.AggregatedResult aggregatedResult =
+ mDbHelper.getAggregatedRecords();
+ final byte[] encodedResult = encodeAggregatedResult(aggregatedResult);
+ if (encodedResult != null) {
+ addEncodedReportToDropBox(encodedResult);
+ }
+ }
+ mDbHelper.cleanup();
+ Settings.Global.putLong(mResolver, Settings.Global.NETWORK_WATCHLIST_LAST_REPORT_TIME,
+ System.currentTimeMillis());
+ } else {
+ Slog.i(TAG, "No need to aggregate record yet.");
+ }
+ }
+
+ private byte[] encodeAggregatedResult(
+ WatchlistReportDbHelper.AggregatedResult aggregatedResult) {
+ // TODO: Encode results using differential privacy.
+ return null;
+ }
+
+ private void addEncodedReportToDropBox(byte[] encodedReport) {
+ final DropBoxManager dbox = mContext.getSystemService(DropBoxManager.class);
+ dbox.addData(DROPBOX_TAG, encodedReport, 0);
+ }
+
+ /**
+ * Get app digest from app uid.
+ */
+ private byte[] getDigestFromUid(int uid) {
+ final byte[] cachedDigest = mCachedUidDigestMap.get(uid);
+ if (cachedDigest != null) {
+ return cachedDigest;
+ }
+ final String[] packageNames = mPm.getPackagesForUid(uid);
+ final int userId = UserHandle.getUserId(uid);
+ if (!ArrayUtils.isEmpty(packageNames)) {
+ for (String packageName : packageNames) {
+ try {
+ final String apkPath = mPm.getPackageInfoAsUser(packageName,
+ PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId)
+ .applicationInfo.publicSourceDir;
+ if (TextUtils.isEmpty(apkPath)) {
+ Slog.w(TAG, "Cannot find apkPath for " + packageName);
+ continue;
+ }
+ final byte[] digest = DigestUtils.getSha256Hash(new File(apkPath));
+ mCachedUidDigestMap.put(uid, digest);
+ return digest;
+ } catch (NameNotFoundException | NoSuchAlgorithmException | IOException e) {
+ Slog.e(TAG, "Should not happen", e);
+ return null;
+ }
+ }
+ } else {
+ Slog.e(TAG, "Should not happen");
+ }
+ return null;
+ }
+
+ /**
+ * Search if any ip addresses are in watchlist.
+ *
+ * @param ipAddresses Ip address that you want to search in watchlist.
+ * @return Ip address that exists in watchlist, null if it does not match anything.
+ */
+ private String searchIpInWatchlist(String[] ipAddresses) {
+ for (String ipAddress : ipAddresses) {
+ if (isIpInWatchlist(ipAddress)) {
+ return ipAddress;
+ }
+ }
+ return null;
+ }
+
+ /** Search if the ip is in watchlist */
+ private boolean isIpInWatchlist(String ipAddr) {
+ if (ipAddr == null) {
+ return false;
+ }
+ return mSettings.containsIp(ipAddr);
+ }
+
+ /** Search if the host is in watchlist */
+ private boolean isHostInWatchlist(String host) {
+ if (host == null) {
+ return false;
+ }
+ return mSettings.containsDomain(host);
+ }
+
+ /**
+ * Search if any sub-domain in host is in watchlist.
+ *
+ * @param host Host that we want to search.
+ * @return Domain that exists in watchlist, null if it does not match anything.
+ */
+ private String searchAllSubDomainsInWatchlist(String host) {
+ if (host == null) {
+ return null;
+ }
+ final String[] subDomains = getAllSubDomains(host);
+ for (String subDomain : subDomains) {
+ if (isHostInWatchlist(subDomain)) {
+ return subDomain;
+ }
+ }
+ return null;
+ }
+
+ /** Get all sub-domains in a host */
+ @VisibleForTesting
+ static String[] getAllSubDomains(String host) {
+ if (host == null) {
+ return null;
+ }
+ final ArrayList<String> subDomainList = new ArrayList<>();
+ subDomainList.add(host);
+ int index = host.indexOf(".");
+ while (index != -1) {
+ host = host.substring(index + 1);
+ if (!TextUtils.isEmpty(host)) {
+ subDomainList.add(host);
+ }
+ index = host.indexOf(".");
+ }
+ return subDomainList.toArray(new String[0]);
+ }
+}
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
new file mode 100644
index 0000000..f48463f
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistReportDbHelper.java
@@ -0,0 +1,203 @@
+/*
+ * 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.server.net.watchlist;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Pair;
+
+import com.android.internal.util.HexDump;
+
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Helper class to process watchlist read / save watchlist reports.
+ */
+class WatchlistReportDbHelper extends SQLiteOpenHelper {
+
+ private static final String TAG = "WatchlistReportDbHelper";
+
+ private static final String NAME = "watchlist_report.db";
+ private static final int VERSION = 2;
+
+ private static final int IDLE_CONNECTION_TIMEOUT_MS = 30000;
+
+ private static class WhiteListReportContract {
+ private static final String TABLE = "records";
+ private static final String APP_DIGEST = "app_digest";
+ private static final String CNC_DOMAIN = "cnc_domain";
+ private static final String TIMESTAMP = "timestamp";
+ }
+
+ private static final String CREATE_TABLE_MODEL = "CREATE TABLE "
+ + WhiteListReportContract.TABLE + "("
+ + WhiteListReportContract.APP_DIGEST + " BLOB,"
+ + WhiteListReportContract.CNC_DOMAIN + " TEXT,"
+ + WhiteListReportContract.TIMESTAMP + " INTEGER DEFAULT 0" + " )";
+
+ private static final int INDEX_DIGEST = 0;
+ private static final int INDEX_CNC_DOMAIN = 1;
+ private static final int INDEX_TIMESTAMP = 2;
+
+ private static final String[] DIGEST_DOMAIN_PROJECTION =
+ new String[] {
+ WhiteListReportContract.APP_DIGEST,
+ WhiteListReportContract.CNC_DOMAIN
+ };
+
+ private static WatchlistReportDbHelper sInstance;
+
+ /**
+ * Aggregated watchlist records.
+ */
+ public static class AggregatedResult {
+ // A list of digests that visited c&c domain or ip before.
+ Set<String> appDigestList;
+
+ // The c&c domain or ip visited before.
+ String cncDomainVisited;
+
+ // A list of app digests and c&c domain visited.
+ HashMap<String, String> appDigestCNCList;
+ }
+
+ private WatchlistReportDbHelper(Context context) {
+ super(context, WatchlistSettings.getSystemWatchlistFile(NAME).getAbsolutePath(),
+ null, VERSION);
+ // Memory optimization - close idle connections after 30s of inactivity
+ setIdleConnectionTimeout(IDLE_CONNECTION_TIMEOUT_MS);
+ }
+
+ public static synchronized WatchlistReportDbHelper getInstance(Context context) {
+ if (sInstance != null) {
+ return sInstance;
+ }
+ sInstance = new WatchlistReportDbHelper(context);
+ return sInstance;
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(CREATE_TABLE_MODEL);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO: For now, drop older tables and recreate new ones.
+ db.execSQL("DROP TABLE IF EXISTS " + WhiteListReportContract.TABLE);
+ onCreate(db);
+ }
+
+ /**
+ * Insert new watchlist record.
+ *
+ * @param appDigest The digest of an app.
+ * @param cncDomain C&C domain that app visited.
+ * @return True if success.
+ */
+ public boolean insertNewRecord(byte[] appDigest, String cncDomain,
+ long timestamp) {
+ final SQLiteDatabase db = getWritableDatabase();
+ final ContentValues values = new ContentValues();
+ values.put(WhiteListReportContract.APP_DIGEST, appDigest);
+ values.put(WhiteListReportContract.CNC_DOMAIN, cncDomain);
+ values.put(WhiteListReportContract.TIMESTAMP, timestamp);
+ return db.insert(WhiteListReportContract.TABLE, null, values) != -1;
+ }
+
+ /**
+ * Aggregate the records in database, and return a rappor encoded result.
+ */
+ public AggregatedResult getAggregatedRecords() {
+ final long twoDaysBefore = getTwoDaysBeforeTimestamp();
+ final long yesterday = getYesterdayTimestamp();
+ final String selectStatement = WhiteListReportContract.TIMESTAMP + " >= ? AND " +
+ WhiteListReportContract.TIMESTAMP + " <= ?";
+
+ final SQLiteDatabase db = getReadableDatabase();
+ Cursor c = null;
+ try {
+ c = db.query(true /* distinct */,
+ WhiteListReportContract.TABLE, DIGEST_DOMAIN_PROJECTION, selectStatement,
+ new String[]{"" + twoDaysBefore, "" + yesterday}, null, null,
+ null, null);
+ if (c == null || c.getCount() == 0) {
+ return null;
+ }
+ final AggregatedResult result = new AggregatedResult();
+ result.cncDomainVisited = null;
+ // After aggregation, each digest maximum will have only 1 record.
+ result.appDigestList = new HashSet<>();
+ result.appDigestCNCList = new HashMap<>();
+ while (c.moveToNext()) {
+ // We use hex string here as byte[] cannot be a key in HashMap.
+ String digestHexStr = HexDump.toHexString(c.getBlob(INDEX_DIGEST));
+ String cncDomain = c.getString(INDEX_CNC_DOMAIN);
+
+ result.appDigestList.add(digestHexStr);
+ if (result.cncDomainVisited != null) {
+ result.cncDomainVisited = cncDomain;
+ }
+ result.appDigestCNCList.put(digestHexStr, cncDomain);
+ }
+ return result;
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+
+ /**
+ * Remove all the records before yesterday.
+ *
+ * @return True if success.
+ */
+ public boolean cleanup() {
+ final SQLiteDatabase db = getWritableDatabase();
+ final long twoDaysBefore = getTwoDaysBeforeTimestamp();
+ final String clause = WhiteListReportContract.TIMESTAMP + "< " + twoDaysBefore;
+ return db.delete(WhiteListReportContract.TABLE, clause, null) != 0;
+ }
+
+ static long getTwoDaysBeforeTimestamp() {
+ return getMidnightTimestamp(2);
+ }
+
+ static long getYesterdayTimestamp() {
+ return getMidnightTimestamp(1);
+ }
+
+ static long getMidnightTimestamp(int daysBefore) {
+ java.util.Calendar date = new GregorianCalendar();
+ // reset hour, minutes, seconds and millis
+ date.set(java.util.Calendar.HOUR_OF_DAY, 0);
+ date.set(java.util.Calendar.MINUTE, 0);
+ date.set(java.util.Calendar.SECOND, 0);
+ date.set(java.util.Calendar.MILLISECOND, 0);
+ date.add(java.util.Calendar.DAY_OF_MONTH, -daysBefore);
+ return date.getTimeInMillis();
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
new file mode 100644
index 0000000..c50f0d5
--- /dev/null
+++ b/services/core/java/com/android/server/net/watchlist/WatchlistSettings.java
@@ -0,0 +1,284 @@
+/*
+ * 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.server.net.watchlist;
+
+import android.os.Environment;
+import android.util.AtomicFile;
+import android.util.Log;
+import android.util.Xml;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.HexDump;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.CRC32;
+
+/**
+ * A util class to do watchlist settings operations, like setting watchlist, query if a domain
+ * exists in watchlist.
+ */
+class WatchlistSettings {
+ private static final String TAG = "WatchlistSettings";
+
+ // Settings xml will be stored in /data/system/network_watchlist/watchlist_settings.xml
+ static final String SYSTEM_WATCHLIST_DIR = "network_watchlist";
+
+ private static final String WATCHLIST_XML_FILE = "watchlist_settings.xml";
+
+ private static class XmlTags {
+ private static final String WATCHLIST_SETTINGS = "watchlist-settings";
+ private static final String SHA256_DOMAIN = "sha256-domain";
+ private static final String CRC32_DOMAIN = "crc32-domain";
+ private static final String SHA256_IP = "sha256-ip";
+ private static final String CRC32_IP = "crc32-ip";
+ private static final String HASH = "hash";
+ }
+
+ private static WatchlistSettings sInstance = new WatchlistSettings();
+ private final AtomicFile mXmlFile;
+ private final Object mLock = new Object();
+ private HarmfulDigests mCrc32DomainDigests = new HarmfulDigests(new ArrayList<>());
+ private HarmfulDigests mSha256DomainDigests = new HarmfulDigests(new ArrayList<>());
+ private HarmfulDigests mCrc32IpDigests = new HarmfulDigests(new ArrayList<>());
+ private HarmfulDigests mSha256IpDigests = new HarmfulDigests(new ArrayList<>());
+
+ public static synchronized WatchlistSettings getInstance() {
+ return sInstance;
+ }
+
+ private WatchlistSettings() {
+ this(getSystemWatchlistFile(WATCHLIST_XML_FILE));
+ }
+
+ @VisibleForTesting
+ protected WatchlistSettings(File xmlFile) {
+ mXmlFile = new AtomicFile(xmlFile);
+ readSettingsLocked();
+ }
+
+ static File getSystemWatchlistFile(String filename) {
+ final File dataSystemDir = Environment.getDataSystemDirectory();
+ final File systemWatchlistDir = new File(dataSystemDir, SYSTEM_WATCHLIST_DIR);
+ systemWatchlistDir.mkdirs();
+ return new File(systemWatchlistDir, filename);
+ }
+
+ private void readSettingsLocked() {
+ synchronized (mLock) {
+ FileInputStream stream;
+ try {
+ stream = mXmlFile.openRead();
+ } catch (FileNotFoundException e) {
+ Log.i(TAG, "No watchlist settings: " + mXmlFile.getBaseFile().getAbsolutePath());
+ return;
+ }
+
+ final List<byte[]> crc32DomainList = new ArrayList<>();
+ final List<byte[]> sha256DomainList = new ArrayList<>();
+ final List<byte[]> crc32IpList = new ArrayList<>();
+ final List<byte[]> sha256IpList = new ArrayList<>();
+
+ try {
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, StandardCharsets.UTF_8.name());
+ parser.nextTag();
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ String tagName = parser.getName();
+ switch (tagName) {
+ case XmlTags.CRC32_DOMAIN:
+ parseHash(parser, tagName, crc32DomainList);
+ break;
+ case XmlTags.CRC32_IP:
+ parseHash(parser, tagName, crc32IpList);
+ break;
+ case XmlTags.SHA256_DOMAIN:
+ parseHash(parser, tagName, sha256DomainList);
+ break;
+ case XmlTags.SHA256_IP:
+ parseHash(parser, tagName, sha256IpList);
+ break;
+ default:
+ Log.w(TAG, "Unknown element: " + parser.getName());
+ XmlUtils.skipCurrentTag(parser);
+ }
+ }
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.WATCHLIST_SETTINGS);
+ writeSettingsToMemory(crc32DomainList, sha256DomainList, crc32IpList, sha256IpList);
+ } catch (IllegalStateException | NullPointerException | NumberFormatException |
+ XmlPullParserException | IOException | IndexOutOfBoundsException e) {
+ Log.w(TAG, "Failed parsing " + e);
+ } finally {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void parseHash(XmlPullParser parser, String tagName, List<byte[]> hashSet)
+ throws IOException, XmlPullParserException {
+ parser.require(XmlPullParser.START_TAG, null, tagName);
+ while (parser.nextTag() == XmlPullParser.START_TAG) {
+ parser.require(XmlPullParser.START_TAG, null, XmlTags.HASH);
+ byte[] hash = HexDump.hexStringToByteArray(parser.nextText());
+ parser.require(XmlPullParser.END_TAG, null, XmlTags.HASH);
+ hashSet.add(hash);
+ }
+ parser.require(XmlPullParser.END_TAG, null, tagName);
+ }
+
+ /**
+ * Write network watchlist settings to disk.
+ * Adb should not use it, should use writeSettingsToMemory directly instead.
+ */
+ public void writeSettingsToDisk(List<byte[]> newCrc32DomainList,
+ List<byte[]> newSha256DomainList,
+ List<byte[]> newCrc32IpList,
+ List<byte[]> newSha256IpList) {
+ synchronized (mLock) {
+ FileOutputStream stream;
+ try {
+ stream = mXmlFile.startWrite();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write display settings: " + e);
+ return;
+ }
+
+ try {
+ XmlSerializer out = new FastXmlSerializer();
+ out.setOutput(stream, StandardCharsets.UTF_8.name());
+ out.startDocument(null, true);
+ out.startTag(null, XmlTags.WATCHLIST_SETTINGS);
+
+ writeHashSetToXml(out, XmlTags.SHA256_DOMAIN, newSha256DomainList);
+ writeHashSetToXml(out, XmlTags.SHA256_IP, newSha256IpList);
+ writeHashSetToXml(out, XmlTags.CRC32_DOMAIN, newCrc32DomainList);
+ writeHashSetToXml(out, XmlTags.CRC32_IP, newCrc32IpList);
+
+ out.endTag(null, XmlTags.WATCHLIST_SETTINGS);
+ out.endDocument();
+ mXmlFile.finishWrite(stream);
+ writeSettingsToMemory(newCrc32DomainList, newSha256DomainList, newCrc32IpList,
+ newSha256IpList);
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to write display settings, restoring backup.", e);
+ mXmlFile.failWrite(stream);
+ }
+ }
+ }
+
+ /**
+ * Write network watchlist settings to memory.
+ */
+ public void writeSettingsToMemory(List<byte[]> newCrc32DomainList,
+ List<byte[]> newSha256DomainList,
+ List<byte[]> newCrc32IpList,
+ List<byte[]> newSha256IpList) {
+ synchronized (mLock) {
+ mCrc32DomainDigests = new HarmfulDigests(newCrc32DomainList);
+ mCrc32IpDigests = new HarmfulDigests(newCrc32IpList);
+ mSha256DomainDigests = new HarmfulDigests(newSha256DomainList);
+ mSha256IpDigests = new HarmfulDigests(newSha256IpList);
+ }
+ }
+
+ private static void writeHashSetToXml(XmlSerializer out, String tagName, List<byte[]> hashSet)
+ throws IOException {
+ out.startTag(null, tagName);
+ for (byte[] hash : hashSet) {
+ out.startTag(null, XmlTags.HASH);
+ out.text(HexDump.toHexString(hash));
+ out.endTag(null, XmlTags.HASH);
+ }
+ out.endTag(null, tagName);
+ }
+
+ public boolean containsDomain(String domain) {
+ // First it does a quick CRC32 check.
+ final byte[] crc32 = getCrc32(domain);
+ if (!mCrc32DomainDigests.contains(crc32)) {
+ return false;
+ }
+ // Now we do a slow SHA256 check.
+ final byte[] sha256 = getSha256(domain);
+ return mSha256DomainDigests.contains(sha256);
+ }
+
+ public boolean containsIp(String ip) {
+ // First it does a quick CRC32 check.
+ final byte[] crc32 = getCrc32(ip);
+ if (!mCrc32IpDigests.contains(crc32)) {
+ return false;
+ }
+ // Now we do a slow SHA256 check.
+ final byte[] sha256 = getSha256(ip);
+ return mSha256IpDigests.contains(sha256);
+ }
+
+
+ /** Get CRC32 of a string */
+ private byte[] getCrc32(String str) {
+ final CRC32 crc = new CRC32();
+ crc.update(str.getBytes());
+ final long tmp = crc.getValue();
+ return new byte[]{(byte)(tmp >> 24 & 255), (byte)(tmp >> 16 & 255),
+ (byte)(tmp >> 8 & 255), (byte)(tmp & 255)};
+ }
+
+ /** Get SHA256 of a string */
+ private byte[] getSha256(String str) {
+ MessageDigest messageDigest;
+ try {
+ messageDigest = MessageDigest.getInstance("SHA256");
+ } catch (NoSuchAlgorithmException e) {
+ /* can't happen */
+ return null;
+ }
+ messageDigest.update(str.getBytes());
+ return messageDigest.digest();
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("Domain CRC32 digest list:");
+ mCrc32DomainDigests.dump(fd, pw, args);
+ pw.println("Domain SHA256 digest list:");
+ mSha256DomainDigests.dump(fd, pw, args);
+ pw.println("Ip CRC32 digest list:");
+ mCrc32IpDigests.dump(fd, pw, args);
+ pw.println("Ip SHA256 digest list:");
+ mSha256IpDigests.dump(fd, pw, args);
+ }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 98b8af1..6cebdd6 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -460,7 +460,7 @@
mRankingHelper.readXml(parser, forRestore);
}
// No non-system managed services are allowed on low ram devices
- if (!ActivityManager.isLowRamDeviceStatic()) {
+ if (canUseManagedServices()) {
if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
mListeners.readXml(parser);
migratedManagedServices = true;
@@ -548,12 +548,6 @@
out.endDocument();
}
- /** Use this to check if a package can post a notification or toast. */
- private boolean checkNotificationOp(String pkg, int uid) {
- return mAppOps.checkOp(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg)
- == AppOpsManager.MODE_ALLOWED && !isPackageSuspendedForUser(pkg, uid);
- }
-
private static final class ToastRecord
{
final int pid;
@@ -2827,7 +2821,7 @@
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
try {
- if (!mActivityManager.isLowRamDevice()) {
+ if (canUseManagedServices()) {
mConditionProviders.setPackageOrComponentEnabled(
pkg, userId, true, granted);
@@ -2923,7 +2917,7 @@
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
try {
- if (!mActivityManager.isLowRamDevice()) {
+ if (canUseManagedServices()) {
mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
userId, false, granted);
mListeners.setPackageOrComponentEnabled(listener.flattenToString(),
@@ -2949,7 +2943,7 @@
checkCallerIsSystemOrShell();
final long identity = Binder.clearCallingIdentity();
try {
- if (!mActivityManager.isLowRamDevice()) {
+ if (canUseManagedServices()) {
mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
userId, false, granted);
mAssistants.setPackageOrComponentEnabled(assistant.flattenToString(),
@@ -5438,6 +5432,11 @@
}
}
+ private boolean canUseManagedServices() {
+ return !mActivityManager.isLowRamDevice()
+ || mPackageManagerClient.hasSystemFeature(PackageManager.FEATURE_WATCH);
+ }
+
private class TrimCache {
StatusBarNotification heavy;
StatusBarNotification sbnClone;
diff --git a/services/core/java/com/android/server/pm/KeySetManagerService.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
index 3574466..fca9585 100644
--- a/services/core/java/com/android/server/pm/KeySetManagerService.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -18,6 +18,8 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_APK;
+import static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
+
import com.android.internal.util.Preconditions;
import android.content.pm.PackageParser;
import android.util.ArrayMap;
@@ -341,6 +343,41 @@
return mKeySets.get(id) != null;
}
+ public boolean shouldCheckUpgradeKeySetLocked(PackageSettingBase oldPs, int scanFlags) {
+ // Can't rotate keys during boot or if sharedUser.
+ if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
+ || !oldPs.keySetData.isUsingUpgradeKeySets()) {
+ return false;
+ }
+ // app is using upgradeKeySets; make sure all are valid
+ long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
+ for (int i = 0; i < upgradeKeySets.length; i++) {
+ if (!isIdValidKeySetId(upgradeKeySets[i])) {
+ Slog.wtf(TAG, "Package "
+ + (oldPs.name != null ? oldPs.name : "<null>")
+ + " contains upgrade-key-set reference to unknown key-set: "
+ + upgradeKeySets[i]
+ + " reverting to signatures check.");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public boolean checkUpgradeKeySetLocked(PackageSettingBase oldPS,
+ PackageParser.Package newPkg) {
+ // Upgrade keysets are being used. Determine if new package has a superset of the
+ // required keys.
+ long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
+ for (int i = 0; i < upgradeKeySets.length; i++) {
+ Set<PublicKey> upgradeSet = getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
+ if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Fetches the {@link PublicKey public keys} which belong to the specified
* KeySet id.
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 86a1c03..50ac409 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -209,7 +209,7 @@
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct
// flags.
- final int dexoptFlags = getDexFlags(pkg, compilerFilter, options.isBootComplete());
+ final int dexoptFlags = getDexFlags(pkg, compilerFilter, options);
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter,
@@ -349,8 +349,7 @@
dexUseInfo.isUsedByOtherApps());
// Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
// Secondary dex files are currently not compiled at boot.
- int dexoptFlags = getDexFlags(info, compilerFilter, /* bootComplete */ true)
- | DEXOPT_SECONDARY_DEX;
+ int dexoptFlags = getDexFlags(info, compilerFilter, options) | DEXOPT_SECONDARY_DEX;
// Check the app storage and add the appropriate flags.
if (info.deviceProtectedDataDir != null &&
FileUtils.contains(info.deviceProtectedDataDir, path)) {
@@ -486,11 +485,11 @@
* filter.
*/
private int getDexFlags(PackageParser.Package pkg, String compilerFilter,
- boolean bootComplete) {
- return getDexFlags(pkg.applicationInfo, compilerFilter, bootComplete);
+ DexoptOptions options) {
+ return getDexFlags(pkg.applicationInfo, compilerFilter, options);
}
- private int getDexFlags(ApplicationInfo info, String compilerFilter, boolean bootComplete) {
+ private int getDexFlags(ApplicationInfo info, String compilerFilter, DexoptOptions options) {
int flags = info.flags;
boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
// Profile guide compiled oat files should not be public.
@@ -501,7 +500,8 @@
(isPublic ? DEXOPT_PUBLIC : 0)
| (debuggable ? DEXOPT_DEBUGGABLE : 0)
| profileFlag
- | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0);
+ | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
+ | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);
return adjustDexoptFlags(dexFlags);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7be0cde..6a0ea4ee 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -102,6 +102,15 @@
import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
+import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
+import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
+import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride;
+import static com.android.server.pm.PackageManagerServiceUtils.dumpCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.getCompressedFiles;
+import static com.android.server.pm.PackageManagerServiceUtils.getLastModifiedTime;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS;
import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
@@ -408,7 +417,7 @@
private static final boolean DEBUG_FILTERS = false;
public static final boolean DEBUG_PERMISSIONS = false;
private static final boolean DEBUG_SHARED_LIBRARIES = false;
- private static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
+ public static final boolean DEBUG_COMPRESSION = Build.IS_DEBUGGABLE;
// Debug output for dexopting. This is shared between PackageManagerService, OtaDexoptService
// and PackageDexOptimizer. All these classes have their own flag to allow switching a single
@@ -462,9 +471,9 @@
private static final String STATIC_SHARED_LIB_DELIMITER = "_";
/** Extension of the compressed packages */
- private final static String COMPRESSED_EXTENSION = ".gz";
+ public final static String COMPRESSED_EXTENSION = ".gz";
/** Suffix of stub packages on the system partition */
- private final static String STUB_SUFFIX = "-Stub";
+ public final static String STUB_SUFFIX = "-Stub";
private static final int[] EMPTY_INT_ARRAY = new int[0];
@@ -574,37 +583,6 @@
public static final int REASON_LAST = REASON_SHARED;
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
-
/**
* Version number for the package parser cache. Increment this whenever the format or
* extent of cached data changes. See {@code PackageParser#setCacheDir}.
@@ -3107,75 +3085,6 @@
}
}
- private int decompressFile(File srcFile, File dstFile) throws ErrnoException {
- if (DEBUG_COMPRESSION) {
- Slog.i(TAG, "Decompress file"
- + "; src: " + srcFile.getAbsolutePath()
- + ", dst: " + dstFile.getAbsolutePath());
- }
- try (
- InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
- OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
- ) {
- Streams.copy(fileIn, fileOut);
- Os.chmod(dstFile.getAbsolutePath(), 0644);
- return PackageManager.INSTALL_SUCCEEDED;
- } catch (IOException e) {
- logCriticalInfo(Log.ERROR, "Failed to decompress file"
- + "; src: " + srcFile.getAbsolutePath()
- + ", dst: " + dstFile.getAbsolutePath());
- }
- return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
- }
-
- private File[] getCompressedFiles(String codePath) {
- final File stubCodePath = new File(codePath);
- final String stubName = stubCodePath.getName();
-
- // The layout of a compressed package on a given partition is as follows :
- //
- // Compressed artifacts:
- //
- // /partition/ModuleName/foo.gz
- // /partation/ModuleName/bar.gz
- //
- // Stub artifact:
- //
- // /partition/ModuleName-Stub/ModuleName-Stub.apk
- //
- // In other words, stub is on the same partition as the compressed artifacts
- // and in a directory that's suffixed with "-Stub".
- int idx = stubName.lastIndexOf(STUB_SUFFIX);
- if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
- return null;
- }
-
- final File stubParentDir = stubCodePath.getParentFile();
- if (stubParentDir == null) {
- Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
- return null;
- }
-
- final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
- final File[] files = compressedPath.listFiles(new FilenameFilter() {
- @Override
- public boolean accept(File dir, String name) {
- return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
- }
- });
-
- if (DEBUG_COMPRESSION && files != null && files.length > 0) {
- Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
- }
-
- return files;
- }
-
- private boolean compressedFileExists(String codePath) {
- final File[] compressedFiles = getCompressedFiles(codePath);
- return compressedFiles != null && compressedFiles.length > 0;
- }
-
/**
* Decompresses the given package on the system image onto
* the /data partition.
@@ -5176,66 +5085,6 @@
getCallingUid(), userId, mPermissionCallback);
}
- /**
- * Get the first event id for the permission.
- *
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
- * @param name name of the permission
- *
- * @return The first event id for the permission
- */
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
-
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
- }
- }
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
-
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
- }
-
@Override
public void resetRuntimePermissions() {
mContext.enforceCallingOrSelfPermission(
@@ -5476,56 +5325,6 @@
}
/**
- * Compares two sets of signatures. Returns:
- * <br />
- * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
- * <br />
- * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
- * <br />
- * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
- * <br />
- * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
- * <br />
- * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
- */
- public static int compareSignatures(Signature[] s1, Signature[] s2) {
- if (s1 == null) {
- return s2 == null
- ? PackageManager.SIGNATURE_NEITHER_SIGNED
- : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
- }
-
- if (s2 == null) {
- return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
- }
-
- if (s1.length != s2.length) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- // Since both signature sets are of size 1, we can compare without HashSets.
- if (s1.length == 1) {
- return s1[0].equals(s2[0]) ?
- PackageManager.SIGNATURE_MATCH :
- PackageManager.SIGNATURE_NO_MATCH;
- }
-
- ArraySet<Signature> set1 = new ArraySet<Signature>();
- for (Signature sig : s1) {
- set1.add(sig);
- }
- ArraySet<Signature> set2 = new ArraySet<Signature>();
- for (Signature sig : s2) {
- set2.add(sig);
- }
- // Make sure s2 contains all signatures in s1.
- if (set1.equals(set2)) {
- return PackageManager.SIGNATURE_MATCH;
- }
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- /**
* If the database version for this type of package (internal storage or
* external storage) is less than the version where package signatures
* were updated, return true.
@@ -5535,76 +5334,11 @@
return ver.databaseVersion < DatabaseVersion.SIGNATURE_END_ENTITY;
}
- /**
- * Used for backward compatibility to make sure any packages with
- * certificate chains get upgraded to the new style. {@code existingSigs}
- * will be in the old format (since they were stored on disk from before the
- * system upgrade) and {@code scannedSigs} will be in the newer format.
- */
- private int compareSignaturesCompat(PackageSignatures existingSigs,
- PackageParser.Package scannedPkg) {
- if (!isCompatSignatureUpdateNeeded(scannedPkg)) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- ArraySet<Signature> existingSet = new ArraySet<Signature>();
- for (Signature sig : existingSigs.mSignatures) {
- existingSet.add(sig);
- }
- ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
- for (Signature sig : scannedPkg.mSignatures) {
- try {
- Signature[] chainSignatures = sig.getChainSignatures();
- for (Signature chainSig : chainSignatures) {
- scannedCompatSet.add(chainSig);
- }
- } catch (CertificateEncodingException e) {
- scannedCompatSet.add(sig);
- }
- }
- /*
- * Make sure the expanded scanned set contains all signatures in the
- * existing one.
- */
- if (scannedCompatSet.equals(existingSet)) {
- // Migrate the old signatures to the new scheme.
- existingSigs.assignSignatures(scannedPkg.mSignatures);
- // The new KeySets will be re-added later in the scanning process.
- synchronized (mPackages) {
- mSettings.mKeySetManagerService.removeAppKeySetDataLPw(scannedPkg.packageName);
- }
- return PackageManager.SIGNATURE_MATCH;
- }
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
private boolean isRecoverSignatureUpdateNeeded(PackageParser.Package scannedPkg) {
final VersionInfo ver = getSettingsVersionForPackage(scannedPkg);
return ver.databaseVersion < DatabaseVersion.SIGNATURE_MALFORMED_RECOVER;
}
- private int compareSignaturesRecover(PackageSignatures existingSigs,
- PackageParser.Package scannedPkg) {
- if (!isRecoverSignatureUpdateNeeded(scannedPkg)) {
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
- String msg = null;
- try {
- if (Signature.areEffectiveMatch(existingSigs.mSignatures, scannedPkg.mSignatures)) {
- logCriticalInfo(Log.INFO, "Recovered effectively matching certificates for "
- + scannedPkg.packageName);
- return PackageManager.SIGNATURE_MATCH;
- }
- } catch (CertificateException e) {
- msg = e.getMessage();
- }
-
- logCriticalInfo(Log.INFO,
- "Failed to recover certificates for " + scannedPkg.packageName + ": " + msg);
- return PackageManager.SIGNATURE_NO_MATCH;
- }
-
@Override
public List<String> getAllPackages() {
final int callingUid = Binder.getCallingUid();
@@ -8328,51 +8062,10 @@
parallelPackageParser.close();
}
- private static File getSettingsProblemFile() {
- File dataDir = Environment.getDataDirectory();
- File systemDir = new File(dataDir, "system");
- File fname = new File(systemDir, "uiderrors.txt");
- return fname;
- }
-
public static void reportSettingsProblem(int priority, String msg) {
logCriticalInfo(priority, msg);
}
- public static void logCriticalInfo(int priority, String msg) {
- Slog.println(priority, TAG, msg);
- EventLogTags.writePmCriticalInfo(msg);
- try {
- File fname = getSettingsProblemFile();
- FileOutputStream out = new FileOutputStream(fname, true);
- PrintWriter pw = new FastPrintWriter(out);
- SimpleDateFormat formatter = new SimpleDateFormat();
- String dateString = formatter.format(new Date(System.currentTimeMillis()));
- pw.println(dateString + ": " + msg);
- pw.close();
- FileUtils.setPermissions(
- fname.toString(),
- FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
- -1, -1);
- } catch (java.io.IOException e) {
- }
- }
-
- private long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
- if (srcFile.isDirectory()) {
- final File baseFile = new File(pkg.baseCodePath);
- long maxModifiedTime = baseFile.lastModified();
- if (pkg.splitCodePaths != null) {
- for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
- final File splitFile = new File(pkg.splitCodePaths[i]);
- maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
- }
- }
- return maxModifiedTime;
- }
- return srcFile.lastModified();
- }
-
private void collectCertificatesLI(PackageSetting ps, PackageParser.Package pkg, File srcFile,
final int policyFlags) throws PackageManagerException {
// When upgrading from pre-N MR1, verify the package time stamp using the package
@@ -8385,7 +8078,7 @@
&& !isCompatSignatureUpdateNeeded(pkg)
&& !isRecoverSignatureUpdateNeeded(pkg)) {
long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ArraySet<PublicKey> signingKs;
synchronized (mPackages) {
signingKs = ksms.getPublicKeysFromKeySetLPr(mSigningKeySetId);
@@ -8687,6 +8380,7 @@
pkg.applicationInfo.primaryCpuAbi = updatedPkg.primaryCpuAbiString;
pkg.applicationInfo.secondaryCpuAbi = updatedPkg.secondaryCpuAbiString;
}
+ pkg.mExtras = updatedPkg;
throw new PackageManagerException(Log.WARN, "Package " + ps.name + " at "
+ scanFile + " ignored: updated version " + ps.versionCode
@@ -8800,7 +8494,7 @@
return scannedPkg;
}
- private void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
+ private static void renameStaticSharedLibraryPackage(PackageParser.Package pkg) {
// Derive the new package synthetic package name
pkg.setPackageName(pkg.packageName + STATIC_SHARED_LIB_DELIMITER
+ pkg.staticSharedLibVersion);
@@ -8814,49 +8508,6 @@
return processName;
}
- private void verifySignaturesLP(PackageSetting pkgSetting, PackageParser.Package pkg)
- throws PackageManagerException {
- if (pkgSetting.signatures.mSignatures != null) {
- // Already existing package. Make sure signatures match
- boolean match = compareSignatures(pkgSetting.signatures.mSignatures, pkg.mSignatures)
- == PackageManager.SIGNATURE_MATCH;
- if (!match) {
- match = compareSignaturesCompat(pkgSetting.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- match = compareSignaturesRecover(pkgSetting.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
- + pkg.packageName + " signatures do not match the "
- + "previously installed version; ignoring!");
- }
- }
-
- // Check for shared user signatures
- if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
- // Already existing package. Make sure signatures match
- boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
- if (!match) {
- match = compareSignaturesCompat(pkgSetting.sharedUser.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- match = compareSignaturesRecover(pkgSetting.sharedUser.signatures, pkg)
- == PackageManager.SIGNATURE_MATCH;
- }
- if (!match) {
- throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
- "Package " + pkg.packageName
- + " has no signatures that match those in shared user "
- + pkgSetting.sharedUser.name + "; ignoring!");
- }
- }
- }
-
/**
* Enforces that only the system UID or root's UID can call a method exposed
* via Binder.
@@ -9827,24 +9478,6 @@
return res;
}
- /**
- * Derive the value of the {@code cpuAbiOverride} based on the provided
- * value and an optional stored value from the package settings.
- */
- private static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
- String cpuAbiOverride = null;
-
- if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
- cpuAbiOverride = null;
- } else if (abiOverride != null) {
- cpuAbiOverride = abiOverride;
- } else if (settings != null) {
- cpuAbiOverride = settings.cpuAbiOverrideString;
- }
-
- return cpuAbiOverride;
- }
-
private PackageParser.Package scanPackageTracedLI(PackageParser.Package pkg,
final int policyFlags, int scanFlags, long currentTime, @Nullable UserHandle user)
throws PackageManagerException {
@@ -10192,8 +9825,9 @@
}
}
- if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
- if (checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -10211,8 +9845,16 @@
}
} else {
try {
- // SIDE EFFECTS; compareSignaturesCompat() changes KeysetManagerService
- verifySignaturesLP(signatureCheckPs, pkg);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+ final boolean compatMatch = verifySignatures(signatureCheckPs, pkg.mSignatures,
+ compareCompat, compareRecover);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ synchronized (mPackages) {
+ ksms.removeAppKeySetDataLPw(pkg.packageName);
+ }
+ }
// We just determined the app is signed correctly, so bring
// over the latest parsed certs.
pkgSetting.signatures.mSignatures = pkg.mSignatures;
@@ -10500,7 +10142,7 @@
}
// Make sure we're not adding any bogus keyset info
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
ksms.assertScannedPackageValid(pkg);
synchronized (mPackages) {
@@ -15656,42 +15298,6 @@
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
- private boolean shouldCheckUpgradeKeySetLP(PackageSettingBase oldPs, int scanFlags) {
- // Can't rotate keys during boot or if sharedUser.
- if (oldPs == null || (scanFlags&SCAN_INITIAL) != 0 || oldPs.isSharedUser()
- || !oldPs.keySetData.isUsingUpgradeKeySets()) {
- return false;
- }
- // app is using upgradeKeySets; make sure all are valid
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- long[] upgradeKeySets = oldPs.keySetData.getUpgradeKeySets();
- for (int i = 0; i < upgradeKeySets.length; i++) {
- if (!ksms.isIdValidKeySetId(upgradeKeySets[i])) {
- Slog.wtf(TAG, "Package "
- + (oldPs.name != null ? oldPs.name : "<null>")
- + " contains upgrade-key-set reference to unknown key-set: "
- + upgradeKeySets[i]
- + " reverting to signatures check.");
- return false;
- }
- }
- return true;
- }
-
- private boolean checkUpgradeKeySetLP(PackageSettingBase oldPS, PackageParser.Package newPkg) {
- // Upgrade keysets are being used. Determine if new package has a superset of the
- // required keys.
- long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
- for (int i = 0; i < upgradeKeySets.length; i++) {
- Set<PublicKey> upgradeSet = ksms.getPublicKeysFromKeySetLPr(upgradeKeySets[i]);
- if (upgradeSet != null && newPkg.mSigningKeys.containsAll(upgradeSet)) {
- return true;
- }
- }
- return false;
- }
-
private static void updateDigest(MessageDigest digest, File file) throws IOException {
try (DigestInputStream digestStream =
new DigestInputStream(new FileInputStream(file), digest)) {
@@ -15730,8 +15336,9 @@
ps = mSettings.mPackages.get(pkgName);
// verify signatures are valid
- if (shouldCheckUpgradeKeySetLP(ps, scanFlags)) {
- if (!checkUpgradeKeySetLP(ps, pkg)) {
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(ps, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(ps, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
"New package not signed by keys specified by upgrade-keysets: "
+ pkgName);
@@ -16632,8 +16239,9 @@
// Quick sanity check that we're signed correctly if updating;
// we'll check this again later when scanning, but we want to
// bail early here before tripping over redefined permissions.
- if (shouldCheckUpgradeKeySetLP(signatureCheckPs, scanFlags)) {
- if (!checkUpgradeKeySetLP(signatureCheckPs, pkg)) {
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ if (ksms.shouldCheckUpgradeKeySetLocked(signatureCheckPs, scanFlags)) {
+ if (!ksms.checkUpgradeKeySetLocked(signatureCheckPs, pkg)) {
res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package "
+ pkg.packageName + " upgrade keys do not match the "
+ "previously installed version");
@@ -16641,7 +16249,16 @@
}
} else {
try {
- verifySignaturesLP(signatureCheckPs, pkg);
+ final boolean compareCompat = isCompatSignatureUpdateNeeded(pkg);
+ final boolean compareRecover = isRecoverSignatureUpdateNeeded(pkg);
+ final boolean compatMatch = verifySignatures(
+ signatureCheckPs, pkg.mSignatures, compareCompat, compareRecover);
+ // The new KeySets will be re-added later in the scanning process.
+ if (compatMatch) {
+ synchronized (mPackages) {
+ ksms.removeAppKeySetDataLPw(pkg.packageName);
+ }
+ }
} catch (PackageManagerException e) {
res.setError(e.error, e.getMessage());
return;
@@ -16679,10 +16296,11 @@
final boolean sigsOk;
final String sourcePackageName = bp.getSourcePackageName();
final PackageSettingBase sourcePackageSetting = bp.getSourcePackageSetting();
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
if (sourcePackageName.equals(pkg.packageName)
- && (shouldCheckUpgradeKeySetLP(sourcePackageSetting,
- scanFlags))) {
- sigsOk = checkUpgradeKeySetLP(sourcePackageSetting, pkg);
+ && (ksms.shouldCheckUpgradeKeySetLocked(
+ sourcePackageSetting, scanFlags))) {
+ sigsOk = ksms.checkUpgradeKeySetLocked(sourcePackageSetting, pkg);
} else {
sigsOk = compareSignatures(sourcePackageSetting.signatures.mSignatures,
pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
@@ -21028,34 +20646,11 @@
pw.println();
pw.println("Package warning messages:");
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- pw.println(line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
+ dumpCriticalInfo(pw, null);
}
if (checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES)) {
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- pw.print("msg,");
- pw.println(line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
+ dumpCriticalInfo(pw, "msg,");
}
}
@@ -21101,26 +20696,11 @@
dumpFeaturesProto(proto);
mSettings.dumpPackagesProto(proto);
mSettings.dumpSharedUsersProto(proto);
- dumpMessagesProto(proto);
+ dumpCriticalInfo(proto);
}
proto.flush();
}
- private void dumpMessagesProto(ProtoOutputStream proto) {
- BufferedReader in = null;
- String line = null;
- try {
- in = new BufferedReader(new FileReader(getSettingsProblemFile()));
- while ((line = in.readLine()) != null) {
- if (line.contains("ignored: updated version")) continue;
- proto.write(PackageServiceDumpProto.MESSAGES, line);
- }
- } catch (IOException ignored) {
- } finally {
- IoUtils.closeQuietly(in);
- }
- }
-
private void dumpFeaturesProto(ProtoOutputStream proto) {
synchronized (mAvailableFeatures) {
final int count = mAvailableFeatures.size();
@@ -22529,7 +22109,7 @@
Slog.w(TAG, "KeySet requested for filtered package: " + packageName);
throw new IllegalArgumentException("Unknown package: " + packageName);
}
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return new KeySet(ksms.getKeySetByAliasAndPackageNameLPr(packageName, alias));
}
}
@@ -22558,7 +22138,7 @@
&& Process.SYSTEM_UID != callingUid) {
throw new SecurityException("May not access signing KeySet of other apps.");
}
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return new KeySet(ksms.getSigningKeySetByPackageNameLPr(packageName));
}
}
@@ -22582,7 +22162,7 @@
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return ksms.packageIsSignedByLPr(packageName, (KeySetHandle) ksh);
}
return false;
@@ -22608,7 +22188,7 @@
}
IBinder ksh = ks.getToken();
if (ksh instanceof KeySetHandle) {
- KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ final KeySetManagerService ksms = mSettings.mKeySetManagerService;
return ksms.packageIsSignedByExactlyLPr(packageName, (KeySetHandle) ksh);
}
return false;
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index 67e06dd..758abd7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -16,42 +16,74 @@
package com.android.server.pm;
+import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
+import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+import static com.android.server.pm.PackageManagerService.COMPRESSED_EXTENSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_COMPRESSION;
+import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
+import static com.android.server.pm.PackageManagerService.STUB_SUFFIX;
+import static com.android.server.pm.PackageManagerService.TAG;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+
+import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FastPrintWriter;
+import com.android.server.EventLogTags;
import com.android.server.pm.dex.DexManager;
import com.android.server.pm.dex.PackageDexUsage;
-import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT;
-import static com.android.server.pm.PackageManagerService.TAG;
-
-import com.android.internal.util.ArrayUtils;
-
import android.annotation.NonNull;
import android.app.AppGlobals;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
import android.os.Build;
import android.os.Debug;
+import android.os.Environment;
+import android.os.FileUtils;
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.service.pm.PackageServiceDumpProto;
import android.system.ErrnoException;
import android.system.Os;
import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
import android.util.jar.StrictJarFile;
-import dalvik.system.VMRuntime;
-import libcore.io.Libcore;
+import android.util.proto.ProtoOutputStream;
+import dalvik.system.VMRuntime;
+
+import libcore.io.IoUtils;
+import libcore.io.Libcore;
+import libcore.io.Streams;
+
+import java.io.BufferedReader;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FilenameFilter;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.text.SimpleDateFormat;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Predicate;
+import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
/**
@@ -200,7 +232,7 @@
*
* If it doesn't have sufficient information about the package, it return <code>false</code>.
*/
- static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
+ public static boolean isUnusedSinceTimeInMillis(long firstInstallTime, long currentTimeInMillis,
long thresholdTimeinMillis, PackageDexUsage.PackageUseInfo packageUseInfo,
long latestPackageUseTimeInMillis, long latestForegroundPackageUseTimeInMillis) {
@@ -263,6 +295,21 @@
return false;
}
+ public static long getLastModifiedTime(PackageParser.Package pkg, File srcFile) {
+ if (srcFile.isDirectory()) {
+ final File baseFile = new File(pkg.baseCodePath);
+ long maxModifiedTime = baseFile.lastModified();
+ if (pkg.splitCodePaths != null) {
+ for (int i = pkg.splitCodePaths.length - 1; i >=0; --i) {
+ final File splitFile = new File(pkg.splitCodePaths[i]);
+ maxModifiedTime = Math.max(maxModifiedTime, splitFile.lastModified());
+ }
+ }
+ return maxModifiedTime;
+ }
+ return srcFile.lastModified();
+ }
+
/**
* Checks that the archive located at {@code fileName} has uncompressed dex file and so
* files that can be direclty mapped.
@@ -318,6 +365,57 @@
}
}
+ private static File getSettingsProblemFile() {
+ File dataDir = Environment.getDataDirectory();
+ File systemDir = new File(dataDir, "system");
+ File fname = new File(systemDir, "uiderrors.txt");
+ return fname;
+ }
+
+ public static void dumpCriticalInfo(ProtoOutputStream proto) {
+ try (BufferedReader in = new BufferedReader(new FileReader(getSettingsProblemFile()))) {
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ if (line.contains("ignored: updated version")) continue;
+ proto.write(PackageServiceDumpProto.MESSAGES, line);
+ }
+ } catch (IOException ignored) {
+ }
+ }
+
+ public static void dumpCriticalInfo(PrintWriter pw, String msg) {
+ try (BufferedReader in = new BufferedReader(new FileReader(getSettingsProblemFile()))) {
+ String line = null;
+ while ((line = in.readLine()) != null) {
+ if (line.contains("ignored: updated version")) continue;
+ if (msg != null) {
+ pw.print(msg);
+ }
+ pw.println(line);
+ }
+ } catch (IOException ignored) {
+ }
+ }
+
+ public static void logCriticalInfo(int priority, String msg) {
+ Slog.println(priority, TAG, msg);
+ EventLogTags.writePmCriticalInfo(msg);
+ try {
+ File fname = getSettingsProblemFile();
+ FileOutputStream out = new FileOutputStream(fname, true);
+ PrintWriter pw = new FastPrintWriter(out);
+ SimpleDateFormat formatter = new SimpleDateFormat();
+ String dateString = formatter.format(new Date(System.currentTimeMillis()));
+ pw.println(dateString + ": " + msg);
+ pw.close();
+ FileUtils.setPermissions(
+ fname.toString(),
+ FileUtils.S_IRWXU|FileUtils.S_IRWXG|FileUtils.S_IROTH,
+ -1, -1);
+ } catch (java.io.IOException e) {
+ }
+ }
+
public static void enforceShellRestriction(String restriction, int callingUid, int userHandle) {
if (callingUid == Process.SHELL_UID) {
if (userHandle >= 0
@@ -331,4 +429,240 @@
}
}
}
+
+ /**
+ * Derive the value of the {@code cpuAbiOverride} based on the provided
+ * value and an optional stored value from the package settings.
+ */
+ public static String deriveAbiOverride(String abiOverride, PackageSetting settings) {
+ String cpuAbiOverride = null;
+ if (NativeLibraryHelper.CLEAR_ABI_OVERRIDE.equals(abiOverride)) {
+ cpuAbiOverride = null;
+ } else if (abiOverride != null) {
+ cpuAbiOverride = abiOverride;
+ } else if (settings != null) {
+ cpuAbiOverride = settings.cpuAbiOverrideString;
+ }
+ return cpuAbiOverride;
+ }
+
+ /**
+ * Compares two sets of signatures. Returns:
+ * <br />
+ * {@link PackageManager#SIGNATURE_NEITHER_SIGNED}: if both signature sets are null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_FIRST_NOT_SIGNED}: if the first signature set is null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_SECOND_NOT_SIGNED}: if the second signature set is null,
+ * <br />
+ * {@link PackageManager#SIGNATURE_MATCH}: if the two signature sets are identical,
+ * <br />
+ * {@link PackageManager#SIGNATURE_NO_MATCH}: if the two signature sets differ.
+ */
+ public static int compareSignatures(Signature[] s1, Signature[] s2) {
+ if (s1 == null) {
+ return s2 == null
+ ? PackageManager.SIGNATURE_NEITHER_SIGNED
+ : PackageManager.SIGNATURE_FIRST_NOT_SIGNED;
+ }
+
+ if (s2 == null) {
+ return PackageManager.SIGNATURE_SECOND_NOT_SIGNED;
+ }
+
+ if (s1.length != s2.length) {
+ return PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ // Since both signature sets are of size 1, we can compare without HashSets.
+ if (s1.length == 1) {
+ return s1[0].equals(s2[0]) ?
+ PackageManager.SIGNATURE_MATCH :
+ PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ ArraySet<Signature> set1 = new ArraySet<Signature>();
+ for (Signature sig : s1) {
+ set1.add(sig);
+ }
+ ArraySet<Signature> set2 = new ArraySet<Signature>();
+ for (Signature sig : s2) {
+ set2.add(sig);
+ }
+ // Make sure s2 contains all signatures in s1.
+ if (set1.equals(set2)) {
+ return PackageManager.SIGNATURE_MATCH;
+ }
+ return PackageManager.SIGNATURE_NO_MATCH;
+ }
+
+ /**
+ * Used for backward compatibility to make sure any packages with
+ * certificate chains get upgraded to the new style. {@code existingSigs}
+ * will be in the old format (since they were stored on disk from before the
+ * system upgrade) and {@code scannedSigs} will be in the newer format.
+ */
+ private static boolean matchSignaturesCompat(String packageName,
+ PackageSignatures packageSignatures, Signature[] parsedSignatures) {
+ ArraySet<Signature> existingSet = new ArraySet<Signature>();
+ for (Signature sig : packageSignatures.mSignatures) {
+ existingSet.add(sig);
+ }
+ ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>();
+ for (Signature sig : parsedSignatures) {
+ try {
+ Signature[] chainSignatures = sig.getChainSignatures();
+ for (Signature chainSig : chainSignatures) {
+ scannedCompatSet.add(chainSig);
+ }
+ } catch (CertificateEncodingException e) {
+ scannedCompatSet.add(sig);
+ }
+ }
+ // make sure the expanded scanned set contains all signatures in the existing one
+ if (scannedCompatSet.equals(existingSet)) {
+ // migrate the old signatures to the new scheme
+ packageSignatures.assignSignatures(parsedSignatures);
+ return true;
+ }
+ return false;
+ }
+
+ private static boolean matchSignaturesRecover(String packageName,
+ Signature[] existingSignatures, Signature[] parsedSignatures) {
+ String msg = null;
+ try {
+ if (Signature.areEffectiveMatch(existingSignatures, parsedSignatures)) {
+ logCriticalInfo(Log.INFO,
+ "Recovered effectively matching certificates for " + packageName);
+ return true;
+ }
+ } catch (CertificateException e) {
+ msg = e.getMessage();
+ }
+ logCriticalInfo(Log.INFO,
+ "Failed to recover certificates for " + packageName + ": " + msg);
+ return false;
+ }
+
+ /**
+ * Verifies that signatures match.
+ * @returns {@code true} if the compat signatures were matched; otherwise, {@code false}.
+ * @throws PackageManagerException if the signatures did not match.
+ */
+ public static boolean verifySignatures(PackageSetting pkgSetting,
+ Signature[] parsedSignatures, boolean compareCompat, boolean compareRecover)
+ throws PackageManagerException {
+ final String packageName = pkgSetting.name;
+ boolean compatMatch = false;
+ if (pkgSetting.signatures.mSignatures != null) {
+ // Already existing package. Make sure signatures match
+ boolean match = compareSignatures(pkgSetting.signatures.mSignatures, parsedSignatures)
+ == PackageManager.SIGNATURE_MATCH;
+ if (!match && compareCompat) {
+ match = matchSignaturesCompat(packageName, pkgSetting.signatures, parsedSignatures);
+ compatMatch = match;
+ }
+ if (!match && compareRecover) {
+ match = matchSignaturesRecover(
+ packageName, pkgSetting.signatures.mSignatures, parsedSignatures);
+ }
+ if (!match) {
+ throw new PackageManagerException(INSTALL_FAILED_UPDATE_INCOMPATIBLE,
+ "Package " + packageName +
+ " signatures don't match previously installed version; ignoring!");
+ }
+ }
+ // Check for shared user signatures
+ if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
+ // Already existing package. Make sure signatures match
+ boolean match = compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
+ parsedSignatures) == PackageManager.SIGNATURE_MATCH;
+ if (!match) {
+ match = matchSignaturesCompat(
+ packageName, pkgSetting.sharedUser.signatures, parsedSignatures);
+ }
+ if (!match && compareCompat) {
+ match = matchSignaturesRecover(
+ packageName, pkgSetting.sharedUser.signatures.mSignatures, parsedSignatures);
+ compatMatch |= match;
+ }
+ if (!match && compareRecover) {
+ throw new PackageManagerException(INSTALL_FAILED_SHARED_USER_INCOMPATIBLE,
+ "Package " + packageName
+ + " has no signatures that match those in shared user "
+ + pkgSetting.sharedUser.name + "; ignoring!");
+ }
+ }
+ return compatMatch;
+ }
+
+ public static int decompressFile(File srcFile, File dstFile) throws ErrnoException {
+ if (DEBUG_COMPRESSION) {
+ Slog.i(TAG, "Decompress file"
+ + "; src: " + srcFile.getAbsolutePath()
+ + ", dst: " + dstFile.getAbsolutePath());
+ }
+ try (
+ InputStream fileIn = new GZIPInputStream(new FileInputStream(srcFile));
+ OutputStream fileOut = new FileOutputStream(dstFile, false /*append*/);
+ ) {
+ Streams.copy(fileIn, fileOut);
+ Os.chmod(dstFile.getAbsolutePath(), 0644);
+ return PackageManager.INSTALL_SUCCEEDED;
+ } catch (IOException e) {
+ logCriticalInfo(Log.ERROR, "Failed to decompress file"
+ + "; src: " + srcFile.getAbsolutePath()
+ + ", dst: " + dstFile.getAbsolutePath());
+ }
+ return PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+ }
+
+ public static File[] getCompressedFiles(String codePath) {
+ final File stubCodePath = new File(codePath);
+ final String stubName = stubCodePath.getName();
+
+ // The layout of a compressed package on a given partition is as follows :
+ //
+ // Compressed artifacts:
+ //
+ // /partition/ModuleName/foo.gz
+ // /partation/ModuleName/bar.gz
+ //
+ // Stub artifact:
+ //
+ // /partition/ModuleName-Stub/ModuleName-Stub.apk
+ //
+ // In other words, stub is on the same partition as the compressed artifacts
+ // and in a directory that's suffixed with "-Stub".
+ int idx = stubName.lastIndexOf(STUB_SUFFIX);
+ if (idx < 0 || (stubName.length() != (idx + STUB_SUFFIX.length()))) {
+ return null;
+ }
+
+ final File stubParentDir = stubCodePath.getParentFile();
+ if (stubParentDir == null) {
+ Slog.e(TAG, "Unable to determine stub parent dir for codePath: " + codePath);
+ return null;
+ }
+
+ final File compressedPath = new File(stubParentDir, stubName.substring(0, idx));
+ final File[] files = compressedPath.listFiles(new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.toLowerCase().endsWith(COMPRESSED_EXTENSION);
+ }
+ });
+
+ if (DEBUG_COMPRESSION && files != null && files.length > 0) {
+ Slog.i(TAG, "getCompressedFiles[" + codePath + "]: " + Arrays.toString(files));
+ }
+
+ return files;
+ }
+
+ public static boolean compressedFileExists(String codePath) {
+ final File[] compressedFiles = getCompressedFiles(codePath);
+ return compressedFiles != null && compressedFiles.length > 0;
+ }
}
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 1c002aa..25e9239 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -2262,6 +2262,10 @@
final ShortcutUser user = getUserShortcutsLocked(userId);
+ if (user.hasHostPackage(packageName)) {
+ return true;
+ }
+
// Always trust the cached component.
final ComponentName cached = user.getCachedLauncher();
if (cached != null) {
@@ -2361,6 +2365,16 @@
}
}
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+ int userId) {
+ synchronized (mLock) {
+ throwIfUserLockedL(userId);
+
+ final ShortcutUser user = getUserShortcutsLocked(userId);
+ user.setShortcutHostPackage(type, packageName);
+ }
+ }
+
// === House keeping ===
private void cleanUpPackageForAllLoadedUsers(String packageName, @UserIdInt int packageUserId,
@@ -2697,6 +2711,12 @@
}
@Override
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName,
+ int userId) {
+ ShortcutService.this.setShortcutHostPackage(type, packageName, userId);
+ }
+
+ @Override
public boolean requestPinAppWidget(@NonNull String callingPackage,
@NonNull AppWidgetProviderInfo appWidget, @Nullable Bundle extras,
@Nullable IntentSender resultIntent, int userId) {
diff --git a/services/core/java/com/android/server/pm/ShortcutUser.java b/services/core/java/com/android/server/pm/ShortcutUser.java
index 48eccd0..1efd765 100644
--- a/services/core/java/com/android/server/pm/ShortcutUser.java
+++ b/services/core/java/com/android/server/pm/ShortcutUser.java
@@ -23,6 +23,7 @@
import android.text.TextUtils;
import android.text.format.Formatter;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -123,6 +124,20 @@
/** In-memory-cached default launcher. */
private ComponentName mCachedLauncher;
+ /**
+ * Keep track of additional packages that other parts of the system have said are
+ * allowed to access shortcuts. The key is the part of the system it came from,
+ * the value is the package name that has access. We don't persist these because
+ * at boot all relevant system services will push this data back to us they do their
+ * normal evaluation of the state of the world.
+ */
+ private final ArrayMap<String, String> mHostPackages = new ArrayMap<>();
+
+ /**
+ * Set of package name values from above.
+ */
+ private final ArraySet<String> mHostPackageSet = new ArraySet<>();
+
private String mKnownLocales;
private long mLastAppScanTime;
@@ -467,6 +482,23 @@
return mCachedLauncher;
}
+ public void setShortcutHostPackage(@NonNull String type, @Nullable String packageName) {
+ if (packageName != null) {
+ mHostPackages.put(type, packageName);
+ } else {
+ mHostPackages.remove(type);
+ }
+
+ mHostPackageSet.clear();
+ for (int i = 0; i < mHostPackages.size(); i++) {
+ mHostPackageSet.add(mHostPackages.valueAt(i));
+ }
+ }
+
+ public boolean hasHostPackage(@NonNull String packageName) {
+ return mHostPackageSet.contains(packageName);
+ }
+
public void resetThrottling() {
for (int i = mPackages.size() - 1; i >= 0; i--) {
mPackages.valueAt(i).resetThrottling();
@@ -555,6 +587,18 @@
pw.print("Last known launcher: ");
pw.print(mLastKnownLauncher);
pw.println();
+
+ if (mHostPackages.size() > 0) {
+ pw.print(prefix);
+ pw.println("Host packages:");
+ for (int i = 0; i < mHostPackages.size(); i++) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print(mHostPackages.keyAt(i));
+ pw.print(": ");
+ pw.println(mHostPackages.valueAt(i));
+ }
+ }
}
for (int i = 0; i < mLaunchers.size(); i++) {
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index bfe09b8..96c102b 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -16,6 +16,8 @@
package com.android.server.pm;
+import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo;
+
import android.content.Context;
import android.content.pm.UserInfo;
import android.os.Environment;
@@ -40,8 +42,6 @@
import java.util.Objects;
import java.util.Set;
-import static com.android.server.pm.PackageManagerService.logCriticalInfo;
-
/**
* Helper class for preparing and destroying user storage
*/
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index d046853..4b13404 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -113,6 +113,7 @@
UserManager.DISALLOW_OEM_UNLOCK,
UserManager.DISALLOW_UNMUTE_DEVICE,
UserManager.DISALLOW_AUTOFILL,
+ UserManager.DISALLOW_USER_SWITCH
});
/**
@@ -144,6 +145,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(
@@ -312,6 +320,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));
}
@@ -364,8 +373,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/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 533b261..c40d1fa 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -16,6 +16,8 @@
package com.android.server.pm.permission;
+import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures;
+
import android.Manifest;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -383,6 +385,7 @@
MediaStore.AUTHORITY, userId);
if (mediaStorePackage != null) {
grantRuntimePermissions(mediaStorePackage, STORAGE_PERMISSIONS, true, userId);
+ grantRuntimePermissions(mediaStorePackage, PHONE_PERMISSIONS, true, userId);
}
// Downloads provider
@@ -1109,8 +1112,8 @@
final String systemPackageName = mServiceInternal.getKnownPackageName(
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage = getPackage(systemPackageName);
- return PackageManagerService.compareSignatures(systemPackage.mSignatures,
- pkg.mSignatures) == PackageManager.SIGNATURE_MATCH;
+ return compareSignatures(systemPackage.mSignatures, pkg.mSignatures)
+ == PackageManager.SIGNATURE_MATCH;
}
private void grantDefaultPermissionExceptions(int userId) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 76805ce..7d8e206 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -37,6 +37,7 @@
import android.content.pm.PermissionGroupInfo;
import android.content.pm.PermissionInfo;
import android.content.pm.PackageParser.Package;
+import android.metrics.LogMaker;
import android.os.Binder;
import android.os.Build;
import android.os.Handler;
@@ -92,36 +93,6 @@
public class PermissionManagerService {
private static final String TAG = "PackageManager";
- /** All dangerous permission names in the same order as the events in MetricsEvent */
- private static final List<String> ALL_DANGEROUS_PERMISSIONS = Arrays.asList(
- Manifest.permission.READ_CALENDAR,
- Manifest.permission.WRITE_CALENDAR,
- Manifest.permission.CAMERA,
- Manifest.permission.READ_CONTACTS,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.GET_ACCOUNTS,
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.ACCESS_COARSE_LOCATION,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.READ_CALL_LOG,
- Manifest.permission.WRITE_CALL_LOG,
- Manifest.permission.ADD_VOICEMAIL,
- Manifest.permission.USE_SIP,
- Manifest.permission.PROCESS_OUTGOING_CALLS,
- Manifest.permission.READ_CELL_BROADCASTS,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.SEND_SMS,
- Manifest.permission.RECEIVE_SMS,
- Manifest.permission.READ_SMS,
- Manifest.permission.RECEIVE_WAP_PUSH,
- Manifest.permission.RECEIVE_MMS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBERS,
- Manifest.permission.ANSWER_PHONE_CALLS);
-
/** Permission grant: not grant the permission. */
private static final int GRANT_DENIED = 1;
/** Permission grant: grant the permission as an install permission. */
@@ -160,6 +131,7 @@
private final HandlerThread mHandlerThread;
private final Handler mHandler;
private final Context mContext;
+ private final MetricsLogger mMetricsLogger = new MetricsLogger();
/** Internal storage for permissions and related settings */
@GuardedBy("mLock")
@@ -1037,10 +1009,10 @@
PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM);
final PackageParser.Package systemPackage =
mPackageManagerInt.getPackage(systemPackageName);
- boolean allowed = (PackageManagerService.compareSignatures(
+ boolean allowed = (PackageManagerServiceUtils.compareSignatures(
bp.getSourceSignatures(), pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH)
- || (PackageManagerService.compareSignatures(
+ || (PackageManagerServiceUtils.compareSignatures(
systemPackage.mSignatures, pkg.mSignatures)
== PackageManager.SIGNATURE_MATCH);
if (!allowed && (privilegedPermission || oemPermission)) {
@@ -1386,7 +1358,7 @@
}
if (bp.isRuntime()) {
- logPermissionGranted(mContext, permName, packageName);
+ logPermission(MetricsEvent.ACTION_PERMISSION_GRANTED, permName, packageName);
}
if (callback != null) {
@@ -1484,7 +1456,7 @@
}
if (bp.isRuntime()) {
- logPermissionRevoked(mContext, permName, packageName);
+ logPermission(MetricsEvent.ACTION_PERMISSION_REVOKED, permName, packageName);
}
if (callback != null) {
@@ -1938,63 +1910,18 @@
}
/**
- * Get the first event id for the permission.
+ * Log that a permission request was granted/revoked.
*
- * <p>There are four events for each permission: <ul>
- * <li>Request permission: first id + 0</li>
- * <li>Grant permission: first id + 1</li>
- * <li>Request for permission denied: first id + 2</li>
- * <li>Revoke permission: first id + 3</li>
- * </ul></p>
- *
+ * @param action the action performed
* @param name name of the permission
- *
- * @return The first event id for the permission
+ * @param packageName package permission is for
*/
- private static int getBaseEventId(@NonNull String name) {
- int eventIdIndex = ALL_DANGEROUS_PERMISSIONS.indexOf(name);
+ private void logPermission(int action, @NonNull String name, @NonNull String packageName) {
+ final LogMaker log = new LogMaker(action);
+ log.setPackageName(packageName);
+ log.addTaggedData(MetricsEvent.FIELD_PERMISSION, name);
- if (eventIdIndex == -1) {
- if (AppOpsManager.permissionToOpCode(name) == AppOpsManager.OP_NONE
- || Build.IS_USER) {
- Log.i(TAG, "Unknown permission " + name);
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_UNKNOWN;
- } else {
- // Most likely #ALL_DANGEROUS_PERMISSIONS needs to be updated.
- //
- // Also update
- // - EventLogger#ALL_DANGEROUS_PERMISSIONS
- // - metrics_constants.proto
- throw new IllegalStateException("Unknown permission " + name);
- }
- }
-
- return MetricsEvent.ACTION_PERMISSION_REQUEST_READ_CALENDAR + eventIdIndex * 4;
- }
-
- /**
- * Log that a permission was revoked.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionRevoked(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 3, packageName);
- }
-
- /**
- * Log that a permission request was granted.
- *
- * @param context Context of the caller
- * @param name name of the permission
- * @param packageName package permission if for
- */
- private static void logPermissionGranted(@NonNull Context context, @NonNull String name,
- @NonNull String packageName) {
- MetricsLogger.action(context, getBaseEventId(name) + 1, packageName);
+ mMetricsLogger.write(log);
}
private class PermissionManagerInternalImpl extends PermissionManagerInternal {
diff --git a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
index 92729dc..6886985 100644
--- a/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
+++ b/services/core/java/com/android/server/policy/BurnInProtectionHelper.java
@@ -253,7 +253,8 @@
public void onDisplayChanged(int displayId) {
if (displayId == mDisplay.getDisplayId()) {
if (mDisplay.getState() == Display.STATE_DOZE
- || mDisplay.getState() == Display.STATE_DOZE_SUSPEND) {
+ || mDisplay.getState() == Display.STATE_DOZE_SUSPEND
+ || mDisplay.getState() == Display.STATE_ON_SUSPEND) {
startBurnInProtection();
} else {
cancelBurnInProtection();
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index edd2fdb..c6ec287 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -52,6 +52,7 @@
import android.widget.FrameLayout;
import com.android.internal.R;
+import com.android.server.vr.VrManagerService;
/**
* Helper to manage showing/hiding a confirmation prompt when the navigation bar is hidden
@@ -147,7 +148,6 @@
&& userSetupComplete
&& !mVrModeEnabled
&& !navBarEmpty
- && !isLockTaskModeLocked()
&& !UserManager.isDeviceInDemoMode(mContext)) {
mHandler.sendEmptyMessageDelayed(H.SHOW, mShowDelayMs);
}
@@ -156,20 +156,6 @@
}
}
- /**
- * @return {@code true} if and only if the device is currently in LockTask mode managed by
- * {@link android.app.admin.DevicePolicyManager}. Note that this differs from the screen pinning
- * mode which is initiated by the user.
- */
- private boolean isLockTaskModeLocked() {
- try {
- return ActivityManager.getService().getLockTaskModeState()
- == ActivityManager.LOCK_TASK_MODE_LOCKED;
- } catch (RemoteException e) {
- return false;
- }
- }
-
public boolean onPowerKeyDown(boolean isScreenOn, long time, boolean inImmersiveMode,
boolean navBarEmpty) {
if (!isScreenOn && (time - mPanicTime < mPanicThresholdMs)) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6520dc9..caf85b0 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -66,6 +66,7 @@
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_ACQUIRES_SLEEP_TOKEN;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SYSTEM_ERROR;
@@ -183,6 +184,7 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UEventObserver;
@@ -197,6 +199,7 @@
import android.service.vr.IPersistentVrStateCallbacks;
import android.speech.RecognizerIntent;
import android.telecom.TelecomManager;
+import android.util.ArraySet;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -455,6 +458,7 @@
private AccessibilityShortcutController mAccessibilityShortcutController;
boolean mSafeMode;
+ private final ArraySet<WindowState> mScreenDecorWindows = new ArraySet<>();
WindowState mStatusBar = null;
int mStatusBarHeight;
WindowState mNavigationBar = null;
@@ -1168,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
@@ -1186,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;
}
@@ -1661,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() {
@@ -2612,7 +2610,19 @@
}
@Override
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission) {
+
+ final boolean isScreenDecor = (attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0;
+ if (mScreenDecorWindows.contains(win)) {
+ if (!isScreenDecor) {
+ // No longer has the flag set, so remove from the set.
+ mScreenDecorWindows.remove(win);
+ }
+ } else if (isScreenDecor && hasStatusBarServicePermission) {
+ mScreenDecorWindows.add(win);
+ }
+
switch (attrs.type) {
case TYPE_SYSTEM_OVERLAY:
case TYPE_SECURE_SYSTEM_OVERLAY:
@@ -3073,6 +3083,14 @@
*/
@Override
public int prepareAddWindowLw(WindowState win, WindowManager.LayoutParams attrs) {
+
+ if ((attrs.privateFlags & PRIVATE_FLAG_IS_SCREEN_DECOR) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.STATUS_BAR_SERVICE,
+ "PhoneWindowManager");
+ mScreenDecorWindows.add(win);
+ }
+
switch (attrs.type) {
case TYPE_STATUS_BAR:
mContext.enforceCallingOrSelfPermission(
@@ -3124,6 +3142,7 @@
mNavigationBar = null;
mNavigationBarController.setWindow(null);
}
+ mScreenDecorWindows.remove(win);
}
static final boolean PRINT_ANIM = false;
@@ -4394,8 +4413,9 @@
/** {@inheritDoc} */
@Override
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
- int displayRotation, int uiMode) {
+ public void beginLayoutLw(int displayId, int displayWidth, int displayHeight,
+ int displayRotation, int uiMode) {
+ final boolean isDefaultDisplay = displayId == DEFAULT_DISPLAY;
mDisplayRotation = displayRotation;
final int overscanLeft, overscanTop, overscanRight, overscanBottom;
if (isDefaultDisplay) {
@@ -4523,6 +4543,71 @@
updateSystemUiVisibilityLw();
}
}
+ layoutScreenDecorWindows(displayId, displayWidth, displayHeight, pf, df, dcf);
+ }
+
+ private void layoutScreenDecorWindows(int displayId, int displayWidth, int displayHeight,
+ Rect pf, Rect df, Rect dcf) {
+ if (mScreenDecorWindows.isEmpty()) {
+ return;
+ }
+
+ for (int i = mScreenDecorWindows.size() - 1; i >= 0; --i) {
+ final WindowState w = mScreenDecorWindows.valueAt(i);
+ if (w.getDisplayId() != displayId || !w.isVisibleLw()) {
+ // Skip if not on the same display or not visible.
+ continue;
+ }
+
+ w.computeFrameLw(pf /* parentFrame */, df /* displayFrame */, df /* overlayFrame */,
+ df /* contentFrame */, df /* visibleFrame */, dcf /* decorFrame */,
+ df /* stableFrame */, df /* outsetFrame */);
+ final Rect frame = w.getFrameLw();
+
+ if (frame.left <= 0 && frame.top <= 0) {
+ // Docked at left or top.
+ if (frame.bottom >= displayHeight) {
+ // Docked left.
+ mDockLeft = Math.max(frame.right, mDockLeft);
+ } else if (frame.right >= displayWidth ) {
+ // Docked top.
+ mDockTop = Math.max(frame.bottom, mDockTop);
+ } else {
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on left or top of display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ } else if (frame.right >= displayWidth && frame.bottom >= displayHeight) {
+ // Docked at right or bottom.
+ if (frame.top <= 0) {
+ // Docked right.
+ mDockRight = Math.min(frame.left, mDockRight);
+ } else if (frame.left <= 0) {
+ // Docked bottom.
+ mDockBottom = Math.min(frame.top, mDockBottom);
+ } else {
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on right or bottom" + " of display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ } else {
+ // Screen decor windows are required to be docked on one of the sides of the screen.
+ Slog.w(TAG, "layoutScreenDecorWindows: Ignoring decor win=" + w
+ + " not docked on one of the sides of the display. frame=" + frame
+ + " displayWidth=" + displayWidth + " displayHeight=" + displayHeight);
+ }
+ }
+
+ mContentTop = mSystemTop = mVoiceContentTop = mCurTop = mRestrictedScreenTop = mDockTop;
+ mContentLeft = mSystemLeft = mVoiceContentLeft = mCurLeft = mRestrictedScreenLeft
+ = mRestrictedOverscanScreenLeft = mDockLeft;
+ mContentBottom = mSystemBottom = mVoiceContentBottom = mCurBottom = mDockBottom;
+ mContentRight = mSystemRight = mVoiceContentRight = mCurRight = mDockRight;
+
+ mRestrictedScreenWidth = mDockRight - mRestrictedScreenLeft;
+ mRestrictedScreenHeight = mDockBottom - mRestrictedScreenTop;
+ mRestrictedOverscanScreenWidth = mDockRight - mRestrictedOverscanScreenLeft;
+ mRestrictedOverscanScreenHeight = mDockBottom - mRestrictedOverscanScreenTop;
}
private boolean layoutStatusBar(Rect pf, Rect df, Rect of, Rect vf, Rect dcf, int sysui,
@@ -4822,9 +4907,11 @@
/** {@inheritDoc} */
@Override
public void layoutWindowLw(WindowState win, WindowState attached) {
- // We've already done the navigation bar and status bar. If the status bar can receive
- // input, we need to layout it again to accomodate for the IME window.
- if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar) {
+ // We've already done the navigation bar, status bar, and all screen decor windows. If the
+ // status bar can receive input, we need to layout it again to accommodate for the IME
+ // window.
+ if ((win == mStatusBar && !canReceiveInput(win)) || win == mNavigationBar
+ || mScreenDecorWindows.contains(win)) {
return;
}
final WindowManager.LayoutParams attrs = win.getAttrs();
@@ -4863,6 +4950,7 @@
}
if (!isDefaultDisplay) {
+ // TODO: Need to fix this and above to take into account decor windows.
if (attached != null) {
// If this window is attached to another, our display
// frame is the same as the one we are attached to.
@@ -5798,6 +5886,15 @@
}
void initializeHdmiState() {
+ final int oldMask = StrictMode.allowThreadDiskReadsMask();
+ try {
+ initializeHdmiStateInternal();
+ } finally {
+ StrictMode.setThreadPolicyMask(oldMask);
+ }
+ }
+
+ void initializeHdmiStateInternal() {
boolean plugged = false;
// watch for HDMI plug messages if the hdmi switch exists
if (new File("/sys/devices/virtual/switch/hdmi/state").exists()) {
@@ -7987,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/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 1781d8c..0c73fe8 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -20,6 +20,8 @@
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
+import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.provider.Settings;
import android.util.KeyValueListParser;
import android.util.Slog;
@@ -34,31 +36,6 @@
* Class to decide whether to turn on battery saver mode for specific service
*/
public class BatterySaverPolicy extends ContentObserver {
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({ServiceType.GPS,
- ServiceType.VIBRATION,
- ServiceType.ANIMATION,
- ServiceType.FULL_BACKUP,
- ServiceType.KEYVALUE_BACKUP,
- ServiceType.NETWORK_FIREWALL,
- ServiceType.SCREEN_BRIGHTNESS,
- ServiceType.SOUND,
- ServiceType.BATTERY_STATS,
- ServiceType.DATA_SAVER})
- public @interface ServiceType {
- int NULL = 0;
- int GPS = 1;
- int VIBRATION = 2;
- int ANIMATION = 3;
- int FULL_BACKUP = 4;
- int KEYVALUE_BACKUP = 5;
- int NETWORK_FIREWALL = 6;
- int SCREEN_BRIGHTNESS = 7;
- int SOUND = 8;
- int BATTERY_STATS = 9;
- int DATA_SAVER = 10;
- }
-
private static final String TAG = "BatterySaverPolicy";
// Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
@@ -79,6 +56,9 @@
private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
+ private static final String KEY_FORCE_ALL_APPS_STANDBY_JOBS = "force_all_apps_standby_jobs";
+ private static final String KEY_FORCE_ALL_APPS_STANDBY_ALARMS = "force_all_apps_standby_alarms";
+ private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -164,6 +144,21 @@
*/
private float mAdjustBrightnessFactor;
+ /**
+ * Whether to put all apps in the stand-by mode or not for job scheduler.
+ */
+ private boolean mForceAllAppsStandbyJobs;
+
+ /**
+ * Whether to put all apps in the stand-by mode or not for alarms.
+ */
+ private boolean mForceAllAppsStandbyAlarms;
+
+ /**
+ * Weather to show non-essential sensors (e.g. edge sensors) or not.
+ */
+ private boolean mOptionalSensorsDisabled;
+
private ContentResolver mContentResolver;
public BatterySaverPolicy(Handler handler) {
@@ -203,10 +198,14 @@
mAdjustBrightnessDisabled = mParser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
mAdjustBrightnessFactor = mParser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
mDataSaverDisabled = mParser.getBoolean(KEY_DATASAVER_DISABLED, true);
+ mForceAllAppsStandbyJobs = mParser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY_JOBS, true);
+ mForceAllAppsStandbyAlarms =
+ mParser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY_ALARMS, true);
+ mOptionalSensorsDisabled = mParser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
// Get default value from Settings.Secure
final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
- GPS_MODE_DISABLED_WHEN_SCREEN_OFF);
+ GPS_MODE_NO_CHANGE);
mGpsMode = mParser.getInt(KEY_GPS_MODE, defaultGpsMode);
}
}
@@ -258,6 +257,15 @@
case ServiceType.VIBRATION:
return builder.setBatterySaverEnabled(mVibrationDisabled)
.build();
+ case ServiceType.FORCE_ALL_APPS_STANDBY_JOBS:
+ return builder.setBatterySaverEnabled(mForceAllAppsStandbyJobs)
+ .build();
+ case ServiceType.FORCE_ALL_APPS_STANDBY_ALARMS:
+ return builder.setBatterySaverEnabled(mForceAllAppsStandbyAlarms)
+ .build();
+ case ServiceType.OPTIONAL_SENSORS:
+ return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
+ .build();
default:
return builder.setBatterySaverEnabled(realMode)
.build();
@@ -282,6 +290,8 @@
pw.println(" " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
pw.println(" " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
pw.println(" " + KEY_GPS_MODE + "=" + mGpsMode);
-
+ pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY_JOBS + "=" + mForceAllAppsStandbyJobs);
+ pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY_ALARMS + "=" + mForceAllAppsStandbyAlarms);
+ pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
}
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 2494bde..a153fdf 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -43,6 +43,7 @@
import android.os.Looper;
import android.os.Message;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.Process;
@@ -70,6 +71,8 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.WindowManagerPolicy;
+import android.widget.Toast;
+
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.app.IBatteryStats;
@@ -89,7 +92,6 @@
import com.android.server.am.BatteryStatsService;
import com.android.server.lights.Light;
import com.android.server.lights.LightsManager;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
@@ -1022,6 +1024,13 @@
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
Manifest.permission.DEVICE_POWER);
+
+ // STOPSHIP Remove the toast.
+ if (mLowPowerModeEnabled) {
+ Toast.makeText(mContext,
+ com.android.internal.R.string.battery_saver_warning,
+ Toast.LENGTH_LONG).show();
+ }
}
});
}
@@ -2364,9 +2373,13 @@
if (mDisplayPowerRequest.policy == DisplayPowerRequest.POLICY_DOZE) {
mDisplayPowerRequest.dozeScreenState = mDozeScreenStateOverrideFromDreamManager;
- if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND
- && (mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
- mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ if ((mWakeLockSummary & WAKE_LOCK_DRAW) != 0) {
+ if (mDisplayPowerRequest.dozeScreenState == Display.STATE_DOZE_SUSPEND) {
+ mDisplayPowerRequest.dozeScreenState = Display.STATE_DOZE;
+ }
+ if (mDisplayPowerRequest.dozeScreenState == Display.STATE_ON_SUSPEND) {
+ mDisplayPowerRequest.dozeScreenState = Display.STATE_ON;
+ }
}
mDisplayPowerRequest.dozeScreenBrightness =
mDozeScreenBrightnessOverrideFromDreamManager;
@@ -4676,6 +4689,7 @@
case Display.STATE_OFF:
case Display.STATE_DOZE:
case Display.STATE_DOZE_SUSPEND:
+ case Display.STATE_ON_SUSPEND:
case Display.STATE_ON:
case Display.STATE_VR:
break;
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 22d2bcf..2488723 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -24,7 +24,8 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
-import android.content.IntentFilter;
+import android.net.NetworkStats;
+import android.os.BatteryStatsInternal;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -37,15 +38,17 @@
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Slog;
+import android.util.StatsLog;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.net.NetworkStatsFactory;
+import com.android.internal.os.KernelWakelockReader;
+import com.android.internal.os.KernelWakelockStats;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
import java.util.ArrayList;
import java.util.List;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.os.KernelWakelockReader;
-import com.android.internal.os.KernelWakelockStats;
-import com.android.server.SystemService;
-
import java.util.Map;
/**
@@ -65,7 +68,7 @@
private static final Object sStatsdLock = new Object();
private final PendingIntent mAnomalyAlarmIntent;
- private final PendingIntent mPollingAlarmIntent;
+ private final PendingIntent mPullingAlarmIntent;
private final BroadcastReceiver mAppUpdateReceiver;
private final BroadcastReceiver mUserUpdateReceiver;
@@ -76,8 +79,8 @@
mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
new Intent(mContext, AnomalyAlarmReceiver.class), 0);
- mPollingAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
- new Intent(mContext, PollingAlarmReceiver.class), 0);
+ mPullingAlarmIntent = PendingIntent.getBroadcast(
+ mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
mAppUpdateReceiver = new AppUpdateReceiver();
mUserUpdateReceiver = new BroadcastReceiver() {
@Override
@@ -144,15 +147,16 @@
public final static class AppUpdateReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
/**
* App updates actually consist of REMOVE, ADD, and then REPLACE broadcasts. To avoid
* waste, we ignore the REMOVE and ADD broadcasts that contain the replacing flag.
+ * If we can't find the value for EXTRA_REPLACING, we default to false.
*/
- if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED) &&
- intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ if (!intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)
+ && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
return; // Keep only replacing or normal add and remove.
}
+ Slog.i(TAG, "StatsCompanionService noticed an app was updated.");
synchronized (sStatsdLock) {
if (sStatsd == null) {
Slog.w(TAG, "Could not access statsd to inform it of anomaly alarm firing");
@@ -205,24 +209,25 @@
}
}
- public final static class PollingAlarmReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DEBUG) Slog.d(TAG, "Time to poll something.");
- synchronized (sStatsdLock) {
- if (sStatsd == null) {
- Slog.w(TAG, "Could not access statsd to inform it of polling alarm firing");
- return;
- }
- try {
- // Two-way call to statsd to retain AlarmManager wakelock
- sStatsd.informPollAlarmFired();
- } catch (RemoteException e) {
- Slog.w(TAG, "Failed to inform statsd of polling alarm firing", e);
- }
- }
- // AlarmManager releases its own wakelock here.
+ public final static class PullingAlarmReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (DEBUG)
+ Slog.d(TAG, "Time to poll something.");
+ synchronized (sStatsdLock) {
+ if (sStatsd == null) {
+ Slog.w(TAG, "Could not access statsd to inform it of pulling alarm firing");
+ return;
+ }
+ try {
+ // Two-way call to statsd to retain AlarmManager wakelock
+ sStatsd.informPollAlarmFired();
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Failed to inform statsd of pulling alarm firing", e);
+ }
}
+ // AlarmManager releases its own wakelock here.
+ }
}
@Override // Binder call
@@ -253,70 +258,199 @@
}
@Override // Binder call
- public void setPollingAlarms(long timestampMs, long intervalMs) {
- enforceCallingPermission();
- if (DEBUG) Slog.d(TAG, "Setting polling alarm for " + timestampMs
- + " every " + intervalMs + "ms");
- final long callingToken = Binder.clearCallingIdentity();
- try {
- // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
- // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
- // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
- mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs,
- mPollingAlarmIntent);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
+ public void setPullingAlarms(long timestampMs, long intervalMs) {
+ enforceCallingPermission();
+ if (DEBUG)
+ Slog.d(TAG, "Setting pulling alarm for " + timestampMs + " every " + intervalMs + "ms");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ // using RTC, not RTC_WAKEUP, so if device is asleep, will only fire when it awakens.
+ // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
+ // TODO: totally inexact means that stats per bucket could be quite off. Is this okay?
+ mAlarmManager.setRepeating(AlarmManager.RTC, timestampMs, intervalMs, mPullingAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
}
@Override // Binder call
- public void cancelPollingAlarms() {
- enforceCallingPermission();
- if (DEBUG) Slog.d(TAG, "Cancelling polling alarm");
- final long callingToken = Binder.clearCallingIdentity();
- try {
- mAlarmManager.cancel(mPollingAlarmIntent);
- } finally {
- Binder.restoreCallingIdentity(callingToken);
- }
+ public void cancelPullingAlarms() {
+ enforceCallingPermission();
+ if (DEBUG)
+ Slog.d(TAG, "Cancelling pulling alarm");
+ final long callingToken = Binder.clearCallingIdentity();
+ try {
+ mAlarmManager.cancel(mPullingAlarmIntent);
+ } finally {
+ Binder.restoreCallingIdentity(callingToken);
+ }
}
- // These values must be kept in sync with cmd/statsd/StatsPullerManager.h.
- // TODO: pull the constant from stats_events.proto instead
- private static final int PULL_CODE_KERNEL_WAKELOCKS = 20;
-
private final KernelWakelockReader mKernelWakelockReader = new KernelWakelockReader();
private final KernelWakelockStats mTmpWakelockStats = new KernelWakelockStats();
- @Override // Binder call
- public StatsLogEventWrapper[] pullData(int pullCode) {
- enforceCallingPermission();
- if (DEBUG) {
- Slog.d(TAG, "Pulling " + pullCode);
- }
-
+ private StatsLogEventWrapper[] addNetworkStats(int tag, NetworkStats stats, boolean withFGBG) {
List<StatsLogEventWrapper> ret = new ArrayList<>();
- switch (pullCode) {
- case PULL_CODE_KERNEL_WAKELOCKS: {
- final KernelWakelockStats wakelockStats =
- mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
- for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
- String name = ent.getKey();
- KernelWakelockStats.Entry kws = ent.getValue();
- StatsLogEventWrapper e = new StatsLogEventWrapper(101, 4);
- e.writeInt(kws.mCount);
- e.writeInt(kws.mVersion);
- e.writeLong(kws.mTotalTime);
- e.writeString(name);
- ret.add(e);
+ int size = stats.size();
+ NetworkStats.Entry entry = new NetworkStats.Entry(); // For recycling
+ for (int j = 0; j < size; j++) {
+ stats.getValues(j, entry);
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tag, withFGBG ? 6 : 5);
+ e.writeInt(entry.uid);
+ if (withFGBG) {
+ e.writeInt(entry.set);
+ }
+ e.writeLong(entry.rxBytes);
+ e.writeLong(entry.rxPackets);
+ e.writeLong(entry.txBytes);
+ e.writeLong(entry.txPackets);
+ ret.add(e);
+ }
+ return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+ }
+
+ /**
+ * Allows rollups per UID but keeping the set (foreground/background) slicing.
+ * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java
+ */
+ private NetworkStats rollupNetworkStatsByFGBG(NetworkStats stats) {
+ final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1);
+
+ final NetworkStats.Entry entry = new NetworkStats.Entry();
+ entry.iface = NetworkStats.IFACE_ALL;
+ entry.tag = NetworkStats.TAG_NONE;
+ entry.metered = NetworkStats.METERED_ALL;
+ entry.roaming = NetworkStats.ROAMING_ALL;
+
+ int size = stats.size();
+ NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values
+ for (int i = 0; i < size; i++) {
+ stats.getValues(i, recycle);
+
+ // Skip specific tags, since already counted in TAG_NONE
+ if (recycle.tag != NetworkStats.TAG_NONE) continue;
+
+ entry.set = recycle.set; // Allows slicing by background/foreground
+ entry.uid = recycle.uid;
+ entry.rxBytes = recycle.rxBytes;
+ entry.rxPackets = recycle.rxPackets;
+ entry.txBytes = recycle.txBytes;
+ entry.txPackets = recycle.txPackets;
+ // Operations purposefully omitted since we don't use them for statsd.
+ ret.combineValues(entry);
+ }
+ return ret;
+ }
+
+ @Override // Binder call
+ public StatsLogEventWrapper[] pullData(int tagId) {
+ enforceCallingPermission();
+ if (DEBUG)
+ Slog.d(TAG, "Pulling " + tagId);
+
+ switch (tagId) {
+ case StatsLog.WIFI_BYTES_TRANSFERRED: {
+ long token = Binder.clearCallingIdentity();
+ try {
+ // TODO: Consider caching the following call to get BatteryStatsInternal.
+ BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+ String[] ifaces = bs.getWifiIfaces();
+ if (ifaces.length == 0) {
+ return null;
+ }
+ NetworkStatsFactory nsf = new NetworkStatsFactory();
+ // Combine all the metrics per Uid into one record.
+ NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+ NetworkStats.TAG_NONE, null).groupedByUid();
+ return addNetworkStats(tagId, stats, false);
+ } catch (java.io.IOException e) {
+ Slog.e(TAG, "Pulling netstats for wifi bytes has error", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
break;
}
+ case StatsLog.MOBILE_BYTES_TRANSFERRED: {
+ long token = Binder.clearCallingIdentity();
+ try {
+ BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+ String[] ifaces = bs.getMobileIfaces();
+ if (ifaces.length == 0) {
+ return null;
+ }
+ NetworkStatsFactory nsf = new NetworkStatsFactory();
+ // Combine all the metrics per Uid into one record.
+ NetworkStats stats = nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+ NetworkStats.TAG_NONE, null).groupedByUid();
+ return addNetworkStats(tagId, stats, false);
+ } catch (java.io.IOException e) {
+ Slog.e(TAG, "Pulling netstats for mobile bytes has error", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ break;
+ }
+ case StatsLog.WIFI_BYTES_TRANSFERRED_BY_FG_BG: {
+ long token = Binder.clearCallingIdentity();
+ try {
+ BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+ String[] ifaces = bs.getWifiIfaces();
+ if (ifaces.length == 0) {
+ return null;
+ }
+ NetworkStatsFactory nsf = new NetworkStatsFactory();
+ NetworkStats stats = rollupNetworkStatsByFGBG(
+ nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+ NetworkStats.TAG_NONE, null));
+ return addNetworkStats(tagId, stats, true);
+ } catch (java.io.IOException e) {
+ Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ break;
+ }
+ case StatsLog.MOBILE_BYTES_TRANSFERRED_BY_FG_BG: {
+ long token = Binder.clearCallingIdentity();
+ try {
+ BatteryStatsInternal bs = LocalServices.getService(BatteryStatsInternal.class);
+ String[] ifaces = bs.getMobileIfaces();
+ if (ifaces.length == 0) {
+ return null;
+ }
+ NetworkStatsFactory nsf = new NetworkStatsFactory();
+ NetworkStats stats = rollupNetworkStatsByFGBG(
+ nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces,
+ NetworkStats.TAG_NONE, null));
+ return addNetworkStats(tagId, stats, true);
+ } catch (java.io.IOException e) {
+ Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ break;
+ }
+ case StatsLog.KERNEL_WAKELOCK_PULLED: {
+ final KernelWakelockStats wakelockStats =
+ mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats);
+ List<StatsLogEventWrapper> ret = new ArrayList();
+ for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) {
+ String name = ent.getKey();
+ KernelWakelockStats.Entry kws = ent.getValue();
+ StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, 4);
+ e.writeString(name);
+ e.writeInt(kws.mCount);
+ e.writeInt(kws.mVersion);
+ e.writeLong(kws.mTotalTime);
+ ret.add(e);
+ }
+ return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+ }
default:
- Slog.w(TAG, "No such pollable data as " + pullCode);
+ Slog.w(TAG, "No such tagId data as " + tagId);
return null;
}
- return ret.toArray(new StatsLogEventWrapper[ret.size()]);
+ return null;
}
@Override // Binder call
@@ -440,7 +574,7 @@
mContext.unregisterReceiver(mAppUpdateReceiver);
mContext.unregisterReceiver(mUserUpdateReceiver);
cancelAnomalyAlarm();
- cancelPollingAlarms();
+ cancelPullingAlarms();
}
}
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
deleted file mode 100644
index cabce18..0000000
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ /dev/null
@@ -1,58 +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.server.updates;
-
-import com.android.timezone.distro.TimeZoneDistro;
-import com.android.timezone.distro.installer.TimeZoneDistroInstaller;
-
-import android.util.Slog;
-
-import java.io.File;
-import java.io.IOException;
-
-/**
- * An install receiver responsible for installing timezone data updates.
- */
-public class TzDataInstallReceiver extends ConfigUpdateInstallReceiver {
-
- private static final String TAG = "TZDataInstallReceiver";
-
- private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
- private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
- private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
- private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
- private static final String UPDATE_VERSION_FILE_NAME = "version";
- private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_distro.zip";
-
- private final TimeZoneDistroInstaller installer;
-
- public TzDataInstallReceiver() {
- super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
- UPDATE_VERSION_FILE_NAME);
- installer = new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
- }
-
- @Override
- protected void install(byte[] content, int version) throws IOException {
- TimeZoneDistro distro = new TimeZoneDistro(content);
- boolean valid = installer.install(distro);
- Slog.i(TAG, "Timezone data install valid for this device: " + valid);
- // Even if !valid, we call super.install(). Only in the event of an exception should we
- // not. If we didn't do this we could attempt to install repeatedly.
- super.install(content, version);
- }
-}
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index e7e4efc..e8ebbe4 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -166,6 +166,8 @@
private boolean mUserUnlocked;
private Vr2dDisplay mVr2dDisplay;
private boolean mBootsToVr;
+ private boolean mStandby;
+ private boolean mUseStandbyToExitVrMode;
// Handles events from the managed services (e.g. VrListenerService and any bound VR compositor
// service).
@@ -203,7 +205,10 @@
*
*/
private void updateVrModeAllowedLocked() {
- boolean allowed = mSystemSleepFlags == FLAG_ALL && mUserUnlocked;
+ boolean ignoreSleepFlags = mBootsToVr && mUseStandbyToExitVrMode;
+ boolean disallowedByStandby = mStandby && mUseStandbyToExitVrMode;
+ boolean allowed = (mSystemSleepFlags == FLAG_ALL || ignoreSleepFlags) && mUserUnlocked
+ && !disallowedByStandby;
if (mVrModeAllowed != allowed) {
mVrModeAllowed = allowed;
if (DBG) Slog.d(TAG, "VR mode is " + ((allowed) ? "allowed" : "disallowed"));
@@ -273,6 +278,17 @@
}
}
+ private void setStandbyEnabled(boolean standby) {
+ synchronized(mLock) {
+ if (!mBootsToVr) {
+ Slog.e(TAG, "Attempting to set standby mode on a non-standalone device");
+ return;
+ }
+ mStandby = standby;
+ updateVrModeAllowedLocked();
+ }
+ }
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -587,6 +603,12 @@
}
@Override
+ public void setStandbyEnabled(boolean standby) {
+ enforceCallerPermissionAnyOf(Manifest.permission.ACCESS_VR_MANAGER);
+ VrManagerService.this.setStandbyEnabled(standby);
+ }
+
+ @Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
@@ -733,6 +755,8 @@
}
mBootsToVr = SystemProperties.getBoolean("ro.boot.vr", false);
+ mUseStandbyToExitVrMode = mBootsToVr
+ && SystemProperties.getBoolean("persist.vr.use_standby_to_exit_vr_mode", false);
publishLocalService(VrManagerInternal.class, new LocalService());
publishBinderService(Context.VR_SERVICE, mVrManager.asBinder());
}
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index e873d32..98db80e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -21,7 +21,6 @@
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
-import static android.os.Build.VERSION_CODES.O_MR1;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
@@ -1101,52 +1100,54 @@
+ " from " + fromToken + " to " + this);
final long origId = Binder.clearCallingIdentity();
+ try {
+ // Transfer the starting window over to the new token.
+ startingData = fromToken.startingData;
+ startingSurface = fromToken.startingSurface;
+ startingDisplayed = fromToken.startingDisplayed;
+ fromToken.startingDisplayed = false;
+ startingWindow = tStartingWindow;
+ reportedVisible = fromToken.reportedVisible;
+ fromToken.startingData = null;
+ fromToken.startingSurface = null;
+ fromToken.startingWindow = null;
+ fromToken.startingMoved = true;
+ tStartingWindow.mToken = this;
+ tStartingWindow.mAppToken = this;
- // Transfer the starting window over to the new token.
- startingData = fromToken.startingData;
- startingSurface = fromToken.startingSurface;
- startingDisplayed = fromToken.startingDisplayed;
- fromToken.startingDisplayed = false;
- startingWindow = tStartingWindow;
- reportedVisible = fromToken.reportedVisible;
- fromToken.startingData = null;
- fromToken.startingSurface = null;
- fromToken.startingWindow = null;
- fromToken.startingMoved = true;
- tStartingWindow.mToken = this;
- tStartingWindow.mAppToken = this;
+ if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
+ "Removing starting " + tStartingWindow + " from " + fromToken);
+ fromToken.removeChild(tStartingWindow);
+ fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
+ fromToken.mHiddenSetFromTransferredStartingWindow = false;
+ addWindow(tStartingWindow);
- if (DEBUG_ADD_REMOVE || DEBUG_STARTING_WINDOW) Slog.v(TAG_WM,
- "Removing starting " + tStartingWindow + " from " + fromToken);
- fromToken.removeChild(tStartingWindow);
- fromToken.postWindowRemoveStartingWindowCleanup(tStartingWindow);
- fromToken.mHiddenSetFromTransferredStartingWindow = false;
- addWindow(tStartingWindow);
+ // Propagate other interesting state between the tokens. If the old token is displayed,
+ // we should immediately force the new one to be displayed. If it is animating, we need
+ // to move that animation to the new one.
+ if (fromToken.allDrawn) {
+ allDrawn = true;
+ deferClearAllDrawn = fromToken.deferClearAllDrawn;
+ }
+ if (fromToken.firstWindowDrawn) {
+ firstWindowDrawn = true;
+ }
+ if (!fromToken.hidden) {
+ hidden = false;
+ hiddenRequested = false;
+ mHiddenSetFromTransferredStartingWindow = true;
+ }
+ setClientHidden(fromToken.mClientHidden);
+ fromToken.mAppAnimator.transferCurrentAnimation(
+ mAppAnimator, tStartingWindow.mWinAnimator);
- // Propagate other interesting state between the tokens. If the old token is displayed,
- // we should immediately force the new one to be displayed. If it is animating, we need
- // to move that animation to the new one.
- if (fromToken.allDrawn) {
- allDrawn = true;
- deferClearAllDrawn = fromToken.deferClearAllDrawn;
+ mService.updateFocusedWindowLocked(
+ UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
+ getDisplayContent().setLayoutNeeded();
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- if (fromToken.firstWindowDrawn) {
- firstWindowDrawn = true;
- }
- if (!fromToken.hidden) {
- hidden = false;
- hiddenRequested = false;
- mHiddenSetFromTransferredStartingWindow = true;
- }
- setClientHidden(fromToken.mClientHidden);
- fromToken.mAppAnimator.transferCurrentAnimation(
- mAppAnimator, tStartingWindow.mWinAnimator);
-
- mService.updateFocusedWindowLocked(
- UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/);
- getDisplayContent().setLayoutNeeded();
- mService.mWindowPlacerLocked.performSurfacePlacement();
- Binder.restoreCallingIdentity(origId);
return true;
} else if (fromToken.startingData != null) {
// The previous app was getting ready to show a
@@ -1201,15 +1202,6 @@
*/
@Override
int getOrientation(int candidate) {
- // We do not allow non-fullscreen apps to influence orientation starting in O-MR1. While we
- // do throw an exception in {@link Activity#onCreate} and
- // {@link Activity#setRequestedOrientation}, we also ignore the orientation here so that
- // other calculations aren't affected.
- if (!fillsParent() && mTargetSdk >= O_MR1) {
- // Can't specify orientation if app doesn't fill parent.
- return SCREEN_ORIENTATION_UNSET;
- }
-
if (candidate == SCREEN_ORIENTATION_BEHIND) {
// Allow app to specify orientation regardless of its visibility state if the current
// candidate want us to use orientation behind. I.e. the visible app on-top of this one
diff --git a/services/core/java/com/android/server/wm/DimLayer.java b/services/core/java/com/android/server/wm/DimLayer.java
index 401547e..8fb2be8 100644
--- a/services/core/java/com/android/server/wm/DimLayer.java
+++ b/services/core/java/com/android/server/wm/DimLayer.java
@@ -119,7 +119,7 @@
} catch (Exception e) {
Slog.e(TAG_WM, "Exception creating Dim surface", e);
} finally {
- service.closeSurfaceTransaction();
+ service.closeSurfaceTransaction("DimLayer.constructSurface");
}
}
@@ -235,7 +235,7 @@
} catch (RuntimeException e) {
Slog.w(TAG, "Failure setting size", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("DimLayer.setBounds");
}
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4c6ab3f..67d62e1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1083,7 +1083,7 @@
mService.mDisplayManagerInternal.performTraversalInTransactionFromWindowManager();
} finally {
if (!inTransaction) {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setRotationUnchecked");
if (SHOW_LIGHT_TRANSACTIONS) {
Slog.i(TAG_WM, "<<< CLOSE TRANSACTION setRotationUnchecked");
}
@@ -1452,17 +1452,17 @@
/**
* @return The primary split-screen stack, but only if it is visible, and {@code null} otherwise.
*/
- TaskStack getSplitScreenPrimaryStackStack() {
- TaskStack stack = mTaskStackContainers.getSplitScreenPrimaryStackStack();
+ TaskStack getSplitScreenPrimaryStack() {
+ TaskStack stack = mTaskStackContainers.getSplitScreenPrimaryStack();
return (stack != null && stack.isVisible()) ? stack : null;
}
/**
- * Like {@link #getSplitScreenPrimaryStackStack}, but also returns the stack if it's currently
+ * Like {@link #getSplitScreenPrimaryStack}, but also returns the stack if it's currently
* not visible.
*/
- TaskStack getSplitScreenPrimaryStackStackIgnoringVisibility() {
- return mTaskStackContainers.getSplitScreenPrimaryStackStack();
+ TaskStack getSplitScreenPrimaryStackIgnoringVisibility() {
+ return mTaskStackContainers.getSplitScreenPrimaryStack();
}
TaskStack getPinnedStack() {
@@ -1877,7 +1877,7 @@
mTouchExcludeRegion.op(mTmpRegion, Region.Op.UNION);
}
// TODO(multi-display): Support docked stacks on secondary displays.
- if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStackStack() != null) {
+ if (mDisplayId == DEFAULT_DISPLAY && getSplitScreenPrimaryStack() != null) {
mDividerControllerLocked.getTouchRegion(mTmpRect);
mTmpRegion.set(mTmpRect);
mTouchExcludeRegion.op(mTmpRegion, Op.UNION);
@@ -2232,7 +2232,7 @@
if (pinnedStack != null) {
pw.println(prefix + "pinnedStack=" + pinnedStack.getName());
}
- final TaskStack splitScreenPrimaryStack = getSplitScreenPrimaryStackStack();
+ final TaskStack splitScreenPrimaryStack = getSplitScreenPrimaryStack();
if (splitScreenPrimaryStack != null) {
pw.println(prefix + "splitScreenPrimaryStack=" + splitScreenPrimaryStack.getName());
}
@@ -2877,8 +2877,7 @@
Slog.v(TAG, "performLayout: needed=" + isLayoutNeeded() + " dw=" + dw + " dh=" + dh);
}
- mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mRotation,
- getConfiguration().uiMode);
+ mService.mPolicy.beginLayoutLw(mDisplayId, dw, dh, mRotation, getConfiguration().uiMode);
if (isDefaultDisplay) {
// Not needed on non-default displays.
mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw();
@@ -3401,7 +3400,7 @@
return mPinnedStack;
}
- TaskStack getSplitScreenPrimaryStackStack() {
+ TaskStack getSplitScreenPrimaryStack() {
return mSplitScreenPrimaryStack;
}
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 5ce4d46..5ea0e1d 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -321,7 +321,7 @@
if (mWindow == null) {
return;
}
- TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
// If the stack is invisible, we policy force hide it in WindowAnimator.shouldForceHide
final boolean visible = stack != null;
@@ -361,7 +361,7 @@
}
void positionDockedStackedDivider(Rect frame) {
- TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStack();
+ TaskStack stack = mDisplayContent.getSplitScreenPrimaryStack();
if (stack == null) {
// Unfortunately we might end up with still having a divider, even though the underlying
// stack was already removed. This is because we are on AM thread and the removal of the
@@ -458,7 +458,7 @@
long animDuration = 0;
if (animate) {
final TaskStack stack =
- mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
final long transitionDuration = isAnimationMaximizing()
? mService.mAppTransition.getLastClipRevealTransitionDuration()
: DEFAULT_APP_TRANSITION_DURATION;
@@ -513,7 +513,7 @@
mDockedStackListeners.register(listener);
notifyDockedDividerVisibilityChanged(wasVisible());
notifyDockedStackExistsChanged(
- mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() != null);
+ mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null);
notifyDockedStackMinimizedChanged(mMinimizedDock, false /* animate */,
isHomeStackResizable());
notifyAdjustedForImeChanged(mAdjustedForIme, 0 /* animDuration */);
@@ -531,7 +531,7 @@
final TaskStack stack = targetWindowingMode != WINDOWING_MODE_UNDEFINED
? mDisplayContent.getStack(targetWindowingMode)
: null;
- final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStackStack();
+ final TaskStack dockedStack = mDisplayContent.getSplitScreenPrimaryStack();
boolean visibleAndValid = visible && stack != null && dockedStack != null;
if (visibleAndValid) {
stack.getDimBounds(mTmpRect);
@@ -543,7 +543,7 @@
mDimLayer.setBounds(mTmpRect);
mDimLayer.show(getResizeDimLayer(), alpha, 0 /* duration */);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setResizeDimLayer");
}
}
mLastDimLayerRect.set(mTmpRect);
@@ -558,7 +558,7 @@
mService.openSurfaceTransaction();
mDimLayer.hide();
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setResizeDimLayer");
}
}
mLastDimLayerAlpha = 0f;
@@ -616,7 +616,7 @@
}
private void checkMinimizeChanged(boolean animate) {
- if (mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() == null) {
+ if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) {
return;
}
final TaskStack homeStack = mDisplayContent.getHomeStack();
@@ -778,7 +778,7 @@
}
private boolean setMinimizedDockedStack(boolean minimized) {
- final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
notifyDockedStackMinimizedChanged(minimized, false /* animate */, isHomeStackResizable());
return stack != null && stack.setAdjustedForMinimizedDock(minimized ? 1f : 0f);
}
@@ -829,7 +829,7 @@
}
private boolean animateForMinimizedDockedStack(long now) {
- final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ final TaskStack stack = mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
if (!mAnimationStarted) {
mAnimationStarted = true;
mAnimationStartTime = now;
diff --git a/services/core/java/com/android/server/wm/DragDropController.java b/services/core/java/com/android/server/wm/DragDropController.java
index 860ff38..4567e10 100644
--- a/services/core/java/com/android/server/wm/DragDropController.java
+++ b/services/core/java/com/android/server/wm/DragDropController.java
@@ -21,6 +21,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.NonNull;
import android.content.ClipData;
import android.graphics.PixelFormat;
import android.os.Binder;
@@ -35,6 +36,9 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
import android.view.View;
+import android.view.WindowManagerInternal.IDragDropCallback;
+import com.android.internal.util.Preconditions;
+import com.android.server.input.InputWindowHandle;
/**
* Managing drag and drop operations initiated by View#startDragAndDrop.
@@ -49,20 +53,80 @@
static final int MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT = 2;
static final int MSG_ANIMATION_END = 3;
- DragState mDragState;
+ /**
+ * 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.
+ */
+ private DragState mDragState;
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();
+
+ /**
+ * Callback which is used to sync drag state with the vendor-specific code.
+ */
+ @NonNull private IDragDropCallback mCallback = new IDragDropCallback() {};
+
boolean dragDropActiveLocked() {
return mDragState != null;
}
+ InputWindowHandle getInputWindowHandleLocked() {
+ return mDragState.getInputWindowHandle();
+ }
+
+ void registerCallback(IDragDropCallback callback) {
+ Preconditions.checkNotNull(callback);
+ synchronized (mWriteLock) {
+ mCallback = callback;
+ }
+ }
+
DragDropController(WindowManagerService service, Looper looper) {
mService = service;
mHandler = new DragHandler(service, looper);
}
+ void sendDragStartedIfNeededLocked(WindowState window) {
+ mDragState.sendDragStartedIfNeededLocked(window);
+ }
+
IBinder prepareDrag(SurfaceSession session, int callerPid,
int callerUid, IWindow window, int flags, int width, int height, Surface outSurface) {
if (DEBUG_DRAG) {
@@ -71,46 +135,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,
@@ -120,77 +184,81 @@
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()");
- }
-
- 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) {
+ synchronized (mWriteLock) {
+ if (!mCallback.performDrag(window, dragToken, touchSource, touchX, touchY, thumbCenterX,
+ thumbCenterY, data)) {
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.unregister();
- mDragState.reset();
- mDragState = null;
- return false;
+ 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);
}
-
- 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();
- if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
- TAG_WM, "<<< CLOSE TRANSACTION performDrag");
- }
-
- mDragState.notifyLocationLocked(touchX, touchY);
}
return true; // success!
@@ -202,32 +270,36 @@
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) {
+ mCallback.reportDropResult(window, consumed);
+ 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();
+ }
}
}
@@ -236,21 +308,50 @@
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) {
+ mCallback.cancelDragAndDrop(dragToken);
+ 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();
+ }
+ }
+ }
+
+ /**
+ * Handles motion events.
+ * @param keepHandling Whether if the drag operation is continuing or this is the last motion
+ * event.
+ * @param newX X coordinate value in dp in the screen coordinate
+ * @param newY Y coordinate value in dp in the screen coordinate
+ */
+ void handleMotionEvent(boolean keepHandling, float newX, float newY) {
+ 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);
+ }
+ }
}
}
@@ -282,6 +383,17 @@
mHandler.sendMessageDelayed(msg, DRAG_TIMEOUT_MS);
}
+ /**
+ * Notifies the current drag state is closed.
+ */
+ void onDragStateClosedLocked(DragState dragState) {
+ if (mDragState != dragState) {
+ Slog.wtf(TAG_WM, "Unknown drag state is closed");
+ return;
+ }
+ mDragState = null;
+ }
+
private class DragHandler extends Handler {
/**
* Lock for window manager.
@@ -301,27 +413,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.unregister();
- mDragState.reset();
- mDragState = null;
+ 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;
@@ -330,23 +444,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.onAnimationEndLocked();
}
break;
}
diff --git a/services/core/java/com/android/server/wm/DragInputEventReceiver.java b/services/core/java/com/android/server/wm/DragInputEventReceiver.java
index b4bbc90..bee2bac 100644
--- a/services/core/java/com/android/server/wm/DragInputEventReceiver.java
+++ b/services/core/java/com/android/server/wm/DragInputEventReceiver.java
@@ -37,7 +37,6 @@
* Input receiver for drag and drop
*/
class DragInputEventReceiver extends InputEventReceiver {
- private final WindowManagerService mService;
private final DragDropController mDragDropController;
// Set, if stylus button was down at the start of the drag.
@@ -48,100 +47,63 @@
// are still being dispatched.
private boolean mMuteInput = false;
- public DragInputEventReceiver(InputChannel inputChannel, Looper looper,
- DragDropController controller, WindowManagerService service) {
+ DragInputEventReceiver(InputChannel inputChannel, Looper looper,
+ DragDropController controller) {
super(inputChannel, looper);
mDragDropController = controller;
- mService = service;
}
@Override
public void onInputEvent(InputEvent event, int displayId) {
boolean handled = false;
try {
- synchronized (mService.mWindowMap) {
- if (!mDragDropController.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.
- handled = true;
- return;
- }
- if (!(event instanceof MotionEvent)
- || (event.getSource() & SOURCE_CLASS_POINTER) == 0
- || mMuteInput) {
- return;
- }
- final MotionEvent motionEvent = (MotionEvent) event;
- boolean endDrag = false;
- final float newX = motionEvent.getRawX();
- final float newY = motionEvent.getRawY();
- final boolean isStylusButtonDown =
- (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0;
-
- if (mIsStartEvent) {
- if (isStylusButtonDown) {
- // First event and the button was down, check for the button being
- // lifted in the future, if that happens we'll drop the item.
- mStylusButtonDownAtStart = true;
- }
- mIsStartEvent = false;
- }
-
- switch (motionEvent.getAction()) {
- case ACTION_DOWN: {
- if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
- }
- break;
-
- case ACTION_MOVE: {
- if (mStylusButtonDownAtStart && !isStylusButtonDown) {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "Button no longer pressed; dropping at "
- + newX + "," + newY);
- }
- mMuteInput = true;
- endDrag = mDragDropController.mDragState
- .notifyDropLocked(newX, newY);
- } else {
- // move the surface and tell the involved window(s) where we are
- mDragDropController.mDragState.notifyMoveLocked(newX, newY);
- }
- }
- break;
-
- case ACTION_UP: {
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "Got UP on move channel; dropping at "
- + newX + "," + newY);
- }
- mMuteInput = true;
- endDrag = mDragDropController.mDragState
- .notifyDropLocked(newX, newY);
- }
- break;
-
- case ACTION_CANCEL: {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
- mMuteInput = true;
- endDrag = true;
- }
- break;
- }
-
- if (endDrag) {
- if (DEBUG_DRAG)
- Slog.d(TAG_WM, "Drag ended; tearing down state");
- // tell all the windows that the drag has ended
- // endDragLocked will post back to looper to dispose the receiver
- // since we still need the receiver for the last finishInputEvent.
- mDragDropController.mDragState.endDragLocked();
- mStylusButtonDownAtStart = false;
- mIsStartEvent = true;
- }
-
- handled = true;
+ if (!(event instanceof MotionEvent)
+ || (event.getSource() & SOURCE_CLASS_POINTER) == 0
+ || mMuteInput) {
+ return;
}
+ final MotionEvent motionEvent = (MotionEvent) event;
+ final float newX = motionEvent.getRawX();
+ final float newY = motionEvent.getRawY();
+ final boolean isStylusButtonDown =
+ (motionEvent.getButtonState() & BUTTON_STYLUS_PRIMARY) != 0;
+
+ if (mIsStartEvent) {
+ // First event and the button was down, check for the button being
+ // lifted in the future, if that happens we'll drop the item.
+ mStylusButtonDownAtStart = isStylusButtonDown;
+ mIsStartEvent = false;
+ }
+
+ switch (motionEvent.getAction()) {
+ case ACTION_DOWN:
+ if (DEBUG_DRAG) Slog.w(TAG_WM, "Unexpected ACTION_DOWN in drag layer");
+ return;
+ case ACTION_MOVE:
+ if (mStylusButtonDownAtStart && !isStylusButtonDown) {
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "Button no longer pressed; dropping at " + newX + ","
+ + newY);
+ }
+ mMuteInput = true;
+ }
+ break;
+ case ACTION_UP:
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "Got UP on move channel; dropping at " + newX + "," + newY);
+ }
+ mMuteInput = true;
+ break;
+ case ACTION_CANCEL:
+ if (DEBUG_DRAG) Slog.d(TAG_WM, "Drag cancelled!");
+ mMuteInput = true;
+ break;
+ default:
+ return;
+ }
+
+ mDragDropController.handleMotionEvent(!mMuteInput /* keepHandling */, newX, newY);
+ handled = true;
} catch (Exception e) {
Slog.e(TAG_WM, "Exception caught by drag handleMotion", e);
} finally {
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index 9a955de..e81d366 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -105,6 +105,11 @@
WindowState mTargetWindow;
ArrayList<WindowState> mNotifiedWindows;
boolean mDragInProgress;
+ /**
+ * Whether if animation is completed. Needs to be volatile to update from the animation thread
+ * without having a WM lock.
+ */
+ volatile boolean mAnimationCompleted = false;
DisplayContent mDisplayContent;
@Nullable private ValueAnimator mAnimator;
@@ -122,21 +127,79 @@
mNotifiedWindows = new ArrayList<WindowState>();
}
- void reset() {
- if (mAnimator != null) {
+ /**
+ * After calling this, DragDropController#onDragStateClosedLocked is invoked, which causes
+ * DragDropController#mDragState becomes null.
+ */
+ void closeLocked() {
+ // Unregister the input interceptor.
+ if (mInputInterceptor != null) {
+ if (DEBUG_DRAG)
+ Slog.d(TAG_WM, "unregistering drag input channel");
+
+ // Input channel should be disposed on the thread where the input is being handled.
+ mDragDropController.sendHandlerMessage(
+ MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
+ mInputInterceptor = null;
+ mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+ }
+
+ // Send drag end broadcast if drag start has been sent.
+ if (mDragInProgress) {
+ final int myPid = Process.myPid();
+
+ if (DEBUG_DRAG) {
+ Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
+ }
+ for (WindowState ws : mNotifiedWindows) {
+ float x = 0;
+ float y = 0;
+ if (!mDragResult && (ws.mSession.mPid == mPid)) {
+ // Report unconsumed drop location back to the app that started the drag.
+ x = mCurrentX;
+ y = mCurrentY;
+ }
+ DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
+ x, y, null, null, null, null, mDragResult);
+ try {
+ ws.mClient.dispatchDragEvent(evt);
+ } catch (RemoteException e) {
+ Slog.w(TAG_WM, "Unable to drag-end window " + ws);
+ }
+ // if the current window is in the same process,
+ // the dispatch has already recycled the event
+ if (myPid != ws.mSession.mPid) {
+ evt.recycle();
+ }
+ }
+ mNotifiedWindows.clear();
+ mDragInProgress = false;
+ }
+
+ // Take the cursor back if it has been changed.
+ if (isFromSource(InputDevice.SOURCE_MOUSE)) {
+ mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
+ mTouchSource = 0;
+ }
+
+ // Clear the internal variables.
+ if (mSurfaceControl != null) {
+ mSurfaceControl.destroy();
+ mSurfaceControl = null;
+ }
+ if (mAnimator != null && !mAnimationCompleted) {
Slog.wtf(TAG_WM,
"Unexpectedly destroying mSurfaceControl while animation is running");
}
- if (mSurfaceControl != null) {
- mSurfaceControl.destroy();
- }
- mSurfaceControl = null;
mFlags = 0;
mLocalWin = null;
mToken = null;
mData = null;
mThumbOffsetX = mThumbOffsetY = 0;
mNotifiedWindows = null;
+
+ // Notifies the controller that the drag state is closed.
+ mDragDropController.onDragStateClosedLocked(this);
}
class InputInterceptor {
@@ -151,7 +214,7 @@
mClientChannel = channels[1];
mService.mInputManager.registerInputChannel(mServerChannel, null);
mInputEventReceiver = new DragInputEventReceiver(mClientChannel,
- mService.mH.getLooper(), mDragDropController, mService);
+ mService.mH.getLooper(), mDragDropController);
mDragApplicationHandle = new InputApplicationHandle(null);
mDragApplicationHandle.name = "drag";
@@ -235,19 +298,6 @@
}
}
- void unregister() {
- if (DEBUG_DRAG) Slog.d(TAG_WM, "unregistering drag input channel");
- if (mInputInterceptor == null) {
- Slog.e(TAG_WM, "Unregister of nonexistent drag input channel");
- } else {
- // Input channel should be disposed on the thread where the input is being handled.
- mDragDropController.sendHandlerMessage(
- MSG_TEAR_DOWN_DRAG_AND_DROP_INPUT, mInputInterceptor);
- mInputInterceptor = null;
- mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
- }
- }
-
int getDragLayerLocked() {
return mService.mPolicy.getWindowLayerFromTypeLw(WindowManager.LayoutParams.TYPE_DRAG)
* WindowManagerService.TYPE_LAYER_MULTIPLIER
@@ -366,46 +416,15 @@
return false;
}
- private void broadcastDragEndedLocked() {
- final int myPid = Process.myPid();
-
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "broadcasting DRAG_ENDED");
- }
- for (WindowState ws : mNotifiedWindows) {
- float x = 0;
- float y = 0;
- if (!mDragResult && (ws.mSession.mPid == mPid)) {
- // Report unconsumed drop location back to the app that started the drag.
- x = mCurrentX;
- y = mCurrentY;
- }
- DragEvent evt = DragEvent.obtain(DragEvent.ACTION_DRAG_ENDED,
- x, y, null, null, null, null, mDragResult);
- try {
- ws.mClient.dispatchDragEvent(evt);
- } catch (RemoteException e) {
- Slog.w(TAG_WM, "Unable to drag-end window " + ws);
- }
- // if the current window is in the same process,
- // the dispatch has already recycled the event
- if (myPid != ws.mSession.mPid) {
- evt.recycle();
- }
- }
- mNotifiedWindows.clear();
- mDragInProgress = false;
- }
-
void endDragLocked() {
if (mAnimator != null) {
return;
}
if (!mDragResult) {
mAnimator = createReturnAnimationLocked();
- return; // Will call cleanUpDragLw when the animation is done.
+ return; // Will call closeLocked() when the animation is done.
}
- cleanUpDragLocked();
+ closeLocked();
}
void cancelDragLocked() {
@@ -414,33 +433,15 @@
}
if (!mDragInProgress) {
// This can happen if an app invokes Session#cancelDragAndDrop before
- // Session#performDrag. Reset the drag state:
- // 1. without sending the end broadcast because the start broadcast has not been sent,
- // and
- // 2. without playing the cancel animation because H.DRAG_START_TIMEOUT may be sent to
- // WindowManagerService, which will cause DragState#reset() while playing the
- // cancel animation.
- reset();
- mDragDropController.mDragState = null;
+ // Session#performDrag. Reset the drag state without playing the cancel animation
+ // because H.DRAG_START_TIMEOUT may be sent to WindowManagerService, which will cause
+ // DragState#reset() while playing the cancel animation.
+ closeLocked();
return;
}
mAnimator = createCancelAnimationLocked();
}
- private void cleanUpDragLocked() {
- broadcastDragEndedLocked();
- if (isFromSource(InputDevice.SOURCE_MOUSE)) {
- mService.restorePointerIconLocked(mDisplayContent, mCurrentX, mCurrentY);
- }
-
- // stop intercepting input
- unregister();
-
- // free our resources and drop all the object references
- reset();
- mDragDropController.mDragState = null;
- }
-
void notifyMoveLocked(float x, float y) {
if (mAnimator != null) {
return;
@@ -458,7 +459,7 @@
+ mSurfaceControl + ": pos=(" +
(int)(x - mThumbOffsetX) + "," + (int)(y - mThumbOffsetY) + ")");
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("notifyMoveLw");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(
TAG_WM, "<<< CLOSE TRANSACTION notifyMoveLocked");
}
@@ -507,34 +508,33 @@
mTargetWindow = touchedWin;
}
- // Find the drop target and tell it about the data. Returns 'true' if we can immediately
- // dispatch the global drag-ended message, 'false' if we need to wait for a
- // result from the recipient.
- boolean notifyDropLocked(float x, float y) {
+ /**
+ * Finds the drop target and tells it about the data. If the drop event is not sent to the
+ * target, invokes {@code endDragLocked} immediately.
+ */
+ void notifyDropLocked(float x, float y) {
if (mAnimator != null) {
- return false;
+ return;
}
mCurrentX = x;
mCurrentY = y;
- WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
+ final WindowState touchedWin = mDisplayContent.getTouchableWinAtPointLocked(x, y);
if (!isWindowNotified(touchedWin)) {
// "drop" outside a valid window -- no recipient to apply a
// timeout to, and we can send the drag-ended message immediately.
mDragResult = false;
- return true;
+ endDragLocked();
+ return;
}
- if (DEBUG_DRAG) {
- Slog.d(TAG_WM, "sending DROP to " + touchedWin);
- }
+ if (DEBUG_DRAG) Slog.d(TAG_WM, "sending DROP to " + touchedWin);
final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
- DragAndDropPermissionsHandler dragAndDropPermissions = null;
- if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
- (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
+ final DragAndDropPermissionsHandler dragAndDropPermissions;
+ if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 && (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
dragAndDropPermissions = new DragAndDropPermissionsHandler(
mData,
mUid,
@@ -542,13 +542,15 @@
mFlags & DRAG_FLAGS_URI_PERMISSIONS,
mSourceUserId,
targetUserId);
+ } else {
+ dragAndDropPermissions = null;
}
if (mSourceUserId != targetUserId){
mData.fixUris(mSourceUserId);
}
final int myPid = Process.myPid();
final IBinder token = touchedWin.mClient.asBinder();
- DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
+ final DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
null, null, mData, dragAndDropPermissions, false);
try {
touchedWin.mClient.dispatchDragEvent(evt);
@@ -557,23 +559,13 @@
mDragDropController.sendTimeoutMessage(MSG_DRAG_END_TIMEOUT, token);
} catch (RemoteException e) {
Slog.w(TAG_WM, "can't send drop notification to win " + touchedWin);
- return true;
+ endDragLocked();
} finally {
if (myPid != touchedWin.mSession.mPid) {
evt.recycle();
}
}
mToken = token;
- return false;
- }
-
- void onAnimationEndLocked() {
- if (mAnimator == null) {
- Slog.wtf(TAG_WM, "Unexpected null mAnimator");
- return;
- }
- mAnimator = null;
- cleanUpDragLocked();
}
private static DragEvent obtainDragEvent(WindowState win, int action,
@@ -677,6 +669,7 @@
@Override
public void onAnimationEnd(Animator animator) {
+ mAnimationCompleted = true;
// Updating mDragState requires the WM lock so continues it on the out of
// AnimationThread.
mDragDropController.sendHandlerMessage(MSG_ANIMATION_END, null);
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 40eab45..a766097 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -381,7 +381,7 @@
Log.d(TAG_WM, "Inserting drag window");
}
final InputWindowHandle dragWindowHandle =
- mService.mDragDropController.mDragState.getInputWindowHandle();
+ mService.mDragDropController.getInputWindowHandleLocked();
if (dragWindowHandle != null) {
addInputWindowHandle(dragWindowHandle);
} else {
@@ -698,7 +698,7 @@
// If there's a drag in progress and 'child' is a potential drop target,
// make sure it's been told about the drag
if (inDrag && isVisible && w.getDisplayContent().isDefaultDisplay) {
- mService.mDragDropController.mDragState.sendDragStartedIfNeededLocked(w);
+ mService.mDragDropController.sendDragStartedIfNeededLocked(w);
}
addInputWindowHandle(
diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java
index 365366a..d8726bf 100644
--- a/services/core/java/com/android/server/wm/PinnedStackController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackController.java
@@ -149,6 +149,9 @@
@Override
public void binderDied() {
// Clean up the state if the listener dies
+ if (mPinnedStackListener != null) {
+ mPinnedStackListener.asBinder().unlinkToDeath(mPinnedStackListenerDeathHandler, 0);
+ }
mPinnedStackListener = null;
}
}
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index a710441..bcb6e673 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -457,7 +457,7 @@
try {
forAllWindows(sRemoveReplacedWindowsConsumer, true /* traverseTopToBottom */);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("removeReplacedWindows");
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION removeReplacedWindows");
}
}
@@ -599,7 +599,7 @@
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("performLayoutAndPlaceSurfaces");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces");
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index c25b19c..3350fea 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -296,7 +296,7 @@
setRotationInTransaction(originalRotation);
} finally {
if (!inTransaction) {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("ScreenRotationAnimation");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation");
}
@@ -567,7 +567,7 @@
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -607,7 +607,7 @@
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
@@ -629,7 +629,7 @@
} catch (OutOfResourcesException e) {
Slog.w(TAG, "Unable to allocate black surface", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("ScreenRotationAnimation.startAnimation");
if (SHOW_LIGHT_TRANSACTIONS || DEBUG_STATE) Slog.i(
TAG_WM,
"<<< CLOSE TRANSACTION ScreenRotationAnimation.startAnimation");
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 7620cb0..13435d7 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -419,7 +419,7 @@
return mFillsParent
|| !inSplitScreenSecondaryWindowingMode()
|| displayContent == null
- || displayContent.getSplitScreenPrimaryStackStackIgnoringVisibility() != null;
+ || displayContent.getSplitScreenPrimaryStackIgnoringVisibility() != null;
}
/** Original bounds of the task if applicable, otherwise fullscreen rect. */
@@ -678,7 +678,7 @@
mChildren.get(i).forceWindowsScaleableInTransaction(force);
}
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("forceWindowsScaleable");
}
}
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a11b333..12f6b5a 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -637,7 +637,7 @@
} else {
showDimLayer();
}
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("updateDimLayerVisibility");
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 7cee66b..6e89e3e 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -294,7 +294,7 @@
if (mFillsParent
|| !inSplitScreenSecondaryWindowingMode()
|| mDisplayContent == null
- || mDisplayContent.getSplitScreenPrimaryStackStack() != null) {
+ || mDisplayContent.getSplitScreenPrimaryStack() != null) {
return true;
}
return false;
@@ -523,7 +523,7 @@
final DividerSnapAlgorithm algorithm = new DividerSnapAlgorithm(
mService.mContext.getResources(), displayWidth, displayHeight,
dividerSize, orientation == Configuration.ORIENTATION_PORTRAIT, outBounds,
- isMinimizedDockAndHomeStackResizable());
+ getDockSide(), isMinimizedDockAndHomeStackResizable());
final SnapTarget target = algorithm.calculateNonDismissingSnapTarget(dividerPosition);
// Recalculate the bounds based on the position of the target.
@@ -693,7 +693,7 @@
"animation background stackId=" + mStackId);
Rect bounds = null;
- final TaskStack dockedStack = dc.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ final TaskStack dockedStack = dc.getSplitScreenPrimaryStackIgnoringVisibility();
if (inSplitScreenPrimaryWindowingMode()
|| (dockedStack != null && inSplitScreenSecondaryWindowingMode()
&& !dockedStack.fillsParent())) {
@@ -773,7 +773,7 @@
}
final TaskStack dockedStack =
- mDisplayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility();
if (dockedStack == null) {
// Not sure why you are calling this method when there is no docked stack...
throw new IllegalStateException(
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index e409a68..1912095 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -233,7 +233,7 @@
} catch (RuntimeException e) {
Slog.wtf(TAG, "Unhandled exception in Window Manager", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("WindowAnimator");
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 391f36e..35870b1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -80,7 +80,6 @@
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
@@ -126,6 +125,7 @@
import android.app.AppOpsManager;
import android.app.IActivityManager;
import android.content.BroadcastReceiver;
+import android.content.ClipData;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
@@ -159,10 +159,13 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.PowerManagerInternal;
import android.os.PowerSaveState;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
+import android.os.ShellCallback;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -202,7 +205,6 @@
import android.view.IWindowSessionCallback;
import android.view.InputChannel;
import android.view.InputDevice;
-import android.view.InputEvent;
import android.view.InputEventReceiver;
import android.view.KeyEvent;
import android.view.MagnificationSpec;
@@ -243,7 +245,6 @@
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.input.InputManagerService;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import com.android.server.power.ShutdownThread;
import com.android.server.utils.PriorityDump;
@@ -363,6 +364,8 @@
private static final int TRANSITION_ANIMATION_SCALE = 1;
private static final int ANIMATION_DURATION_SCALE = 2;
+ final WindowTracing mWindowTracing;
+
final private KeyguardDisableHandler mKeyguardDisableHandler;
boolean mKeyguardGoingAway;
// VR Vr2d Display Id.
@@ -822,15 +825,20 @@
/**
* Closes a surface transaction.
+ * @param where debug string indicating where the transaction originated
*/
- void closeSurfaceTransaction() {
+ void closeSurfaceTransaction(String where) {
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "closeSurfaceTransaction");
synchronized (mWindowMap) {
- if (mRoot.mSurfaceTraceEnabled) {
- mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+ try {
+ traceStateLocked(where);
+ } finally {
+ if (mRoot.mSurfaceTraceEnabled) {
+ mRoot.mRemoteEventTrace.closeSurfaceTransaction();
+ }
+ SurfaceControl.closeTransaction();
}
- SurfaceControl.closeTransaction();
}
} finally {
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -931,6 +939,12 @@
}, 0);
}
+ @Override
+ public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
+ String[] args, ShellCallback callback, ResultReceiver result) {
+ new WindowManagerShellCommand(this).exec(this, in, out, err, args, callback, result);
+ }
+
private WindowManagerService(Context context, InputManagerService inputManager,
boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore,
WindowManagerPolicy policy) {
@@ -961,6 +975,8 @@
mPolicy = policy;
mTaskSnapshotController = new TaskSnapshotController(this);
+ mWindowTracing = WindowTracing.createDefaultAndStartLooper(context);
+
LocalServices.addService(WindowManagerPolicy.class, mPolicy);
if(mInputManager != null) {
@@ -1070,7 +1086,7 @@
try {
createWatermarkInTransaction();
} finally {
- closeSurfaceTransaction();
+ closeSurfaceTransaction("createWatermarkInTransaction");
}
showEmulatorDisplayOverlayIfNeeded();
@@ -1305,7 +1321,10 @@
return WindowManagerGlobal.ADD_INVALID_DISPLAY;
}
- mPolicy.adjustWindowParamsLw(win.mAttrs);
+ final boolean hasStatusBarServicePermission =
+ mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
+ == PackageManager.PERMISSION_GRANTED;
+ mPolicy.adjustWindowParamsLw(win, win.mAttrs, hasStatusBarServicePermission);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));
res = mPolicy.prepareAddWindowLw(win, attrs);
@@ -1831,8 +1850,11 @@
MergedConfiguration mergedConfiguration, Surface outSurface) {
int result = 0;
boolean configChanged;
- boolean hasStatusBarPermission =
- mContext.checkCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR)
+ final boolean hasStatusBarPermission =
+ mContext.checkCallingOrSelfPermission(permission.STATUS_BAR)
+ == PackageManager.PERMISSION_GRANTED;
+ final boolean hasStatusBarServicePermission =
+ mContext.checkCallingOrSelfPermission(permission.STATUS_BAR_SERVICE)
== PackageManager.PERMISSION_GRANTED;
long origId = Binder.clearCallingIdentity();
@@ -1852,7 +1874,7 @@
int attrChanges = 0;
int flagChanges = 0;
if (attrs != null) {
- mPolicy.adjustWindowParamsLw(attrs);
+ mPolicy.adjustWindowParamsLw(win, attrs, hasStatusBarServicePermission);
// if they don't have the permission, mask out the status bar bits
if (seq == win.mSeq) {
int systemUiVisibility = attrs.systemUiVisibility
@@ -2895,10 +2917,9 @@
}
public void setKeyguardGoingAway(boolean keyguardGoingAway) {
-// TODO: Use of this can be removed. Revert ag/I8369723d6a77f2c602f1ef080371fa7cd9ee094e
-// synchronized (mWindowMap) {
-// mKeyguardGoingAway = keyguardGoingAway;
-// }
+ synchronized (mWindowMap) {
+ mKeyguardGoingAway = keyguardGoingAway;
+ }
}
// -------------------------------------------------------------
@@ -3286,7 +3307,7 @@
// Notify whether the docked stack exists for the current user
final DisplayContent displayContent = getDefaultDisplayContentLocked();
final TaskStack stack =
- displayContent.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ displayContent.getSplitScreenPrimaryStackIgnoringVisibility();
displayContent.mDividerControllerLocked.notifyDockedStackExistsChanged(
stack != null && stack.hasTaskForUser(newUserId));
@@ -3574,7 +3595,7 @@
mCircularDisplayMask = null;
}
} finally {
- closeSurfaceTransaction();
+ closeSurfaceTransaction("showCircularMask");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
"<<< CLOSE TRANSACTION showCircularMask(visible=" + visible + ")");
}
@@ -3599,7 +3620,7 @@
}
mEmulatorDisplayOverlay.setVisibility(true);
} finally {
- closeSurfaceTransaction();
+ closeSurfaceTransaction("showEmulatorDisplayOverlay");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG_WM,
"<<< CLOSE TRANSACTION showEmulatorDisplayOverlay");
}
@@ -6322,7 +6343,7 @@
* @param proto Stream to write the WindowContainer object to.
* @param trim If true, reduce the amount of data written.
*/
- private void writeToProtoLocked(ProtoOutputStream proto, boolean trim) {
+ void writeToProtoLocked(ProtoOutputStream proto, boolean trim) {
mPolicy.writeToProto(proto, POLICY);
mRoot.writeToProto(proto, ROOT_WINDOW_CONTAINER, trim);
if (mCurrentFocus != null) {
@@ -6341,6 +6362,17 @@
mAppTransition.writeToProto(proto, APP_TRANSITION);
}
+ void traceStateLocked(String where) {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "traceStateLocked");
+ try {
+ mWindowTracing.traceStateLocked(where, this);
+ } catch (Exception e) {
+ Log.wtf(TAG, "Exception while tracing state", e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ }
+
private void dumpWindowsLocked(PrintWriter pw, boolean dumpAll,
ArrayList<WindowState> windows) {
pw.println("WINDOW MANAGER WINDOWS (dumpsys window windows)");
@@ -6909,7 +6941,7 @@
public int getDockedStackSide() {
synchronized (mWindowMap) {
final TaskStack dockedStack = getDefaultDisplayContentLocked()
- .getSplitScreenPrimaryStackStackIgnoringVisibility();
+ .getSplitScreenPrimaryStackIgnoringVisibility();
return dockedStack == null ? DOCKED_INVALID : dockedStack.getDockSide();
}
}
@@ -7055,7 +7087,7 @@
}
synchronized (mWindowMap) {
- if (mDragDropController.mDragState != null) {
+ if (mDragDropController.dragDropActiveLocked()) {
// Drag cursor overrides the app cursor.
return;
}
@@ -7246,11 +7278,6 @@
}
@Override
- public boolean isKeyguardGoingAway() {
- return WindowManagerService.this.mKeyguardGoingAway;
- }
-
- @Override
public boolean isKeyguardShowingAndNotOccluded() {
return WindowManagerService.this.isKeyguardShowingAndNotOccluded();
}
@@ -7415,6 +7442,11 @@
mVr2dDisplayId = vr2dDisplayId;
}
}
+
+ @Override
+ public void registerDragDropControllerCallback(IDragDropCallback callback) {
+ mDragDropController.registerCallback(callback);
+ }
}
void registerAppFreezeListener(AppFreezeListener listener) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
new file mode 100644
index 0000000..4b98d9d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java
@@ -0,0 +1,57 @@
+/*
+ * 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.server.wm;
+
+import android.os.ShellCommand;
+
+import java.io.PrintWriter;
+
+/**
+ * ShellCommands for WindowManagerService.
+ *
+ * Use with {@code adb shell cmd window ...}.
+ */
+public class WindowManagerShellCommand extends ShellCommand {
+
+ private final WindowManagerService mService;
+
+ public WindowManagerShellCommand(WindowManagerService service) {
+ mService = service;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ switch (cmd) {
+ case "tracing":
+ return mService.mWindowTracing.onShellCommand(this, getNextArgRequired());
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ @Override
+ public void onHelp() {
+ PrintWriter pw = getOutPrintWriter();
+ pw.println("Window Manager (window) commands:");
+ pw.println(" help");
+ pw.println(" Print this help text.");
+ pw.println();
+ pw.println(" tracing (start | stop)");
+ pw.println(" start or stop window tracing");
+ pw.println();
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4370a76..6b1932d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1849,110 +1849,109 @@
final long origId = Binder.clearCallingIdentity();
- disposeInputChannel();
+ try {
+ disposeInputChannel();
- if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Remove " + this
- + ": mSurfaceController=" + mWinAnimator.mSurfaceController
- + " mAnimatingExit=" + mAnimatingExit
- + " mRemoveOnExit=" + mRemoveOnExit
- + " mHasSurface=" + mHasSurface
- + " surfaceShowing=" + mWinAnimator.getShown()
- + " isAnimationSet=" + mWinAnimator.isAnimationSet()
- + " app-animation="
- + (mAppToken != null ? mAppToken.mAppAnimator.animation : null)
- + " mWillReplaceWindow=" + mWillReplaceWindow
- + " inPendingTransaction="
- + (mAppToken != null ? mAppToken.inPendingTransaction : false)
- + " mDisplayFrozen=" + mService.mDisplayFrozen
- + " callers=" + Debug.getCallers(6));
+ if (DEBUG_APP_TRANSITIONS) Slog.v(TAG_WM, "Remove " + this
+ + ": mSurfaceController=" + mWinAnimator.mSurfaceController
+ + " mAnimatingExit=" + mAnimatingExit
+ + " mRemoveOnExit=" + mRemoveOnExit
+ + " mHasSurface=" + mHasSurface
+ + " surfaceShowing=" + mWinAnimator.getShown()
+ + " isAnimationSet=" + mWinAnimator.isAnimationSet()
+ + " app-animation="
+ + (mAppToken != null ? mAppToken.mAppAnimator.animation : null)
+ + " mWillReplaceWindow=" + mWillReplaceWindow
+ + " inPendingTransaction="
+ + (mAppToken != null ? mAppToken.inPendingTransaction : false)
+ + " mDisplayFrozen=" + mService.mDisplayFrozen
+ + " callers=" + Debug.getCallers(6));
- // Visibility of the removed window. Will be used later to update orientation later on.
- boolean wasVisible = false;
+ // Visibility of the removed window. Will be used later to update orientation later on.
+ boolean wasVisible = false;
- final int displayId = getDisplayId();
+ final int displayId = getDisplayId();
- // First, see if we need to run an animation. If we do, we have to hold off on removing the
- // window until the animation is done. If the display is frozen, just remove immediately,
- // since the animation wouldn't be seen.
- if (mHasSurface && mToken.okToAnimate()) {
- if (mWillReplaceWindow) {
- // This window is going to be replaced. We need to keep it around until the new one
- // gets added, then we will get rid of this one.
- if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
- "Preserving " + this + " until the new one is " + "added");
- // TODO: We are overloading mAnimatingExit flag to prevent the window state from
- // been removed. We probably need another flag to indicate that window removal
- // should be deffered vs. overloading the flag that says we are playing an exit
- // animation.
- mAnimatingExit = true;
- mReplacingRemoveRequested = true;
- Binder.restoreCallingIdentity(origId);
- return;
- }
-
- // If we are not currently running the exit animation, we need to see about starting one
- wasVisible = isWinVisibleLw();
-
- if (keepVisibleDeadWindow) {
- if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
- "Not removing " + this + " because app died while it's visible");
-
- mAppDied = true;
- setDisplayLayoutNeeded();
- mService.mWindowPlacerLocked.performSurfacePlacement();
-
- // Set up a replacement input channel since the app is now dead.
- // We need to catch tapping on the dead window to restart the app.
- openInputChannel(null);
- mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
-
- Binder.restoreCallingIdentity(origId);
- return;
- }
-
- if (wasVisible) {
- final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
-
- // Try starting an animation.
- if (mWinAnimator.applyAnimationLocked(transit, false)) {
+ // First, see if we need to run an animation. If we do, we have to hold off on removing the
+ // window until the animation is done. If the display is frozen, just remove immediately,
+ // since the animation wouldn't be seen.
+ if (mHasSurface && mToken.okToAnimate()) {
+ if (mWillReplaceWindow) {
+ // This window is going to be replaced. We need to keep it around until the new one
+ // gets added, then we will get rid of this one.
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "Preserving " + this + " until the new one is " + "added");
+ // TODO: We are overloading mAnimatingExit flag to prevent the window state from
+ // been removed. We probably need another flag to indicate that window removal
+ // should be deffered vs. overloading the flag that says we are playing an exit
+ // animation.
mAnimatingExit = true;
+ mReplacingRemoveRequested = true;
+ return;
}
- //TODO (multidisplay): Magnification is supported only for the default display.
- if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
- mService.mAccessibilityController.onWindowTransitionLocked(this, transit);
- }
- }
- final boolean isAnimating =
- mWinAnimator.isAnimationSet() && !mWinAnimator.isDummyAnimation();
- final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null
- && mAppToken.isLastWindow(this);
- // We delay the removal of a window if it has a showing surface that can be used to run
- // exit animation and it is marked as exiting.
- // Also, If isn't the an animating starting window that is the last window in the app.
- // We allow the removal of the non-animating starting window now as there is no
- // additional window or animation that will trigger its removal.
- if (mWinAnimator.getShown() && mAnimatingExit
- && (!lastWindowIsStartingWindow || isAnimating)) {
- // The exit animation is running or should run... wait for it!
- if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
- "Not removing " + this + " due to exit animation ");
- setupWindowForRemoveOnExit();
- if (mAppToken != null) {
- mAppToken.updateReportedVisibilityLocked();
- }
- Binder.restoreCallingIdentity(origId);
- return;
- }
- }
- removeImmediately();
- // Removing a visible window will effect the computed orientation
- // So just update orientation if needed.
- if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
- mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
+ // If we are not currently running the exit animation, we need to see about starting one
+ wasVisible = isWinVisibleLw();
+
+ if (keepVisibleDeadWindow) {
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "Not removing " + this + " because app died while it's visible");
+
+ mAppDied = true;
+ setDisplayLayoutNeeded();
+ mService.mWindowPlacerLocked.performSurfacePlacement();
+
+ // Set up a replacement input channel since the app is now dead.
+ // We need to catch tapping on the dead window to restart the app.
+ openInputChannel(null);
+ mService.mInputMonitor.updateInputWindowsLw(true /*force*/);
+ return;
+ }
+
+ if (wasVisible) {
+ final int transit = (!startingWindow) ? TRANSIT_EXIT : TRANSIT_PREVIEW_DONE;
+
+ // Try starting an animation.
+ if (mWinAnimator.applyAnimationLocked(transit, false)) {
+ mAnimatingExit = true;
+ }
+ //TODO (multidisplay): Magnification is supported only for the default display.
+ if (mService.mAccessibilityController != null && displayId == DEFAULT_DISPLAY) {
+ mService.mAccessibilityController.onWindowTransitionLocked(this, transit);
+ }
+ }
+ final boolean isAnimating =
+ mWinAnimator.isAnimationSet() && !mWinAnimator.isDummyAnimation();
+ final boolean lastWindowIsStartingWindow = startingWindow && mAppToken != null
+ && mAppToken.isLastWindow(this);
+ // We delay the removal of a window if it has a showing surface that can be used to run
+ // exit animation and it is marked as exiting.
+ // Also, If isn't the an animating starting window that is the last window in the app.
+ // We allow the removal of the non-animating starting window now as there is no
+ // additional window or animation that will trigger its removal.
+ if (mWinAnimator.getShown() && mAnimatingExit
+ && (!lastWindowIsStartingWindow || isAnimating)) {
+ // The exit animation is running or should run... wait for it!
+ if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM,
+ "Not removing " + this + " due to exit animation ");
+ setupWindowForRemoveOnExit();
+ if (mAppToken != null) {
+ mAppToken.updateReportedVisibilityLocked();
+ }
+ return;
+ }
+ }
+
+ removeImmediately();
+ // Removing a visible window will effect the computed orientation
+ // So just update orientation if needed.
+ if (wasVisible && mService.updateOrientationFromAppTokensLocked(false, displayId)) {
+ mService.mH.obtainMessage(SEND_NEW_CONFIGURATION, displayId).sendToTarget();
+ }
+ mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
- mService.updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL, true /*updateInputWindows*/);
- Binder.restoreCallingIdentity(origId);
}
private void setupWindowForRemoveOnExit() {
@@ -2361,7 +2360,7 @@
// also reset drag resizing state, because the owner can't do it
// anymore.
final TaskStack stack =
- dc.getSplitScreenPrimaryStackStackIgnoringVisibility();
+ dc.getSplitScreenPrimaryStackIgnoringVisibility();
if (stack != null) {
stack.resetDockedStackToMiddle();
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 5266903..86397ae 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -732,7 +732,7 @@
mSurfaceController.setLayerStackInTransaction(getLayerStack());
mSurfaceController.setLayer(mAnimLayer);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("createSurfaceLocked");
}
mLastHidden = true;
@@ -1711,7 +1711,7 @@
Slog.w(TAG, "Error positioning surface of " + mWin
+ " pos=(" + left + "," + top + ")", e);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setWallpaperOffset");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION setWallpaperOffset");
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index edd650a..a214523 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -259,7 +259,7 @@
mSurfaceControl.setLayer(layer);
}
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setLayer");
}
}
}
@@ -385,7 +385,7 @@
try {
mSurfaceControl.setTransparentRegionHint(region);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setTransparentRegion");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION setTransparentRegion");
}
@@ -403,7 +403,7 @@
try {
mSurfaceControl.setOpaque(isOpaque);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setOpaqueLocked");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setOpaqueLocked");
}
}
@@ -420,7 +420,7 @@
try {
mSurfaceControl.setSecure(isSecure);
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("setSecure");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setSecureLocked");
}
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index d57fdd2..cd5e475 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -429,7 +429,7 @@
try {
mService.mAnimator.orAnimating(appAnimator.showAllWindowsLocked());
} finally {
- mService.closeSurfaceTransaction();
+ mService.closeSurfaceTransaction("handleAppTransitionReadyLocked");
if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG,
"<<< CLOSE TRANSACTION handleAppTransitionReadyLocked()");
}
diff --git a/services/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
new file mode 100644
index 0000000..5657f6c
--- /dev/null
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -0,0 +1,197 @@
+/*
+ * 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.server.wm;
+
+import static com.android.server.wm.proto.WindowManagerTraceFileProto.ENTRY;
+import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER;
+import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER_H;
+import static com.android.server.wm.proto.WindowManagerTraceFileProto.MAGIC_NUMBER_L;
+import static com.android.server.wm.proto.WindowManagerTraceProto.ELAPSED_REALTIME_NANOS;
+import static com.android.server.wm.proto.WindowManagerTraceProto.WHERE;
+import static com.android.server.wm.proto.WindowManagerTraceProto.WINDOW_MANAGER_SERVICE;
+
+import android.content.Context;
+import android.os.ShellCommand;
+import android.os.SystemClock;
+import android.os.Trace;
+import android.util.Log;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+/**
+ * A class that allows window manager to dump its state continuously to a trace file, such that a
+ * time series of window manager state can be analyzed after the fact.
+ */
+class WindowTracing {
+
+ private static final String TAG = "WindowTracing";
+ private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
+
+ private final Object mLock = new Object();
+ private final File mTraceFile;
+ private final BlockingQueue<ProtoOutputStream> mWriteQueue = new ArrayBlockingQueue<>(200);
+
+ private boolean mEnabled;
+ private volatile boolean mEnabledLockFree;
+
+ WindowTracing(File file) {
+ mTraceFile = file;
+ }
+
+ void startTrace(PrintWriter pw) throws IOException {
+ synchronized (mLock) {
+ logAndPrintln(pw, "Start tracing to " + mTraceFile + ".");
+ mWriteQueue.clear();
+ mTraceFile.delete();
+ try (OutputStream os = new FileOutputStream(mTraceFile)) {
+ ProtoOutputStream proto = new ProtoOutputStream(os);
+ proto.write(MAGIC_NUMBER, MAGIC_NUMBER_VALUE);
+ proto.flush();
+ }
+ mEnabled = mEnabledLockFree = true;
+ }
+ }
+
+ private void logAndPrintln(PrintWriter pw, String msg) {
+ Log.i(TAG, msg);
+ pw.println(msg);
+ pw.flush();
+ }
+
+ void stopTrace(PrintWriter pw) {
+ synchronized (mLock) {
+ logAndPrintln(pw, "Stop tracing to " + mTraceFile + ". Waiting for traces to flush.");
+ mEnabled = mEnabledLockFree = false;
+ while (!mWriteQueue.isEmpty()) {
+ if (mEnabled) {
+ logAndPrintln(pw, "ERROR: tracing was re-enabled while waiting for flush.");
+ throw new IllegalStateException("tracing enabled while waiting for flush.");
+ }
+ try {
+ mLock.wait();
+ mLock.notify();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ logAndPrintln(pw, "Trace written to " + mTraceFile + ".");
+ }
+ }
+
+ void appendTraceEntry(ProtoOutputStream proto) {
+ if (!mEnabledLockFree) {
+ return;
+ }
+
+ if (!mWriteQueue.offer(proto)) {
+ Log.e(TAG, "Dropping window trace entry, queue full");
+ }
+ }
+
+ void loop() {
+ for (;;) {
+ loopOnce();
+ }
+ }
+
+ @VisibleForTesting
+ void loopOnce() {
+ ProtoOutputStream proto;
+ try {
+ proto = mWriteQueue.take();
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ return;
+ }
+
+ synchronized (mLock) {
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToFile");
+ try (OutputStream os = new FileOutputStream(mTraceFile, true /* append */)) {
+ os.write(proto.getBytes());
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to write file " + mTraceFile, e);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ mLock.notify();
+ }
+ }
+
+ boolean isEnabled() {
+ return mEnabledLockFree;
+ }
+
+ static WindowTracing createDefaultAndStartLooper(Context context) {
+ File file = new File("/data/system/window_trace.proto");
+ WindowTracing windowTracing = new WindowTracing(file);
+ new Thread(windowTracing::loop, "window_tracing").start();
+ return windowTracing;
+ }
+
+ int onShellCommand(ShellCommand shell, String cmd) {
+ PrintWriter pw = shell.getOutPrintWriter();
+ try {
+ switch (cmd) {
+ case "start":
+ startTrace(pw);
+ return 0;
+ case "stop":
+ stopTrace(pw);
+ return 0;
+ default:
+ pw.println("Unknown command: " + cmd);
+ return -1;
+ }
+ } catch (IOException e) {
+ logAndPrintln(pw, e.toString());
+ throw new RuntimeException(e);
+ }
+ }
+
+ void traceStateLocked(String where, WindowManagerService service) {
+ if (!isEnabled()) {
+ return;
+ }
+ ProtoOutputStream os = new ProtoOutputStream();
+ long tokenOuter = os.start(ENTRY);
+ os.write(ELAPSED_REALTIME_NANOS, SystemClock.elapsedRealtimeNanos());
+ os.write(WHERE, where);
+
+ Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "writeToProtoLocked");
+ try {
+ long tokenInner = os.start(WINDOW_MANAGER_SERVICE);
+ service.writeToProtoLocked(os, true /* trim */);
+ os.end(tokenInner);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+ os.end(tokenOuter);
+ appendTraceEntry(os);
+ Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+ }
+}
diff --git a/services/core/jni/com_android_server_UsbDescriptorParser.cpp b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
index df85e31..35e65bc 100644
--- a/services/core/jni/com_android_server_UsbDescriptorParser.cpp
+++ b/services/core/jni/com_android_server_UsbDescriptorParser.cpp
@@ -17,16 +17,18 @@
#define LOG_TAG "UsbHostManagerJNI"
#include "utils/Log.h"
+#include <stdlib.h>
+
#include "jni.h"
#include <nativehelper/JNIHelp.h>
#include <usbhost/usbhost.h>
-#define MAX_DESCRIPTORS_LENGTH 16384
+#define MAX_DESCRIPTORS_LENGTH 4096
// com.android.server.usb.descriptors
extern "C" {
-jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors(
+jbyteArray JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getRawDescriptors_1native(
JNIEnv* env, jobject thiz, jstring deviceAddr) {
const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
struct usb_device* device = usb_device_open(deviceAddrStr);
@@ -39,6 +41,7 @@
int fd = usb_device_get_fd(device);
if (fd < 0) {
+ usb_device_close(device);
return NULL;
}
@@ -46,17 +49,48 @@
jbyte buffer[MAX_DESCRIPTORS_LENGTH];
lseek(fd, 0, SEEK_SET);
int numBytes = read(fd, buffer, sizeof(buffer));
-
+ jbyteArray ret = NULL;
usb_device_close(device);
- jbyteArray ret = NULL;
- if (numBytes != 0) {
+ if (numBytes > 0) {
ret = env->NewByteArray(numBytes);
env->SetByteArrayRegion(ret, 0, numBytes, buffer);
+ } else {
+ ALOGE("error reading descriptors\n");
}
+
return ret;
}
+jstring JNICALL Java_com_android_server_usb_descriptors_UsbDescriptorParser_getDescriptorString_1native(
+ JNIEnv* env, jobject thiz, jstring deviceAddr, jint stringId) {
+
+ const char *deviceAddrStr = env->GetStringUTFChars(deviceAddr, NULL);
+ struct usb_device* device = usb_device_open(deviceAddrStr);
+ env->ReleaseStringUTFChars(deviceAddr, deviceAddrStr);
+
+ if (!device) {
+ ALOGE("usb_device_open failed");
+ return NULL;
+ }
+
+ int fd = usb_device_get_fd(device);
+ if (fd < 0) {
+ ALOGE("usb_device_get_fd failed");
+ usb_device_close(device);
+ return NULL;
+ }
+
+ char* c_str = usb_device_get_string(device, stringId, 0 /*timeout*/);
+
+ jstring j_str = env->NewStringUTF(c_str);
+
+ free(c_str);
+ usb_device_close(device);
+
+ return j_str;
+}
+
} // extern "C"
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index 88ae824..24f2014 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -22,8 +22,6 @@
#include "android_runtime/AndroidRuntime.h"
#include "android_runtime/Log.h"
-#include <usbhost/usbhost.h>
-
#include <stdio.h>
#include <asm/byteorder.h>
#include <sys/types.h>
@@ -31,22 +29,20 @@
#include <fcntl.h>
#include <sys/ioctl.h>
+#include <usbhost/usbhost.h>
+
+#define MAX_DESCRIPTORS_LENGTH 4096
+
namespace android
{
-static const int USB_CONTROL_TRANSFER_TIMEOUT_MS = 200;
-
static struct parcel_file_descriptor_offsets_t
{
jclass mClass;
jmethodID mConstructor;
} gParcelFileDescriptorOffsets;
-static jmethodID method_beginUsbDeviceAdded;
-static jmethodID method_addUsbConfiguration;
-static jmethodID method_addUsbInterface;
-static jmethodID method_addUsbEndpoint;
-static jmethodID method_endUsbDeviceAdded;
+static jmethodID method_usbDeviceAdded;
static jmethodID method_usbDeviceRemoved;
static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
@@ -57,101 +53,52 @@
}
}
-static int usb_device_added(const char *devname, void* client_data) {
- struct usb_descriptor_header* desc;
- struct usb_descriptor_iter iter;
-
- struct usb_device *device = usb_device_open(devname);
+static int usb_device_added(const char *devAddress, void* clientData) {
+ struct usb_device *device = usb_device_open(devAddress);
if (!device) {
ALOGE("usb_device_open failed\n");
return 0;
}
- JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject thiz = (jobject)client_data;
const usb_device_descriptor* deviceDesc = usb_device_get_device_descriptor(device);
+ int classID = deviceDesc->bDeviceClass;
+ int subClassID = deviceDesc->bDeviceSubClass;
- char *manufacturer = usb_device_get_manufacturer_name(device,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- char *product = usb_device_get_product_name(device,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- int version = usb_device_get_version(device);
- char *serial = usb_device_get_serial(device,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
+ // get the raw descriptors
+ int numBytes = usb_device_get_descriptors_length(device);
+ if (numBytes > 0) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jobject thiz = (jobject)clientData;
+ jstring deviceAddress = env->NewStringUTF(devAddress);
- jstring deviceName = env->NewStringUTF(devname);
- jstring manufacturerName = AndroidRuntime::NewStringLatin1(env, manufacturer);
- jstring productName = AndroidRuntime::NewStringLatin1(env, product);
- jstring serialNumber = AndroidRuntime::NewStringLatin1(env, serial);
+ jbyteArray descriptorsArray = env->NewByteArray(numBytes);
+ const jbyte* rawDescriptors = (const jbyte*)usb_device_get_raw_descriptors(device);
+ env->SetByteArrayRegion(descriptorsArray, 0, numBytes, rawDescriptors);
- jboolean result = env->CallBooleanMethod(thiz, method_beginUsbDeviceAdded,
- deviceName, usb_device_get_vendor_id(device), usb_device_get_product_id(device),
- deviceDesc->bDeviceClass, deviceDesc->bDeviceSubClass, deviceDesc->bDeviceProtocol,
- manufacturerName, productName, version, serialNumber);
+ env->CallBooleanMethod(thiz, method_usbDeviceAdded,
+ deviceAddress, classID, subClassID, descriptorsArray);
- env->DeleteLocalRef(serialNumber);
- env->DeleteLocalRef(productName);
- env->DeleteLocalRef(manufacturerName);
- env->DeleteLocalRef(deviceName);
- free(manufacturer);
- free(product);
- free(serial);
+ env->DeleteLocalRef(descriptorsArray);
+ env->DeleteLocalRef(deviceAddress);
- if (!result) goto fail;
-
- usb_descriptor_iter_init(device, &iter);
-
- while ((desc = usb_descriptor_iter_next(&iter)) != NULL) {
- if (desc->bDescriptorType == USB_DT_CONFIG) {
- struct usb_config_descriptor *config = (struct usb_config_descriptor *)desc;
- char *name = usb_device_get_string(device, config->iConfiguration,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- jstring configName = AndroidRuntime::NewStringLatin1(env, name);
-
- env->CallVoidMethod(thiz, method_addUsbConfiguration,
- config->bConfigurationValue, configName, config->bmAttributes,
- config->bMaxPower);
-
- env->DeleteLocalRef(configName);
- free(name);
- } else if (desc->bDescriptorType == USB_DT_INTERFACE) {
- struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)desc;
- char *name = usb_device_get_string(device, interface->iInterface,
- USB_CONTROL_TRANSFER_TIMEOUT_MS);
- jstring interfaceName = AndroidRuntime::NewStringLatin1(env, name);
-
- env->CallVoidMethod(thiz, method_addUsbInterface,
- interface->bInterfaceNumber, interfaceName, interface->bAlternateSetting,
- interface->bInterfaceClass, interface->bInterfaceSubClass,
- interface->bInterfaceProtocol);
-
- env->DeleteLocalRef(interfaceName);
- free(name);
- } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
- struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)desc;
-
- env->CallVoidMethod(thiz, method_addUsbEndpoint,
- endpoint->bEndpointAddress, endpoint->bmAttributes,
- __le16_to_cpu(endpoint->wMaxPacketSize), endpoint->bInterval);
- }
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+ } else {
+ // TODO return an error code here?
+ ALOGE("error reading descriptors\n");
}
- env->CallVoidMethod(thiz, method_endUsbDeviceAdded);
-
-fail:
usb_device_close(device);
- checkAndClearExceptionFromCallback(env, __FUNCTION__);
return 0;
}
-static int usb_device_removed(const char *devname, void* client_data) {
+static int usb_device_removed(const char *devAddress, void* clientData) {
JNIEnv* env = AndroidRuntime::getJNIEnv();
- jobject thiz = (jobject)client_data;
+ jobject thiz = (jobject)clientData;
- jstring deviceName = env->NewStringUTF(devname);
- env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceName);
- env->DeleteLocalRef(deviceName);
+ jstring deviceAddress = env->NewStringUTF(devAddress);
+ env->CallVoidMethod(thiz, method_usbDeviceRemoved, deviceAddress);
+ env->DeleteLocalRef(deviceAddress);
checkAndClearExceptionFromCallback(env, __FUNCTION__);
return 0;
}
@@ -168,11 +115,11 @@
}
static jobject android_server_UsbHostManager_openDevice(JNIEnv *env, jobject /* thiz */,
- jstring deviceName)
+ jstring deviceAddress)
{
- const char *deviceNameStr = env->GetStringUTFChars(deviceName, NULL);
- struct usb_device* device = usb_device_open(deviceNameStr);
- env->ReleaseStringUTFChars(deviceName, deviceNameStr);
+ const char *deviceAddressStr = env->GetStringUTFChars(deviceAddress, NULL);
+ struct usb_device* device = usb_device_open(deviceAddressStr);
+ env->ReleaseStringUTFChars(deviceAddress, deviceAddressStr);
if (!device)
return NULL;
@@ -206,34 +153,12 @@
ALOGE("Can't find com/android/server/usb/UsbHostManager");
return -1;
}
- method_beginUsbDeviceAdded = env->GetMethodID(clazz, "beginUsbDeviceAdded",
- "(Ljava/lang/String;IIIIILjava/lang/String;Ljava/lang/String;ILjava/lang/String;)Z");
- if (method_beginUsbDeviceAdded == NULL) {
+ method_usbDeviceAdded =
+ env->GetMethodID(clazz, "usbDeviceAdded", "(Ljava/lang/String;II[B)Z");
+ if (method_usbDeviceAdded == NULL) {
ALOGE("Can't find beginUsbDeviceAdded");
return -1;
}
- method_addUsbConfiguration = env->GetMethodID(clazz, "addUsbConfiguration",
- "(ILjava/lang/String;II)V");
- if (method_addUsbConfiguration == NULL) {
- ALOGE("Can't find addUsbConfiguration");
- return -1;
- }
- method_addUsbInterface = env->GetMethodID(clazz, "addUsbInterface",
- "(ILjava/lang/String;IIII)V");
- if (method_addUsbInterface == NULL) {
- ALOGE("Can't find addUsbInterface");
- return -1;
- }
- method_addUsbEndpoint = env->GetMethodID(clazz, "addUsbEndpoint", "(IIII)V");
- if (method_addUsbEndpoint == NULL) {
- ALOGE("Can't find addUsbEndpoint");
- return -1;
- }
- method_endUsbDeviceAdded = env->GetMethodID(clazz, "endUsbDeviceAdded", "()V");
- if (method_endUsbDeviceAdded == NULL) {
- ALOGE("Can't find endUsbDeviceAdded");
- return -1;
- }
method_usbDeviceRemoved = env->GetMethodID(clazz, "usbDeviceRemoved",
"(Ljava/lang/String;)V");
if (method_usbDeviceRemoved == NULL) {
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index e8ef168..2f45181 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -92,7 +92,6 @@
register_android_server_tv_TvUinputBridge(env);
register_android_server_tv_TvInputHal(env);
register_android_server_PersistentDataBlockService(env);
- register_android_server_Watchdog(env);
register_android_server_HardwarePropertiesManagerService(env);
register_android_server_storage_AppFuse(env);
register_android_server_SyntheticPasswordManager(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
index 0085931..0aaf32c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/NetworkLogger.java
@@ -107,7 +107,8 @@
return false;
}
try {
- if (mIpConnectivityMetrics.registerNetdEventCallback(mNetdEventCallback)) {
+ if (mIpConnectivityMetrics.addNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY, mNetdEventCallback)) {
mHandlerThread = new ServiceThread(TAG, Process.THREAD_PRIORITY_BACKGROUND,
/* allowIo */ false);
mHandlerThread.start();
@@ -138,7 +139,8 @@
// logging is forcefully disabled even if unregistering fails
return true;
}
- return mIpConnectivityMetrics.unregisterNetdEventCallback();
+ return mIpConnectivityMetrics.removeNetdEventCallback(
+ INetdEventCallback.CALLBACK_CALLER_DEVICE_POLICY);
} catch (RemoteException re) {
Slog.wtf(TAG, "Failed to make remote calls to unregister the callback", re);
return true;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index de5d879..e2e491a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -83,6 +83,7 @@
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
+import com.android.server.net.watchlist.NetworkWatchlistService;
import com.android.server.notification.NotificationManagerService;
import com.android.server.oemlock.OemLockService;
import com.android.server.om.OverlayManagerService;
@@ -193,6 +194,8 @@
"com.google.android.clockwork.ThermalObserver";
private static final String WEAR_CONNECTIVITY_SERVICE_CLASS =
"com.google.android.clockwork.connectivity.WearConnectivityService";
+ private static final String WEAR_SIDEKICK_SERVICE_CLASS =
+ "com.google.android.clockwork.sidekick.SidekickService";
private static final String WEAR_DISPLAY_SERVICE_CLASS =
"com.google.android.clockwork.display.WearDisplayService";
private static final String WEAR_LEFTY_SERVICE_CLASS =
@@ -404,10 +407,8 @@
traceEnd();
}
- // For debug builds, log event loop stalls to dropbox for analysis.
- if (StrictMode.conditionallyEnableDebugLogging()) {
- Slog.i(TAG, "Enabled StrictMode for system server main thread.");
- }
+ StrictMode.initVmDefaults(null);
+
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
int uptimeMillis = (int) SystemClock.elapsedRealtime();
MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
@@ -545,11 +546,9 @@
traceEnd();
// Bring up recovery system in case a rescue party needs a reboot
- if (!SystemProperties.getBoolean("config.disable_noncore", false)) {
- traceBeginAndSlog("StartRecoverySystemService");
- mSystemServiceManager.startService(RecoverySystemService.class);
- traceEnd();
- }
+ traceBeginAndSlog("StartRecoverySystemService");
+ mSystemServiceManager.startService(RecoverySystemService.class);
+ traceEnd();
// Now that we have the bare essentials of the OS up and running, take
// note that we just booted, which might send out a rescue party if
@@ -561,6 +560,13 @@
mSystemServiceManager.startService(LightsService.class);
traceEnd();
+ traceBeginAndSlog("StartSidekickService");
+ // Package manager isn't started yet; need to use SysProp not hardware feature
+ if (SystemProperties.getBoolean("config.enable_sidekick_graphics", false)) {
+ mSystemServiceManager.startService(WEAR_SIDEKICK_SERVICE_CLASS);
+ }
+ traceEnd();
+
// Display manager is needed to provide display metrics before package manager
// starts up.
traceBeginAndSlog("StartDisplayManager");
@@ -705,13 +711,7 @@
MmsServiceBroker mmsService = null;
HardwarePropertiesManagerService hardwarePropertiesService = null;
- boolean disableStorage = SystemProperties.getBoolean("config.disable_storage", false);
- boolean disableBluetooth = SystemProperties.getBoolean("config.disable_bluetooth", false);
- boolean disableLocation = SystemProperties.getBoolean("config.disable_location", false);
boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false);
- boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false);
- boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false);
- boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false);
boolean disableRtt = SystemProperties.getBoolean("config.disable_rtt", false);
boolean disableMediaProjection = SystemProperties.getBoolean("config.disable_mediaproj",
false);
@@ -875,8 +875,6 @@
} else if (!context.getPackageManager().hasSystemFeature
(PackageManager.FEATURE_BLUETOOTH)) {
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
- } else if (disableBluetooth) {
- Slog.i(TAG, "Bluetooth Service disabled by config");
} else {
traceBeginAndSlog("StartBluetoothService");
mSystemServiceManager.startService(BluetoothService.class);
@@ -887,6 +885,10 @@
mSystemServiceManager.startService(IpConnectivityMetrics.class);
traceEnd();
+ traceBeginAndSlog("NetworkWatchlistService");
+ mSystemServiceManager.startService(NetworkWatchlistService.Lifecycle.class);
+ traceEnd();
+
traceBeginAndSlog("PinnerService");
mSystemServiceManager.startService(PinnerService.class);
traceEnd();
@@ -927,8 +929,7 @@
traceEnd();
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- if (!disableStorage &&
- !"0".equals(SystemProperties.get("system_init.startmountservice"))) {
+ if (!"0".equals(SystemProperties.get("system_init.startmountservice"))) {
traceBeginAndSlog("StartStorageManagerService");
try {
/*
@@ -978,42 +979,40 @@
traceEnd();
if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
- if (!disableNonCoreServices) {
- traceBeginAndSlog("StartLockSettingsService");
- try {
- mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
- lockSettings = ILockSettings.Stub.asInterface(
- ServiceManager.getService("lock_settings"));
- } catch (Throwable e) {
- reportWtf("starting LockSettingsService service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartLockSettingsService");
+ try {
+ mSystemServiceManager.startService(LOCK_SETTINGS_SERVICE_CLASS);
+ lockSettings = ILockSettings.Stub.asInterface(
+ ServiceManager.getService("lock_settings"));
+ } catch (Throwable e) {
+ reportWtf("starting LockSettingsService service", e);
+ }
+ traceEnd();
- final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
- if (hasPdb) {
- traceBeginAndSlog("StartPersistentDataBlock");
- mSystemServiceManager.startService(PersistentDataBlockService.class);
- traceEnd();
- }
-
- if (hasPdb || OemLockService.isHalPresent()) {
- // Implementation depends on pdb or the OemLock HAL
- traceBeginAndSlog("StartOemLockService");
- mSystemServiceManager.startService(OemLockService.class);
- traceEnd();
- }
-
- traceBeginAndSlog("StartDeviceIdleController");
- mSystemServiceManager.startService(DeviceIdleController.class);
- traceEnd();
-
- // Always start the Device Policy Manager, so that the API is compatible with
- // API8.
- traceBeginAndSlog("StartDevicePolicyManager");
- mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
+ final boolean hasPdb = !SystemProperties.get(PERSISTENT_DATA_BLOCK_PROP).equals("");
+ if (hasPdb) {
+ traceBeginAndSlog("StartPersistentDataBlock");
+ mSystemServiceManager.startService(PersistentDataBlockService.class);
traceEnd();
}
+ if (hasPdb || OemLockService.isHalPresent()) {
+ // Implementation depends on pdb or the OemLock HAL
+ traceBeginAndSlog("StartOemLockService");
+ mSystemServiceManager.startService(OemLockService.class);
+ traceEnd();
+ }
+
+ traceBeginAndSlog("StartDeviceIdleController");
+ mSystemServiceManager.startService(DeviceIdleController.class);
+ traceEnd();
+
+ // Always start the Device Policy Manager, so that the API is compatible with
+ // API8.
+ traceBeginAndSlog("StartDevicePolicyManager");
+ mSystemServiceManager.startService(DevicePolicyManagerService.Lifecycle.class);
+ traceEnd();
+
if (!disableSystemUI) {
traceBeginAndSlog("StartStatusBarManagerService");
try {
@@ -1025,153 +1024,145 @@
traceEnd();
}
- if (!disableNonCoreServices) {
- traceBeginAndSlog("StartClipboardService");
- mSystemServiceManager.startService(ClipboardService.class);
- traceEnd();
+ traceBeginAndSlog("StartClipboardService");
+ mSystemServiceManager.startService(ClipboardService.class);
+ traceEnd();
+
+ traceBeginAndSlog("StartNetworkManagementService");
+ try {
+ networkManagement = NetworkManagementService.create(context);
+ ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
+ } catch (Throwable e) {
+ reportWtf("starting NetworkManagement Service", e);
}
+ traceEnd();
- if (!disableNetwork) {
- traceBeginAndSlog("StartNetworkManagementService");
- try {
- networkManagement = NetworkManagementService.create(context);
- ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE, networkManagement);
- } catch (Throwable e) {
- reportWtf("starting NetworkManagement Service", e);
- }
- traceEnd();
-
- traceBeginAndSlog("StartIpSecService");
- try {
- ipSecService = IpSecService.create(context);
- ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
- } catch (Throwable e) {
- reportWtf("starting IpSec Service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartIpSecService");
+ try {
+ ipSecService = IpSecService.create(context);
+ ServiceManager.addService(Context.IPSEC_SERVICE, ipSecService);
+ } catch (Throwable e) {
+ reportWtf("starting IpSec Service", e);
}
+ traceEnd();
- if (!disableNonCoreServices && !disableTextServices) {
+ if (!disableTextServices) {
traceBeginAndSlog("StartTextServicesManager");
mSystemServiceManager.startService(TextServicesManagerService.Lifecycle.class);
traceEnd();
}
- if (!disableNetwork) {
- traceBeginAndSlog("StartNetworkScoreService");
- try {
- networkScore = new NetworkScoreService(context);
- ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
- } catch (Throwable e) {
- reportWtf("starting Network Score Service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartNetworkScoreService");
+ try {
+ networkScore = new NetworkScoreService(context);
+ ServiceManager.addService(Context.NETWORK_SCORE_SERVICE, networkScore);
+ } catch (Throwable e) {
+ reportWtf("starting Network Score Service", e);
+ }
+ traceEnd();
- traceBeginAndSlog("StartNetworkStatsService");
- try {
- networkStats = NetworkStatsService.create(context, networkManagement);
- ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
- } catch (Throwable e) {
- reportWtf("starting NetworkStats Service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartNetworkStatsService");
+ try {
+ networkStats = NetworkStatsService.create(context, networkManagement);
+ ServiceManager.addService(Context.NETWORK_STATS_SERVICE, networkStats);
+ } catch (Throwable e) {
+ reportWtf("starting NetworkStats Service", e);
+ }
+ traceEnd();
- traceBeginAndSlog("StartNetworkPolicyManagerService");
- try {
- networkPolicy = new NetworkPolicyManagerService(context,
- mActivityManagerService, networkStats, networkManagement);
- ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
- } catch (Throwable e) {
- reportWtf("starting NetworkPolicy Service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartNetworkPolicyManagerService");
+ try {
+ networkPolicy = new NetworkPolicyManagerService(context,
+ mActivityManagerService, networkStats, networkManagement);
+ ServiceManager.addService(Context.NETWORK_POLICY_SERVICE, networkPolicy);
+ } catch (Throwable e) {
+ reportWtf("starting NetworkPolicy Service", e);
+ }
+ traceEnd();
- // Wifi Service must be started first for wifi-related services.
- traceBeginAndSlog("StartWifi");
- mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
- traceEnd();
- traceBeginAndSlog("StartWifiScanning");
- mSystemServiceManager.startService(
- "com.android.server.wifi.scanner.WifiScanningService");
- traceEnd();
+ // Wifi Service must be started first for wifi-related services.
+ traceBeginAndSlog("StartWifi");
+ mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+ traceEnd();
+ traceBeginAndSlog("StartWifiScanning");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.scanner.WifiScanningService");
+ traceEnd();
- if (!disableRtt) {
- traceBeginAndSlog("StartWifiRtt");
- mSystemServiceManager.startService("com.android.server.wifi.RttService");
- traceEnd();
-
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_RTT)) {
- traceBeginAndSlog("StartRttService");
- mSystemServiceManager.startService(
- "com.android.server.wifi.rtt.RttService");
- traceEnd();
- }
- }
+ if (!disableRtt) {
+ traceBeginAndSlog("StartWifiRtt");
+ mSystemServiceManager.startService("com.android.server.wifi.RttService");
+ traceEnd();
if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_AWARE)) {
- traceBeginAndSlog("StartWifiAware");
- mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+ PackageManager.FEATURE_WIFI_RTT)) {
+ traceBeginAndSlog("StartRttService");
+ mSystemServiceManager.startService(
+ "com.android.server.wifi.rtt.RttService");
traceEnd();
}
+ }
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_WIFI_DIRECT)) {
- traceBeginAndSlog("StartWifiP2P");
- mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_AWARE)) {
+ traceBeginAndSlog("StartWifiAware");
+ mSystemServiceManager.startService(WIFI_AWARE_SERVICE_CLASS);
+ traceEnd();
+ }
- if (context.getPackageManager().hasSystemFeature(
- PackageManager.FEATURE_LOWPAN)) {
- traceBeginAndSlog("StartLowpan");
- mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_WIFI_DIRECT)) {
+ traceBeginAndSlog("StartWifiP2P");
+ mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
+ traceEnd();
+ }
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
- mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
- traceBeginAndSlog("StartEthernet");
- mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_LOWPAN)) {
+ traceBeginAndSlog("StartLowpan");
+ mSystemServiceManager.startService(LOWPAN_SERVICE_CLASS);
+ traceEnd();
+ }
- traceBeginAndSlog("StartConnectivityService");
- try {
- connectivity = new ConnectivityService(
- context, networkManagement, networkStats, networkPolicy);
- ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity,
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
+ traceBeginAndSlog("StartEthernet");
+ mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
+ traceEnd();
+ }
+
+ traceBeginAndSlog("StartConnectivityService");
+ try {
+ connectivity = new ConnectivityService(
+ context, networkManagement, networkStats, networkPolicy);
+ ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity,
/* allowIsolated= */ false,
- DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
- networkStats.bindConnectivityManager(connectivity);
- networkPolicy.bindConnectivityManager(connectivity);
- } catch (Throwable e) {
- reportWtf("starting Connectivity Service", e);
- }
- traceEnd();
-
- traceBeginAndSlog("StartNsdService");
- try {
- serviceDiscovery = NsdService.create(context);
- ServiceManager.addService(
- Context.NSD_SERVICE, serviceDiscovery);
- } catch (Throwable e) {
- reportWtf("starting Service Discovery Service", e);
- }
- traceEnd();
+ DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+ networkStats.bindConnectivityManager(connectivity);
+ networkPolicy.bindConnectivityManager(connectivity);
+ } catch (Throwable e) {
+ reportWtf("starting Connectivity Service", e);
}
+ traceEnd();
- if (!disableNonCoreServices) {
- traceBeginAndSlog("StartUpdateLockService");
- try {
- ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
- new UpdateLockService(context));
- } catch (Throwable e) {
- reportWtf("starting UpdateLockService", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartNsdService");
+ try {
+ serviceDiscovery = NsdService.create(context);
+ ServiceManager.addService(
+ Context.NSD_SERVICE, serviceDiscovery);
+ } catch (Throwable e) {
+ reportWtf("starting Service Discovery Service", e);
}
+ traceEnd();
+
+ traceBeginAndSlog("StartUpdateLockService");
+ try {
+ ServiceManager.addService(Context.UPDATE_LOCK_SERVICE,
+ new UpdateLockService(context));
+ } catch (Throwable e) {
+ reportWtf("starting UpdateLockService", e);
+ }
+ traceEnd();
traceBeginAndSlog("StartNotificationManager");
mSystemServiceManager.startService(NotificationManagerService.class);
@@ -1185,27 +1176,25 @@
mSystemServiceManager.startService(DeviceStorageMonitorService.class);
traceEnd();
- if (!disableLocation) {
- traceBeginAndSlog("StartLocationManagerService");
- try {
- location = new LocationManagerService(context);
- ServiceManager.addService(Context.LOCATION_SERVICE, location);
- } catch (Throwable e) {
- reportWtf("starting Location Manager", e);
- }
- traceEnd();
-
- traceBeginAndSlog("StartCountryDetectorService");
- try {
- countryDetector = new CountryDetectorService(context);
- ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
- } catch (Throwable e) {
- reportWtf("starting Country Detector", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartLocationManagerService");
+ try {
+ location = new LocationManagerService(context);
+ ServiceManager.addService(Context.LOCATION_SERVICE, location);
+ } catch (Throwable e) {
+ reportWtf("starting Location Manager", e);
}
+ traceEnd();
- if (!disableNonCoreServices && !disableSearchManager) {
+ traceBeginAndSlog("StartCountryDetectorService");
+ try {
+ countryDetector = new CountryDetectorService(context);
+ ServiceManager.addService(Context.COUNTRY_DETECTOR, countryDetector);
+ } catch (Throwable e) {
+ reportWtf("starting Country Detector", e);
+ }
+ traceEnd();
+
+ if (!disableSearchManager) {
traceBeginAndSlog("StartSearchManagerService");
try {
mSystemServiceManager.startService(SEARCH_MANAGER_SERVICE_CLASS);
@@ -1215,8 +1204,7 @@
traceEnd();
}
- if (!disableNonCoreServices && context.getResources().getBoolean(
- R.bool.config_enableWallpaperService)) {
+ if (context.getResources().getBoolean(R.bool.config_enableWallpaperService)) {
traceBeginAndSlog("StartWallpaperManagerService");
mSystemServiceManager.startService(WALLPAPER_SERVICE_CLASS);
traceEnd();
@@ -1232,16 +1220,14 @@
traceEnd();
}
- if (!disableNonCoreServices) {
- traceBeginAndSlog("StartDockObserver");
- mSystemServiceManager.startService(DockObserver.class);
- traceEnd();
+ traceBeginAndSlog("StartDockObserver");
+ mSystemServiceManager.startService(DockObserver.class);
+ traceEnd();
- if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
- traceBeginAndSlog("StartThermalObserver");
- mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
- traceEnd();
- }
+ if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ traceBeginAndSlog("StartThermalObserver");
+ mSystemServiceManager.startService(THERMAL_OBSERVER_CLASS);
+ traceEnd();
}
traceBeginAndSlog("StartWiredAccessoryManager");
@@ -1254,46 +1240,44 @@
}
traceEnd();
- if (!disableNonCoreServices) {
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
- // Start MIDI Manager service
- traceBeginAndSlog("StartMidiManager");
- mSystemServiceManager.startService(MIDI_SERVICE_CLASS);
- traceEnd();
- }
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_MIDI)) {
+ // Start MIDI Manager service
+ traceBeginAndSlog("StartMidiManager");
+ mSystemServiceManager.startService(MIDI_SERVICE_CLASS);
+ traceEnd();
+ }
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
- || mPackageManager.hasSystemFeature(
- PackageManager.FEATURE_USB_ACCESSORY)) {
- // Manage USB host and device support
- traceBeginAndSlog("StartUsbService");
- mSystemServiceManager.startService(USB_SERVICE_CLASS);
- traceEnd();
- }
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)
+ || mPackageManager.hasSystemFeature(
+ PackageManager.FEATURE_USB_ACCESSORY)) {
+ // Manage USB host and device support
+ traceBeginAndSlog("StartUsbService");
+ mSystemServiceManager.startService(USB_SERVICE_CLASS);
+ traceEnd();
+ }
- if (!disableSerial) {
- traceBeginAndSlog("StartSerialService");
- try {
- // Serial port support
- serial = new SerialService(context);
- ServiceManager.addService(Context.SERIAL_SERVICE, serial);
- } catch (Throwable e) {
- Slog.e(TAG, "Failure starting SerialService", e);
- }
- traceEnd();
- }
-
- traceBeginAndSlog("StartHardwarePropertiesManagerService");
+ if (!disableSerial) {
+ traceBeginAndSlog("StartSerialService");
try {
- hardwarePropertiesService = new HardwarePropertiesManagerService(context);
- ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
- hardwarePropertiesService);
+ // Serial port support
+ serial = new SerialService(context);
+ ServiceManager.addService(Context.SERIAL_SERVICE, serial);
} catch (Throwable e) {
- Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
+ Slog.e(TAG, "Failure starting SerialService", e);
}
traceEnd();
}
+ traceBeginAndSlog("StartHardwarePropertiesManagerService");
+ try {
+ hardwarePropertiesService = new HardwarePropertiesManagerService(context);
+ ServiceManager.addService(Context.HARDWARE_PROPERTIES_SERVICE,
+ hardwarePropertiesService);
+ } catch (Throwable e) {
+ Slog.e(TAG, "Failure starting HardwarePropertiesManagerService", e);
+ }
+ traceEnd();
+
traceBeginAndSlog("StartTwilightService");
mSystemServiceManager.startService(TwilightService.class);
traceEnd();
@@ -1312,48 +1296,46 @@
mSystemServiceManager.startService(SoundTriggerService.class);
traceEnd();
- if (!disableNonCoreServices) {
- if (!disableTrustManager) {
- traceBeginAndSlog("StartTrustManager");
- mSystemServiceManager.startService(TrustManagerService.class);
- traceEnd();
- }
-
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
- traceBeginAndSlog("StartBackupManager");
- mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
- traceEnd();
- }
-
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
- || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
- traceBeginAndSlog("StartAppWidgerService");
- mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
- traceEnd();
- }
-
- // We need to always start this service, regardless of whether the
- // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
- // of initializing various settings. It will internally modify its behavior
- // based on that feature.
- traceBeginAndSlog("StartVoiceRecognitionManager");
- mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
- traceEnd();
-
- if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
- traceBeginAndSlog("StartGestureLauncher");
- mSystemServiceManager.startService(GestureLauncherService.class);
- traceEnd();
- }
- traceBeginAndSlog("StartSensorNotification");
- mSystemServiceManager.startService(SensorNotificationService.class);
- traceEnd();
-
- traceBeginAndSlog("StartContextHubSystemService");
- mSystemServiceManager.startService(ContextHubSystemService.class);
+ if (!disableTrustManager) {
+ traceBeginAndSlog("StartTrustManager");
+ mSystemServiceManager.startService(TrustManagerService.class);
traceEnd();
}
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_BACKUP)) {
+ traceBeginAndSlog("StartBackupManager");
+ mSystemServiceManager.startService(BACKUP_MANAGER_SERVICE_CLASS);
+ traceEnd();
+ }
+
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_APP_WIDGETS)
+ || context.getResources().getBoolean(R.bool.config_enableAppWidgetService)) {
+ traceBeginAndSlog("StartAppWidgerService");
+ mSystemServiceManager.startService(APPWIDGET_SERVICE_CLASS);
+ traceEnd();
+ }
+
+ // We need to always start this service, regardless of whether the
+ // FEATURE_VOICE_RECOGNIZERS feature is set, because it needs to take care
+ // of initializing various settings. It will internally modify its behavior
+ // based on that feature.
+ traceBeginAndSlog("StartVoiceRecognitionManager");
+ mSystemServiceManager.startService(VOICE_RECOGNITION_MANAGER_SERVICE_CLASS);
+ traceEnd();
+
+ if (GestureLauncherService.isGestureLauncherEnabled(context.getResources())) {
+ traceBeginAndSlog("StartGestureLauncher");
+ mSystemServiceManager.startService(GestureLauncherService.class);
+ traceEnd();
+ }
+ traceBeginAndSlog("StartSensorNotification");
+ mSystemServiceManager.startService(SensorNotificationService.class);
+ traceEnd();
+
+ traceBeginAndSlog("StartContextHubSystemService");
+ mSystemServiceManager.startService(ContextHubSystemService.class);
+ traceEnd();
+
traceBeginAndSlog("StartDiskStatsService");
try {
ServiceManager.addService("diskstats", new DiskStatsService(context));
@@ -1375,16 +1357,14 @@
traceEnd();
}
- if (!disableNetwork && !disableNetworkTime) {
- traceBeginAndSlog("StartNetworkTimeUpdateService");
- try {
- networkTimeUpdater = new NetworkTimeUpdateService(context);
- ServiceManager.addService("network_time_update_service", networkTimeUpdater);
- } catch (Throwable e) {
- reportWtf("starting NetworkTimeUpdate service", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartNetworkTimeUpdateService");
+ try {
+ networkTimeUpdater = new NetworkTimeUpdateService(context);
+ ServiceManager.addService("network_time_update_service", networkTimeUpdater);
+ } catch (Throwable e) {
+ reportWtf("starting NetworkTimeUpdate service", e);
}
+ traceEnd();
traceBeginAndSlog("StartCommonTimeManagementService");
try {
@@ -1395,38 +1375,32 @@
}
traceEnd();
- if (!disableNetwork) {
- traceBeginAndSlog("CertBlacklister");
- try {
- CertBlacklister blacklister = new CertBlacklister(context);
- } catch (Throwable e) {
- reportWtf("starting CertBlacklister", e);
- }
- traceEnd();
+ traceBeginAndSlog("CertBlacklister");
+ try {
+ CertBlacklister blacklister = new CertBlacklister(context);
+ } catch (Throwable e) {
+ reportWtf("starting CertBlacklister", e);
}
+ traceEnd();
- if (!disableNetwork && !disableNonCoreServices && EmergencyAffordanceManager.ENABLED) {
+ if (EmergencyAffordanceManager.ENABLED) {
// EmergencyMode service
traceBeginAndSlog("StartEmergencyAffordanceService");
mSystemServiceManager.startService(EmergencyAffordanceService.class);
traceEnd();
}
- if (!disableNonCoreServices) {
- // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
- traceBeginAndSlog("StartDreamManager");
- mSystemServiceManager.startService(DreamManagerService.class);
- traceEnd();
- }
+ // Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
+ traceBeginAndSlog("StartDreamManager");
+ mSystemServiceManager.startService(DreamManagerService.class);
+ traceEnd();
- if (!disableNonCoreServices) {
- traceBeginAndSlog("AddGraphicsStatsService");
- ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
- new GraphicsStatsService(context));
- traceEnd();
- }
+ traceBeginAndSlog("AddGraphicsStatsService");
+ ServiceManager.addService(GraphicsStatsService.GRAPHICS_STATS_SERVICE,
+ new GraphicsStatsService(context));
+ traceEnd();
- if (!disableNonCoreServices && CoverageService.ENABLED) {
+ if (CoverageService.ENABLED) {
traceBeginAndSlog("AddCoverageService");
ServiceManager.addService(CoverageService.COVERAGE_SERVICE, new CoverageService());
traceEnd();
@@ -1477,38 +1451,37 @@
traceEnd();
}
- if (!disableNonCoreServices) {
- traceBeginAndSlog("StartMediaRouterService");
- try {
- mediaRouter = new MediaRouterService(context);
- ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
- } catch (Throwable e) {
- reportWtf("starting MediaRouterService", e);
- }
- traceEnd();
+ traceBeginAndSlog("StartMediaRouterService");
+ try {
+ mediaRouter = new MediaRouterService(context);
+ ServiceManager.addService(Context.MEDIA_ROUTER_SERVICE, mediaRouter);
+ } catch (Throwable e) {
+ reportWtf("starting MediaRouterService", e);
+ }
+ traceEnd();
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
- traceBeginAndSlog("StartFingerprintSensor");
- mSystemServiceManager.startService(FingerprintService.class);
- traceEnd();
- }
-
- traceBeginAndSlog("StartBackgroundDexOptService");
- try {
- BackgroundDexOptService.schedule(context);
- } catch (Throwable e) {
- reportWtf("starting StartBackgroundDexOptService", e);
- }
- traceEnd();
-
- traceBeginAndSlog("StartPruneInstantAppsJobService");
- try {
- PruneInstantAppsJobService.schedule(context);
- } catch (Throwable e) {
- reportWtf("StartPruneInstantAppsJobService", e);
- }
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
+ traceBeginAndSlog("StartFingerprintSensor");
+ mSystemServiceManager.startService(FingerprintService.class);
traceEnd();
}
+
+ traceBeginAndSlog("StartBackgroundDexOptService");
+ try {
+ BackgroundDexOptService.schedule(context);
+ } catch (Throwable e) {
+ reportWtf("starting StartBackgroundDexOptService", e);
+ }
+ traceEnd();
+
+ traceBeginAndSlog("StartPruneInstantAppsJobService");
+ try {
+ PruneInstantAppsJobService.schedule(context);
+ } catch (Throwable e) {
+ reportWtf("StartPruneInstantAppsJobService", e);
+ }
+ traceEnd();
+
// LauncherAppsService uses ShortcutService.
traceBeginAndSlog("StartShortcutServiceLifecycle");
mSystemServiceManager.startService(ShortcutService.Lifecycle.class);
@@ -1519,7 +1492,7 @@
traceEnd();
}
- if (!disableNonCoreServices && !disableMediaProjection) {
+ if (!disableMediaProjection) {
traceBeginAndSlog("StartMediaProjectionManager");
mSystemServiceManager.startService(MediaProjectionManagerService.class);
traceEnd();
@@ -1530,17 +1503,15 @@
mSystemServiceManager.startService(WEAR_CONNECTIVITY_SERVICE_CLASS);
traceEnd();
- if (!disableNonCoreServices) {
- traceBeginAndSlog("StartWearTimeService");
- mSystemServiceManager.startService(WEAR_DISPLAY_SERVICE_CLASS);
- mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
- traceEnd();
+ traceBeginAndSlog("StartWearTimeService");
+ mSystemServiceManager.startService(WEAR_DISPLAY_SERVICE_CLASS);
+ mSystemServiceManager.startService(WEAR_TIME_SERVICE_CLASS);
+ traceEnd();
- if (enableLeftyService) {
- traceBeginAndSlog("StartWearLeftyService");
- mSystemServiceManager.startService(WEAR_LEFTY_SERVICE_CLASS);
- traceEnd();
- }
+ if (enableLeftyService) {
+ traceBeginAndSlog("StartWearLeftyService");
+ mSystemServiceManager.startService(WEAR_LEFTY_SERVICE_CLASS);
+ traceEnd();
}
}
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 2359fab..70983c8 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -310,12 +310,12 @@
return this;
}
- public Builder withIPv6AddrGenModeEUI64() {
+ public Builder withRandomMacAddress() {
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_EUI64;
return this;
}
- public Builder withIPv6AddrGenModeStablePrivacy() {
+ public Builder withStableMacAddress() {
mConfig.mIPv6AddrGenMode = INetd.IPV6_ADDR_GEN_MODE_STABLE_PRIVACY;
return this;
}
@@ -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/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b12cb32..3898145 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -88,16 +88,6 @@
return this;
}
@Override
- public Builder withIPv6AddrGenModeEUI64() {
- super.withIPv6AddrGenModeEUI64();
- return this;
- }
- @Override
- public Builder withIPv6AddrGenModeStablePrivacy() {
- super.withIPv6AddrGenModeStablePrivacy();
- return this;
- }
- @Override
public Builder withNetwork(Network network) {
super.withNetwork(network);
return this;
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 2452b44..70e8a16 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -20,6 +20,7 @@
import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static junit.framework.Assert.assertEquals;
@@ -187,6 +188,7 @@
final LightsManager mockLightsManager = mock(LightsManager.class);
when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL);
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false);
// write to a test file; the system file isn't readable from tests
mFile = new File(mContext.getCacheDir(), "test.xml");
@@ -1472,9 +1474,9 @@
mBinderService.setNotificationListenerAccessGranted(c, true);
verify(mListeners, never()).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, never()).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -1485,11 +1487,10 @@
ComponentName c = ComponentName.unflattenFromString("package/Component");
mBinderService.setNotificationAssistantAccessGranted(c, true);
-
verify(mListeners, never()).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, never()).setPackageOrComponentEnabled(
- c.flattenToString(), 0, false, true);
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@@ -1501,14 +1502,77 @@
mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
verify(mListeners, never()).setPackageOrComponentEnabled(
- c.flattenToString(), 0, true, true);
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
verify(mConditionProviders, never()).setPackageOrComponentEnabled(
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
+ verify(mAssistants, never()).setPackageOrComponentEnabled(
+ any(), anyInt(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
+ public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
+ when(mActivityManager.isLowRamDevice()).thenReturn(true);
+ ComponentName c = ComponentName.unflattenFromString("package/Component");
+ try {
+ mBinderService.setNotificationListenerAccessGranted(c, true);
+ } catch (SecurityException e) {
+ if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
+ throw e;
+ }
+ }
+
+ verify(mListeners, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 0, true, true);
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
c.flattenToString(), 0, false, true);
verify(mAssistants, never()).setPackageOrComponentEnabled(
any(), anyInt(), anyBoolean(), anyBoolean());
}
@Test
+ public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
+ when(mActivityManager.isLowRamDevice()).thenReturn(true);
+ ComponentName c = ComponentName.unflattenFromString("package/Component");
+ try {
+ mBinderService.setNotificationAssistantAccessGranted(c, true);
+ } catch (SecurityException e) {
+ if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
+ throw e;
+ }
+ }
+
+ verify(mListeners, never()).setPackageOrComponentEnabled(
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 0, false, true);
+ verify(mAssistants, times(1)).setPackageOrComponentEnabled(
+ c.flattenToString(), 0, true, true);
+ }
+
+ @Test
+ public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception {
+ when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true);
+ when(mActivityManager.isLowRamDevice()).thenReturn(true);
+ ComponentName c = ComponentName.unflattenFromString("package/Component");
+ try {
+ mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true);
+ } catch (SecurityException e) {
+ if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
+ throw e;
+ }
+ }
+
+ verify(mListeners, never()).setPackageOrComponentEnabled(
+ anyString(), anyInt(), anyBoolean(), anyBoolean());
+ verify(mConditionProviders, times(1)).setPackageOrComponentEnabled(
+ c.getPackageName(), 0, true, true);
+ verify(mAssistants, never()).setPackageOrComponentEnabled(
+ any(), anyInt(), anyBoolean(), anyBoolean());
+ }
+
+ @Test
public void testOnlyAutogroupIfGroupChanged_noPriorNoti_autogroups() throws Exception {
NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
mService.addEnqueuedNotification(r);
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 4729d06..f1e76ab 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -55,6 +55,8 @@
<uses-permission android:name="android.permission.DEVICE_POWER" />
<uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
+ <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
<!-- Uses API introduced in O (26) -->
<uses-sdk android:minSdkVersion="1"
@@ -132,6 +134,8 @@
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity2" />
<activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
+ <activity android:name="com.android.server.wm.ScreenDecorWindowTests$TestActivity" />
+
<activity android:name="com.android.server.pm.ShortcutTestActivity"
android:enabled="true" android:exported="true" />
diff --git a/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
new file mode 100644
index 0000000..bb97e94
--- /dev/null
+++ b/services/tests/servicestests/assets/NetworkWatchlistTest/watchlist_settings_test1.xml
@@ -0,0 +1,27 @@
+<?xml version='1.0'?>
+<watchlist-settings>
+ <sha256-domain>
+ <!-- test-cc-domain.com -->
+ <hash>8E7DCD2AEB4F364358242BB3F403263E61E3B4AECE4E2500FF28BF32E52FF0F1</hash>
+ <!-- test-cc-match-sha256-only.com -->
+ <hash>F0905DA7549614957B449034C281EF7BDEFDBC2B6E050AD1E78D6DE18FBD0D5F</hash>
+ </sha256-domain>
+ <sha256-ip>
+ <!-- 127.0.0.2 -->
+ <hash>1EDD62868F2767A1FFF68DF0A4CB3C23448E45100715768DB9310B5E719536A1</hash>
+ <!-- 127.0.0.3, match in sha256 only -->
+ <hash>18DD41C9F2E8E4879A1575FB780514EF33CF6E1F66578C4AE7CCA31F49B9F2ED</hash>
+ </sha256-ip>
+ <crc32-domain>
+ <!-- test-cc-domain.com -->
+ <hash>6C67059D</hash>
+ <!-- test-cc-match-crc32-only.com -->
+ <hash>3DC775F8</hash>
+ </crc32-domain>
+ <crc32-ip>
+ <!-- 127.0.0.2 -->
+ <hash>4EBEB612</hash>
+ <!-- 127.0.0.4, match in crc32 only -->
+ <hash>A7DD1327</hash>
+ </crc32-ip>
+</watchlist-settings>
diff --git a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
index daaad7a8..106f9e8 100644
--- a/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/BatteryServiceTest.java
@@ -36,12 +36,14 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
public class BatteryServiceTest extends AndroidTestCase {
@Mock IServiceManager mMockedManager;
@Mock IHealth mMockedHal;
+ @Mock IHealth mMockedHal2;
@Mock BatteryService.HealthServiceWrapper.Callback mCallback;
@Mock BatteryService.HealthServiceWrapper.IServiceManagerSupplier mManagerSupplier;
@@ -56,6 +58,12 @@
MockitoAnnotations.initMocks(this);
}
+ @Override
+ public void tearDown() {
+ if (mWrapper != null)
+ mWrapper.getHandlerThread().quitSafely();
+ }
+
public static <T> ArgumentMatcher<T> isOneOf(Collection<T> collection) {
return new ArgumentMatcher<T>() {
@Override public boolean matches(T e) {
@@ -70,42 +78,64 @@
private void initForInstances(String... instanceNamesArr) throws Exception {
final Collection<String> instanceNames = Arrays.asList(instanceNamesArr);
doAnswer((invocation) -> {
- Slog.e("BatteryServiceTest", "health: onRegistration " + invocation.getArguments()[2]);
- ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
- IHealth.kInterfaceName,
- (String)invocation.getArguments()[1],
- true /* preexisting */);
+ // technically, preexisting is ignored by
+ // BatteryService.HealthServiceWrapper.Notification, but still call it correctly.
+ sendNotification(invocation, true);
+ sendNotification(invocation, true);
+ sendNotification(invocation, false);
return null;
}).when(mMockedManager).registerForNotifications(
eq(IHealth.kInterfaceName),
argThat(isOneOf(instanceNames)),
any(IServiceNotification.class));
- doReturn(mMockedHal).when(mMockedManager)
- .get(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
-
- doReturn(IServiceManager.Transport.HWBINDER).when(mMockedManager)
- .getTransport(eq(IHealth.kInterfaceName), argThat(isOneOf(instanceNames)));
-
doReturn(mMockedManager).when(mManagerSupplier).get();
- doReturn(mMockedHal).when(mHealthServiceSupplier)
- .get(argThat(isOneOf(instanceNames)));
+ doReturn(mMockedHal) // init calls this
+ .doReturn(mMockedHal) // notification 1
+ .doReturn(mMockedHal) // notification 2
+ .doReturn(mMockedHal2) // notification 3
+ .doThrow(new RuntimeException("Should not call getService for more than 4 times"))
+ .when(mHealthServiceSupplier).get(argThat(isOneOf(instanceNames)));
mWrapper = new BatteryService.HealthServiceWrapper();
}
+ private void waitHandlerThreadFinish() throws Exception {
+ for (int i = 0; i < 5; i++) {
+ if (!mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks()) {
+ return;
+ }
+ Thread.sleep(300);
+ }
+ assertFalse(mWrapper.getHandlerThread().getThreadHandler().hasMessagesOrCallbacks());
+ }
+
+ private static void sendNotification(InvocationOnMock invocation, boolean preexisting)
+ throws Exception {
+ ((IServiceNotification)invocation.getArguments()[2]).onRegistration(
+ IHealth.kInterfaceName,
+ (String)invocation.getArguments()[1],
+ preexisting);
+ }
+
@SmallTest
public void testWrapPreferVendor() throws Exception {
initForInstances(VENDOR, HEALTHD);
mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- verify(mCallback).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+ waitHandlerThreadFinish();
+ verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(VENDOR));
+ verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
+ verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(VENDOR));
}
@SmallTest
public void testUseHealthd() throws Exception {
initForInstances(HEALTHD);
mWrapper.init(mCallback, mManagerSupplier, mHealthServiceSupplier);
- verify(mCallback).onRegistration(same(null), same(mMockedHal), eq(HEALTHD));
+ waitHandlerThreadFinish();
+ verify(mCallback, times(1)).onRegistration(same(null), same(mMockedHal), eq(HEALTHD));
+ verify(mCallback, never()).onRegistration(same(mMockedHal), same(mMockedHal), anyString());
+ verify(mCallback, times(1)).onRegistration(same(mMockedHal), same(mMockedHal2), eq(HEALTHD));
}
@SmallTest
diff --git a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
index bec46db..ce88d84 100644
--- a/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AssistDataRequesterTest.java
@@ -22,6 +22,7 @@
import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
import static android.graphics.Bitmap.Config.ARGB_8888;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -74,6 +75,8 @@
private static final boolean CALLER_ASSIST_SCREENSHOT_ALLOWED = true;
private static final boolean FETCH_DATA = true;
private static final boolean FETCH_SCREENSHOTS = true;
+ private static final boolean ALLOW_FETCH_DATA = true;
+ private static final boolean ALLOW_FETCH_SCREENSHOTS = true;
private static final int TEST_UID = 0;
private static final String TEST_PACKAGE = "";
@@ -128,8 +131,7 @@
mHandler.post(() -> {
try {
mGate.await(10, TimeUnit.SECONDS);
- mDataRequester.onHandleAssistScreenshot(Bitmap.createBitmap(1, 1,
- ARGB_8888));
+ mDataRequester.onHandleAssistScreenshot(Bitmap.createBitmap(1, 1, ARGB_8888));
} catch (InterruptedException e) {
Log.e(TAG, "Failed to wait", e);
}
@@ -153,7 +155,7 @@
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertReceivedDataCount(5, 5, 1, 1);
}
@@ -163,18 +165,18 @@
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(0), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertReceivedDataCount(0, 0, 0, 0);
}
@Test
- public void testCurrentAppDisallow_expectNoCallbacks() throws Exception {
+ public void testCurrentAppDisallow_expectNullCallbacks() throws Exception {
setupMocks(!CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
- assertReceivedDataCount(0, 0, 0, 0);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ assertReceivedDataCount(0, 1, 0, 1);
}
@Test
@@ -184,7 +186,7 @@
mCallbacks.canHandleReceivedData = false;
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertTrue(mDataRequester.getPendingDataCount() == 5);
assertTrue(mDataRequester.getPendingScreenshotCount() == 1);
mGate.countDown();
@@ -195,21 +197,32 @@
assertTrue(mDataRequester.getPendingScreenshotCount() == 0);
assertTrue(mCallbacks.receivedData.isEmpty());
assertTrue(mCallbacks.receivedScreenshots.isEmpty());
+ assertFalse(mCallbacks.requestCompleted);
mCallbacks.canHandleReceivedData = true;
mDataRequester.processPendingAssistData();
+ // Since we are posting the callback for the request-complete, flush the handler as well
+ mGate.countDown();
+ waitForIdle(mHandler);
assertTrue(mCallbacks.receivedData.size() == 5);
assertTrue(mCallbacks.receivedScreenshots.size() == 1);
+ assertTrue(mCallbacks.requestCompleted);
+
+ // Clear the state and ensure that we only process pending data once
+ mCallbacks.reset();
+ mDataRequester.processPendingAssistData();
+ assertTrue(mCallbacks.receivedData.isEmpty());
+ assertTrue(mCallbacks.receivedScreenshots.isEmpty());
}
@Test
- public void testNoFetchData_expectNoCallbacks() throws Exception {
+ public void testNoFetchData_expectNoDataCallbacks() throws Exception {
setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), !FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
- assertReceivedDataCount(0, 0, 0, 0);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ assertReceivedDataCount(0, 0, 0, 1);
}
@Test
@@ -218,9 +231,9 @@
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
// Expect a single null data when the appops is denied
- assertReceivedDataCount(0, 1, 0, 0);
+ assertReceivedDataCount(0, 1, 0, 1);
}
@Test
@@ -231,9 +244,9 @@
anyBoolean(), anyBoolean());
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
// Expect a single null data when requestAssistContextExtras() fails
- assertReceivedDataCount(0, 1, 0, 0);
+ assertReceivedDataCount(0, 1, 0, 1);
}
@Test
@@ -242,7 +255,7 @@
CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, !FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
assertReceivedDataCount(5, 5, 0, 0);
}
@@ -252,11 +265,35 @@
!CALLER_ASSIST_SCREENSHOT_ALLOWED);
mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
- TEST_UID, TEST_PACKAGE);
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
// Expect a single null screenshot when the appops is denied
assertReceivedDataCount(5, 5, 0, 1);
}
+ @Test
+ public void testCanNotHandleReceivedData_expectNoCallbacks() throws Exception {
+ setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, !CALLER_ASSIST_STRUCTURE_ALLOWED,
+ !CALLER_ASSIST_SCREENSHOT_ALLOWED);
+
+ mCallbacks.canHandleReceivedData = false;
+ mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
+ ALLOW_FETCH_DATA, ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ mGate.countDown();
+ waitForIdle(mHandler);
+ assertTrue(mCallbacks.receivedData.isEmpty());
+ assertTrue(mCallbacks.receivedScreenshots.isEmpty());
+ }
+
+ @Test
+ public void testRequestDataNoneAllowed_expectNullCallbacks() throws Exception {
+ setupMocks(CURRENT_ACTIVITY_ASSIST_ALLOWED, CALLER_ASSIST_STRUCTURE_ALLOWED,
+ CALLER_ASSIST_SCREENSHOT_ALLOWED);
+
+ mDataRequester.requestAssistData(createActivityList(5), FETCH_DATA, FETCH_SCREENSHOTS,
+ !ALLOW_FETCH_DATA, !ALLOW_FETCH_SCREENSHOTS, TEST_UID, TEST_PACKAGE);
+ assertReceivedDataCount(0, 1, 0, 1);
+ }
+
private void assertReceivedDataCount(int numPendingData, int numReceivedData,
int numPendingScreenshots, int numReceivedScreenshots) throws Exception {
assertTrue("Expected " + numPendingData + " pending data, got "
@@ -265,6 +302,7 @@
assertTrue("Expected " + numPendingScreenshots + " pending screenshots, got "
+ mDataRequester.getPendingScreenshotCount(),
mDataRequester.getPendingScreenshotCount() == numPendingScreenshots);
+ assertFalse("Expected request NOT completed", mCallbacks.requestCompleted);
mGate.countDown();
waitForIdle(mHandler);
assertTrue("Expected " + numReceivedData + " data, received "
@@ -273,6 +311,7 @@
assertTrue("Expected " + numReceivedScreenshots + " screenshots, received "
+ mCallbacks.receivedScreenshots.size(),
mCallbacks.receivedScreenshots.size() == numReceivedScreenshots);
+ assertTrue("Expected request completed", mCallbacks.requestCompleted);
}
private List<IBinder> createActivityList(int size) {
@@ -292,12 +331,19 @@
latch.await(2, TimeUnit.SECONDS);
}
- private static class Callbacks implements AssistDataRequesterCallbacks {
+ private class Callbacks implements AssistDataRequesterCallbacks {
boolean canHandleReceivedData = true;
+ boolean requestCompleted = false;
ArrayList<Bundle> receivedData = new ArrayList<>();
ArrayList<Bitmap> receivedScreenshots = new ArrayList<>();
+ void reset() {
+ canHandleReceivedData = true;
+ receivedData.clear();
+ receivedScreenshots.clear();
+ }
+
@Override
public boolean canHandleReceivedAssistDataLocked() {
return canHandleReceivedData;
@@ -312,5 +358,17 @@
public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
receivedScreenshots.add(screenshot);
}
+
+ @Override
+ public void onAssistRequestCompleted() {
+ mHandler.post(() -> {
+ try {
+ mGate.await(10, TimeUnit.SECONDS);
+ requestCompleted = true;
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Failed to wait", e);
+ }
+ });
+ }
}
}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 9d23fe9..6de3395 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -3193,7 +3193,7 @@
// setUp() adds a secondary user for CALLER_USER_HANDLE. Remove it as otherwise the
// feature is disabled because there are non-affiliated secondary users.
getServices().removeUser(DpmMockContext.CALLER_USER_HANDLE);
- when(getServices().iipConnectivityMetrics.registerNetdEventCallback(anyObject()))
+ when(getServices().iipConnectivityMetrics.addNetdEventCallback(anyInt(), anyObject()))
.thenReturn(true);
// No logs were retrieved so far.
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java
new file mode 100644
index 0000000..a34f95e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/HarmfulDigestsTests.java
@@ -0,0 +1,63 @@
+/*
+ * 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.server.net.watchlist;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.HarmfulDigestsTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class HarmfulDigestsTests {
+
+ private static final byte[] TEST_DIGEST_1 = HexDump.hexStringToByteArray("AAAAAA");
+ private static final byte[] TEST_DIGEST_2 = HexDump.hexStringToByteArray("BBBBBB");
+ private static final byte[] TEST_DIGEST_3 = HexDump.hexStringToByteArray("AAAABB");
+ private static final byte[] TEST_DIGEST_4 = HexDump.hexStringToByteArray("BBBBAA");
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testHarmfulDigests_setAndContains() throws Exception {
+ HarmfulDigests harmfulDigests = new HarmfulDigests(
+ Arrays.asList(new byte[][] {TEST_DIGEST_1}));
+ assertTrue(harmfulDigests.contains(TEST_DIGEST_1));
+ assertFalse(harmfulDigests.contains(TEST_DIGEST_2));
+ assertFalse(harmfulDigests.contains(TEST_DIGEST_3));
+ assertFalse(harmfulDigests.contains(TEST_DIGEST_4));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
new file mode 100644
index 0000000..ccd3cdd
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/NetworkWatchlistServiceTests.java
@@ -0,0 +1,217 @@
+/*
+ * 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.server.net.watchlist;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.IIpConnectivityMetrics;
+import android.net.INetdEventCallback;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Process;
+import android.os.RemoteException;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.server.ServiceThread;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.NetworkWatchlistServiceTests
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NetworkWatchlistServiceTests {
+
+ private static final long NETWOR_EVENT_TIMEOUT_SEC = 1;
+ private static final String TEST_HOST = "testhost.com";
+ private static final String TEST_IP = "7.6.8.9";
+ private static final String[] TEST_IPS =
+ new String[] {"1.2.3.4", "4.6.8.9", "2001:0db8:0001:0000:0000:0ab9:C0A8:0102"};
+
+ private static class TestHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case WatchlistLoggingHandler.LOG_WATCHLIST_EVENT_MSG:
+ onLogEvent();
+ break;
+ case WatchlistLoggingHandler.REPORT_RECORDS_IF_NECESSARY_MSG:
+ onAggregateEvent();
+ break;
+ default:
+ fail("Unexpected message: " + msg.what);
+ }
+ }
+
+ public void onLogEvent() {}
+ public void onAggregateEvent() {}
+ }
+
+ private static class TestIIpConnectivityMetrics implements IIpConnectivityMetrics {
+
+ int counter = 0;
+ INetdEventCallback callback = null;
+
+ @Override
+ public IBinder asBinder() {
+ return null;
+ }
+
+ @Override
+ public int logEvent(ConnectivityMetricsEvent connectivityMetricsEvent)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+ counter++;
+ this.callback = callback;
+ return true;
+ }
+
+ @Override
+ public boolean removeNetdEventCallback(int callerType) {
+ counter--;
+ return true;
+ }
+ };
+
+ ServiceThread mHandlerThread;
+ WatchlistLoggingHandler mWatchlistHandler;
+ NetworkWatchlistService mWatchlistService;
+
+ @Before
+ public void setUp() {
+ mHandlerThread = new ServiceThread("NetworkWatchlistServiceTests",
+ Process.THREAD_PRIORITY_BACKGROUND, /* allowIo */ false);
+ mHandlerThread.start();
+ mWatchlistHandler = new WatchlistLoggingHandler(InstrumentationRegistry.getContext(),
+ mHandlerThread.getLooper());
+ mWatchlistService = new NetworkWatchlistService(InstrumentationRegistry.getContext(),
+ mHandlerThread, mWatchlistHandler, null);
+ }
+
+ @After
+ public void tearDown() {
+ mHandlerThread.quitSafely();
+ }
+
+ @Test
+ public void testStartStopWatchlistLogging() throws Exception {
+ TestIIpConnectivityMetrics connectivityMetrics = new TestIIpConnectivityMetrics() {
+ @Override
+ public boolean addNetdEventCallback(int callerType, INetdEventCallback callback) {
+ super.addNetdEventCallback(callerType, callback);
+ assertEquals(callerType, INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST);
+ return true;
+ }
+
+ @Override
+ public boolean removeNetdEventCallback(int callerType) {
+ super.removeNetdEventCallback(callerType);
+ assertEquals(callerType, INetdEventCallback.CALLBACK_CALLER_NETWORK_WATCHLIST);
+ return true;
+ }
+ };
+ assertEquals(connectivityMetrics.counter, 0);
+ mWatchlistService.mIpConnectivityMetrics = connectivityMetrics;
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 1);
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 1);
+ assertTrue(mWatchlistService.stopWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 0);
+ assertTrue(mWatchlistService.stopWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 0);
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 1);
+ assertTrue(mWatchlistService.stopWatchlistLoggingImpl());
+ assertEquals(connectivityMetrics.counter, 0);
+ }
+
+ @Test
+ public void testNetworkEvents() throws Exception {
+ TestIIpConnectivityMetrics connectivityMetrics = new TestIIpConnectivityMetrics();
+ mWatchlistService.mIpConnectivityMetrics = connectivityMetrics;
+ assertTrue(mWatchlistService.startWatchlistLoggingImpl());
+
+ // Test DNS events
+ final CountDownLatch testDnsLatch = new CountDownLatch(1);
+ final Object[] dnsParams = new Object[3];
+ final WatchlistLoggingHandler testDnsHandler =
+ new WatchlistLoggingHandler(InstrumentationRegistry.getContext(),
+ mHandlerThread.getLooper()) {
+ @Override
+ public void asyncNetworkEvent(String host, String[] ipAddresses, int uid) {
+ dnsParams[0] = host;
+ dnsParams[1] = ipAddresses;
+ dnsParams[2] = uid;
+ testDnsLatch.countDown();
+ }
+ };
+ mWatchlistService.mNetworkWatchlistHandler = testDnsHandler;
+ connectivityMetrics.callback.onDnsEvent(TEST_HOST, TEST_IPS, TEST_IPS.length, 123L, 456);
+ if (!testDnsLatch.await(NETWOR_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for network event");
+ }
+ assertEquals(TEST_HOST, dnsParams[0]);
+ for (int i = 0; i < TEST_IPS.length; i++) {
+ assertEquals(TEST_IPS[i], ((String[])dnsParams[1])[i]);
+ }
+ assertEquals(456, dnsParams[2]);
+
+ // Test connect events
+ final CountDownLatch testConnectLatch = new CountDownLatch(1);
+ final Object[] connectParams = new Object[3];
+ final WatchlistLoggingHandler testConnectHandler =
+ new WatchlistLoggingHandler(InstrumentationRegistry.getContext(),
+ mHandlerThread.getLooper()) {
+ @Override
+ public void asyncNetworkEvent(String host, String[] ipAddresses, int uid) {
+ connectParams[0] = host;
+ connectParams[1] = ipAddresses;
+ connectParams[2] = uid;
+ testConnectLatch.countDown();
+ }
+ };
+ mWatchlistService.mNetworkWatchlistHandler = testConnectHandler;
+ connectivityMetrics.callback.onConnectEvent(TEST_IP, 80, 123L, 456);
+ if (!testConnectLatch.await(NETWOR_EVENT_TIMEOUT_SEC, TimeUnit.SECONDS)) {
+ fail("Timed out waiting for network event");
+ }
+ assertNull(connectParams[0]);
+ assertEquals(1, ((String[]) connectParams[1]).length);
+ assertEquals(TEST_IP, ((String[]) connectParams[1])[0]);
+ assertEquals(456, connectParams[2]);
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
new file mode 100644
index 0000000..e356b13
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistLoggingHandlerTests.java
@@ -0,0 +1,61 @@
+/*
+ * 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.server.net.watchlist;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistLoggingHandlerTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WatchlistLoggingHandlerTests {
+
+ @Before
+ public void setUp() throws Exception {
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ }
+
+ @Test
+ public void testWatchlistLoggingHandler_getAllSubDomains() throws Exception {
+ String[] subDomains = WatchlistLoggingHandler.getAllSubDomains("abc.def.gh.i.jkl.mm");
+ assertTrue(Arrays.equals(subDomains, new String[] {"abc.def.gh.i.jkl.mm",
+ "def.gh.i.jkl.mm", "gh.i.jkl.mm", "i.jkl.mm", "jkl.mm", "mm"}));
+ subDomains = WatchlistLoggingHandler.getAllSubDomains(null);
+ assertNull(subDomains);
+ subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm");
+ assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm", "mm"}));
+ subDomains = WatchlistLoggingHandler.getAllSubDomains("abc");
+ assertTrue(Arrays.equals(subDomains, new String[] {"abc"}));
+ subDomains = WatchlistLoggingHandler.getAllSubDomains("jkl.mm.");
+ assertTrue(Arrays.equals(subDomains, new String[] {"jkl.mm.", "mm."}));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
new file mode 100644
index 0000000..f3cb980
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/net/watchlist/WatchlistSettingsTests.java
@@ -0,0 +1,195 @@
+/*
+ * 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.server.net.watchlist;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.HexDump;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+
+/**
+ * runtest frameworks-services -c com.android.server.net.watchlist.WatchlistSettingsTests
+ */
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class WatchlistSettingsTests {
+
+ private static final String TEST_XML_1 = "NetworkWatchlistTest/watchlist_settings_test1.xml";
+ private static final String TEST_CC_DOMAIN = "test-cc-domain.com";
+ private static final String TEST_CC_IP = "127.0.0.2";
+ private static final String TEST_NOT_EXIST_CC_DOMAIN = "test-not-exist-cc-domain.com";
+ private static final String TEST_NOT_EXIST_CC_IP = "1.2.3.4";
+ private static final String TEST_SHA256_ONLY_DOMAIN = "test-cc-match-sha256-only.com";
+ private static final String TEST_SHA256_ONLY_IP = "127.0.0.3";
+ private static final String TEST_CRC32_ONLY_DOMAIN = "test-cc-match-crc32-only.com";
+ private static final String TEST_CRC32_ONLY_IP = "127.0.0.4";
+
+ private static final String TEST_NEW_CC_DOMAIN = "test-new-cc-domain.com";
+ private static final byte[] TEST_NEW_CC_DOMAIN_SHA256 = HexDump.hexStringToByteArray(
+ "B86F9D37425340B635F43D6BC2506630761ADA71F5E6BBDBCA4651C479F9FB43");
+ private static final byte[] TEST_NEW_CC_DOMAIN_CRC32 = HexDump.hexStringToByteArray("76795BD3");
+
+ private static final String TEST_NEW_CC_IP = "1.1.1.2";
+ private static final byte[] TEST_NEW_CC_IP_SHA256 = HexDump.hexStringToByteArray(
+ "721BAB5E313CF0CC76B10F9592F18B9D1B8996497501A3306A55B3AE9F1CC87C");
+ private static final byte[] TEST_NEW_CC_IP_CRC32 = HexDump.hexStringToByteArray("940B8BEE");
+
+ private Context mContext;
+ private File mTestXmlFile;
+
+ @Before
+ public void setUp() throws Exception {
+ mContext = InstrumentationRegistry.getContext();
+ mTestXmlFile = new File(mContext.getFilesDir(), "test_watchlist_settings.xml");
+ mTestXmlFile.delete();
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mTestXmlFile.delete();
+ }
+
+ @Test
+ public void testWatchlistSettings_parsing() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ assertTrue(settings.containsDomain(TEST_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ }
+
+ @Test
+ public void testWatchlistSettings_writeSettingsToDisk() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ settings.writeSettingsToDisk(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
+ Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
+ Arrays.asList(TEST_NEW_CC_IP_SHA256));
+ // Ensure old watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_NEW_CC_IP));
+ // Reload settings from disk and test again
+ settings = new WatchlistSettings(mTestXmlFile);
+ // Ensure old watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_NEW_CC_IP));
+ }
+
+ @Test
+ public void testWatchlistSettings_writeSettingsToMemory() throws Exception {
+ copyWatchlistSettingsXml(mContext, TEST_XML_1, mTestXmlFile);
+ WatchlistSettings settings = new WatchlistSettings(mTestXmlFile);
+ settings.writeSettingsToMemory(Arrays.asList(TEST_NEW_CC_DOMAIN_CRC32),
+ Arrays.asList(TEST_NEW_CC_DOMAIN_SHA256), Arrays.asList(TEST_NEW_CC_IP_CRC32),
+ Arrays.asList(TEST_NEW_CC_IP_SHA256));
+ // Ensure old watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_NEW_CC_IP));
+ // Reload settings from disk and test again
+ settings = new WatchlistSettings(mTestXmlFile);
+ // Ensure old watchlist is in memory
+ assertTrue(settings.containsDomain(TEST_CC_DOMAIN));
+ assertTrue(settings.containsIp(TEST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_NOT_EXIST_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NOT_EXIST_CC_IP));
+ assertFalse(settings.containsDomain(TEST_SHA256_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_SHA256_ONLY_IP));
+ assertFalse(settings.containsDomain(TEST_CRC32_ONLY_DOMAIN));
+ assertFalse(settings.containsIp(TEST_CRC32_ONLY_IP));
+ // Ensure new watchlist is not in memory
+ assertFalse(settings.containsDomain(TEST_NEW_CC_DOMAIN));
+ assertFalse(settings.containsIp(TEST_NEW_CC_IP));;
+ }
+
+ private static void copyWatchlistSettingsXml(Context context, String xmlAsset, File outFile)
+ throws IOException {
+ writeToFile(outFile, readAsset(context, xmlAsset));
+
+ }
+
+ private static String readAsset(Context context, String assetPath) throws IOException {
+ final StringBuilder sb = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(
+ context.getResources().getAssets().open(assetPath)))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ sb.append(line);
+ sb.append(System.lineSeparator());
+ }
+ }
+ return sb.toString();
+ }
+
+ private static void writeToFile(File path, String content)
+ throws IOException {
+ path.getParentFile().mkdirs();
+
+ try (FileWriter writer = new FileWriter(path)) {
+ writer.write(content);
+ }
+ }
+}
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/power/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
index 69589e7..50ac41c 100644
--- a/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
@@ -15,13 +15,12 @@
*/
package com.android.server.power;
+import android.os.PowerManager.ServiceType;
import android.os.PowerSaveState;
import android.os.Handler;
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
-
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 4559660..b60d5bf 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -66,7 +66,7 @@
.setBrightnessFactor(BRIGHTNESS_FACTOR)
.build();
when(mBatterySaverPolicy.getBatterySaverPolicy(
- eq(BatterySaverPolicy.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
+ eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS), anyBoolean()))
.thenReturn(mPowerSaveState);
mDisplayPowerRequest = new DisplayPowerRequest();
mService = new PowerManagerService(getContext(), mBatterySaverPolicy);
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
index 67ffe58..39d256a 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppIdleHistoryTests.java
@@ -16,16 +16,14 @@
package com.android.server.usage;
-import static android.app.usage.AppStandby.REASON_TIMEOUT;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_ACTIVE;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_RARE;
-
import android.app.usage.AppStandby;
import android.os.FileUtils;
import android.test.AndroidTestCase;
import java.io.File;
+import static android.app.usage.AppStandby.*;
+
public class AppIdleHistoryTests extends AndroidTestCase {
File mStorageDir;
@@ -111,5 +109,9 @@
assertEquals(aih.getAppStandbyBucket(PACKAGE_1, USER_ID, 5000), STANDBY_BUCKET_RARE);
assertEquals(aih.getAppStandbyBucket(PACKAGE_2, USER_ID, 5000), STANDBY_BUCKET_ACTIVE);
assertEquals(aih.getAppStandbyReason(PACKAGE_1, USER_ID, 5000), REASON_TIMEOUT);
+
+ assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
+ assertFalse(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_RARE));
+ assertTrue(aih.shouldInformListeners(PACKAGE_1, USER_ID, 5000, STANDBY_BUCKET_FREQUENT));
}
}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index 9846d6f..8531baf5 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -16,11 +16,7 @@
package com.android.server.usage;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_ACTIVE;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_FREQUENT;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_RARE;
-import static android.app.usage.AppStandby.STANDBY_BUCKET_WORKING_SET;
-
+import static android.app.usage.AppStandby.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
@@ -251,10 +247,22 @@
false));
}
+ private void reportEvent(AppStandbyController controller, long elapsedTime) {
+ // Back to ACTIVE on event
+ UsageEvents.Event ev = new UsageEvents.Event();
+ ev.mPackage = PACKAGE_1;
+ ev.mEventType = UsageEvents.Event.USER_INTERACTION;
+ controller.reportEvent(ev, elapsedTime, USER_ID);
+ }
+
@Test
public void testBuckets() throws Exception {
AppStandbyController controller = setupController();
+ assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
+
+ reportEvent(controller, 0);
+
// ACTIVE bucket
assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE);
@@ -270,11 +278,7 @@
// RARE bucket
assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_RARE);
- // Back to ACTIVE on event
- UsageEvents.Event ev = new UsageEvents.Event();
- ev.mPackage = PACKAGE_1;
- ev.mEventType = UsageEvents.Event.USER_INTERACTION;
- controller.reportEvent(ev, mInjector.mElapsedRealtime, USER_ID);
+ reportEvent(controller, 9 * DAY_MS);
assertTimeout(controller, 9 * DAY_MS, STANDBY_BUCKET_ACTIVE);
@@ -287,6 +291,10 @@
AppStandbyController controller = setupController();
mInjector.setDisplayOn(false);
+ assertTimeout(controller, 0, STANDBY_BUCKET_NEVER);
+
+ reportEvent(controller, 0);
+
// ACTIVE bucket
assertTimeout(controller, 11 * HOUR_MS, STANDBY_BUCKET_ACTIVE);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 9ad7add..bb88264 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -46,11 +46,13 @@
* bit FrameworksServicesTests:com.android.server.wm.AppWindowTokenTests
*/
@SmallTest
-@Presubmit
+// TODO: b/68267650
+// @Presubmit
@RunWith(AndroidJUnit4.class)
public class AppWindowTokenTests extends WindowTestsBase {
@Test
+ @Presubmit
public void testAddWindow_Order() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -79,6 +81,7 @@
}
@Test
+ @Presubmit
public void testFindMainWindow() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -97,6 +100,7 @@
}
@Test
+ @Presubmit
public void testGetTopFullscreenWindow() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
@@ -187,13 +191,14 @@
}
@Test
+ @Presubmit
public void testGetOrientation() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
token.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
token.setFillsParent(false);
- // Can specify orientation if app doesn't fill parent. Allowed for SDK <= 25.
+ // Can specify orientation if app doesn't fill parent.
assertEquals(SCREEN_ORIENTATION_LANDSCAPE, token.getOrientation());
token.setFillsParent(true);
@@ -211,6 +216,7 @@
}
@Test
+ @Presubmit
public void testKeyguardFlagsDuringRelaunch() throws Exception {
final WindowTestUtils.TestAppWindowToken token =
new WindowTestUtils.TestAppWindowToken(mDisplayContent);
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/ScreenDecorWindowTests.java b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
new file mode 100644
index 0000000..9c80544
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/ScreenDecorWindowTests.java
@@ -0,0 +1,281 @@
+/*
+ * 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.server.wm;
+
+import static android.graphics.Color.BLUE;
+import static android.graphics.Color.RED;
+import static android.view.Gravity.BOTTOM;
+import static android.view.Gravity.LEFT;
+import static android.view.Gravity.RIGHT;
+import static android.view.Gravity.TOP;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
+import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_SCREEN_DECOR;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Point;
+import android.os.Handler;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+import android.view.WindowInsets;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+
+/**
+ * Tests for the {@link android.view.WindowManager.LayoutParams#PRIVATE_FLAG_IS_SCREEN_DECOR} flag.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.ScreenDecorWindowTests
+ */
+// TODO: Add test for FLAG_FULLSCREEN which hides the status bar and also other flags.
+// TODO: Test non-Activity windows.
+// TODO: Test secondary display.
+@SmallTest
+// TODO(b/68957554)
+//@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class ScreenDecorWindowTests {
+
+ private final Context mContext = InstrumentationRegistry.getTargetContext();
+ private final Instrumentation mInstrumentation = InstrumentationRegistry.getInstrumentation();
+
+ private WindowManager mWm;
+ private ArrayList<View> mWindows = new ArrayList<>();
+
+ @Rule
+ public ActivityTestRule<TestActivity> mTestActivityRule = new ActivityTestRule<>(
+ TestActivity.class, false /* initialTouchMode */, false /* launchActivity */);
+ private Activity mTestActivity;
+
+ private int mDecorThickness;
+ private int mHalfDecorThickness;
+
+ @Before
+ public void setUp() {
+ mWm = mContext.getSystemService(WindowManager.class);
+ final Point size = new Point();
+ mWm.getDefaultDisplay().getSize(size);
+ mDecorThickness = Math.min(size.x, size.y) / 3;
+ mHalfDecorThickness = mDecorThickness / 2;
+ mTestActivity = launchActivity(mTestActivityRule);
+ }
+
+ @After
+ public void tearDown() {
+ while (!mWindows.isEmpty()) {
+ removeWindow(mWindows.get(0));
+ }
+ finishActivity(mTestActivityRule);
+ }
+
+ @Test
+ public void testScreenSides() throws Exception {
+ // Decor on top
+ final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+
+ // Decor at the bottom
+ updateWindow(decorWindow, BOTTOM, MATCH_PARENT, mDecorThickness, 0, 0);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), mDecorThickness);
+
+ // Decor to the left
+ updateWindow(decorWindow, LEFT, mDecorThickness, MATCH_PARENT, 0, 0);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetLeft(), mDecorThickness);
+
+ // Decor to the right
+ updateWindow(decorWindow, RIGHT, mDecorThickness, MATCH_PARENT, 0, 0);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetRight(), mDecorThickness);
+ }
+
+ @Test
+ public void testMultipleDecors() throws Exception {
+ // Test 2 decor windows on-top.
+ createDecorWindow(TOP, MATCH_PARENT, mHalfDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mHalfDecorThickness);
+ createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+
+ // And one at the bottom.
+ createDecorWindow(BOTTOM, MATCH_PARENT, mHalfDecorThickness);
+ insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+ assertGreaterOrEqual(insets.getSystemWindowInsetBottom(), mHalfDecorThickness);
+ }
+
+ @Test
+ public void testFlagChange() throws Exception {
+ WindowInsets initialInsets = getInsets(mTestActivity);
+
+ final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertEquals(mDecorThickness, insets.getSystemWindowInsetTop());
+
+ updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
+ 0, PRIVATE_FLAG_IS_SCREEN_DECOR);
+ insets = getInsets(mTestActivity);
+ assertEquals(initialInsets.getSystemWindowInsetTop(), insets.getSystemWindowInsetTop());
+
+ updateWindow(decorWindow, TOP, MATCH_PARENT, mDecorThickness,
+ PRIVATE_FLAG_IS_SCREEN_DECOR, PRIVATE_FLAG_IS_SCREEN_DECOR);
+ insets = getInsets(mTestActivity);
+ assertEquals(mDecorThickness, insets.getSystemWindowInsetTop());
+ }
+
+ @Test
+ public void testRemoval() throws Exception {
+ WindowInsets initialInsets = getInsets(mTestActivity);
+
+ final View decorWindow = createDecorWindow(TOP, MATCH_PARENT, mDecorThickness);
+ WindowInsets insets = getInsets(mTestActivity);
+ assertGreaterOrEqual(insets.getSystemWindowInsetTop(), mDecorThickness);
+
+ removeWindow(decorWindow);
+ insets = getInsets(mTestActivity);
+ assertEquals(initialInsets.getSystemWindowInsetTop(), insets.getSystemWindowInsetTop());
+ }
+
+ private View createAppWindow() {
+ return createWindow("appWindow", TOP, MATCH_PARENT, MATCH_PARENT, BLUE,
+ FLAG_LAYOUT_IN_SCREEN | FLAG_LAYOUT_INSET_DECOR, 0);
+ }
+
+ private View createDecorWindow(int gravity, int width, int height) {
+ return createWindow("decorWindow", gravity, width, height, RED,
+ FLAG_LAYOUT_IN_SCREEN, PRIVATE_FLAG_IS_SCREEN_DECOR);
+ }
+
+ private View createWindow(String name, int gravity, int width, int height, int color, int flags,
+ int privateFlags) {
+
+ final View[] viewHolder = new View[1];
+ final int finalFlag = flags
+ | FLAG_NOT_FOCUSABLE | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_NOT_TOUCHABLE;
+
+ // Needs to run on the UI thread.
+ Handler.getMain().runWithScissors(() -> {
+ final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+ width, height, TYPE_APPLICATION_OVERLAY, finalFlag, PixelFormat.OPAQUE);
+ lp.gravity = gravity;
+ lp.privateFlags |= privateFlags;
+
+ final TextView view = new TextView(mContext);
+ view.setText("ScreenDecorWindowTests - " + name);
+ view.setBackgroundColor(color);
+ mWm.addView(view, lp);
+ mWindows.add(view);
+ viewHolder[0] = view;
+ }, 0);
+
+ waitForIdle();
+ return viewHolder[0];
+ }
+
+ private void updateWindow(View v, int gravity, int width, int height,
+ int privateFlags, int privateFlagsMask) {
+ // Needs to run on the UI thread.
+ Handler.getMain().runWithScissors(() -> {
+ final WindowManager.LayoutParams lp = (WindowManager.LayoutParams) v.getLayoutParams();
+ lp.gravity = gravity;
+ lp.width = width;
+ lp.height = height;
+ setPrivateFlags(lp, privateFlags, privateFlagsMask);
+
+ mWm.updateViewLayout(v, lp);
+ }, 0);
+
+ waitForIdle();
+ }
+
+ private void removeWindow(View v) {
+ Handler.getMain().runWithScissors(() -> mWm.removeView(v), 0);
+ mWindows.remove(v);
+ waitForIdle();
+ }
+
+ private WindowInsets getInsets(View v) {
+ return new WindowInsets(v.getRootWindowInsets());
+ }
+
+ private WindowInsets getInsets(Activity a) {
+ return new WindowInsets(a.getWindow().getDecorView().getRootWindowInsets());
+ }
+
+ /**
+ * Set the flags of the window, as per the
+ * {@link WindowManager.LayoutParams WindowManager.LayoutParams}
+ * flags.
+ *
+ * @param flags The new window flags (see WindowManager.LayoutParams).
+ * @param mask Which of the window flag bits to modify.
+ */
+ public void setPrivateFlags(WindowManager.LayoutParams lp, int flags, int mask) {
+ lp.flags = (lp.flags & ~mask) | (flags & mask);
+ }
+
+ /** Asserts that the first entry is greater than or equal to the second entry. */
+ private void assertGreaterOrEqual(int first, int second) throws Exception {
+ Assert.assertTrue("Excepted " + first + " >= " + second, first >= second);
+ }
+
+ private Activity launchActivity(ActivityTestRule activityRule) {
+ final Activity activity = activityRule.launchActivity(null);
+ waitForIdle();
+ return activity;
+ }
+
+ private void finishActivity(ActivityTestRule activityRule) {
+ final Activity activity = activityRule.getActivity();
+ if (activity != null) {
+ activity.finish();
+ }
+ }
+
+ private void waitForIdle() {
+ mInstrumentation.waitForIdleSync();
+ }
+
+ public static class TestActivity extends Activity {
+ }
+}
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 9f57f49..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;
@@ -148,8 +148,8 @@
}
@Override
- public void adjustWindowParamsLw(WindowManager.LayoutParams attrs) {
-
+ public void adjustWindowParamsLw(WindowState win, WindowManager.LayoutParams attrs,
+ boolean hasStatusBarServicePermission) {
}
@Override
@@ -189,7 +189,7 @@
@Override
public boolean isKeyguardHostWindow(WindowManager.LayoutParams attrs) {
- return false;
+ return attrs.type == TYPE_STATUS_BAR;
}
@Override
@@ -290,7 +290,7 @@
}
@Override
- public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight,
+ public void beginLayoutLw(int displayId, int displayWidth, int displayHeight,
int displayRotation, int uiMode) {
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
new file mode 100644
index 0000000..ad9aea7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTracingTest.java
@@ -0,0 +1,194 @@
+/*
+ * 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.server.wm;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+
+import android.content.Context;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.internal.util.Preconditions;
+import com.android.server.wm.proto.WindowManagerTraceProto;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Test class for {@link WindowTracing}.
+ *
+ * Build/Install/Run:
+ * bit FrameworksServicesTests:com.android.server.wm.WindowTracingTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class WindowTracingTest extends WindowTestsBase {
+
+ private static final byte[] MAGIC_HEADER = new byte[] {
+ 0x9, 0x57, 0x49, 0x4e, 0x54, 0x52, 0x41, 0x43, 0x45,
+ };
+
+ private Context mTestContext;
+ private WindowTracing mWindowTracing;
+ private WindowManagerService mWmMock;
+ private File mFile;
+
+ @Override
+ @Before
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mWmMock = mock(WindowManagerService.class);
+
+ mTestContext = InstrumentationRegistry.getContext();
+
+ mFile = mTestContext.getFileStreamPath("tracing_test.dat");
+ mFile.delete();
+
+ mWindowTracing = new WindowTracing(mFile);
+ }
+
+ @Test
+ public void isEnabled_returnsFalseByDefault() throws Exception {
+ assertFalse(mWindowTracing.isEnabled());
+ }
+
+ @Test
+ public void isEnabled_returnsTrueAfterStart() throws Exception {
+ mWindowTracing.startTrace(mock(PrintWriter.class));
+ assertTrue(mWindowTracing.isEnabled());
+ }
+
+ @Test
+ public void isEnabled_returnsFalseAfterStop() throws Exception {
+ mWindowTracing.startTrace(mock(PrintWriter.class));
+ mWindowTracing.stopTrace(mock(PrintWriter.class));
+ assertFalse(mWindowTracing.isEnabled());
+ }
+
+ @Test
+ public void trace_discared_whenNotTracing() throws Exception {
+ mWindowTracing.traceStateLocked("where", mWmMock);
+ verifyZeroInteractions(mWmMock);
+ }
+
+ @Test
+ public void trace_dumpsWindowManagerState_whenTracing() throws Exception {
+ mWindowTracing.startTrace(mock(PrintWriter.class));
+ mWindowTracing.traceStateLocked("where", mWmMock);
+
+ verify(mWmMock).writeToProtoLocked(any(), eq(true));
+ }
+
+ @Test
+ public void traceFile_startsWithMagicHeader() throws Exception {
+ mWindowTracing.startTrace(mock(PrintWriter.class));
+ mWindowTracing.stopTrace(mock(PrintWriter.class));
+
+ byte[] header = new byte[MAGIC_HEADER.length];
+ try (InputStream is = new FileInputStream(mFile)) {
+ assertEquals(MAGIC_HEADER.length, is.read(header));
+ assertArrayEquals(MAGIC_HEADER, header);
+ }
+ }
+
+ @Test
+ @Ignore("Figure out why this test is crashing when setting up mWmMock.")
+ public void tracing_endsUpInFile() throws Exception {
+ mWindowTracing.startTrace(mock(PrintWriter.class));
+
+ doAnswer((inv) -> {
+ inv.<ProtoOutputStream>getArgument(0).write(
+ WindowManagerTraceProto.WHERE, "TEST_WM_PROTO");
+ return null;
+ }).when(mWmMock).writeToProtoLocked(any(), any());
+ mWindowTracing.traceStateLocked("TEST_WHERE", mWmMock);
+
+ mWindowTracing.stopTrace(mock(PrintWriter.class));
+
+ byte[] file = new byte[1000];
+ int fileLength;
+ try (InputStream is = new FileInputStream(mFile)) {
+ fileLength = is.read(file);
+ assertTrue(containsBytes(file, fileLength,
+ "TEST_WHERE".getBytes(StandardCharsets.UTF_8)));
+ assertTrue(containsBytes(file, fileLength,
+ "TEST_WM_PROTO".getBytes(StandardCharsets.UTF_8)));
+ }
+ }
+
+ @Override
+ @After
+ public void tearDown() throws Exception {
+ super.tearDown();
+
+ mFile.delete();
+ }
+
+ /** Return true if {@code needle} appears anywhere in {@code haystack[0..length]} */
+ boolean containsBytes(byte[] haystack, int haystackLenght, byte[] needle) {
+ Preconditions.checkArgument(haystackLenght > 0);
+ Preconditions.checkArgument(needle.length > 0);
+
+ outer: for (int i = 0; i <= haystackLenght - needle.length; i++) {
+ for (int j = 0; j < needle.length; j++) {
+ if (haystack[i+j] != needle[j]) {
+ continue outer;
+ }
+ }
+ return true;
+ }
+ return false;
+ }
+
+ @Test
+ public void test_containsBytes() {
+ byte[] haystack = "hello_world".getBytes(StandardCharsets.UTF_8);
+ assertTrue(containsBytes(haystack, haystack.length,
+ "hello".getBytes(StandardCharsets.UTF_8)));
+ assertTrue(containsBytes(haystack, haystack.length,
+ "world".getBytes(StandardCharsets.UTF_8)));
+ assertFalse(containsBytes(haystack, 6,
+ "world".getBytes(StandardCharsets.UTF_8)));
+ assertFalse(containsBytes(haystack, haystack.length,
+ "world_".getBytes(StandardCharsets.UTF_8)));
+ assertFalse(containsBytes(haystack, haystack.length,
+ "absent".getBytes(StandardCharsets.UTF_8)));
+ }
+}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index e5d3915..c5ca330 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -103,7 +103,7 @@
long lastUsedScreenTime;
@StandbyBuckets int currentBucket;
String bucketingReason;
- int lastInformedState;
+ int lastInformedBucket;
}
AppIdleHistory(File storageDir, long elapsedRealtime) {
@@ -333,13 +333,12 @@
}
boolean shouldInformListeners(String packageName, int userId,
- long elapsedRealtime, boolean isIdle) {
+ long elapsedRealtime, int bucket) {
ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
AppUsageHistory appUsageHistory = getPackageHistory(userHistory, packageName,
elapsedRealtime, true);
- int targetState = isIdle? STATE_IDLE : STATE_ACTIVE;
- if (appUsageHistory.lastInformedState != (isIdle ? STATE_IDLE : STATE_ACTIVE)) {
- appUsageHistory.lastInformedState = targetState;
+ if (appUsageHistory.lastInformedBucket != bucket) {
+ appUsageHistory.lastInformedBucket = bucket;
return true;
}
return false;
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 17fde57..5623a68 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -160,7 +160,6 @@
private final Context mContext;
// TODO: Provide a mechanism to set an external bucketing service
- private boolean mUseInternalBucketingHeuristics = true;
private AppWidgetManager mAppWidgetManager;
private PowerManager mPowerManager;
@@ -367,29 +366,33 @@
Slog.d(TAG, " Checking idle state for " + packageName);
}
if (isSpecial) {
- maybeInformListeners(packageName, userId, elapsedRealtime, false);
- } else if (mUseInternalBucketingHeuristics) {
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ AppStandby.STANDBY_BUCKET_ACTIVE);
+ } else {
synchronized (mAppIdleLock) {
- int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId,
- elapsedRealtime);
String bucketingReason = mAppIdleHistory.getAppStandbyReason(packageName,
userId, elapsedRealtime);
- if (bucketingReason != null
- && (bucketingReason.equals(AppStandby.REASON_FORCED)
- || bucketingReason.startsWith(AppStandby.REASON_PREDICTED))) {
+ // If the bucket was forced by the developer, leave it alone
+ if (AppStandby.REASON_FORCED.equals(bucketingReason)) {
continue;
}
- int newBucket = getBucketForLocked(packageName, userId,
- elapsedRealtime);
- if (DEBUG) {
- Slog.d(TAG, " Old bucket=" + oldBucket
- + ", newBucket=" + newBucket);
- }
- if (oldBucket != newBucket) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId,
- elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT);
- maybeInformListeners(packageName, userId, elapsedRealtime,
- newBucket >= AppStandby.STANDBY_BUCKET_RARE);
+ // If the bucket was moved up due to usage, let the timeouts apply.
+ if (AppStandby.REASON_USAGE.equals(bucketingReason)
+ || AppStandby.REASON_TIMEOUT.equals(bucketingReason)) {
+ int oldBucket = mAppIdleHistory.getAppStandbyBucket(packageName, userId,
+ elapsedRealtime);
+ int newBucket = getBucketForLocked(packageName, userId,
+ elapsedRealtime);
+ if (DEBUG) {
+ Slog.d(TAG, " Old bucket=" + oldBucket
+ + ", newBucket=" + newBucket);
+ }
+ if (oldBucket < newBucket) {
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId,
+ elapsedRealtime, newBucket, AppStandby.REASON_TIMEOUT);
+ maybeInformListeners(packageName, userId, elapsedRealtime,
+ newBucket);
+ }
}
}
}
@@ -403,12 +406,12 @@
}
private void maybeInformListeners(String packageName, int userId,
- long elapsedRealtime, boolean isIdle) {
+ long elapsedRealtime, int bucket) {
synchronized (mAppIdleLock) {
if (mAppIdleHistory.shouldInformListeners(packageName, userId,
- elapsedRealtime, isIdle)) {
+ elapsedRealtime, bucket)) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS,
- userId, isIdle ? 1 : 0, packageName));
+ userId, bucket, packageName));
}
}
}
@@ -461,11 +464,13 @@
if (DEBUG) Slog.i(TAG, "DeviceIdleMode changed to " + deviceIdle);
boolean paroled = false;
synchronized (mAppIdleLock) {
- final long timeSinceLastParole = mInjector.currentTimeMillis() - mLastAppIdleParoledTime;
+ final long timeSinceLastParole =
+ mInjector.currentTimeMillis() - mLastAppIdleParoledTime;
if (!deviceIdle
&& timeSinceLastParole >= mAppIdleParoleIntervalMillis) {
if (DEBUG) {
- Slog.i(TAG, "Bringing idle apps out of inactive state due to deviceIdleMode=false");
+ Slog.i(TAG,
+ "Bringing idle apps out of inactive state due to deviceIdleMode=false");
}
paroled = true;
} else if (deviceIdle) {
@@ -491,7 +496,8 @@
|| event.mEventType == UsageEvents.Event.USER_INTERACTION)) {
mAppIdleHistory.reportUsage(event.mPackage, userId, elapsedRealtime);
if (previouslyIdle) {
- maybeInformListeners(event.mPackage, userId, elapsedRealtime, false);
+ maybeInformListeners(event.mPackage, userId, elapsedRealtime,
+ AppStandby.STANDBY_BUCKET_ACTIVE);
notifyBatteryStats(event.mPackage, userId, false);
}
}
@@ -729,7 +735,8 @@
void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
String reason, long elapsedRealtime) {
- mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket, reason);
+ mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
+ reason);
}
private boolean isActiveDeviceAdmin(String packageName, int userId) {
@@ -786,9 +793,10 @@
return packageName != null && packageName.equals(activeScorer);
}
- void informListeners(String packageName, int userId, boolean isIdle) {
+ void informListeners(String packageName, int userId, int bucket) {
+ final boolean idle = bucket >= AppStandby.STANDBY_BUCKET_RARE;
for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
- listener.onAppIdleStateChanged(packageName, userId, isIdle);
+ listener.onAppIdleStateChanged(packageName, userId, idle, bucket);
}
}
@@ -1037,7 +1045,7 @@
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_INFORM_LISTENERS:
- informListeners((String) msg.obj, msg.arg1, msg.arg2 == 1);
+ informListeners((String) msg.obj, msg.arg1, msg.arg2);
break;
case MSG_FORCE_IDLE_STATE:
@@ -1187,7 +1195,8 @@
mAppStandbyScreenThresholds = parseLongArray(screenThresholdsValue,
SCREEN_TIME_THRESHOLDS);
- String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS, null);
+ String elapsedThresholdsValue = mParser.getString(KEY_ELAPSED_TIME_THRESHOLDS,
+ null);
mAppStandbyElapsedThresholds = parseLongArray(elapsedThresholdsValue,
ELAPSED_TIME_THRESHOLDS);
}
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index d359b70..7bea8a1 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -255,6 +255,7 @@
}
private void alsaFileAdded(String name) {
+ Slog.i(TAG, "alsaFileAdded(" + name + ")");
int type = AlsaDevice.TYPE_UNKNOWN;
int card = -1, device = -1;
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index e65d360..1b057f9 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -893,7 +893,7 @@
updateCurrentAccessory();
}
if (mBootCompleted) {
- if (!mConnected) {
+ if (!mConnected && !hasMessages(MSG_ACCESSORY_MODE_ENTER_TIMEOUT)) {
// restore defaults when USB is disconnected
setEnabledFunctions(null, !mAdbEnabled, false);
}
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 095fdc6..c29a335 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -19,13 +19,8 @@
import android.annotation.Nullable;
import android.content.ComponentName;
import android.content.Context;
-import android.hardware.usb.UsbConfiguration;
import android.hardware.usb.UsbConstants;
import android.hardware.usb.UsbDevice;
-import android.hardware.usb.UsbDeviceConnection;
-import android.hardware.usb.UsbEndpoint;
-import android.hardware.usb.UsbInterface;
-import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;
@@ -37,7 +32,6 @@
import com.android.server.usb.descriptors.report.TextReportCanvas;
import com.android.server.usb.descriptors.tree.UsbDescriptorsTree;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -50,28 +44,23 @@
private final Context mContext;
- // contains all connected USB devices
- private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
-
// USB busses to exclude from USB host support
private final String[] mHostBlacklist;
- private final Object mLock = new Object();
-
- private UsbDevice mNewDevice;
- private UsbConfiguration mNewConfiguration;
- private UsbInterface mNewInterface;
- private ArrayList<UsbConfiguration> mNewConfigurations;
- private ArrayList<UsbInterface> mNewInterfaces;
- private ArrayList<UsbEndpoint> mNewEndpoints;
-
private final UsbAlsaManager mUsbAlsaManager;
private final UsbSettingsManager mSettingsManager;
+ private final Object mLock = new Object();
@GuardedBy("mLock")
+ // contains all connected USB devices
+ private final HashMap<String, UsbDevice> mDevices = new HashMap<>();
+
+ private Object mSettingsLock = new Object();
+ @GuardedBy("mSettingsLock")
private UsbProfileGroupSettingsManager mCurrentSettings;
- @GuardedBy("mLock")
+ private Object mHandlerLock = new Object();
+ @GuardedBy("mHandlerLock")
private ComponentName mUsbDeviceConnectionHandler;
public UsbHostManager(Context context, UsbAlsaManager alsaManager,
@@ -91,33 +80,33 @@
}
public void setCurrentUserSettings(UsbProfileGroupSettingsManager settings) {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
mCurrentSettings = settings;
}
}
private UsbProfileGroupSettingsManager getCurrentUserSettings() {
- synchronized (mLock) {
+ synchronized (mSettingsLock) {
return mCurrentSettings;
}
}
public void setUsbDeviceConnectionHandler(@Nullable ComponentName usbDeviceConnectionHandler) {
- synchronized (mLock) {
+ synchronized (mHandlerLock) {
mUsbDeviceConnectionHandler = usbDeviceConnectionHandler;
}
}
private @Nullable ComponentName getUsbDeviceConnectionHandler() {
- synchronized (mLock) {
+ synchronized (mHandlerLock) {
return mUsbDeviceConnectionHandler;
}
}
- private boolean isBlackListed(String deviceName) {
+ private boolean isBlackListed(String deviceAddress) {
int count = mHostBlacklist.length;
for (int i = 0; i < count; i++) {
- if (deviceName.startsWith(mHostBlacklist[i])) {
+ if (deviceAddress.startsWith(mHostBlacklist[i])) {
return true;
}
}
@@ -136,166 +125,73 @@
}
/* Called from JNI in monitorUsbHostBus() to report new USB devices
- Returns true if successful, in which case the JNI code will continue adding configurations,
- interfaces and endpoints, and finally call endUsbDeviceAdded after all descriptors
- have been processed
+ Returns true if successful, i.e. the USB Audio device descriptors are
+ correctly parsed and the unique device is added to the audio device list.
*/
@SuppressWarnings("unused")
- private boolean beginUsbDeviceAdded(String deviceName, int vendorID, int productID,
- int deviceClass, int deviceSubclass, int deviceProtocol,
- String manufacturerName, String productName, int version, String serialNumber) {
-
+ private boolean usbDeviceAdded(String deviceAddress, int deviceClass, int deviceSubclass,
+ byte[] descriptors) {
if (DEBUG) {
- Slog.d(TAG, "usb:UsbHostManager.beginUsbDeviceAdded(" + deviceName + ")");
- // Audio Class Codes:
- // Audio: 0x01
- // Audio Subclass Codes:
- // undefined: 0x00
- // audio control: 0x01
- // audio streaming: 0x02
- // midi streaming: 0x03
-
- // some useful debugging info
- Slog.d(TAG, "usb: nm:" + deviceName + " vnd:" + vendorID + " prd:" + productID + " cls:"
- + deviceClass + " sub:" + deviceSubclass + " proto:" + deviceProtocol);
+ Slog.d(TAG, "usbDeviceAdded(" + deviceAddress + ") - start");
}
- // OK this is non-obvious, but true. One can't tell if the device being attached is even
- // potentially an audio device without parsing the interface descriptors, so punt on any
- // such test until endUsbDeviceAdded() when we have that info.
-
- if (isBlackListed(deviceName) ||
- isBlackListed(deviceClass, deviceSubclass)) {
+ // check class/subclass first as it is more likely to be blacklisted
+ if (isBlackListed(deviceClass, deviceSubclass) || isBlackListed(deviceAddress)) {
+ if (DEBUG) {
+ Slog.d(TAG, "device is black listed");
+ }
return false;
}
synchronized (mLock) {
- if (mDevices.get(deviceName) != null) {
- Slog.w(TAG, "device already on mDevices list: " + deviceName);
+ if (mDevices.get(deviceAddress) != null) {
+ Slog.w(TAG, "device already on mDevices list: " + deviceAddress);
+ //TODO If this is the same peripheral as is being connected, replace
+ // it with the new connection.
return false;
}
- if (mNewDevice != null) {
- Slog.e(TAG, "mNewDevice is not null in endUsbDeviceAdded");
- return false;
- }
+ UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress);
+ if (parser.parseDescriptors(descriptors)) {
- // Create version string in "%.%" format
- String versionString = Integer.toString(version >> 8) + "." + (version & 0xFF);
-
- mNewDevice = new UsbDevice(deviceName, vendorID, productID,
- deviceClass, deviceSubclass, deviceProtocol,
- manufacturerName, productName, versionString, serialNumber);
-
- mNewConfigurations = new ArrayList<>();
- mNewInterfaces = new ArrayList<>();
- mNewEndpoints = new ArrayList<>();
- }
-
- return true;
- }
-
- /* Called from JNI in monitorUsbHostBus() to report new USB configuration for the device
- currently being added. Returns true if successful, false in case of error.
- */
- @SuppressWarnings("unused")
- private void addUsbConfiguration(int id, String name, int attributes, int maxPower) {
- if (mNewConfiguration != null) {
- mNewConfiguration.setInterfaces(
- mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
- mNewInterfaces.clear();
- }
-
- mNewConfiguration = new UsbConfiguration(id, name, attributes, maxPower);
- mNewConfigurations.add(mNewConfiguration);
- }
-
- /* Called from JNI in monitorUsbHostBus() to report new USB interface for the device
- currently being added. Returns true if successful, false in case of error.
- */
- @SuppressWarnings("unused")
- private void addUsbInterface(int id, String name, int altSetting,
- int Class, int subClass, int protocol) {
- if (mNewInterface != null) {
- mNewInterface.setEndpoints(
- mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
- mNewEndpoints.clear();
- }
-
- mNewInterface = new UsbInterface(id, altSetting, name, Class, subClass, protocol);
- mNewInterfaces.add(mNewInterface);
- }
-
- /* Called from JNI in monitorUsbHostBus() to report new USB endpoint for the device
- currently being added. Returns true if successful, false in case of error.
- */
- @SuppressWarnings("unused")
- private void addUsbEndpoint(int address, int attributes, int maxPacketSize, int interval) {
- mNewEndpoints.add(new UsbEndpoint(address, attributes, maxPacketSize, interval));
- }
-
- /* Called from JNI in monitorUsbHostBus() to finish adding a new device */
- @SuppressWarnings("unused")
- private void endUsbDeviceAdded() {
- if (DEBUG) {
- Slog.d(TAG, "usb:UsbHostManager.endUsbDeviceAdded()");
- }
- if (mNewInterface != null) {
- mNewInterface.setEndpoints(
- mNewEndpoints.toArray(new UsbEndpoint[mNewEndpoints.size()]));
- }
- if (mNewConfiguration != null) {
- mNewConfiguration.setInterfaces(
- mNewInterfaces.toArray(new UsbInterface[mNewInterfaces.size()]));
- }
-
-
- synchronized (mLock) {
- if (mNewDevice != null) {
- mNewDevice.setConfigurations(
- mNewConfigurations.toArray(
- new UsbConfiguration[mNewConfigurations.size()]));
- mDevices.put(mNewDevice.getDeviceName(), mNewDevice);
- Slog.d(TAG, "Added device " + mNewDevice);
+ UsbDevice newDevice = parser.toAndroidUsbDevice();
+ mDevices.put(deviceAddress, newDevice);
// It is fine to call this only for the current user as all broadcasts are sent to
// all profiles of the user and the dialogs should only show once.
ComponentName usbDeviceConnectionHandler = getUsbDeviceConnectionHandler();
if (usbDeviceConnectionHandler == null) {
- getCurrentUserSettings().deviceAttached(mNewDevice);
+ getCurrentUserSettings().deviceAttached(newDevice);
} else {
- getCurrentUserSettings().deviceAttachedForFixedHandler(mNewDevice,
+ getCurrentUserSettings().deviceAttachedForFixedHandler(newDevice,
usbDeviceConnectionHandler);
}
- // deviceName is something like: "/dev/bus/usb/001/001"
- UsbDescriptorParser parser = new UsbDescriptorParser();
- boolean isInputHeadset = false;
- boolean isOutputHeadset = false;
- if (parser.parseDevice(mNewDevice.getDeviceName())) {
- isInputHeadset = parser.isInputHeadset();
- isOutputHeadset = parser.isOutputHeadset();
- Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
- + " , out: " + isOutputHeadset + "]");
- }
- mUsbAlsaManager.usbDeviceAdded(mNewDevice,
- isInputHeadset, isOutputHeadset);
+
+ // Headset?
+ boolean isInputHeadset = parser.isInputHeadset();
+ boolean isOutputHeadset = parser.isOutputHeadset();
+ Slog.i(TAG, "---- isHeadset[in: " + isInputHeadset
+ + " , out: " + isOutputHeadset + "]");
+
+ mUsbAlsaManager.usbDeviceAdded(newDevice, isInputHeadset, isOutputHeadset);
} else {
- Slog.e(TAG, "mNewDevice is null in endUsbDeviceAdded");
+ Slog.e(TAG, "Error parsing USB device descriptors for " + deviceAddress);
+ return false;
}
- mNewDevice = null;
- mNewConfigurations = null;
- mNewInterfaces = null;
- mNewEndpoints = null;
- mNewConfiguration = null;
- mNewInterface = null;
}
+
+ if (DEBUG) {
+ Slog.d(TAG, "beginUsbDeviceAdded(" + deviceAddress + ") end");
+ }
+
+ return true;
}
/* Called from JNI in monitorUsbHostBus to report USB device removal */
@SuppressWarnings("unused")
- private void usbDeviceRemoved(String deviceName) {
+ private void usbDeviceRemoved(String deviceAddress) {
synchronized (mLock) {
- UsbDevice device = mDevices.remove(deviceName);
+ UsbDevice device = mDevices.remove(deviceAddress);
if (device != null) {
mUsbAlsaManager.usbDeviceRemoved(device);
mSettingsManager.usbDeviceRemoved(device);
@@ -322,32 +218,37 @@
}
}
- /* Opens the specified USB device */
- public ParcelFileDescriptor openDevice(String deviceName, UsbUserSettingsManager settings) {
+ /**
+ * Opens the specified USB device
+ * @hide
+ */
+ public ParcelFileDescriptor openDevice(String deviceAddress, UsbUserSettingsManager settings) {
synchronized (mLock) {
- if (isBlackListed(deviceName)) {
+ if (isBlackListed(deviceAddress)) {
throw new SecurityException("USB device is on a restricted bus");
}
- UsbDevice device = mDevices.get(deviceName);
+ UsbDevice device = mDevices.get(deviceAddress);
if (device == null) {
// if it is not in mDevices, it either does not exist or is blacklisted
throw new IllegalArgumentException(
- "device " + deviceName + " does not exist or is restricted");
+ "device " + deviceAddress + " does not exist or is restricted");
}
settings.checkPermission(device);
- return nativeOpenDevice(deviceName);
+ return nativeOpenDevice(deviceAddress);
}
}
public void dump(IndentingPrintWriter pw) {
- synchronized (mLock) {
- pw.println("USB Host State:");
- for (String name : mDevices.keySet()) {
- pw.println(" " + name + ": " + mDevices.get(name));
- }
+ pw.println("USB Host State:");
+ synchronized (mHandlerLock) {
if (mUsbDeviceConnectionHandler != null) {
pw.println("Default USB Host Connection handler: " + mUsbDeviceConnectionHandler);
}
+ }
+ synchronized (mLock) {
+ for (String name : mDevices.keySet()) {
+ pw.println(" " + name + ": " + mDevices.get(name));
+ }
Collection<UsbDevice> devices = mDevices.values();
if (devices.size() != 0) {
@@ -355,17 +256,12 @@
for (UsbDevice device : devices) {
StringBuilder stringBuilder = new StringBuilder();
- UsbDescriptorParser parser = new UsbDescriptorParser();
- if (parser.parseDevice(device.getDeviceName())) {
+ UsbDescriptorParser parser = new UsbDescriptorParser(device.getDeviceName());
+ if (parser.parseDevice()) {
UsbDescriptorsTree descriptorTree = new UsbDescriptorsTree();
descriptorTree.parse(parser);
- UsbManager usbManager =
- (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
- UsbDeviceConnection connection = usbManager.openDevice(device);
-
- descriptorTree.report(new TextReportCanvas(connection, stringBuilder));
- connection.close();
+ descriptorTree.report(new TextReportCanvas(parser, stringBuilder));
stringBuilder.append("isHeadset[in: " + parser.isInputHeadset()
+ " , out: " + parser.isOutputHeadset() + "]");
@@ -381,5 +277,5 @@
}
private native void monitorUsbHostBus();
- private native ParcelFileDescriptor nativeOpenDevice(String deviceName);
+ private native ParcelFileDescriptor nativeOpenDevice(String deviceAddress);
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
index 75279c6..511e59a 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbConfigDescriptor.java
@@ -15,8 +15,13 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbInterface;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
+import java.util.ArrayList;
+
/**
* @hide
* An USB Config Descriptor.
@@ -35,6 +40,9 @@
// D4..0 Reserved, set to 0.
private byte mMaxPower; // 8:1 Maximum Power Consumption in 2mA units
+ private ArrayList<UsbInterfaceDescriptor> mInterfaceDescriptors =
+ new ArrayList<UsbInterfaceDescriptor>();
+
UsbConfigDescriptor(int length, byte type) {
super(length, type);
mHierarchyLevel = 2;
@@ -64,6 +72,22 @@
return mMaxPower;
}
+ void addInterfaceDescriptor(UsbInterfaceDescriptor interfaceDesc) {
+ mInterfaceDescriptors.add(interfaceDesc);
+ }
+
+ UsbConfiguration toAndroid(UsbDescriptorParser parser) {
+ String name = parser.getDescriptorString(mConfigIndex);
+ UsbConfiguration config = new
+ UsbConfiguration(mConfigValue, name, mAttribs, mMaxPower);
+ UsbInterface[] interfaces = new UsbInterface[mInterfaceDescriptors.size()];
+ for (int index = 0; index < mInterfaceDescriptors.size(); index++) {
+ interfaces[index] = mInterfaceDescriptors.get(index).toAndroid(parser);
+ }
+ config.setInterfaces(interfaces);
+ return config;
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
mTotalLength = stream.unpackUsbShort();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
index ad7bde5c..c5052c8 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java
@@ -15,6 +15,7 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbDevice;
import android.util.Log;
import java.util.ArrayList;
@@ -25,11 +26,16 @@
*/
public final class UsbDescriptorParser {
private static final String TAG = "UsbDescriptorParser";
+ private static final boolean DEBUG = false;
+
+ private final String mDeviceAddr;
// Descriptor Objects
+ private static final int DESCRIPTORS_ALLOC_SIZE = 128;
private ArrayList<UsbDescriptor> mDescriptors = new ArrayList<UsbDescriptor>();
private UsbDeviceDescriptor mDeviceDescriptor;
+ private UsbConfigDescriptor mCurConfigDescriptor;
private UsbInterfaceDescriptor mCurInterfaceDescriptor;
// The AudioClass spec implemented by the AudioClass Interfaces
@@ -37,7 +43,13 @@
// Obtained from the first AudioClass Header descriptor.
private int mACInterfacesSpec = UsbDeviceDescriptor.USBSPEC_1_0;
- public UsbDescriptorParser() {}
+ public UsbDescriptorParser(String deviceAddr) {
+ mDeviceAddr = deviceAddr;
+ }
+
+ public String getDeviceAddr() {
+ return mDeviceAddr;
+ }
/**
* @return the USB Spec value associated with the Device descriptor for the
@@ -60,6 +72,18 @@
public int getACInterfaceSpec() {
return mACInterfacesSpec;
}
+
+ private class UsbDescriptorsStreamFormatException extends Exception {
+ String mMessage;
+ UsbDescriptorsStreamFormatException(String message) {
+ mMessage = message;
+ }
+
+ public String toString() {
+ return "Descriptor Stream Format Exception: " + mMessage;
+ }
+ }
+
/**
* The probability (as returned by getHeadsetProbability() at which we conclude
* the peripheral is a headset.
@@ -67,7 +91,8 @@
private static final float IN_HEADSET_TRIGGER = 0.75f;
private static final float OUT_HEADSET_TRIGGER = 0.75f;
- private UsbDescriptor allocDescriptor(ByteStream stream) {
+ private UsbDescriptor allocDescriptor(ByteStream stream)
+ throws UsbDescriptorsStreamFormatException {
stream.resetReadCount();
int length = stream.getUnsignedByte();
@@ -83,15 +108,38 @@
break;
case UsbDescriptor.DESCRIPTORTYPE_CONFIG:
- descriptor = new UsbConfigDescriptor(length, type);
+ descriptor = mCurConfigDescriptor = new UsbConfigDescriptor(length, type);
+ if (mDeviceDescriptor != null) {
+ mDeviceDescriptor.addConfigDescriptor(mCurConfigDescriptor);
+ } else {
+ Log.e(TAG, "Config Descriptor found with no associated Device Descriptor!");
+ throw new UsbDescriptorsStreamFormatException(
+ "Config Descriptor found with no associated Device Descriptor!");
+ }
break;
case UsbDescriptor.DESCRIPTORTYPE_INTERFACE:
descriptor = mCurInterfaceDescriptor = new UsbInterfaceDescriptor(length, type);
+ if (mCurConfigDescriptor != null) {
+ mCurConfigDescriptor.addInterfaceDescriptor(mCurInterfaceDescriptor);
+ } else {
+ Log.e(TAG, "Interface Descriptor found with no associated Config Descriptor!");
+ throw new UsbDescriptorsStreamFormatException(
+ "Interface Descriptor found with no associated Config Descriptor!");
+ }
break;
case UsbDescriptor.DESCRIPTORTYPE_ENDPOINT:
descriptor = new UsbEndpointDescriptor(length, type);
+ if (mCurInterfaceDescriptor != null) {
+ mCurInterfaceDescriptor.addEndpointDescriptor(
+ (UsbEndpointDescriptor) descriptor);
+ } else {
+ Log.e(TAG,
+ "Endpoint Descriptor found with no associated Interface Descriptor!");
+ throw new UsbDescriptorsStreamFormatException(
+ "Endpoint Descriptor found with no associated Interface Descriptor!");
+ }
break;
/*
@@ -144,8 +192,12 @@
/**
* @hide
*/
- public void parseDescriptors(byte[] descriptors) {
- mDescriptors.clear();
+ public boolean parseDescriptors(byte[] descriptors) {
+ if (DEBUG) {
+ Log.d(TAG, "parseDescriptors() - start");
+ }
+ // This will allow us to (probably) alloc mDescriptors just once.
+ mDescriptors = new ArrayList<UsbDescriptor>(DESCRIPTORS_ALLOC_SIZE);
ByteStream stream = new ByteStream(descriptors);
while (stream.available() > 0) {
@@ -173,21 +225,36 @@
}
}
}
+ if (DEBUG) {
+ Log.d(TAG, "parseDescriptors() - end " + mDescriptors.size() + " descriptors.");
+ }
+ return true;
}
/**
* @hide
*/
- public boolean parseDevice(String deviceAddr) {
- byte[] rawDescriptors = getRawDescriptors(deviceAddr);
- if (rawDescriptors != null) {
- parseDescriptors(rawDescriptors);
- return true;
- }
- return false;
+ public boolean parseDevice() {
+ byte[] rawDescriptors = getRawDescriptors();
+
+ return rawDescriptors != null
+ ? parseDescriptors(rawDescriptors) : false;
}
- private native byte[] getRawDescriptors(String deviceAddr);
+ private byte[] getRawDescriptors() {
+ return getRawDescriptors_native(mDeviceAddr);
+ }
+
+ private native byte[] getRawDescriptors_native(String deviceAddr);
+
+ /**
+ * @hide
+ */
+ public String getDescriptorString(int stringId) {
+ return getDescriptorString_native(mDeviceAddr, stringId);
+ }
+
+ private native String getDescriptorString_native(String deviceAddr, int stringId);
public int getParsingSpec() {
return mDeviceDescriptor != null ? mDeviceDescriptor.getSpec() : 0;
@@ -200,6 +267,17 @@
/**
* @hide
*/
+ public UsbDevice toAndroidUsbDevice() {
+ if (mDeviceDescriptor == null) {
+ return null;
+ }
+
+ return mDeviceDescriptor.toAndroid(this);
+ }
+
+ /**
+ * @hide
+ */
public ArrayList<UsbDescriptor> getDescriptors(byte type) {
ArrayList<UsbDescriptor> list = new ArrayList<UsbDescriptor>();
for (UsbDescriptor descriptor : mDescriptors) {
@@ -355,8 +433,6 @@
* to count on the peripheral being a headset.
*/
public boolean isInputHeadset() {
- // TEMP
- Log.i(TAG, "---- isInputHeadset() prob:" + (getInputHeadsetProbability() * 100f) + "%");
return getInputHeadsetProbability() >= IN_HEADSET_TRIGGER;
}
@@ -410,8 +486,6 @@
* to count on the peripheral being a headset.
*/
public boolean isOutputHeadset() {
- // TEMP
- Log.i(TAG, "---- isOutputHeadset() prob:" + (getOutputHeadsetProbability() * 100f) + "%");
return getOutputHeadsetProbability() >= OUT_HEADSET_TRIGGER;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
index d5cb89e..c89d9b6 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbDeviceDescriptor.java
@@ -15,9 +15,14 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbConfiguration;
+import android.hardware.usb.UsbDevice;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
import com.android.server.usb.descriptors.report.UsbStrings;
+import java.util.ArrayList;
+
/**
* @hide
* A USB Device Descriptor.
@@ -44,6 +49,9 @@
private byte mSerialNum; // 16:1 Index of Serial Number String Descriptor
private byte mNumConfigs; // 17:1 Number of Possible Configurations
+ private ArrayList<UsbConfigDescriptor> mConfigDescriptors =
+ new ArrayList<UsbConfigDescriptor>();
+
UsbDeviceDescriptor(int length, byte type) {
super(length, type);
mHierarchyLevel = 1;
@@ -97,6 +105,35 @@
return mNumConfigs;
}
+ void addConfigDescriptor(UsbConfigDescriptor config) {
+ mConfigDescriptors.add(config);
+ }
+
+ /**
+ * @hide
+ */
+ public UsbDevice toAndroid(UsbDescriptorParser parser) {
+ String mfgName = parser.getDescriptorString(mMfgIndex);
+ String prodName = parser.getDescriptorString(mProductIndex);
+
+ // Create version string in "%.%" format
+ String versionString =
+ Integer.toString(mDeviceRelease >> 8) + "." + (mDeviceRelease & 0xFF);
+ String serialStr = parser.getDescriptorString(mSerialNum);
+
+ UsbDevice device = new UsbDevice(parser.getDeviceAddr(), mVendorID, mProductID,
+ mDevClass, mDevSubClass,
+ mProtocol, mfgName, prodName,
+ versionString, serialStr);
+ UsbConfiguration[] configs = new UsbConfiguration[mConfigDescriptors.size()];
+ for (int index = 0; index < mConfigDescriptors.size(); index++) {
+ configs[index] = mConfigDescriptors.get(index).toAndroid(parser);
+ }
+ device.setConfigurations(configs);
+
+ return device;
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
mSpec = stream.unpackUsbShort();
@@ -134,12 +171,11 @@
+ " Product ID: " + ReportCanvas.getHexString(getProductID())
+ " Product Release: " + ReportCanvas.getBCDString(getDeviceRelease()));
+ UsbDescriptorParser parser = canvas.getParser();
byte mfgIndex = getMfgIndex();
- String manufacturer =
- UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), mfgIndex);
+ String manufacturer = parser.getDescriptorString(mfgIndex);
byte productIndex = getProductIndex();
- String product =
- UsbDescriptor.getUsbDescriptorString(canvas.getConnection(), productIndex);
+ String product = parser.getDescriptorString(productIndex);
canvas.writeListItem("Manufacturer " + mfgIndex + ": " + manufacturer
+ " Product " + productIndex + ": " + product);
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
index 6322fbe..9cb8f05 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbEndpointDescriptor.java
@@ -15,6 +15,8 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbEndpoint;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
/**
@@ -105,6 +107,10 @@
return mSyncAddress;
}
+ /* package */ UsbEndpoint toAndroid(UsbDescriptorParser parser) {
+ return new UsbEndpoint(mEndpointAddress, mAttributes, mPacketSize, mInterval);
+ }
+
@Override
public int parseRawDescriptors(ByteStream stream) {
mEndpointAddress = stream.getByte();
diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
index 4eef6ca..645807d 100644
--- a/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
+++ b/services/usb/java/com/android/server/usb/descriptors/UsbInterfaceDescriptor.java
@@ -15,9 +15,14 @@
*/
package com.android.server.usb.descriptors;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+
import com.android.server.usb.descriptors.report.ReportCanvas;
import com.android.server.usb.descriptors.report.UsbStrings;
+import java.util.ArrayList;
+
/**
* @hide
* A common super-class for all USB Interface Descritor subtypes.
@@ -34,6 +39,9 @@
protected byte mProtocol; // 7:1 Protocol Code
protected byte mDescrIndex; // 8:1 Index of String Descriptor Describing this interface
+ private ArrayList<UsbEndpointDescriptor> mEndpointDescriptors =
+ new ArrayList<UsbEndpointDescriptor>();
+
UsbInterfaceDescriptor(int length, byte type) {
super(length, type);
mHierarchyLevel = 3;
@@ -80,6 +88,22 @@
return mDescrIndex;
}
+ void addEndpointDescriptor(UsbEndpointDescriptor endpoint) {
+ mEndpointDescriptors.add(endpoint);
+ }
+
+ UsbInterface toAndroid(UsbDescriptorParser parser) {
+ String name = parser.getDescriptorString(mDescrIndex);
+ UsbInterface ntrface = new UsbInterface(
+ mInterfaceNumber, mAlternateSetting, name, mUsbClass, mUsbSubclass, mProtocol);
+ UsbEndpoint[] endpoints = new UsbEndpoint[mEndpointDescriptors.size()];
+ for (int index = 0; index < mEndpointDescriptors.size(); index++) {
+ endpoints[index] = mEndpointDescriptors.get(index).toAndroid(parser);
+ }
+ ntrface.setEndpoints(endpoints);
+ return ntrface;
+ }
+
@Override
public void report(ReportCanvas canvas) {
super.report(canvas);
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
index 99ebcca..adfc514 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/HTMLReportCanvas.java
@@ -15,7 +15,7 @@
*/
package com.android.server.usb.descriptors.report;
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
/**
* @hide
@@ -32,8 +32,8 @@
* from the USB device.
* @param stringBuilder Generated output gets written into this object.
*/
- public HTMLReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
- super(connection);
+ public HTMLReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+ super(parser);
mStringBuilder = stringBuilder;
}
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
index 9e0adf5..c34dc98 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/ReportCanvas.java
@@ -15,7 +15,7 @@
*/
package com.android.server.usb.descriptors.report;
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
/**
* @hide
@@ -24,22 +24,19 @@
public abstract class ReportCanvas {
private static final String TAG = "ReportCanvas";
- private final UsbDeviceConnection mConnection;
+ private final UsbDescriptorParser mParser;
/**
* Constructor.
* @param connection The USB connection object used to retrieve strings
* from the USB device.
*/
- public ReportCanvas(UsbDeviceConnection connection) {
- mConnection = connection;
+ public ReportCanvas(UsbDescriptorParser parser) {
+ mParser = parser;
}
- /**
- * @returns the UsbDeviceConnection member (mConnection).
- */
- public UsbDeviceConnection getConnection() {
- return mConnection;
+ public UsbDescriptorParser getParser() {
+ return mParser;
}
/**
diff --git a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
index a43569d..1e19ea1 100644
--- a/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
+++ b/services/usb/java/com/android/server/usb/descriptors/report/TextReportCanvas.java
@@ -15,7 +15,7 @@
*/
package com.android.server.usb.descriptors.report;
-import android.hardware.usb.UsbDeviceConnection;
+import com.android.server.usb.descriptors.UsbDescriptorParser;
/**
* @hide
@@ -34,8 +34,8 @@
* from the USB device.
* @param stringBuilder Generated output gets written into this object.
*/
- public TextReportCanvas(UsbDeviceConnection connection, StringBuilder stringBuilder) {
- super(connection);
+ public TextReportCanvas(UsbDescriptorParser parser, StringBuilder stringBuilder) {
+ super(parser);
mStringBuilder = stringBuilder;
}
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f53eb15..25c54b3 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -36,12 +36,12 @@
import android.hardware.soundtrigger.SoundTriggerModule;
import android.os.DeadObjectException;
import android.os.PowerManager;
+import android.os.PowerManager.ServiceType;
import android.os.RemoteException;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.util.Slog;
import com.android.internal.logging.MetricsLogger;
-import com.android.server.power.BatterySaverPolicy.ServiceType;
import java.io.FileDescriptor;
import java.io.PrintWriter;
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 1569ac3..44e5314 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -30,6 +30,7 @@
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
+import android.content.pm.ShortcutServiceInternal;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -44,6 +45,7 @@
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.service.voice.IVoiceInteractionService;
import android.service.voice.IVoiceInteractionSession;
@@ -53,6 +55,7 @@
import android.service.voice.VoiceInteractionSession;
import android.speech.RecognitionService;
import android.text.TextUtils;
+import android.util.ArraySet;
import android.util.Log;
import android.util.Slog;
@@ -63,6 +66,7 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.UiThread;
@@ -84,7 +88,9 @@
final ContentResolver mResolver;
final DatabaseHelper mDbHelper;
final ActivityManagerInternal mAmInternal;
- final TreeSet<Integer> mLoadedKeyphraseIds;
+ final UserManager mUserManager;
+ final ArraySet<Integer> mLoadedKeyphraseIds = new ArraySet<>();
+ ShortcutServiceInternal mShortcutServiceInternal;
SoundTriggerInternal mSoundTriggerInternal;
private final RemoteCallbackList<IVoiceInteractionSessionListener>
@@ -96,8 +102,10 @@
mResolver = context.getContentResolver();
mDbHelper = new DatabaseHelper(context);
mServiceStub = new VoiceInteractionManagerServiceStub();
- mAmInternal = LocalServices.getService(ActivityManagerInternal.class);
- mLoadedKeyphraseIds = new TreeSet<Integer>();
+ mAmInternal = Preconditions.checkNotNull(
+ LocalServices.getService(ActivityManagerInternal.class));
+ mUserManager = Preconditions.checkNotNull(
+ context.getSystemService(UserManager.class));
PackageManagerInternal packageManagerInternal = LocalServices.getService(
PackageManagerInternal.class);
@@ -124,6 +132,8 @@
@Override
public void onBootPhase(int phase) {
if (PHASE_SYSTEM_SERVICES_READY == phase) {
+ mShortcutServiceInternal = Preconditions.checkNotNull(
+ LocalServices.getService(ShortcutServiceInternal.class));
mSoundTriggerInternal = LocalServices.getService(SoundTriggerInternal.class);
} else if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) {
mServiceStub.systemRunning(isSafeMode());
@@ -180,6 +190,7 @@
private boolean mSafeMode;
private int mCurUser;
+ private boolean mCurUserUnlocked;
private final boolean mEnableService;
VoiceInteractionManagerServiceStub() {
@@ -381,6 +392,7 @@
public void switchUser(int userHandle) {
synchronized (this) {
mCurUser = userHandle;
+ mCurUserUnlocked = false;
switchImplementationIfNeededLocked(false);
}
}
@@ -409,13 +421,24 @@
}
}
+ final boolean hasComponent = serviceComponent != null && serviceInfo != null;
+
+ if (mUserManager.isUserUnlockingOrUnlocked(mCurUser)) {
+ if (hasComponent) {
+ mShortcutServiceInternal.setShortcutHostPackage(TAG,
+ serviceComponent.getPackageName(), mCurUser);
+ } else {
+ mShortcutServiceInternal.setShortcutHostPackage(TAG, null, mCurUser);
+ }
+ }
+
if (force || mImpl == null || mImpl.mUser != mCurUser
|| !mImpl.mComponent.equals(serviceComponent)) {
unloadAllKeyphraseModels();
if (mImpl != null) {
mImpl.shutdownLocked();
}
- if (serviceComponent != null && serviceInfo != null) {
+ if (hasComponent) {
mImpl = new VoiceInteractionManagerServiceImpl(mContext,
UiThread.getHandler(), this, mCurUser, serviceComponent);
mImpl.startLocked();
@@ -953,12 +976,14 @@
}
private synchronized void unloadAllKeyphraseModels() {
- for (int keyphraseId : mLoadedKeyphraseIds) {
+ for (int i = 0; i < mLoadedKeyphraseIds.size(); i++) {
final long caller = Binder.clearCallingIdentity();
try {
- int status = mSoundTriggerInternal.unloadKeyphraseModel(keyphraseId);
+ int status = mSoundTriggerInternal.unloadKeyphraseModel(
+ mLoadedKeyphraseIds.valueAt(i));
if (status != SoundTriggerInternal.STATUS_OK) {
- Slog.w(TAG, "Failed to unload keyphrase " + keyphraseId + ":" + status);
+ Slog.w(TAG, "Failed to unload keyphrase " + mLoadedKeyphraseIds.valueAt(i)
+ + ":" + status);
}
} finally {
Binder.restoreCallingIdentity(caller);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 925219d..e0d9c73 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -198,7 +198,10 @@
mShowArgs = args;
mShowFlags = flags;
+ disabledContext |= getUserDisabledShowContextLocked();
mAssistDataRequester.requestAssistData(topActivities,
+ (flags & VoiceInteractionSession.SHOW_WITH_ASSIST) != 0,
+ (flags & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0,
(disabledContext & VoiceInteractionSession.SHOW_WITH_ASSIST) == 0,
(disabledContext & VoiceInteractionSession.SHOW_WITH_SCREENSHOT) == 0,
mCallingUid, mSessionComponentName.getPackageName());
@@ -215,6 +218,7 @@
mShowFlags = 0;
} catch (RemoteException e) {
}
+ mAssistDataRequester.processPendingAssistData();
} else if (showCallback != null) {
mPendingShowCallbacks.add(showCallback);
}
@@ -237,11 +241,16 @@
@Override
public void onAssistDataReceivedLocked(Bundle data, int activityIndex, int activityCount) {
+ // Return early if we have no session
+ if (mSession == null) {
+ return;
+ }
+
if (data == null) {
try {
mSession.handleAssist(null, null, null, 0, 0);
} catch (RemoteException e) {
- // Can't happen
+ // Ignore
}
} else {
final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
@@ -267,17 +276,22 @@
mSession.handleAssist(assistData, structure, content, activityIndex,
activityCount);
} catch (RemoteException e) {
- // Can't happen
+ // Ignore
}
}
}
@Override
public void onAssistScreenshotReceivedLocked(Bitmap screenshot) {
+ // Return early if we have no session
+ if (mSession == null) {
+ return;
+ }
+
try {
mSession.handleScreenshot(screenshot);
} catch (RemoteException e) {
- // Can't happen
+ // Ignore
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index eb8a8b9..061e55a 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1198,24 +1198,21 @@
*/
public static final String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
-
/**
- * @hide
- * The default value for preferred CDMA roaming mode (aka CDMA system select.)
- * CDMA_ROAMING_MODE_RADIO_DEFAULT = the default roaming mode from the radio
- * CDMA_ROAMING_MODE_HOME = Home Networks
- * CDMA_ROAMING_MODE_AFFILIATED = Roaming on Affiliated networks
- * CDMA_ROAMING_MODE_ANY = Roaming on any networks
+ * The CDMA roaming mode (aka CDMA system select).
+ *
+ * <p>The value should be one of the CDMA_ROAMING_MODE_ constants in {@link TelephonyManager}.
+ * Values other than {@link TelephonyManager#CDMA_ROAMING_MODE_RADIO_DEFAULT} (which is the
+ * default) will take precedence over user selection.
+ *
+ * @see TelephonyManager#CDMA_ROAMING_MODE_RADIO_DEFAULT
+ * @see TelephonyManager#CDMA_ROAMING_MODE_HOME
+ * @see TelephonyManager#CDMA_ROAMING_MODE_AFFILIATED
+ * @see TelephonyManager#CDMA_ROAMING_MODE_ANY
*/
public static final String KEY_CDMA_ROAMING_MODE_INT = "cdma_roaming_mode_int";
- /** @hide */
- public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1;
- /** @hide */
- public static final int CDMA_ROAMING_MODE_HOME = 0;
- /** @hide */
- public static final int CDMA_ROAMING_MODE_AFFILIATED = 1;
- /** @hide */
- public static final int CDMA_ROAMING_MODE_ANY = 2;
+
+
/**
* Boolean indicating if support is provided for directly dialing FDN number from FDN list.
* If false, this feature is not supported.
@@ -1546,6 +1543,13 @@
"boosted_lte_earfcns_string_array";
/**
+ * Determine whether to use only RSRP for the number of LTE signal bars.
+ * @hide
+ */
+ public static final String KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL =
+ "use_only_rsrp_for_lte_signal_bar_bool";
+
+ /**
* Key identifying if voice call barring notification is required to be shown to the user.
* @hide
*/
@@ -1639,6 +1643,13 @@
public static final String KEY_FEATURE_ACCESS_CODES_STRING_ARRAY =
"feature_access_codes_string_array";
+ /**
+ * Determines if the carrier wants to identify high definition calls in the call log.
+ * @hide
+ */
+ public static final String KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL =
+ "identify_high_definition_calls_in_call_log_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1833,7 +1844,8 @@
sDefaults.putBoolean(KEY_ALLOW_NON_EMERGENCY_CALLS_IN_ECM_BOOL, true);
sDefaults.putBoolean(KEY_USE_RCS_PRESENCE_BOOL, false);
sDefaults.putBoolean(KEY_FORCE_IMEI_BOOL, false);
- sDefaults.putInt(KEY_CDMA_ROAMING_MODE_INT, CDMA_ROAMING_MODE_RADIO_DEFAULT);
+ sDefaults.putInt(
+ KEY_CDMA_ROAMING_MODE_INT, TelephonyManager.CDMA_ROAMING_MODE_RADIO_DEFAULT);
sDefaults.putString(KEY_RCS_CONFIG_SERVER_URL_STRING, "");
// Carrier Signalling Receivers
@@ -1904,6 +1916,7 @@
null);
sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
+ sDefaults.putBoolean(KEY_USE_ONLY_RSRP_FOR_LTE_SIGNAL_BAR_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
sDefaults.putInt(IMSI_KEY_AVAILABILITY_INT, 0);
sDefaults.putString(IMSI_KEY_DOWNLOAD_URL_STRING, null);
@@ -1914,6 +1927,7 @@
sDefaults.putBoolean(KEY_SHOW_IMS_REGISTRATION_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_DISABLE_CHARGE_INDICATION_BOOL, false);
sDefaults.putStringArray(KEY_FEATURE_ACCESS_CODES_STRING_ARRAY, null);
+ sDefaults.putBoolean(KEY_IDENTIFY_HIGH_DEFINITION_CALLS_IN_CALL_LOG_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java
index c8b4776..de02de7 100644
--- a/telephony/java/android/telephony/SignalStrength.java
+++ b/telephony/java/android/telephony/SignalStrength.java
@@ -68,6 +68,7 @@
private int mTdScdmaRscp;
private boolean isGsm; // This value is set by the ServiceStateTracker onSignalStrengthResult
+ private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar.
/**
* Create a new SignalStrength from a intent notifier Bundle
@@ -108,6 +109,7 @@
mLteRsrpBoost = 0;
mTdScdmaRscp = INVALID;
isGsm = true;
+ mUseOnlyRsrpForLteLevel = false;
}
/**
@@ -134,6 +136,7 @@
mLteRsrpBoost = 0;
mTdScdmaRscp = INVALID;
isGsm = gsmFlag;
+ mUseOnlyRsrpForLteLevel = false;
}
/**
@@ -145,10 +148,10 @@
int cdmaDbm, int cdmaEcio,
int evdoDbm, int evdoEcio, int evdoSnr,
int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
- int lteRsrpBoost, int tdScdmaRscp, boolean gsmFlag) {
+ int lteRsrpBoost, int tdScdmaRscp, boolean gsmFlag, boolean lteLevelBaseOnRsrp) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
- lteRsrq, lteRssnr, lteCqi, lteRsrpBoost, gsmFlag);
+ lteRsrq, lteRssnr, lteCqi, lteRsrpBoost, gsmFlag, lteLevelBaseOnRsrp);
mTdScdmaRscp = tdScdmaRscp;
}
@@ -164,7 +167,7 @@
int tdScdmaRscp, boolean gsmFlag) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
- lteRsrq, lteRssnr, lteCqi, 0, gsmFlag);
+ lteRsrq, lteRssnr, lteCqi, 0, gsmFlag, false);
mTdScdmaRscp = tdScdmaRscp;
}
@@ -180,7 +183,7 @@
boolean gsmFlag) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, lteSignalStrength, lteRsrp,
- lteRsrq, lteRssnr, lteCqi, 0, gsmFlag);
+ lteRsrq, lteRssnr, lteCqi, 0, gsmFlag, false);
}
/**
@@ -194,7 +197,7 @@
boolean gsmFlag) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
- INVALID, INVALID, INVALID, 0, gsmFlag);
+ INVALID, INVALID, INVALID, 0, gsmFlag, false);
}
/**
@@ -228,7 +231,7 @@
boolean gsm) {
initialize(gsmSignalStrength, gsmBitErrorRate, cdmaDbm, cdmaEcio,
evdoDbm, evdoEcio, evdoSnr, 99, INVALID,
- INVALID, INVALID, INVALID, 0, gsm);
+ INVALID, INVALID, INVALID, 0, gsm, false);
}
/**
@@ -248,6 +251,7 @@
* @param lteCqi
* @param lteRsrpBoost
* @param gsm
+ * @param useOnlyRsrpForLteLevel
*
* @hide
*/
@@ -255,7 +259,7 @@
int cdmaDbm, int cdmaEcio,
int evdoDbm, int evdoEcio, int evdoSnr,
int lteSignalStrength, int lteRsrp, int lteRsrq, int lteRssnr, int lteCqi,
- int lteRsrpBoost, boolean gsm) {
+ int lteRsrpBoost, boolean gsm, boolean useOnlyRsrpForLteLevel) {
mGsmSignalStrength = gsmSignalStrength;
mGsmBitErrorRate = gsmBitErrorRate;
mCdmaDbm = cdmaDbm;
@@ -271,6 +275,7 @@
mLteRsrpBoost = lteRsrpBoost;
mTdScdmaRscp = INVALID;
isGsm = gsm;
+ mUseOnlyRsrpForLteLevel = useOnlyRsrpForLteLevel;
if (DBG) log("initialize: " + toString());
}
@@ -293,6 +298,7 @@
mLteRsrpBoost = s.mLteRsrpBoost;
mTdScdmaRscp = s.mTdScdmaRscp;
isGsm = s.isGsm;
+ mUseOnlyRsrpForLteLevel = s.mUseOnlyRsrpForLteLevel;
}
/**
@@ -318,6 +324,7 @@
mLteRsrpBoost = in.readInt();
mTdScdmaRscp = in.readInt();
isGsm = (in.readInt() != 0);
+ mUseOnlyRsrpForLteLevel = (in.readInt() != 0);
}
/**
@@ -366,6 +373,7 @@
out.writeInt(mLteRsrpBoost);
out.writeInt(mTdScdmaRscp);
out.writeInt(isGsm ? 1 : 0);
+ out.writeInt(mUseOnlyRsrpForLteLevel ? 1 : 0);
}
/**
@@ -449,6 +457,17 @@
}
/**
+ * @param useOnlyRsrpForLteLevel true if it uses only RSRP for the number of LTE signal bar,
+ * otherwise false.
+ *
+ * Used by phone to use only RSRP or not for the number of LTE signal bar.
+ * @hide
+ */
+ public void setUseOnlyRsrpForLteLevel(boolean useOnlyRsrpForLteLevel) {
+ mUseOnlyRsrpForLteLevel = useOnlyRsrpForLteLevel;
+ }
+
+ /**
* @param lteRsrpBoost - signal strength offset
*
* Used by phone to set the lte signal strength offset which will be
@@ -835,6 +854,13 @@
}
}
+ if (useOnlyRsrpForLteLevel()) {
+ log("getLTELevel - rsrp = " + rsrpIconLevel);
+ if (rsrpIconLevel != -1) {
+ return rsrpIconLevel;
+ }
+ }
+
/*
* Values are -200 dB to +300 (SNR*10dB) RS_SNR >= 13.0 dB =>4 bars 4.5
* dB <= RS_SNR < 13.0 dB => 3 bars 1.0 dB <= RS_SNR < 4.5 dB => 2 bars
@@ -915,6 +941,15 @@
}
/**
+ * @return true if it uses only RSRP for the number of LTE signal bar, otherwise false.
+ *
+ * @hide
+ */
+ public boolean useOnlyRsrpForLteLevel() {
+ return this.mUseOnlyRsrpForLteLevel;
+ }
+
+ /**
* @return get TD_SCDMA dbm
*
* @hide
@@ -974,7 +1009,8 @@
+ (mEvdoDbm * primeNum) + (mEvdoEcio * primeNum) + (mEvdoSnr * primeNum)
+ (mLteSignalStrength * primeNum) + (mLteRsrp * primeNum)
+ (mLteRsrq * primeNum) + (mLteRssnr * primeNum) + (mLteCqi * primeNum)
- + (mLteRsrpBoost * primeNum) + (mTdScdmaRscp * primeNum) + (isGsm ? 1 : 0));
+ + (mLteRsrpBoost * primeNum) + (mTdScdmaRscp * primeNum) + (isGsm ? 1 : 0)
+ + (mUseOnlyRsrpForLteLevel ? 1 : 0));
}
/**
@@ -1008,7 +1044,8 @@
&& mLteCqi == s.mLteCqi
&& mLteRsrpBoost == s.mLteRsrpBoost
&& mTdScdmaRscp == s.mTdScdmaRscp
- && isGsm == s.isGsm);
+ && isGsm == s.isGsm
+ && mUseOnlyRsrpForLteLevel == s.mUseOnlyRsrpForLteLevel);
}
/**
@@ -1031,7 +1068,9 @@
+ " " + mLteCqi
+ " " + mLteRsrpBoost
+ " " + mTdScdmaRscp
- + " " + (isGsm ? "gsm|lte" : "cdma"));
+ + " " + (isGsm ? "gsm|lte" : "cdma")
+ + " " + (mUseOnlyRsrpForLteLevel ? "use_only_rsrp_for_lte_level" :
+ "use_rsrp_and_rssnr_for_lte_level"));
}
/** Returns the signal strength related to GSM. */
@@ -1086,6 +1125,7 @@
mLteRsrpBoost = m.getInt("lteRsrpBoost");
mTdScdmaRscp = m.getInt("TdScdma");
isGsm = m.getBoolean("isGsm");
+ mUseOnlyRsrpForLteLevel = m.getBoolean("useOnlyRsrpForLteLevel");
}
/**
@@ -1110,6 +1150,7 @@
m.putInt("lteRsrpBoost", mLteRsrpBoost);
m.putInt("TdScdma", mTdScdmaRscp);
m.putBoolean("isGsm", isGsm);
+ m.putBoolean("useOnlyRsrpForLteLevel", mUseOnlyRsrpForLteLevel);
}
/**
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 216d28c..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;
}
/**
@@ -3273,4 +3293,69 @@
*/
public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
}
+
+ /**
+ * Contains carrier identification information.
+ * @hide
+ */
+ public static final class CarrierIdentification implements BaseColumns {
+ /**
+ * Numeric operator ID (as String). {@code MCC + MNC}
+ * <P>Type: TEXT </P>
+ */
+ public static final String MCCMNC = "mccmnc";
+
+ /**
+ * Group id level 1 (as String).
+ * <P>Type: TEXT </P>
+ */
+ public static final String GID1 = "gid1";
+
+ /**
+ * Group id level 2 (as String).
+ * <P>Type: TEXT </P>
+ */
+ public static final String GID2 = "gid2";
+
+ /**
+ * Public Land Mobile Network name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String PLMN = "plmn";
+
+ /**
+ * Prefix xpattern of IMSI (International Mobile Subscriber Identity).
+ * <P>Type: TEXT </P>
+ */
+ public static final String IMSI_PREFIX_XPATTERN = "imsi_prefix_xpattern";
+
+ /**
+ * Service Provider Name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String SPN = "spn";
+
+ /**
+ * Prefer APN name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String APN = "apn";
+
+ /**
+ * User facing carrier name.
+ * <P>Type: TEXT </P>
+ */
+ public static final String NAME = "carrier_name";
+
+ /**
+ * A unique carrier id
+ * <P>Type: INTEGER </P>
+ */
+ public static final String CID = "carrier_id";
+
+ /**
+ * The {@code content://} URI for this table.
+ */
+ public static final Uri CONTENT_URI = Uri.parse("content://carrier_identification");
+ }
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c0564c5..42c3de5 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -953,6 +953,27 @@
*/
public static final int USSD_ERROR_SERVICE_UNAVAIL = -2;
+ /**
+ * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which leaves the roaming
+ * mode set to the radio default or to the user's preference if they've indicated one.
+ */
+ public static final int CDMA_ROAMING_MODE_RADIO_DEFAULT = -1;
+ /**
+ * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which only permits
+ * connections on home networks.
+ */
+ public static final int CDMA_ROAMING_MODE_HOME = 0;
+ /**
+ * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which permits roaming on
+ * affiliated networks.
+ */
+ public static final int CDMA_ROAMING_MODE_AFFILIATED = 1;
+ /**
+ * Value for {@link CarrierConfigManager#KEY_CDMA_ROAMING_MODE_INT} which permits roaming on
+ * any network.
+ */
+ public static final int CDMA_ROAMING_MODE_ANY = 2;
+
//
//
// Device Info
@@ -2145,13 +2166,16 @@
* @hide
*/
public String getSimOperatorNumeric() {
- int subId = SubscriptionManager.getDefaultDataSubscriptionId();
+ int subId = mSubId;
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
- subId = SubscriptionManager.getDefaultSmsSubscriptionId();
+ subId = SubscriptionManager.getDefaultDataSubscriptionId();
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
- subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+ subId = SubscriptionManager.getDefaultSmsSubscriptionId();
if (!SubscriptionManager.isUsableSubIdValue(subId)) {
- subId = SubscriptionManager.getDefaultSubscriptionId();
+ subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
+ if (!SubscriptionManager.isUsableSubIdValue(subId)) {
+ subId = SubscriptionManager.getDefaultSubscriptionId();
+ }
}
}
}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
deleted file mode 100644
index 038e295..0000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxy.java
+++ /dev/null
@@ -1,335 +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;
- }
-
- /**
- * @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;
- }
-
- @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 bbd5f02..0000000
--- a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
+++ /dev/null
@@ -1,183 +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();
- }
-
- 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/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/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
index d8d7f48..b30a3af 100644
--- a/telephony/java/android/telephony/mbms/FileServiceInfo.java
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -17,6 +17,7 @@
package android.telephony.mbms;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -35,6 +36,7 @@
/** @hide */
@SystemApi
+ @TestApi
public FileServiceInfo(Map<Locale, String> newNames, String newClassName,
List<Locale> newLocales, String newServiceId, Date start, Date end,
List<FileInfo> newFiles) {
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
index 9ccdd56..4fee3df 100644
--- a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
@@ -42,6 +43,7 @@
* @hide
*/
@SystemApi
+@TestApi
public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
private final Map<IBinder, DownloadStateCallback> mDownloadCallbackBinderMap = new HashMap<>();
private final Map<IBinder, DeathRecipient> mDownloadCallbackDeathRecipients = new HashMap<>();
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/telephony/java/com/android/internal/telephony/uicc/IccUtils.java b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
index 62d570c..99a82ad 100644
--- a/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/uicc/IccUtils.java
@@ -567,4 +567,12 @@
} while (valueIndex < endIndex);
return result;
}
+
+ public static String getDecimalSubstring(String iccId) {
+ int position;
+ for (position = 0; position < iccId.length(); position ++) {
+ if (!Character.isDigit(iccId.charAt(position))) break;
+ }
+ return iccId.substring( 0, position );
+ }
}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 29a95e6..3367aba 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -50,6 +50,9 @@
include $(BUILD_STATIC_JAVA_LIBRARY)
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
# Generate the stub source files for android.test.runner.stubs
# ============================================================
include $(CLEAR_VARS)
@@ -149,6 +152,8 @@
@echo Copying removed.txt
$(hide) $(ACP) $(ANDROID_TEST_RUNNER_OUTPUT_REMOVED_API_FILE) $(ANDROID_TEST_RUNNER_REMOVED_API_FILE)
+endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
+
# Build the android.test.mock library
# ===================================
include $(CLEAR_VARS)
@@ -161,6 +166,9 @@
include $(BUILD_JAVA_LIBRARY)
+# For unbundled build we'll use the prebuilt jar from prebuilts/sdk.
+ifeq (,$(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)))
+
# Generate the stub source files for android.test.mock.stubs
# ==========================================================
include $(CLEAR_VARS)
@@ -257,3 +265,5 @@
# additionally, build unit tests in a separate .apk
include $(call all-makefiles-under,$(LOCAL_PATH))
+
+endif # not TARGET_BUILD_APPS not TARGET_BUILD_PDK=true
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/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index f2de7db..c6b4a54 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -92,6 +92,15 @@
</intent-filter>
</activity>
<activity
+ android:name=".TrivialAnimationActivityWideGamut"
+ android:label="General/Trivial Animation (Wide Gamut)"
+ android:colorMode="wideColorGamut">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.test.uibench.TEST" />
+ </intent-filter>
+ </activity>
+ <activity
android:name=".TrivialListActivity"
android:label="General/Trivial ListView" >
<intent-filter>
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java
similarity index 70%
copy from telephony/java/android/telephony/ims/feature/IRcsFeature.java
copy to tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java
index e28e1b3..c492753 100644
--- a/telephony/java/android/telephony/ims/feature/IRcsFeature.java
+++ b/tests/UiBench/src/com/android/test/uibench/TrivialAnimationActivityWideGamut.java
@@ -11,16 +11,8 @@
* 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
+ * limitations under the License.
*/
+package com.android.test.uibench;
-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 {
-}
+public class TrivialAnimationActivityWideGamut extends TrivialAnimationActivity { }
diff --git a/tests/net/java/android/net/MacAddressTest.java b/tests/net/java/android/net/MacAddressTest.java
new file mode 100644
index 0000000..fcbb9da
--- /dev/null
+++ b/tests/net/java/android/net/MacAddressTest.java
@@ -0,0 +1,208 @@
+/*
+ * 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 static org.junit.Assert.fail;
+
+import android.net.MacAddress.MacAddressType;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import java.util.Arrays;
+import java.util.Random;
+
+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);
+
+ if (got != null) {
+ assertEquals(got, new MacAddress(t.addr).addressType());
+ }
+ }
+ }
+
+ @Test
+ public void testIsMulticastAddress() {
+ MacAddress[] multicastAddresses = {
+ MacAddress.BROADCAST_ADDRESS,
+ new MacAddress("07:00:d3:56:8a:c4"),
+ new MacAddress("33:33:aa:bb:cc:dd"),
+ };
+ MacAddress[] unicastAddresses = {
+ MacAddress.ALL_ZEROS_ADDRESS,
+ new MacAddress("00:01:44:55:66:77"),
+ new MacAddress("08:00:22:33:44:55"),
+ new MacAddress("06:00:00:00:00:00"),
+ };
+
+ for (MacAddress mac : multicastAddresses) {
+ String msg = mac.toString() + " expected to be a multicast address";
+ assertTrue(msg, mac.isMulticastAddress());
+ }
+ for (MacAddress mac : unicastAddresses) {
+ String msg = mac.toString() + " expected not to be a multicast address";
+ assertFalse(msg, mac.isMulticastAddress());
+ }
+ }
+
+ @Test
+ public void testIsLocallyAssignedAddress() {
+ MacAddress[] localAddresses = {
+ new MacAddress("06:00:00:00:00:00"),
+ new MacAddress("07:00:d3:56:8a:c4"),
+ new MacAddress("33:33:aa:bb:cc:dd"),
+ };
+ MacAddress[] universalAddresses = {
+ new MacAddress("00:01:44:55:66:77"),
+ new MacAddress("08:00:22:33:44:55"),
+ };
+
+ for (MacAddress mac : localAddresses) {
+ String msg = mac.toString() + " expected to be a locally assigned address";
+ assertTrue(msg, mac.isLocallyAssigned());
+ }
+ for (MacAddress mac : universalAddresses) {
+ String msg = mac.toString() + " expected not to be globally unique address";
+ assertFalse(msg, mac.isLocallyAssigned());
+ }
+ }
+
+ @Test
+ public void testMacAddressConversions() {
+ final int iterations = 10000;
+ for (int i = 0; i < iterations; i++) {
+ MacAddress mac = MacAddress.getRandomAddress();
+
+ String stringRepr = mac.toString();
+ byte[] bytesRepr = mac.toByteArray();
+
+ assertEquals(mac, new MacAddress(stringRepr));
+ assertEquals(mac, new MacAddress(bytesRepr));
+ }
+ }
+
+ @Test
+ public void testMacAddressRandomGeneration() {
+ final int iterations = 1000;
+ final String expectedAndroidOui = "da:a1:19";
+ for (int i = 0; i < iterations; i++) {
+ MacAddress mac = MacAddress.getRandomAddress();
+ String stringRepr = mac.toString();
+
+ assertTrue(stringRepr + " expected to be a locally assigned address",
+ mac.isLocallyAssigned());
+ assertTrue(stringRepr + " expected to begin with " + expectedAndroidOui,
+ stringRepr.startsWith(expectedAndroidOui));
+ }
+
+ final Random r = new Random();
+ final String anotherOui = "24:5f:78";
+ final String expectedLocalOui = "26:5f:78";
+ final MacAddress base = new MacAddress(anotherOui + ":0:0:0");
+ for (int i = 0; i < iterations; i++) {
+ MacAddress mac = MacAddress.getRandomAddress(base, r);
+ String stringRepr = mac.toString();
+
+ assertTrue(stringRepr + " expected to be a locally assigned address",
+ mac.isLocallyAssigned());
+ assertTrue(stringRepr + " expected to begin with " + expectedLocalOui,
+ stringRepr.startsWith(expectedLocalOui));
+ }
+ }
+
+ @Test
+ public void testConstructorInputValidation() {
+ String[] invalidStringAddresses = {
+ null,
+ "",
+ "abcd",
+ "1:2:3:4:5",
+ "1:2:3:4:5:6:7",
+ "10000:2:3:4:5:6",
+ };
+
+ for (String s : invalidStringAddresses) {
+ try {
+ MacAddress mac = new MacAddress(s);
+ fail("new MacAddress(" + s + ") should have failed, but returned " + mac);
+ } catch (IllegalArgumentException excepted) {
+ }
+ }
+
+ byte[][] invalidBytesAddresses = {
+ null,
+ {},
+ {1,2,3,4,5},
+ {1,2,3,4,5,6,7},
+ };
+
+ for (byte[] b : invalidBytesAddresses) {
+ try {
+ MacAddress mac = new MacAddress(b);
+ fail("new MacAddress(" + Arrays.toString(b)
+ + ") should have failed, but returned " + mac);
+ } catch (IllegalArgumentException excepted) {
+ }
+ }
+ }
+
+ 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/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 7346f9f..cd2d098 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -16,6 +16,7 @@
package android.net;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -26,13 +27,12 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-
-import android.net.NetworkCapabilities;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -159,4 +159,25 @@
assertNotEquals("", nc1.describeImmutableDifferences(nc2));
assertEquals("", nc1.describeImmutableDifferences(nc1));
}
+
+ @Test
+ public void testLinkBandwidthUtils() {
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
+ .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(10, 20));
+
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
+ .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
+ assertEquals(10, NetworkCapabilities
+ .maxBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(20, NetworkCapabilities
+ .maxBandwidth(10, 20));
+ }
}
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/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 27a29b6..113cd37 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,21 +23,44 @@
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.NetworkCapabilities.*;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+
+import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
@@ -45,7 +68,6 @@
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
@@ -64,7 +86,6 @@
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
-import android.net.NetworkConfig;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -79,13 +100,9 @@
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
-import android.os.MessageQueue;
-import android.os.Messenger;
-import android.os.MessageQueue.IdleHandler;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -96,10 +113,8 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import android.util.LogPrinter;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -109,7 +124,6 @@
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
-import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -160,6 +174,7 @@
@Mock IpConnectivityMetrics.Logger mMetricsService;
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
+ @Mock INetworkStatsService mStatsService;
// This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
// do not go through ConnectivityService but talk to netd directly, so they don't automatically
@@ -858,7 +873,7 @@
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
mService = new WrappedConnectivityService(mServiceContext,
mock(INetworkManagementService.class),
- mock(INetworkStatsService.class),
+ mStatsService,
mock(INetworkPolicyManager.class),
mock(IpConnectivityLog.class));
@@ -3440,6 +3455,40 @@
mCm.unregisterNetworkCallback(networkCallback);
}
+ @Test
+ public void testStatsIfacesChanged() throws Exception {
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+
+ // Simple connection should have updated ifaces
+ mCellNetworkAgent.connect(false);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Metered change should update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Captive portal change shouldn't update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ waitForIdle();
+ verify(mStatsService, never()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Roaming change should update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+ }
+
private void checkDirectlyConnectedRoutes(Object callbackObj,
Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
assertTrue(callbackObj instanceof LinkProperties);
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/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
index ad6ebf9..a65bb24 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityEventBuilderTest.java
@@ -198,37 +198,33 @@
@Test
public void testDefaultNetworkEventSerialization() {
- DefaultNetworkEvent ev = new DefaultNetworkEvent();
+ DefaultNetworkEvent ev = new DefaultNetworkEvent(1001);
ev.netId = 102;
- ev.prevNetId = 101;
- ev.transportTypes = new int[]{1, 2, 3};
- ev.prevIPv4 = true;
- ev.prevIPv6 = true;
+ ev.transports = 2;
+ ev.previousTransports = 4;
+ ev.ipv4 = true;
+ ev.initialScore = 20;
+ ev.finalScore = 60;
+ ev.durationMs = 54;
+ ev.validatedMs = 27;
String want = String.join("\n",
"dropped_events: 0",
"events <",
" if_name: \"\"",
- " link_layer: 0",
+ " link_layer: 4",
" network_id: 102",
" time_ms: 0",
- " transports: 0",
+ " transports: 2",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 102",
- " >",
+ " default_network_duration_ms: 54",
+ " final_score: 60",
+ " initial_score: 20",
+ " ip_support: 1",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 101",
- " >",
- " previous_network_ip_support: 3",
- " transport_types: 1",
- " transport_types: 2",
- " transport_types: 3",
+ " previous_default_network_link_layer: 1",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 27",
" >",
">",
"version: 2\n");
diff --git a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
index 6c1decc..b48ff8d 100644
--- a/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
+++ b/tests/net/java/com/android/server/connectivity/IpConnectivityMetricsTest.java
@@ -188,119 +188,99 @@
{makeNai(102, 50, true, true, cell), makeNai(103, 20, true, false, wifi)},
};
+ long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
+ long durationMs = 1001;
for (NetworkAgentInfo[] pair : defaultNetworks) {
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(pair[1], pair[0]);
+ timeMs += durationMs;
+ durationMs += durationMs;
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs, pair[1], pair[0]);
}
String want = String.join("\n",
"dropped_events: 0",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 100",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 100",
- " >",
- " no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 0",
- " >",
- " previous_network_ip_support: 0",
- " transport_types: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 101",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 101",
- " >",
- " no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 100",
- " >",
- " previous_network_ip_support: 3",
- " transport_types: 1",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
+ " link_layer: 5",
" network_id: 0",
" time_ms: 0",
" transports: 0",
" default_network_event <",
- " default_network_duration_ms: 0",
+ " default_network_duration_ms: 1001",
" final_score: 0",
" initial_score: 0",
" ip_support: 0",
- " network_id <",
- " network_id: 0",
- " >",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 101",
- " >",
- " previous_network_ip_support: 1",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 0",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
+ " link_layer: 2",
+ " network_id: 100",
+ " time_ms: 0",
+ " transports: 1",
+ " default_network_event <",
+ " default_network_duration_ms: 2002",
+ " final_score: 50",
+ " initial_score: 10",
+ " ip_support: 3",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 2002",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 4",
+ " network_id: 101",
+ " time_ms: 0",
+ " transports: 2",
+ " default_network_event <",
+ " default_network_duration_ms: 4004",
+ " final_score: 60",
+ " initial_score: 20",
+ " ip_support: 1",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 2",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 4004",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 5",
+ " network_id: 0",
+ " time_ms: 0",
+ " transports: 0",
+ " default_network_event <",
+ " default_network_duration_ms: 8008",
+ " final_score: 0",
+ " initial_score: 0",
+ " ip_support: 0",
+ " no_default_network_duration_ms: 0",
+ " previous_default_network_link_layer: 4",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 0",
+ " >",
+ ">",
+ "events <",
+ " if_name: \"\"",
+ " link_layer: 2",
" network_id: 102",
" time_ms: 0",
- " transports: 0",
+ " transports: 1",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 102",
- " >",
+ " default_network_duration_ms: 16016",
+ " final_score: 50",
+ " initial_score: 10",
+ " ip_support: 3",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 0",
- " >",
+ " previous_default_network_link_layer: 4",
" previous_network_ip_support: 0",
- " transport_types: 0",
- " >",
- ">",
- "events <",
- " if_name: \"\"",
- " link_layer: 0",
- " network_id: 103",
- " time_ms: 0",
- " transports: 0",
- " default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 103",
- " >",
- " no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 102",
- " >",
- " previous_network_ip_support: 3",
- " transport_types: 1",
+ " validation_duration_ms: 16016",
" >",
">",
"version: 2\n");
@@ -379,12 +359,13 @@
wakeupEvent("wlan0", 10008);
wakeupEvent("rmnet0", 1000);
+ long timeMs = mService.mDefaultNetworkMetrics.creationTimeMs;
final long cell = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_CELLULAR});
final long wifi = BitUtils.packBits(new int[]{NetworkCapabilities.TRANSPORT_WIFI});
NetworkAgentInfo cellNai = makeNai(100, 50, false, true, cell);
NetworkAgentInfo wifiNai = makeNai(101, 60, true, false, wifi);
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(cellNai, null);
- mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(wifiNai, cellNai);
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 200, cellNai, null);
+ mService.mDefaultNetworkMetrics.logDefaultNetworkEvent(timeMs + 300, wifiNai, cellNai);
String want = String.join("\n",
"dropped_events: 0",
@@ -473,46 +454,36 @@
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 100",
+ " link_layer: 5",
+ " network_id: 0",
" time_ms: 0",
" transports: 0",
" default_network_event <",
- " default_network_duration_ms: 0",
+ " default_network_duration_ms: 200",
" final_score: 0",
" initial_score: 0",
" ip_support: 0",
- " network_id <",
- " network_id: 100",
- " >",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 0",
- " >",
+ " previous_default_network_link_layer: 0",
" previous_network_ip_support: 0",
- " transport_types: 0",
+ " validation_duration_ms: 0",
" >",
">",
"events <",
" if_name: \"\"",
- " link_layer: 0",
- " network_id: 101",
+ " link_layer: 2",
+ " network_id: 100",
" time_ms: 0",
- " transports: 0",
+ " transports: 1",
" default_network_event <",
- " default_network_duration_ms: 0",
- " final_score: 0",
- " initial_score: 0",
- " ip_support: 0",
- " network_id <",
- " network_id: 101",
- " >",
+ " default_network_duration_ms: 100",
+ " final_score: 50",
+ " initial_score: 50",
+ " ip_support: 2",
" no_default_network_duration_ms: 0",
- " previous_network_id <",
- " network_id: 100",
- " >",
- " previous_network_ip_support: 2",
- " transport_types: 1",
+ " previous_default_network_link_layer: 0",
+ " previous_network_ip_support: 0",
+ " validation_duration_ms: 100",
" >",
">",
"events <",
diff --git a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
index 6723601..83194d9 100644
--- a/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetdEventListenerServiceTest.java
@@ -82,9 +82,8 @@
public void testWakeupEventLogging() throws Exception {
final int BUFFER_LENGTH = NetdEventListenerService.WAKEUP_EVENT_BUFFER_LENGTH;
- // Assert no events
- String[] events1 = listNetdEvent();
- assertEquals(new String[]{""}, events1);
+ // Baseline without any event
+ String[] baseline = listNetdEvent();
long now = System.currentTimeMillis();
String prefix = "iface:wlan0";
@@ -93,7 +92,7 @@
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
}
- String[] events2 = listNetdEvent();
+ String[] events2 = remove(listNetdEvent(), baseline);
int expectedLength2 = uids.length + 1; // +1 for the WakeupStats line
assertEquals(expectedLength2, events2.length);
assertContains(events2[0], "WakeupStats");
@@ -111,7 +110,7 @@
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, ts);
}
- String[] events3 = listNetdEvent();
+ String[] events3 = remove(listNetdEvent(), baseline);
int expectedLength3 = BUFFER_LENGTH + 1; // +1 for the WakeupStats line
assertEquals(expectedLength3, events3.length);
assertContains(events2[0], "WakeupStats");
@@ -126,7 +125,7 @@
uid = 45678;
mNetdEventListenerService.onWakeupEvent(prefix, uid, uid, now);
- String[] events4 = listNetdEvent();
+ String[] events4 = remove(listNetdEvent(), baseline);
String lastEvent = events4[events4.length - 1];
assertContains(lastEvent, "WakeupEvent");
assertContains(lastEvent, "wlan0");
@@ -423,7 +422,7 @@
final PrintWriter pw = new PrintWriter(new FileOutputStream("/dev/null"));
new Thread(() -> {
while (System.currentTimeMillis() < stop) {
- mNetdEventListenerService.dump(pw);
+ mNetdEventListenerService.list(pw);
}
}).start();
}
@@ -461,4 +460,16 @@
static void assertContains(String got, String want) {
assertTrue(got + " did not contain \"" + want + "\"", got.contains(want));
}
+
+ static <T> T[] remove(T[] array, T[] filtered) {
+ List<T> c = Arrays.asList(filtered);
+ int next = 0;
+ for (int i = 0; i < array.length; i++) {
+ if (c.contains(array[i])) {
+ continue;
+ }
+ array[next++] = array[i];
+ }
+ return Arrays.copyOf(array, next);
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index fe396c3..c29363c 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -20,11 +20,30 @@
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
@@ -36,6 +55,9 @@
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.UidRange;
import android.net.VpnService;
@@ -45,17 +67,17 @@
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
-import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -64,6 +86,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -114,6 +137,7 @@
@Mock private AppOpsManager mAppOps;
@Mock private NotificationManager mNotificationManager;
@Mock private Vpn.SystemServices mSystemServices;
+ @Mock private ConnectivityManager mConnectivityManager;
@Before
public void setUp() throws Exception {
@@ -127,6 +151,8 @@
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
+ when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
+ .thenReturn(mConnectivityManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -397,6 +423,66 @@
order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
}
+ @Test
+ public void testCapabilities() {
+ final Vpn vpn = createVpn(primaryUser.id);
+ setMockedUsers(primaryUser);
+
+ final Network mobile = new Network(1);
+ final Network wifi = new Network(2);
+
+ final Map<Network, NetworkCapabilities> networks = new HashMap<>();
+ networks.put(mobile, new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkDownstreamBandwidthKbps(10));
+ networks.put(wifi, new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .setLinkUpstreamBandwidthKbps(20));
+ setMockedNetworks(networks);
+
+ final NetworkCapabilities caps = new NetworkCapabilities();
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ }
+
/**
* Mock some methods of vpn object.
*/
@@ -463,4 +549,11 @@
} catch (Exception e) {
}
}
+
+ private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
+ doAnswer(invocation -> {
+ final Network network = (Network) invocation.getArguments()[0];
+ return networks.get(network);
+ }).when(mConnectivityManager).getNetworkCapabilities(any());
+ }
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 7f1bc5b..65be5ff 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -1158,9 +1158,8 @@
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
- if (!isMetered) {
- capabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- }
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
}
@@ -1176,6 +1175,8 @@
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
return new NetworkState(info, prop, capabilities, null, subscriberId, null);
}
@@ -1185,6 +1186,8 @@
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
return new NetworkState(info, prop, capabilities, null, null, null);
}
diff --git a/tests/testables/tests/AndroidManifest.xml b/tests/testables/tests/AndroidManifest.xml
index f6006b0..6435ad9 100644
--- a/tests/testables/tests/AndroidManifest.xml
+++ b/tests/testables/tests/AndroidManifest.xml
@@ -15,9 +15,11 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.testables">
+ package="com.android.testables" android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
index 058504d..eb3a99a 100644
--- a/tools/aapt2/Android.bp
+++ b/tools/aapt2/Android.bp
@@ -16,6 +16,7 @@
toolSources = [
"cmd/Compile.cpp",
+ "cmd/Convert.cpp",
"cmd/Diff.cpp",
"cmd/Dump.cpp",
"cmd/Link.cpp",
@@ -112,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/Android.mk b/tools/aapt2/Android.mk
new file mode 100644
index 0000000..e0c9d1c
--- /dev/null
+++ b/tools/aapt2/Android.mk
@@ -0,0 +1,7 @@
+include $(CLEAR_VARS)
+
+.PHONY: aapt2_run_host_unit_tests
+aapt2_run_host_unit_tests: PRIVATE_GTEST_OPTIONS := --gtest_output=xml:$(DIST_DIR)/gtest/aapt2_host_unit_tests_result.xml
+aapt2_run_host_unit_tests: $(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests
+ -$(HOST_OUT_NATIVE_TESTS)/aapt2_tests/aapt2_tests $(PRIVATE_GTEST_OPTIONS) > /dev/null 2>&1
+
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/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp
index ae32ee9..921d853 100644
--- a/tools/aapt2/LoadedApk.cpp
+++ b/tools/aapt2/LoadedApk.cpp
@@ -21,43 +21,139 @@
#include "format/Archive.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
+#include "format/proto/ProtoDeserialize.h"
#include "io/BigBufferStream.h"
#include "io/Util.h"
#include "xml/XmlDom.h"
+using ::aapt::io::IFile;
+using ::aapt::io::IFileCollection;
+using ::aapt::xml::XmlResource;
+using ::android::StringPiece;
+using ::std::unique_ptr;
+
namespace aapt {
-using xml::XmlResource;
-
-std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(IAaptContext* context,
- const android::StringPiece& path) {
+std::unique_ptr<LoadedApk> LoadedApk::LoadApkFromPath(const StringPiece& path, IDiagnostics* diag) {
Source source(path);
std::string error;
std::unique_ptr<io::ZipFileCollection> apk = io::ZipFileCollection::Create(path, &error);
- if (!apk) {
- context->GetDiagnostics()->Error(DiagMessage(source) << error);
+ if (apk == nullptr) {
+ diag->Error(DiagMessage(path) << "failed opening zip: " << error);
return {};
}
- io::IFile* file = apk->FindFile("resources.arsc");
- if (!file) {
- context->GetDiagnostics()->Error(DiagMessage(source) << "no resources.arsc found");
+ if (apk->FindFile("resources.arsc") != nullptr) {
+ return LoadBinaryApkFromFileCollection(source, std::move(apk), diag);
+ } else if (apk->FindFile("resources.pb") != nullptr) {
+ return LoadProtoApkFromFileCollection(source, std::move(apk), diag);
+ }
+ diag->Error(DiagMessage(path) << "no resource table found");
+ return {};
+}
+
+std::unique_ptr<LoadedApk> LoadedApk::LoadProtoApkFromFileCollection(
+ const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ io::IFile* table_file = collection->FindFile(kProtoResourceTablePath);
+ if (table_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kProtoResourceTablePath);
return {};
}
- std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
- context->GetDiagnostics()->Error(DiagMessage(source) << "could not open resources.arsc");
+ std::unique_ptr<io::InputStream> in = table_file->OpenInputStream();
+ if (in == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kProtoResourceTablePath);
+ return {};
+ }
+
+ pb::ResourceTable pb_table;
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ if (!pb_table.ParseFromZeroCopyStream(&adaptor)) {
+ diag->Error(DiagMessage(source) << "failed to read " << kProtoResourceTablePath);
+ return {};
+ }
+
+ std::string error;
+ std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
+ if (!DeserializeTableFromPb(pb_table, collection.get(), table.get(), &error)) {
+ diag->Error(DiagMessage(source)
+ << "failed to deserialize " << kProtoResourceTablePath << ": " << error);
+ return {};
+ }
+
+ io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::unique_ptr<io::InputStream> manifest_in = manifest_file->OpenInputStream();
+ if (manifest_in == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ return {};
+ }
+
+ pb::XmlNode pb_node;
+ io::ZeroCopyInputAdaptor manifest_adaptor(manifest_in.get());
+ if (!pb_node.ParseFromZeroCopyStream(&manifest_adaptor)) {
+ diag->Error(DiagMessage(source) << "failed to read proto " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::unique_ptr<xml::XmlResource> manifest = DeserializeXmlResourceFromPb(pb_node, &error);
+ if (manifest == nullptr) {
+ diag->Error(DiagMessage(source)
+ << "failed to deserialize proto " << kAndroidManifestPath << ": " << error);
+ return {};
+ }
+ return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table),
+ std::move(manifest));
+}
+
+std::unique_ptr<LoadedApk> LoadedApk::LoadBinaryApkFromFileCollection(
+ const Source& source, unique_ptr<io::IFileCollection> collection, IDiagnostics* diag) {
+ io::IFile* table_file = collection->FindFile(kApkResourceTablePath);
+ if (table_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kApkResourceTablePath);
+
+ return {};
+ }
+
+ std::unique_ptr<io::IData> data = table_file->OpenAsData();
+ if (data == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kApkResourceTablePath);
return {};
}
std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- BinaryResourceParser parser(context, table.get(), source, data->data(), data->size(), apk.get());
+ BinaryResourceParser parser(diag, table.get(), source, data->data(), data->size(),
+ collection.get());
if (!parser.Parse()) {
return {};
}
- return util::make_unique<LoadedApk>(source, std::move(apk), std::move(table));
+ io::IFile* manifest_file = collection->FindFile(kAndroidManifestPath);
+ if (manifest_file == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to find " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
+ if (manifest_data == nullptr) {
+ diag->Error(DiagMessage(source) << "failed to open " << kAndroidManifestPath);
+ return {};
+ }
+
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest =
+ xml::Inflate(manifest_data->data(), manifest_data->size(), &error);
+ if (manifest == nullptr) {
+ diag->Error(DiagMessage(source)
+ << "failed to parse binary " << kAndroidManifestPath << ": " << error);
+ return {};
+ }
+ return util::make_unique<LoadedApk>(source, std::move(collection), std::move(table),
+ std::move(manifest));
}
bool LoadedApk::WriteToArchive(IAaptContext* context, const TableFlattenerOptions& options,
@@ -148,26 +244,4 @@
return true;
}
-std::unique_ptr<xml::XmlResource> LoadedApk::InflateManifest(IAaptContext* context) {
- IDiagnostics* diag = context->GetDiagnostics();
-
- io::IFile* manifest_file = GetFileCollection()->FindFile("AndroidManifest.xml");
- if (manifest_file == nullptr) {
- diag->Error(DiagMessage(source_) << "no AndroidManifest.xml found");
- return {};
- }
-
- std::unique_ptr<io::IData> manifest_data = manifest_file->OpenAsData();
- if (manifest_data == nullptr) {
- diag->Error(DiagMessage(manifest_file->GetSource()) << "could not open AndroidManifest.xml");
- return {};
- }
-
- std::unique_ptr<xml::XmlResource> manifest =
- xml::Inflate(manifest_data->data(), manifest_data->size(), diag, manifest_file->GetSource());
- if (manifest == nullptr) {
- diag->Error(DiagMessage() << "failed to read binary AndroidManifest.xml");
- }
- return manifest;
-}
} // namespace aapt
diff --git a/tools/aapt2/LoadedApk.h b/tools/aapt2/LoadedApk.h
index d2dd5cf..ef97de3 100644
--- a/tools/aapt2/LoadedApk.h
+++ b/tools/aapt2/LoadedApk.h
@@ -29,20 +29,41 @@
namespace aapt {
+constexpr static const char kApkResourceTablePath[] = "resources.arsc";
+constexpr static const char kProtoResourceTablePath[] = "resources.pb";
+constexpr static const char kAndroidManifestPath[] = "AndroidManifest.xml";
+
// Info about an APK loaded in memory.
class LoadedApk {
public:
- LoadedApk(
- const Source& source,
- std::unique_ptr<io::IFileCollection> apk,
- std::unique_ptr<ResourceTable> table)
- : source_(source), apk_(std::move(apk)), table_(std::move(table)) {}
- virtual ~LoadedApk() = default;
+ // Loads both binary and proto APKs from disk.
+ static std::unique_ptr<LoadedApk> LoadApkFromPath(const ::android::StringPiece& path,
+ IDiagnostics* diag);
+
+ // Loads a proto APK from the given file collection.
+ static std::unique_ptr<LoadedApk> LoadProtoApkFromFileCollection(
+ const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+
+ // Loads a binary APK from the given file collection.
+ static std::unique_ptr<LoadedApk> LoadBinaryApkFromFileCollection(
+ const Source& source, std::unique_ptr<io::IFileCollection> collection, IDiagnostics* diag);
+
+ LoadedApk(const Source& source, std::unique_ptr<io::IFileCollection> apk,
+ std::unique_ptr<ResourceTable> table, std::unique_ptr<xml::XmlResource> manifest)
+ : source_(source),
+ apk_(std::move(apk)),
+ table_(std::move(table)),
+ manifest_(std::move(manifest)) {
+ }
io::IFileCollection* GetFileCollection() {
return apk_.get();
}
+ const ResourceTable* GetResourceTable() const {
+ return table_.get();
+ }
+
ResourceTable* GetResourceTable() {
return table_.get();
}
@@ -51,6 +72,10 @@
return source_;
}
+ const xml::XmlResource* GetManifest() const {
+ return manifest_.get();
+ }
+
/**
* Writes the APK on disk at the given path, while also removing the resource
* files that are not referenced in the resource table.
@@ -71,11 +96,6 @@
const TableFlattenerOptions& options, FilterChain* filters,
IArchiveWriter* writer, xml::XmlResource* manifest = nullptr);
- /** Inflates the AndroidManifest.xml file from the APK. */
- std::unique_ptr<xml::XmlResource> InflateManifest(IAaptContext* context);
-
- static std::unique_ptr<LoadedApk> LoadApkFromPath(IAaptContext* context,
- const android::StringPiece& path);
private:
DISALLOW_COPY_AND_ASSIGN(LoadedApk);
@@ -83,6 +103,7 @@
Source source_;
std::unique_ptr<io::IFileCollection> apk_;
std::unique_ptr<ResourceTable> table_;
+ std::unique_ptr<xml::XmlResource> manifest_;
};
} // namespace aapt
diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp
index 36ab30c..808b29c 100644
--- a/tools/aapt2/Main.cpp
+++ b/tools/aapt2/Main.cpp
@@ -50,7 +50,7 @@
}
static void PrintUsage() {
- std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|version] ..." << std::endl;
+ std::cerr << "\nusage: aapt2 [compile|link|dump|diff|optimize|convert|version] ..." << std::endl;
}
extern int Compile(const std::vector<StringPiece>& args, IDiagnostics* diagnostics);
@@ -58,6 +58,7 @@
extern int Dump(const std::vector<StringPiece>& args);
extern int Diff(const std::vector<StringPiece>& args);
extern int Optimize(const std::vector<StringPiece>& args);
+extern int Convert(const std::vector<StringPiece>& args);
static int ExecuteCommand(const StringPiece& command, const std::vector<StringPiece>& args,
IDiagnostics* diagnostics) {
@@ -71,6 +72,8 @@
return Diff(args);
} else if (command == "optimize") {
return Optimize(args);
+ } else if (command == "convert") {
+ return Convert(args);
} else if (command == "version") {
PrintVersion();
return 0;
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/Compile.cpp b/tools/aapt2/cmd/Compile.cpp
index 53910af..83512b9 100644
--- a/tools/aapt2/cmd/Compile.cpp
+++ b/tools/aapt2/cmd/Compile.cpp
@@ -674,7 +674,7 @@
// Determine how to compile the file based on its type.
auto compile_func = &CompileFile;
- if (path_data.resource_dir == "values") {
+ if (path_data.resource_dir == "values" && path_data.extension == "xml") {
compile_func = &CompileTable;
// We use a different extension (not necessary anymore, but avoids altering the existing
// build system logic).
diff --git a/tools/aapt2/cmd/Convert.cpp b/tools/aapt2/cmd/Convert.cpp
new file mode 100644
index 0000000..89ae9e8
--- /dev/null
+++ b/tools/aapt2/cmd/Convert.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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 <vector>
+
+#include "android-base/macros.h"
+#include "androidfw/StringPiece.h"
+
+#include "Flags.h"
+#include "LoadedApk.h"
+#include "ValueVisitor.h"
+#include "cmd/Util.h"
+#include "format/binary/TableFlattener.h"
+#include "format/binary/XmlFlattener.h"
+#include "format/proto/ProtoDeserialize.h"
+#include "io/BigBufferStream.h"
+#include "io/Util.h"
+#include "process/IResourceTableConsumer.h"
+#include "process/SymbolTable.h"
+
+using ::android::StringPiece;
+using ::std::unique_ptr;
+using ::std::vector;
+
+namespace aapt {
+
+static bool FlattenXml(IAaptContext* context, const xml::XmlResource& xml,
+ const std::string& entry_path, bool utf16, IArchiveWriter* writer) {
+ BigBuffer buffer(4096);
+ XmlFlattenerOptions options = {};
+ options.use_utf16 = utf16;
+ XmlFlattener flattener(&buffer, options);
+ if (!flattener.Consume(context, &xml)) {
+ return false;
+ }
+ io::BigBufferInputStream input_stream(&buffer);
+ return io::CopyInputStreamToArchive(context, &input_stream, entry_path, ArchiveEntry::kCompress,
+ writer);
+}
+
+bool ConvertProtoApkToBinaryApk(IAaptContext* context, unique_ptr<LoadedApk> apk,
+ const TableFlattenerOptions& options, IArchiveWriter* writer) {
+ if (!FlattenXml(context, *apk->GetManifest(), kAndroidManifestPath, true /*utf16*/, writer)) {
+ return false;
+ }
+
+ BigBuffer buffer(4096);
+ TableFlattener table_flattener(options, &buffer);
+ if (!table_flattener.Consume(context, apk->GetResourceTable())) {
+ return false;
+ }
+
+ io::BigBufferInputStream input_stream(&buffer);
+ if (!io::CopyInputStreamToArchive(context, &input_stream, kApkResourceTablePath,
+ ArchiveEntry::kAlign, writer)) {
+ return false;
+ }
+
+ for (const auto& package : apk->GetResourceTable()->packages) {
+ for (const auto& type : package->types) {
+ for (const auto& entry : type->entries) {
+ for (const auto& config_value : entry->values) {
+ const FileReference* file = ValueCast<FileReference>(config_value->value.get());
+ if (file != nullptr) {
+ if (file->file == nullptr) {
+ context->GetDiagnostics()->Warn(DiagMessage(apk->GetSource())
+ << "no file associated with " << *file);
+ return false;
+ }
+
+ if (file->type == ResourceFile::Type::kProtoXml) {
+ unique_ptr<io::InputStream> in = file->file->OpenInputStream();
+ if (in == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to open file " << *file->path);
+ return false;
+ }
+
+ pb::XmlNode pb_node;
+ io::ZeroCopyInputAdaptor adaptor(in.get());
+ if (!pb_node.ParseFromZeroCopyStream(&adaptor)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to parse proto XML " << *file->path);
+ return false;
+ }
+
+ std::string error;
+ unique_ptr<xml::XmlResource> xml = DeserializeXmlResourceFromPb(pb_node, &error);
+ if (xml == nullptr) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to deserialize proto XML "
+ << *file->path << ": " << error);
+ return false;
+ }
+
+ if (!FlattenXml(context, *xml, *file->path, false /*utf16*/, writer)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to serialize XML " << *file->path);
+ return false;
+ }
+ } else {
+ if (!io::CopyFileToArchive(context, file->file, *file->path,
+ file->file->WasCompressed() ? ArchiveEntry::kCompress : 0u,
+ writer)) {
+ context->GetDiagnostics()->Error(DiagMessage(apk->GetSource())
+ << "failed to copy file " << *file->path);
+ return false;
+ }
+ }
+
+ } // file
+ } // config_value
+ } // entry
+ } // type
+ } // package
+ return true;
+}
+
+class Context : public IAaptContext {
+ public:
+ Context() : mangler_({}), symbols_(&mangler_) {
+ }
+
+ PackageType GetPackageType() override {
+ return PackageType::kApp;
+ }
+
+ SymbolTable* GetExternalSymbols() override {
+ return &symbols_;
+ }
+
+ IDiagnostics* GetDiagnostics() override {
+ return &diag_;
+ }
+
+ const std::string& GetCompilationPackage() override {
+ return package_;
+ }
+
+ uint8_t GetPackageId() override {
+ // Nothing should call this.
+ UNIMPLEMENTED(FATAL) << "PackageID should not be necessary";
+ return 0;
+ }
+
+ NameMangler* GetNameMangler() override {
+ UNIMPLEMENTED(FATAL);
+ return nullptr;
+ }
+
+ bool IsVerbose() override {
+ return verbose_;
+ }
+
+ int GetMinSdkVersion() override {
+ return 0u;
+ }
+
+ bool verbose_ = false;
+ std::string package_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(Context);
+
+ NameMangler mangler_;
+ SymbolTable symbols_;
+ StdErrDiagnostics diag_;
+};
+
+int Convert(const vector<StringPiece>& args) {
+ Context context;
+ std::string output_path;
+ TableFlattenerOptions options;
+ Flags flags =
+ Flags()
+ .RequiredFlag("-o", "Output path", &output_path)
+ .OptionalSwitch("--enable-sparse-encoding",
+ "Enables encoding sparse entries using a binary search tree.\n"
+ "This decreases APK size at the cost of resource retrieval performance.",
+ &options.use_sparse_entries)
+ .OptionalSwitch("-v", "Enables verbose logging", &context.verbose_);
+ if (!flags.Parse("aapt2 convert", args, &std::cerr)) {
+ return 1;
+ }
+
+ if (flags.GetArgs().size() != 1) {
+ std::cerr << "must supply a single proto APK\n";
+ flags.Usage("aapt2 convert", &std::cerr);
+ return 1;
+ }
+
+ const StringPiece& path = flags.GetArgs()[0];
+ unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(path, context.GetDiagnostics());
+ if (apk == nullptr) {
+ context.GetDiagnostics()->Error(DiagMessage(path) << "failed to load APK");
+ return 1;
+ }
+
+ Maybe<AppInfo> app_info =
+ ExtractAppInfoFromBinaryManifest(*apk->GetManifest(), context.GetDiagnostics());
+ if (!app_info) {
+ return 1;
+ }
+
+ context.package_ = app_info.value().package;
+
+ unique_ptr<IArchiveWriter> writer =
+ CreateZipFileArchiveWriter(context.GetDiagnostics(), output_path);
+ if (writer == nullptr) {
+ return 1;
+ }
+ return ConvertProtoApkToBinaryApk(&context, std::move(apk), options, writer.get()) ? 0 : 1;
+}
+
+} // namespace aapt
diff --git a/tools/aapt2/cmd/Diff.cpp b/tools/aapt2/cmd/Diff.cpp
index 625c47c..fc1f1d6 100644
--- a/tools/aapt2/cmd/Diff.cpp
+++ b/tools/aapt2/cmd/Diff.cpp
@@ -357,8 +357,9 @@
return 1;
}
- std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[0]);
- std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(&context, flags.GetArgs()[1]);
+ IDiagnostics* diag = context.GetDiagnostics();
+ std::unique_ptr<LoadedApk> apk_a = LoadedApk::LoadApkFromPath(flags.GetArgs()[0], diag);
+ std::unique_ptr<LoadedApk> apk_b = LoadedApk::LoadApkFromPath(flags.GetArgs()[1], diag);
if (!apk_a || !apk_b) {
return 1;
}
diff --git a/tools/aapt2/cmd/Dump.cpp b/tools/aapt2/cmd/Dump.cpp
index 090c3fb..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;
@@ -78,11 +95,13 @@
return false;
}
- if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+ if (!DeserializeTableFromPb(pb_table, zip.get(), &table, &err)) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
<< "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) {
@@ -90,13 +109,16 @@
return false;
}
- BinaryResourceParser parser(context, &table, Source(file_path), data->data(), data->size());
+ BinaryResourceParser parser(context->GetDiagnostics(), &table, Source(file_path),
+ data->data(), data->size());
if (!parser.Parse()) {
return false;
}
+
+ printer.Println("Binary APK");
}
- Debug::PrintTable(table, print_options);
+ Debug::PrintTable(table, print_options, &printer);
return true;
}
@@ -117,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)
@@ -129,14 +154,17 @@
ResourceTable table;
err.clear();
- if (!DeserializeTableFromPb(pb_table, &table, &err)) {
+ if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &err)) {
context->GetDiagnostics()->Error(DiagMessage(file_path)
<< "failed to parse table: " << err);
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;
@@ -154,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/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index e0dae1b..b372923 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -29,6 +29,7 @@
#include "AppInfo.h"
#include "Debug.h"
#include "Flags.h"
+#include "LoadedApk.h"
#include "Locale.h"
#include "NameMangler.h"
#include "ResourceUtils.h"
@@ -39,7 +40,6 @@
#include "filter/ConfigFilter.h"
#include "format/Archive.h"
#include "format/Container.h"
-#include "format/binary/BinaryResourceParser.h"
#include "format/binary/TableFlattener.h"
#include "format/binary/XmlFlattener.h"
#include "format/proto/ProtoDeserialize.h"
@@ -71,9 +71,6 @@
namespace aapt {
-constexpr static const char kApkResourceTablePath[] = "resources.arsc";
-constexpr static const char kProtoResourceTablePath[] = "resources.pb";
-
enum class OutputFormat {
kApk,
kProto,
@@ -298,23 +295,6 @@
return false;
}
-static std::unique_ptr<ResourceTable> LoadTableFromPb(const Source& source, const void* data,
- size_t len, IDiagnostics* diag) {
- pb::ResourceTable pb_table;
- if (!pb_table.ParseFromArray(data, len)) {
- diag->Error(DiagMessage(source) << "invalid compiled table");
- return {};
- }
-
- std::unique_ptr<ResourceTable> table = util::make_unique<ResourceTable>();
- std::string error;
- if (!DeserializeTableFromPb(pb_table, table.get(), &error)) {
- diag->Error(DiagMessage(source) << "invalid compiled table: " << error);
- return {};
- }
- return table;
-}
-
// Inflates an XML file from the source path.
static std::unique_ptr<xml::XmlResource> LoadXml(const std::string& path, IDiagnostics* diag) {
FileInputStream fin(path);
@@ -587,7 +567,7 @@
pb::XmlNode pb_xml_node;
if (!pb_xml_node.ParseFromArray(data->data(), static_cast<int>(data->size()))) {
context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
- << "failed to parse proto xml");
+ << "failed to parse proto XML");
return false;
}
@@ -595,13 +575,15 @@
file_op.xml_to_flatten = DeserializeXmlResourceFromPb(pb_xml_node, &error);
if (file_op.xml_to_flatten == nullptr) {
context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
- << "failed to deserialize proto xml: " << error);
+ << "failed to deserialize proto XML: " << error);
return false;
}
} else {
- file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(),
- context_->GetDiagnostics(), file->GetSource());
+ std::string error_str;
+ file_op.xml_to_flatten = xml::Inflate(data->data(), data->size(), &error_str);
if (file_op.xml_to_flatten == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage(file->GetSource())
+ << "failed to parse binary XML: " << error_str);
return false;
}
}
@@ -748,22 +730,29 @@
file_collection_(util::make_unique<io::FileCollection>()) {
}
- /**
- * Creates a SymbolTable that loads symbols from the various APKs and caches
- * the results for faster lookup.
- */
+ // Creates a SymbolTable that loads symbols from the various APKs.
bool LoadSymbolsFromIncludePaths() {
- std::unique_ptr<AssetManagerSymbolSource> asset_source =
- util::make_unique<AssetManagerSymbolSource>();
+ auto asset_source = util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : options_.include_paths) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage() << "including " << path);
}
- // First try to load the file as a static lib.
- std::string error_str;
- std::unique_ptr<ResourceTable> include_static = LoadStaticLibrary(path, &error_str);
- if (include_static) {
+ std::string error;
+ auto zip_collection = io::ZipFileCollection::Create(path, &error);
+ if (zip_collection == nullptr) {
+ context_->GetDiagnostics()->Error(DiagMessage() << "failed to open APK: " << error);
+ return false;
+ }
+
+ if (zip_collection->FindFile(kProtoResourceTablePath) != nullptr) {
+ // Load this as a static library include.
+ std::unique_ptr<LoadedApk> static_apk = LoadedApk::LoadProtoApkFromFileCollection(
+ Source(path), std::move(zip_collection), context_->GetDiagnostics());
+ if (static_apk == nullptr) {
+ return false;
+ }
+
if (context_->GetPackageType() != PackageType::kStaticLib) {
// Can't include static libraries when not building a static library (they have no IDs
// assigned).
@@ -772,13 +761,15 @@
return false;
}
- // If we are using --no-static-lib-packages, we need to rename the
- // package of this table to our compilation package.
+ ResourceTable* table = static_apk->GetResourceTable();
+
+ // If we are using --no-static-lib-packages, we need to rename the package of this table to
+ // our compilation package.
if (options_.no_static_lib_packages) {
// Since package names can differ, and multiple packages can exist in a ResourceTable,
// we place the requirement that all static libraries are built with the package
// ID 0x7f. So if one is not found, this is an error.
- if (ResourceTablePackage* pkg = include_static->FindPackageById(kAppPackageId)) {
+ if (ResourceTablePackage* pkg = table->FindPackageById(kAppPackageId)) {
pkg->name = context_->GetCompilationPackage();
} else {
context_->GetDiagnostics()->Error(DiagMessage(path)
@@ -788,19 +779,14 @@
}
context_->GetExternalSymbols()->AppendSource(
- util::make_unique<ResourceTableSymbolSource>(include_static.get()));
-
- static_table_includes_.push_back(std::move(include_static));
-
- } else if (!error_str.empty()) {
- // We had an error with reading, so fail.
- context_->GetDiagnostics()->Error(DiagMessage(path) << error_str);
- return false;
- }
-
- if (!asset_source->AddAssetPath(path)) {
- context_->GetDiagnostics()->Error(DiagMessage(path) << "failed to load include path");
- return false;
+ util::make_unique<ResourceTableSymbolSource>(table));
+ static_library_includes_.push_back(std::move(static_apk));
+ } else {
+ if (!asset_source->AddAssetPath(path)) {
+ context_->GetDiagnostics()->Error(DiagMessage()
+ << "failed to load include path " << path);
+ return false;
+ }
}
}
@@ -1194,46 +1180,18 @@
return true;
}
- std::unique_ptr<ResourceTable> LoadStaticLibrary(const std::string& input,
- std::string* out_error) {
- std::unique_ptr<io::ZipFileCollection> collection =
- io::ZipFileCollection::Create(input, out_error);
- if (!collection) {
- return {};
- }
- return LoadTablePbFromCollection(collection.get());
- }
-
- std::unique_ptr<ResourceTable> LoadTablePbFromCollection(io::IFileCollection* collection) {
- io::IFile* file = collection->FindFile(kProtoResourceTablePath);
- if (!file) {
- return {};
- }
-
- std::unique_ptr<io::IData> data = file->OpenAsData();
- return LoadTableFromPb(file->GetSource(), data->data(), data->size(),
- context_->GetDiagnostics());
- }
-
bool MergeStaticLibrary(const std::string& input, bool override) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage() << "merging static library " << input);
}
- std::string error_str;
- std::unique_ptr<io::ZipFileCollection> collection =
- io::ZipFileCollection::Create(input, &error_str);
- if (!collection) {
- context_->GetDiagnostics()->Error(DiagMessage(input) << error_str);
- return false;
- }
-
- std::unique_ptr<ResourceTable> table = LoadTablePbFromCollection(collection.get());
- if (!table) {
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(input, context_->GetDiagnostics());
+ if (apk == nullptr) {
context_->GetDiagnostics()->Error(DiagMessage(input) << "invalid static library");
return false;
}
+ ResourceTable* table = apk->GetResourceTable();
ResourceTablePackage* pkg = table->FindPackageById(kAppPackageId);
if (!pkg) {
context_->GetDiagnostics()->Error(DiagMessage(input) << "static library has no package");
@@ -1254,13 +1212,12 @@
// Clear the package name, so as to make the resources look like they are coming from the
// local package.
pkg->name = "";
- result = table_merger_->Merge(Source(input), table.get(), override, collection.get());
+ result = table_merger_->Merge(Source(input), table, override);
} else {
// This is the proper way to merge libraries, where the package name is
// preserved and resource names are mangled.
- result =
- table_merger_->MergeAndMangle(Source(input), pkg->name, table.get(), collection.get());
+ result = table_merger_->MergeAndMangle(Source(input), pkg->name, table);
}
if (!result) {
@@ -1268,31 +1225,10 @@
}
// Make sure to move the collection into the set of IFileCollections.
- collections_.push_back(std::move(collection));
+ merged_apks_.push_back(std::move(apk));
return true;
}
- bool MergeResourceTable(io::IFile* file, bool override) {
- if (context_->IsVerbose()) {
- context_->GetDiagnostics()->Note(DiagMessage() << "merging resource table "
- << file->GetSource());
- }
-
- std::unique_ptr<io::IData> data = file->OpenAsData();
- if (!data) {
- context_->GetDiagnostics()->Error(DiagMessage(file->GetSource()) << "failed to open file");
- return false;
- }
-
- std::unique_ptr<ResourceTable> table =
- LoadTableFromPb(file->GetSource(), data->data(), data->size(), context_->GetDiagnostics());
- if (!table) {
- return false;
- }
-
- return table_merger_->Merge(file->GetSource(), table.get(), override);
- }
-
bool MergeCompiledFile(const ResourceFile& compiled_file, io::IFile* file, bool override) {
if (context_->IsVerbose()) {
context_->GetDiagnostics()->Note(DiagMessage()
@@ -1423,7 +1359,7 @@
ResourceTable table;
std::string error;
- if (!DeserializeTableFromPb(pb_table, &table, &error)) {
+ if (!DeserializeTableFromPb(pb_table, nullptr /*files*/, &table, &error)) {
context_->GetDiagnostics()->Error(DiagMessage(src)
<< "failed to deserialize resource table: " << error);
return false;
@@ -1868,13 +1804,15 @@
// A pointer to the FileCollection representing the filesystem (not archives).
std::unique_ptr<io::FileCollection> file_collection_;
- // A vector of IFileCollections. This is mainly here to keep ownership of the
+ // A vector of IFileCollections. This is mainly here to retain ownership of the
// collections.
std::vector<std::unique_ptr<io::IFileCollection>> collections_;
- // A vector of ResourceTables. This is here to retain ownership, so that the
- // SymbolTable can use these.
- std::vector<std::unique_ptr<ResourceTable>> static_table_includes_;
+ // The set of merged APKs. This is mainly here to retain ownership of the APKs.
+ std::vector<std::unique_ptr<LoadedApk>> merged_apks_;
+
+ // The set of included APKs (not merged). This is mainly here to retain ownership of the APKs.
+ std::vector<std::unique_ptr<LoadedApk>> static_library_includes_;
// The set of shared libraries being used, mapping their assigned package ID to package name.
std::map<size_t, std::string> shared_libs_;
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 44e148e..688b6a7 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -281,15 +281,14 @@
OptimizeContext* context_;
};
-bool ExtractAppDataFromManifest(OptimizeContext* context, LoadedApk* apk,
+bool ExtractAppDataFromManifest(OptimizeContext* context, const LoadedApk* apk,
OptimizeOptions* out_options) {
- std::unique_ptr<xml::XmlResource> manifest = apk->InflateManifest(context);
+ const xml::XmlResource* manifest = apk->GetManifest();
if (manifest == nullptr) {
return false;
}
- Maybe<AppInfo> app_info =
- ExtractAppInfoFromBinaryManifest(manifest.get(), context->GetDiagnostics());
+ Maybe<AppInfo> app_info = ExtractAppInfoFromBinaryManifest(*manifest, context->GetDiagnostics());
if (!app_info) {
context->GetDiagnostics()->Error(DiagMessage()
<< "failed to extract data from AndroidManifest.xml");
@@ -355,7 +354,7 @@
}
const std::string& apk_path = flags.GetArgs()[0];
- std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(&context, apk_path);
+ std::unique_ptr<LoadedApk> apk = LoadedApk::LoadApkFromPath(apk_path, context.GetDiagnostics());
if (!apk) {
return 1;
}
diff --git a/tools/aapt2/cmd/Util.cpp b/tools/aapt2/cmd/Util.cpp
index 708bed8..d39f43e8 100644
--- a/tools/aapt2/cmd/Util.cpp
+++ b/tools/aapt2/cmd/Util.cpp
@@ -214,9 +214,10 @@
return doc;
}
-static Maybe<std::string> ExtractCompiledString(xml::Attribute* attr, std::string* out_error) {
- if (attr->compiled_value != nullptr) {
- String* compiled_str = ValueCast<String>(attr->compiled_value.get());
+static Maybe<std::string> ExtractCompiledString(const xml::Attribute& attr,
+ std::string* out_error) {
+ if (attr.compiled_value != nullptr) {
+ const String* compiled_str = ValueCast<String>(attr.compiled_value.get());
if (compiled_str != nullptr) {
if (!compiled_str->value->empty()) {
return *compiled_str->value;
@@ -230,16 +231,16 @@
}
// Fallback to the plain text value if there is one.
- if (!attr->value.empty()) {
- return attr->value;
+ if (!attr.value.empty()) {
+ return attr.value;
}
*out_error = "value is an empty string";
return {};
}
-static Maybe<uint32_t> ExtractCompiledInt(xml::Attribute* attr, std::string* out_error) {
- if (attr->compiled_value != nullptr) {
- BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get());
+static Maybe<uint32_t> ExtractCompiledInt(const xml::Attribute& attr, std::string* out_error) {
+ if (attr.compiled_value != nullptr) {
+ const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get());
if (compiled_prim != nullptr) {
if (compiled_prim->value.dataType >= android::Res_value::TYPE_FIRST_INT &&
compiled_prim->value.dataType <= android::Res_value::TYPE_LAST_INT) {
@@ -251,19 +252,19 @@
}
// Fallback to the plain text value if there is one.
- Maybe<uint32_t> integer = ResourceUtils::ParseInt(attr->value);
+ Maybe<uint32_t> integer = ResourceUtils::ParseInt(attr.value);
if (integer) {
return integer;
}
std::stringstream error_msg;
- error_msg << "'" << attr->value << "' is not a valid integer";
+ error_msg << "'" << attr.value << "' is not a valid integer";
*out_error = error_msg.str();
return {};
}
-static Maybe<int> ExtractSdkVersion(xml::Attribute* attr, std::string* out_error) {
- if (attr->compiled_value != nullptr) {
- BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get());
+static Maybe<int> ExtractSdkVersion(const xml::Attribute& attr, std::string* out_error) {
+ if (attr.compiled_value != nullptr) {
+ const BinaryPrimitive* compiled_prim = ValueCast<BinaryPrimitive>(attr.compiled_value.get());
if (compiled_prim != nullptr) {
if (compiled_prim->value.dataType >= android::Res_value::TYPE_FIRST_INT &&
compiled_prim->value.dataType <= android::Res_value::TYPE_LAST_INT) {
@@ -273,7 +274,7 @@
return {};
}
- String* compiled_str = ValueCast<String>(attr->compiled_value.get());
+ const String* compiled_str = ValueCast<String>(attr.compiled_value.get());
if (compiled_str != nullptr) {
Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(*compiled_str->value);
if (sdk_version) {
@@ -288,19 +289,20 @@
}
// Fallback to the plain text value if there is one.
- Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(attr->value);
+ Maybe<int> sdk_version = ResourceUtils::ParseSdkVersion(attr.value);
if (sdk_version) {
return sdk_version;
}
std::stringstream error_msg;
- error_msg << "'" << attr->value << "' is not a valid SDK version";
+ error_msg << "'" << attr.value << "' is not a valid SDK version";
*out_error = error_msg.str();
return {};
}
-Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag) {
+Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
+ IDiagnostics* diag) {
// Make sure the first element is <manifest> with package attribute.
- xml::Element* manifest_el = xml_res->root.get();
+ const xml::Element* manifest_el = xml_res.root.get();
if (manifest_el == nullptr) {
return {};
}
@@ -308,63 +310,63 @@
AppInfo app_info;
if (!manifest_el->namespace_uri.empty() || manifest_el->name != "manifest") {
- diag->Error(DiagMessage(xml_res->file.source) << "root tag must be <manifest>");
+ diag->Error(DiagMessage(xml_res.file.source) << "root tag must be <manifest>");
return {};
}
- xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
+ const xml::Attribute* package_attr = manifest_el->FindAttribute({}, "package");
if (!package_attr) {
- diag->Error(DiagMessage(xml_res->file.source) << "<manifest> must have a 'package' attribute");
+ diag->Error(DiagMessage(xml_res.file.source) << "<manifest> must have a 'package' attribute");
return {};
}
std::string error_msg;
- Maybe<std::string> maybe_package = ExtractCompiledString(package_attr, &error_msg);
+ Maybe<std::string> maybe_package = ExtractCompiledString(*package_attr, &error_msg);
if (!maybe_package) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid package name: " << error_msg);
return {};
}
app_info.package = maybe_package.value();
- if (xml::Attribute* version_code_attr =
+ if (const xml::Attribute* version_code_attr =
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode")) {
- Maybe<uint32_t> maybe_code = ExtractCompiledInt(version_code_attr, &error_msg);
+ Maybe<uint32_t> maybe_code = ExtractCompiledInt(*version_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:versionCode: " << error_msg);
return {};
}
app_info.version_code = maybe_code.value();
}
- if (xml::Attribute* revision_code_attr =
+ if (const xml::Attribute* revision_code_attr =
manifest_el->FindAttribute(xml::kSchemaAndroid, "revisionCode")) {
- Maybe<uint32_t> maybe_code = ExtractCompiledInt(revision_code_attr, &error_msg);
+ Maybe<uint32_t> maybe_code = ExtractCompiledInt(*revision_code_attr, &error_msg);
if (!maybe_code) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid android:revisionCode: " << error_msg);
return {};
}
app_info.revision_code = maybe_code.value();
}
- if (xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
- Maybe<std::string> maybe_split_name = ExtractCompiledString(split_name_attr, &error_msg);
+ if (const xml::Attribute* split_name_attr = manifest_el->FindAttribute({}, "split")) {
+ Maybe<std::string> maybe_split_name = ExtractCompiledString(*split_name_attr, &error_msg);
if (!maybe_split_name) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(manifest_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(manifest_el->line_number))
<< "invalid split name: " << error_msg);
return {};
}
app_info.split_name = maybe_split_name.value();
}
- if (xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
- if (xml::Attribute* min_sdk =
+ if (const xml::Element* uses_sdk_el = manifest_el->FindChild({}, "uses-sdk")) {
+ if (const xml::Attribute* min_sdk =
uses_sdk_el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion")) {
- Maybe<int> maybe_sdk = ExtractSdkVersion(min_sdk, &error_msg);
+ Maybe<int> maybe_sdk = ExtractSdkVersion(*min_sdk, &error_msg);
if (!maybe_sdk) {
- diag->Error(DiagMessage(xml_res->file.source.WithLine(uses_sdk_el->line_number))
+ diag->Error(DiagMessage(xml_res.file.source.WithLine(uses_sdk_el->line_number))
<< "invalid android:minSdkVersion: " << error_msg);
return {};
}
diff --git a/tools/aapt2/cmd/Util.h b/tools/aapt2/cmd/Util.h
index fd9b39c..7611c15 100644
--- a/tools/aapt2/cmd/Util.h
+++ b/tools/aapt2/cmd/Util.h
@@ -57,7 +57,8 @@
const SplitConstraints& constraints);
// Extracts relevant info from the AndroidManifest.xml.
-Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(xml::XmlResource* xml_res, IDiagnostics* diag);
+Maybe<AppInfo> ExtractAppInfoFromBinaryManifest(const xml::XmlResource& xml_res,
+ IDiagnostics* diag);
} // namespace aapt
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/configuration/ConfigurationParser_test.cpp b/tools/aapt2/configuration/ConfigurationParser_test.cpp
index 3654901..afa155f 100644
--- a/tools/aapt2/configuration/ConfigurationParser_test.cpp
+++ b/tools/aapt2/configuration/ConfigurationParser_test.cpp
@@ -423,11 +423,11 @@
TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
static constexpr const char* xml = R"xml(
- <android-sdk-group label="O">
+ <android-sdk-group label="P">
<android-sdk
minSdkVersion="M"
- targetSdkVersion="O"
- maxSdkVersion="O">
+ targetSdkVersion="P"
+ maxSdkVersion="P">
</android-sdk>
</android-sdk-group>)xml";
@@ -438,14 +438,14 @@
ASSERT_TRUE(ok);
ASSERT_EQ(1ul, config.android_sdk_groups.size());
- ASSERT_EQ(1u, config.android_sdk_groups.count("O"));
+ ASSERT_EQ(1u, config.android_sdk_groups.count("P"));
- auto& out = config.android_sdk_groups["O"];
+ auto& out = config.android_sdk_groups["P"];
AndroidSdk sdk;
sdk.min_sdk_version = {}; // Only the latest development version is supported.
- sdk.target_sdk_version = 26;
- sdk.max_sdk_version = 26;
+ sdk.target_sdk_version = 28;
+ sdk.max_sdk_version = 28;
ASSERT_EQ(sdk, out);
}
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp
index 95eec4a..5078678 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.cpp
+++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp
@@ -73,29 +73,22 @@
} // namespace
-BinaryResourceParser::BinaryResourceParser(IAaptContext* context, ResourceTable* table,
+BinaryResourceParser::BinaryResourceParser(IDiagnostics* diag, ResourceTable* table,
const Source& source, const void* data, size_t len,
io::IFileCollection* files)
- : context_(context),
- table_(table),
- source_(source),
- data_(data),
- data_len_(len),
- files_(files) {
+ : diag_(diag), table_(table), source_(source), data_(data), data_len_(len), files_(files) {
}
bool BinaryResourceParser::Parse() {
ResChunkPullParser parser(data_, data_len_);
if (!ResChunkPullParser::IsGoodEvent(parser.Next())) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt resources.arsc: " << parser.error());
+ diag_->Error(DiagMessage(source_) << "corrupt resources.arsc: " << parser.error());
return false;
}
if (parser.chunk()->type != android::RES_TABLE_TYPE) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << StringPrintf("unknown chunk of type 0x%02x",
+ diag_->Error(DiagMessage(source_) << StringPrintf("unknown chunk of type 0x%02x",
static_cast<int>(parser.chunk()->type)));
return false;
}
@@ -106,13 +99,12 @@
if (parser.Next() != ResChunkPullParser::Event::kEndDocument) {
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
+ diag_->Warn(DiagMessage(source_)
+ << "invalid chunk trailing RES_TABLE_TYPE: " << parser.error());
} else {
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << StringPrintf(
- "unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
- static_cast<int>(parser.chunk()->type)));
+ diag_->Warn(DiagMessage(source_)
+ << StringPrintf("unexpected chunk of type 0x%02x trailing RES_TABLE_TYPE",
+ static_cast<int>(parser.chunk()->type)));
}
}
return true;
@@ -122,7 +114,7 @@
bool BinaryResourceParser::ParseTable(const ResChunk_header* chunk) {
const ResTable_header* table_header = ConvertTo<ResTable_header>(chunk);
if (!table_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_header chunk");
return false;
}
@@ -135,17 +127,15 @@
status_t err =
value_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt string pool in ResTable: "
- << value_pool_.getError());
+ diag_->Error(DiagMessage(source_)
+ << "corrupt string pool in ResTable: " << value_pool_.getError());
return false;
}
// Reserve some space for the strings we are going to add.
table_->string_pool.HintWillAdd(value_pool_.size(), value_pool_.styleCount());
} else {
- context_->GetDiagnostics()->Warn(DiagMessage(source_)
- << "unexpected string pool in ResTable");
+ diag_->Warn(DiagMessage(source_) << "unexpected string pool in ResTable");
}
break;
@@ -156,16 +146,15 @@
break;
default:
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ diag_->Warn(DiagMessage(source_)
+ << "unexpected chunk type "
+ << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt resource table: " << parser.error());
+ diag_->Error(DiagMessage(source_) << "corrupt resource table: " << parser.error());
return false;
}
return true;
@@ -176,14 +165,13 @@
sizeof(ResTable_package) - sizeof(ResTable_package::typeIdOffset);
const ResTable_package* package_header = ConvertTo<ResTable_package, kMinPackageSize>(chunk);
if (!package_header) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_package chunk");
return false;
}
uint32_t package_id = util::DeviceToHost32(package_header->id);
if (package_id > std::numeric_limits<uint8_t>::max()) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "package ID is too big (" << package_id << ")");
+ diag_->Error(DiagMessage(source_) << "package ID is too big (" << package_id << ")");
return false;
}
@@ -198,9 +186,8 @@
ResourceTablePackage* package =
table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id));
if (!package) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "incompatible package '" << package_name << "' with ID "
- << package_id);
+ diag_->Error(DiagMessage(source_)
+ << "incompatible package '" << package_name << "' with ID " << package_id);
return false;
}
@@ -218,8 +205,7 @@
status_t err =
type_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt type string pool in "
+ diag_->Error(DiagMessage(source_) << "corrupt type string pool in "
<< "ResTable_package: " << type_pool_.getError());
return false;
}
@@ -227,13 +213,12 @@
status_t err =
key_pool_.setTo(parser.chunk(), util::DeviceToHost32(parser.chunk()->size));
if (err != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt key string pool in "
+ diag_->Error(DiagMessage(source_) << "corrupt key string pool in "
<< "ResTable_package: " << key_pool_.getError());
return false;
}
} else {
- context_->GetDiagnostics()->Warn(DiagMessage(source_) << "unexpected string pool");
+ diag_->Warn(DiagMessage(source_) << "unexpected string pool");
}
break;
@@ -256,16 +241,15 @@
break;
default:
- context_->GetDiagnostics()->Warn(
- DiagMessage(source_) << "unexpected chunk type "
- << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
+ diag_->Warn(DiagMessage(source_)
+ << "unexpected chunk type "
+ << static_cast<int>(util::DeviceToHost16(parser.chunk()->type)));
break;
}
}
if (parser.event() == ResChunkPullParser::Event::kBadDocument) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "corrupt ResTable_package: " << parser.error());
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_package: " << parser.error());
return false;
}
@@ -278,19 +262,18 @@
bool BinaryResourceParser::ParseTypeSpec(const ResChunk_header* chunk) {
if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(DiagMessage(source_) << "missing type string pool");
return false;
}
const ResTable_typeSpec* type_spec = ConvertTo<ResTable_typeSpec>(chunk);
if (!type_spec) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_typeSpec chunk");
return false;
}
if (type_spec->id == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_typeSpec has invalid id: " << type_spec->id);
+ diag_->Error(DiagMessage(source_) << "ResTable_typeSpec has invalid id: " << type_spec->id);
return false;
}
return true;
@@ -299,12 +282,12 @@
bool BinaryResourceParser::ParseType(const ResourceTablePackage* package,
const ResChunk_header* chunk) {
if (type_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing type string pool");
+ diag_->Error(DiagMessage(source_) << "missing type string pool");
return false;
}
if (key_pool_.getError() != NO_ERROR) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "missing key string pool");
+ diag_->Error(DiagMessage(source_) << "missing key string pool");
return false;
}
@@ -312,13 +295,12 @@
// a lot and has its own code to handle variable size.
const ResTable_type* type = ConvertTo<ResTable_type, kResTableTypeMinSize>(chunk);
if (!type) {
- context_->GetDiagnostics()->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
+ diag_->Error(DiagMessage(source_) << "corrupt ResTable_type chunk");
return false;
}
if (type->id == 0) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "ResTable_type has invalid id: " << (int)type->id);
+ diag_->Error(DiagMessage(source_) << "ResTable_type has invalid id: " << (int)type->id);
return false;
}
@@ -329,9 +311,8 @@
const ResourceType* parsed_type = ParseResourceType(type_str);
if (!parsed_type) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "invalid type name '" << type_str << "' for type with ID "
- << (int)type->id);
+ diag_->Error(DiagMessage(source_)
+ << "invalid type name '" << type_str << "' for type with ID " << (int)type->id);
return false;
}
@@ -360,14 +341,13 @@
}
if (!resource_value) {
- context_->GetDiagnostics()->Error(DiagMessage(source_)
- << "failed to parse value for resource " << name << " ("
+ diag_->Error(DiagMessage(source_) << "failed to parse value for resource " << name << " ("
<< res_id << ") with configuration '" << config << "'");
return false;
}
if (!table_->AddResourceAllowMangled(name, res_id, config, {}, std::move(resource_value),
- context_->GetDiagnostics())) {
+ diag_)) {
return false;
}
@@ -375,7 +355,7 @@
Symbol symbol;
symbol.state = SymbolState::kPublic;
symbol.source = source_.WithLine(0);
- if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, context_->GetDiagnostics())) {
+ if (!table_->SetSymbolStateAllowMangled(name, res_id, symbol, diag_)) {
return false;
}
}
@@ -410,15 +390,14 @@
const android::Res_value& value) {
std::unique_ptr<Item> item = ResourceUtils::ParseBinaryResValue(name.type, config, value_pool_,
value, &table_->string_pool);
- if (files_ != nullptr && item != nullptr) {
+ if (files_ != nullptr) {
FileReference* file_ref = ValueCast<FileReference>(item.get());
if (file_ref != nullptr) {
file_ref->file = files_->FindFile(*file_ref->path);
if (file_ref->file == nullptr) {
- context_->GetDiagnostics()->Warn(DiagMessage()
- << "resource " << name << " for config '" << config
- << "' is a file reference to '" << *file_ref->path
- << "' but no such path exists");
+ diag_->Warn(DiagMessage() << "resource " << name << " for config '" << config
+ << "' is a file reference to '" << *file_ref->path
+ << "' but no such path exists");
}
}
}
@@ -432,7 +411,7 @@
case ResourceType::kStyle:
return ParseStyle(name, config, map);
case ResourceType::kAttrPrivate:
- // fallthrough
+ // fallthrough
case ResourceType::kAttr:
return ParseAttr(name, config, map);
case ResourceType::kArray:
@@ -445,8 +424,8 @@
// We can ignore the value here.
return util::make_unique<Id>();
default:
- context_->GetDiagnostics()->Error(DiagMessage() << "illegal map type '" << ToString(name.type)
- << "' (" << (int)name.type << ")");
+ diag_->Error(DiagMessage() << "illegal map type '" << to_string(name.type) << "' ("
+ << (int)name.type << ")");
break;
}
return {};
diff --git a/tools/aapt2/format/binary/BinaryResourceParser.h b/tools/aapt2/format/binary/BinaryResourceParser.h
index dc9a384..052f806 100644
--- a/tools/aapt2/format/binary/BinaryResourceParser.h
+++ b/tools/aapt2/format/binary/BinaryResourceParser.h
@@ -39,7 +39,7 @@
public:
// Creates a parser, which will read `len` bytes from `data`, and add any resources parsed to
// `table`. `source` is for logging purposes.
- BinaryResourceParser(IAaptContext* context, ResourceTable* table, const Source& source,
+ BinaryResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source,
const void* data, size_t data_len, io::IFileCollection* files = nullptr);
// Parses the binary resource table and returns true if successful.
@@ -80,7 +80,7 @@
*/
bool CollectMetaData(const android::ResTable_map& map_entry, Value* value);
- IAaptContext* context_;
+ IDiagnostics* diag_;
ResourceTable* table_;
const Source source_;
diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp
index 57565a5..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()) {
@@ -568,14 +568,6 @@
ResTable_header* table_header = table_writer.StartChunk<ResTable_header>(RES_TABLE_TYPE);
table_header->packageCount = util::HostToDevice32(table->packages.size());
- // Write a self mapping entry for this package if the ID is non-standard (0x7f).
- if (context->GetPackageType() == PackageType::kApp) {
- const uint8_t package_id = context->GetPackageId();
- if (package_id != kFrameworkPackageId && package_id != kAppPackageId) {
- table->included_packages_[package_id] = context->GetCompilationPackage();
- }
- }
-
// Flatten the values string pool.
StringPool::FlattenUtf8(table_writer.buffer(), table->string_pool);
@@ -583,6 +575,14 @@
// Flatten each package.
for (auto& package : table->packages) {
+ if (context->GetPackageType() == PackageType::kApp) {
+ // Write a self mapping entry for this package if the ID is non-standard (0x7f).
+ const uint8_t package_id = package->id.value();
+ if (package_id != kFrameworkPackageId && package_id != kAppPackageId) {
+ table->included_packages_[package_id] = package->name;
+ }
+ }
+
PackageFlattener flattener(context, package.get(), &table->included_packages_,
options_.use_sparse_entries);
if (!flattener.FlattenPackage(&package_buffer)) {
diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp
index 6d75973..e11890b 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -71,7 +71,8 @@
return result;
}
- BinaryResourceParser parser(context, out_table, {}, content.data(), content.size());
+ BinaryResourceParser parser(context->GetDiagnostics(), out_table, {}, content.data(),
+ content.size());
if (!parser.Parse()) {
return ::testing::AssertionFailure() << "flattened ResTable is corrupt";
}
@@ -278,7 +279,7 @@
// Attempt to parse the sparse contents.
ResourceTable sparse_table;
- BinaryResourceParser parser(context.get(), &sparse_table, Source("test.arsc"),
+ BinaryResourceParser parser(context->GetDiagnostics(), &sparse_table, Source("test.arsc"),
sparse_contents.data(), sparse_contents.size());
ASSERT_TRUE(parser.Parse());
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp
index 86bd865..0f0bce8 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -371,7 +371,8 @@
}
static bool DeserializePackageFromPb(const pb::Package& pb_package, const ResStringPool& src_pool,
- ResourceTable* out_table, std::string* out_error) {
+ io::IFileCollection* files, ResourceTable* out_table,
+ std::string* out_error) {
Maybe<uint8_t> id;
if (pb_package.has_package_id()) {
id = static_cast<uint8_t>(pb_package.package_id().id());
@@ -444,7 +445,7 @@
}
config_value->value = DeserializeValueFromPb(pb_config_value.value(), src_pool, config,
- &out_table->string_pool, out_error);
+ &out_table->string_pool, files, out_error);
if (config_value->value == nullptr) {
return false;
}
@@ -457,8 +458,8 @@
return true;
}
-bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
- std::string* out_error) {
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollection* files,
+ ResourceTable* out_table, std::string* out_error) {
// We import the android namespace because on Windows NO_ERROR is a macro, not an enum, which
// causes errors when qualifying it with android::
using namespace android;
@@ -474,7 +475,7 @@
}
for (const pb::Package& pb_package : pb_table.package()) {
- if (!DeserializePackageFromPb(pb_package, source_pool, out_table, out_error)) {
+ if (!DeserializePackageFromPb(pb_package, source_pool, files, out_table, out_error)) {
return false;
}
}
@@ -600,10 +601,11 @@
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const ConfigDescription& config,
- StringPool* value_pool, std::string* out_error) {
+ StringPool* value_pool, io::IFileCollection* files,
+ std::string* out_error) {
std::unique_ptr<Value> value;
if (pb_value.has_item()) {
- value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, out_error);
+ value = DeserializeItemFromPb(pb_value.item(), src_pool, config, value_pool, files, out_error);
if (value == nullptr) {
return {};
}
@@ -651,8 +653,8 @@
return {};
}
DeserializeItemMetaDataFromPb(pb_entry, src_pool, &entry.key);
- entry.value =
- DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ entry.value = DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, files,
+ out_error);
if (entry.value == nullptr) {
return {};
}
@@ -680,8 +682,8 @@
const pb::Array& pb_array = pb_compound_value.array();
std::unique_ptr<Array> array = util::make_unique<Array>();
for (const pb::Array_Element& pb_entry : pb_array.element()) {
- std::unique_ptr<Item> item =
- DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ std::unique_ptr<Item> item = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
+ value_pool, files, out_error);
if (item == nullptr) {
return {};
}
@@ -697,8 +699,8 @@
std::unique_ptr<Plural> plural = util::make_unique<Plural>();
for (const pb::Plural_Entry& pb_entry : pb_plural.entry()) {
size_t plural_idx = DeserializePluralEnumFromPb(pb_entry.arity());
- plural->values[plural_idx] =
- DeserializeItemFromPb(pb_entry.item(), src_pool, config, value_pool, out_error);
+ plural->values[plural_idx] = DeserializeItemFromPb(pb_entry.item(), src_pool, config,
+ value_pool, files, out_error);
if (!plural->values[plural_idx]) {
return {};
}
@@ -727,7 +729,7 @@
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
const ConfigDescription& config, StringPool* value_pool,
- std::string* out_error) {
+ io::IFileCollection* files, std::string* out_error) {
switch (pb_item.value_case()) {
case pb::Item::kRef: {
const pb::Reference& pb_ref = pb_item.ref();
@@ -774,6 +776,9 @@
util::make_unique<FileReference>(value_pool->MakeRef(
pb_file.path(), StringPool::Context(StringPool::Context::kHighPriority, config)));
file_ref->type = DeserializeFileReferenceTypeFromPb(pb_file.type());
+ if (files != nullptr) {
+ file_ref->file = files->FindFile(*file_ref->path);
+ }
return std::move(file_ref);
} break;
@@ -825,7 +830,7 @@
}
if (pb_attr.has_compiled_item()) {
attr.compiled_value =
- DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, out_error);
+ DeserializeItemFromPb(pb_attr.compiled_item(), {}, {}, value_pool, nullptr, out_error);
if (attr.compiled_value == nullptr) {
return {};
}
diff --git a/tools/aapt2/format/proto/ProtoDeserialize.h b/tools/aapt2/format/proto/ProtoDeserialize.h
index 7dc54f2..0c581a1 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.h
+++ b/tools/aapt2/format/proto/ProtoDeserialize.h
@@ -27,6 +27,7 @@
#include "Resources.pb.h"
#include "ResourcesInternal.pb.h"
#include "StringPool.h"
+#include "io/File.h"
#include "xml/XmlDom.h"
namespace aapt {
@@ -34,12 +35,13 @@
std::unique_ptr<Value> DeserializeValueFromPb(const pb::Value& pb_value,
const android::ResStringPool& src_pool,
const ConfigDescription& config,
- StringPool* value_pool, std::string* out_error);
+ StringPool* value_pool, io::IFileCollection* files,
+ std::string* out_error);
std::unique_ptr<Item> DeserializeItemFromPb(const pb::Item& pb_item,
const android::ResStringPool& src_pool,
const ConfigDescription& config, StringPool* value_pool,
- std::string* out_error);
+ io::IFileCollection* files, std::string* out_error);
std::unique_ptr<xml::XmlResource> DeserializeXmlResourceFromPb(const pb::XmlNode& pb_node,
std::string* out_error);
@@ -50,8 +52,9 @@
bool DeserializeConfigFromPb(const pb::Configuration& pb_config, ConfigDescription* out_config,
std::string* out_error);
-bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, ResourceTable* out_table,
- std::string* out_error);
+// Optional io::IFileCollection used to lookup references to files in the ResourceTable.
+bool DeserializeTableFromPb(const pb::ResourceTable& pb_table, io::IFileCollection* files,
+ ResourceTable* out_table, std::string* out_error);
bool DeserializeCompiledFileFromPb(const pb::internal::CompiledFile& pb_file,
ResourceFile* out_file, std::string* out_error);
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/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
index 8efac8a..9649a4d 100644
--- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp
@@ -29,6 +29,12 @@
namespace aapt {
+class MockFileCollection : public io::IFileCollection {
+ public:
+ MOCK_METHOD1(FindFile, io::IFile*(const StringPiece& path));
+ MOCK_METHOD0(Iterator, std::unique_ptr<io::IFileCollectionIterator>());
+};
+
TEST(ProtoSerializeTest, SerializeSinglePackage) {
std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build();
std::unique_ptr<ResourceTable> table =
@@ -86,9 +92,14 @@
pb::ResourceTable pb_table;
SerializeTableToPb(*table, &pb_table);
+ test::TestFile file_a("res/layout/main.xml");
+ MockFileCollection files;
+ EXPECT_CALL(files, FindFile(Eq("res/layout/main.xml")))
+ .WillRepeatedly(::testing::Return(&file_a));
+
ResourceTable new_table;
std::string error;
- ASSERT_TRUE(DeserializeTableFromPb(pb_table, &new_table, &error));
+ ASSERT_TRUE(DeserializeTableFromPb(pb_table, &files, &new_table, &error));
EXPECT_THAT(error, IsEmpty());
Id* new_id = test::GetValue<Id>(&new_table, "com.app.a:id/foo");
@@ -124,6 +135,11 @@
ASSERT_TRUE(actual_ref->id);
EXPECT_THAT(*actual_ref, Eq(expected_ref));
+ FileReference* actual_file_ref =
+ test::GetValue<FileReference>(&new_table, "com.app.a:layout/main");
+ ASSERT_THAT(actual_file_ref, NotNull());
+ EXPECT_THAT(actual_file_ref->file, Eq(&file_a));
+
StyledString* actual_styled_str =
test::GetValue<StyledString>(&new_table, "com.app.a:string/styled");
ASSERT_THAT(actual_styled_str, NotNull());
diff --git a/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
index 6ed07b0..94686c0 100644
--- a/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
+++ b/tools/aapt2/integration-tests/NamespaceTest/App/Android.mk
@@ -25,5 +25,4 @@
LOCAL_STATIC_ANDROID_LIBRARIES := \
AaptTestNamespace_LibOne \
AaptTestNamespace_LibTwo
-LOCAL_AAPT_FLAGS := -v
include $(BUILD_PACKAGE)
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/link/TableMerger.cpp b/tools/aapt2/link/TableMerger.cpp
index 21c6b11..58d0607 100644
--- a/tools/aapt2/link/TableMerger.cpp
+++ b/tools/aapt2/link/TableMerger.cpp
@@ -37,17 +37,14 @@
CHECK(master_package_ != nullptr) << "package name or ID already taken";
}
-bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay,
- io::IFileCollection* collection) {
+bool TableMerger::Merge(const Source& src, ResourceTable* table, bool overlay) {
// We allow adding new resources if this is not an overlay, or if the options allow overlays
// to add new resources.
- return MergeImpl(src, table, collection, overlay,
- options_.auto_add_overlay || !overlay /*allow_new*/);
+ return MergeImpl(src, table, overlay, options_.auto_add_overlay || !overlay /*allow_new*/);
}
// This will merge packages with the same package name (or no package name).
-bool TableMerger::MergeImpl(const Source& src, ResourceTable* table,
- io::IFileCollection* collection, bool overlay, bool allow_new) {
+bool TableMerger::MergeImpl(const Source& src, ResourceTable* table, bool overlay, bool allow_new) {
bool error = false;
for (auto& package : table->packages) {
// Only merge an empty package or the package we're building.
@@ -55,37 +52,20 @@
// This is because at compile time it is unknown if the attributes are
// simply uses of the attribute or definitions.
if (package->name.empty() || context_->GetCompilationPackage() == package->name) {
- FileMergeCallback callback;
- if (collection) {
- callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
- FileReference* new_file, FileReference* old_file) -> bool {
- // The old file's path points inside the APK, so we can use it as is.
- io::IFile* f = collection->FindFile(*old_file->path);
- if (!f) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
- << "file '" << *old_file->path << "' not found");
- return false;
- }
-
- new_file->file = f;
- return true;
- };
- }
-
// Merge here. Once the entries are merged and mangled, any references to them are still
// valid. This is because un-mangled references are mangled, then looked up at resolution
// time. Also, when linking, we convert references with no package name to use the compilation
// package name.
- error |=
- !DoMerge(src, table, package.get(), false /* mangle */, overlay, allow_new, callback);
+ error |= !DoMerge(src, table, package.get(), false /*mangle*/, overlay, allow_new);
}
}
return !error;
}
-// This will merge and mangle resources from a static library.
+// This will merge and mangle resources from a static library. It is assumed that all FileReferences
+// have correctly set their io::IFile*.
bool TableMerger::MergeAndMangle(const Source& src, const StringPiece& package_name,
- ResourceTable* table, io::IFileCollection* collection) {
+ ResourceTable* table) {
bool error = false;
for (auto& package : table->packages) {
// Warn of packages with an unrelated ID.
@@ -96,23 +76,7 @@
bool mangle = package_name != context_->GetCompilationPackage();
merged_packages_.insert(package->name);
-
- auto callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
- FileReference* new_file, FileReference* old_file) -> bool {
- // The old file's path points inside the APK, so we can use it as is.
- io::IFile* f = collection->FindFile(*old_file->path);
- if (!f) {
- context_->GetDiagnostics()->Error(DiagMessage(src)
- << "file '" << *old_file->path << "' not found");
- return false;
- }
-
- new_file->file = f;
- return true;
- };
-
- error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/,
- callback);
+ error |= !DoMerge(src, table, package.get(), mangle, false /*overlay*/, true /*allow_new*/);
}
return !error;
}
@@ -187,7 +151,7 @@
static ResourceTable::CollisionResult MergeConfigValue(IAaptContext* context,
const ResourceNameRef& res_name,
- const bool overlay,
+ bool overlay,
ResourceConfigValue* dst_config_value,
ResourceConfigValue* src_config_value,
StringPool* pool) {
@@ -220,10 +184,8 @@
}
bool TableMerger::DoMerge(const Source& src, ResourceTable* src_table,
- ResourceTablePackage* src_package,
- const bool mangle_package, const bool overlay,
- const bool allow_new_resources,
- const FileMergeCallback& callback) {
+ ResourceTablePackage* src_package, bool mangle_package, bool overlay,
+ bool allow_new_resources) {
bool error = false;
for (auto& src_type : src_package->types) {
@@ -292,13 +254,6 @@
} else {
new_file_ref = std::unique_ptr<FileReference>(f->Clone(&master_table_->string_pool));
}
-
- if (callback) {
- if (!callback(res_name, src_config_value->config, new_file_ref.get(), f)) {
- error = true;
- continue;
- }
- }
dst_config_value->value = std::move(new_file_ref);
} else {
@@ -343,8 +298,8 @@
->FindOrCreateValue(file_desc.config, {})
->value = std::move(file_ref);
- return DoMerge(file->GetSource(), &table, pkg, false /* mangle */, overlay /* overlay */,
- true /* allow_new */, {});
+ return DoMerge(file->GetSource(), &table, pkg, false /*mangle*/, overlay /*overlay*/,
+ true /*allow_new*/);
}
} // namespace aapt
diff --git a/tools/aapt2/link/TableMerger.h b/tools/aapt2/link/TableMerger.h
index d024aa4..47e23dd 100644
--- a/tools/aapt2/link/TableMerger.h
+++ b/tools/aapt2/link/TableMerger.h
@@ -40,6 +40,9 @@
// TableMerger takes resource tables and merges all packages within the tables that have the same
// package ID.
//
+// It is assumed that any FileReference values have their io::IFile pointer set to point to the
+// file they represent.
+//
// If a package has a different name, all the entries in that table have their names mangled
// to include the package name. This way there are no collisions. In order to do this correctly,
// the TableMerger needs to also mangle any FileReference paths. Once these are mangled, the
@@ -60,14 +63,11 @@
// Merges resources from the same or empty package. This is for local sources.
// If overlay is true, the resources are treated as overlays.
- // An io::IFileCollection is optional and used to find the referenced Files and process them.
- bool Merge(const Source& src, ResourceTable* table, bool overlay,
- io::IFileCollection* collection = nullptr);
+ bool Merge(const Source& src, ResourceTable* table, bool overlay);
// Merges resources from the given package, mangling the name. This is for static libraries.
- // An io::IFileCollection is needed in order to find the referenced Files and process them.
- bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table,
- io::IFileCollection* collection);
+ // All FileReference values must have their io::IFile set.
+ bool MergeAndMangle(const Source& src, const android::StringPiece& package, ResourceTable* table);
// Merges a compiled file that belongs to this same or empty package.
bool MergeFile(const ResourceFile& fileDesc, bool overlay, io::IFile* file);
@@ -75,23 +75,16 @@
private:
DISALLOW_COPY_AND_ASSIGN(TableMerger);
- using FileMergeCallback = std::function<bool(const ResourceNameRef&,
- const ConfigDescription& config,
- FileReference*, FileReference*)>;
-
IAaptContext* context_;
ResourceTable* master_table_;
TableMergerOptions options_;
ResourceTablePackage* master_package_;
std::set<std::string> merged_packages_;
- bool MergeImpl(const Source& src, ResourceTable* src_table,
- io::IFileCollection* collection, bool overlay, bool allow_new);
+ bool MergeImpl(const Source& src, ResourceTable* src_table, bool overlay, bool allow_new);
- bool DoMerge(const Source& src, ResourceTable* src_table,
- ResourceTablePackage* src_package, const bool mangle_package,
- const bool overlay, const bool allow_new_resources,
- const FileMergeCallback& callback);
+ bool DoMerge(const Source& src, ResourceTable* src_table, ResourceTablePackage* src_package,
+ bool mangle_package, bool overlay, bool allow_new_resources);
std::unique_ptr<FileReference> CloneAndMangleFile(const std::string& package,
const FileReference& value);
diff --git a/tools/aapt2/link/TableMerger_test.cpp b/tools/aapt2/link/TableMerger_test.cpp
index 3499809..6aab8de 100644
--- a/tools/aapt2/link/TableMerger_test.cpp
+++ b/tools/aapt2/link/TableMerger_test.cpp
@@ -22,11 +22,12 @@
using ::aapt::test::ValueEq;
using ::testing::Contains;
-using ::testing::NotNull;
-using ::testing::UnorderedElementsAreArray;
-using ::testing::Pointee;
-using ::testing::Field;
using ::testing::Eq;
+using ::testing::Field;
+using ::testing::NotNull;
+using ::testing::Pointee;
+using ::testing::StrEq;
+using ::testing::UnorderedElementsAreArray;
namespace aapt {
@@ -67,10 +68,9 @@
ResourceTable final_table;
TableMerger merger(context_.get(), &final_table, TableMergerOptions{});
- io::FileCollection collection;
ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
- ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get(), &collection));
+ ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get()));
EXPECT_TRUE(merger.merged_packages().count("com.app.b") != 0);
@@ -122,32 +122,35 @@
}
TEST_F(TableMergerTest, MergeFileReferences) {
+ test::TestFile file_a("res/xml/file.xml");
+ test::TestFile file_b("res/xml/file.xml");
+
std::unique_ptr<ResourceTable> table_a =
test::ResourceTableBuilder()
.SetPackageId("com.app.a", 0x7f)
- .AddFileReference("com.app.a:xml/file", "res/xml/file.xml")
+ .AddFileReference("com.app.a:xml/file", "res/xml/file.xml", &file_a)
.Build();
std::unique_ptr<ResourceTable> table_b =
test::ResourceTableBuilder()
.SetPackageId("com.app.b", 0x7f)
- .AddFileReference("com.app.b:xml/file", "res/xml/file.xml")
+ .AddFileReference("com.app.b:xml/file", "res/xml/file.xml", &file_b)
.Build();
ResourceTable final_table;
TableMerger merger(context_.get(), &final_table, TableMergerOptions{});
- io::FileCollection collection;
- collection.InsertFile("res/xml/file.xml");
ASSERT_TRUE(merger.Merge({}, table_a.get(), false /*overlay*/));
- ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get(), &collection));
+ ASSERT_TRUE(merger.MergeAndMangle({}, "com.app.b", table_b.get()));
FileReference* f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/file");
ASSERT_THAT(f, NotNull());
- EXPECT_EQ(std::string("res/xml/file.xml"), *f->path);
+ EXPECT_THAT(*f->path, StrEq("res/xml/file.xml"));
+ EXPECT_THAT(f->file, Eq(&file_a));
f = test::GetValue<FileReference>(&final_table, "com.app.a:xml/com.app.b$file");
ASSERT_THAT(f, NotNull());
- EXPECT_EQ(std::string("res/xml/com.app.b$file.xml"), *f->path);
+ EXPECT_THAT(*f->path, StrEq("res/xml/com.app.b$file.xml"));
+ EXPECT_THAT(f->file, Eq(&file_b));
}
TEST_F(TableMergerTest, OverrideResourceWithOverlay) {
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 6803088..473693c 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -265,12 +265,14 @@
const PostProcessingConfiguration& config,
std::unique_ptr<XmlResource>* updated_manifest,
IDiagnostics* diag) {
- *updated_manifest = apk_->InflateManifest(context_);
- XmlResource* manifest = updated_manifest->get();
- if (manifest == nullptr) {
+ const xml::XmlResource* apk_manifest = apk_->GetManifest();
+ if (apk_manifest == nullptr) {
return false;
}
+ *updated_manifest = apk_manifest->Clone();
+ XmlResource* manifest = updated_manifest->get();
+
// Make sure the first element is <manifest> with package attribute.
xml::Element* manifest_el = manifest->root.get();
if (manifest_el == nullptr) {
diff --git a/tools/aapt2/optimize/MultiApkGenerator_test.cpp b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
index c8f3524..30c9146 100644
--- a/tools/aapt2/optimize/MultiApkGenerator_test.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator_test.cpp
@@ -106,7 +106,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterNewerVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(19).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
@@ -147,7 +147,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterOlderVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
@@ -186,7 +186,7 @@
TEST_F(MultiApkGeneratorTest, VersionFilterNoVersion) {
std::unique_ptr<ResourceTable> table = BuildTable();
- LoadedApk apk = {{"test.apk"}, {}, std::move(table)};
+ LoadedApk apk = {{"test.apk"}, {}, std::move(table), {}};
std::unique_ptr<IAaptContext> ctx = test::ContextBuilder().SetMinSdkVersion(1).Build();
PostProcessingConfiguration empty_config;
TableFlattenerOptions table_flattener_options;
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/test/Builders.cpp b/tools/aapt2/test/Builders.cpp
index 5a62e97..ecec63f 100644
--- a/tools/aapt2/test/Builders.cpp
+++ b/tools/aapt2/test/Builders.cpp
@@ -78,21 +78,27 @@
}
ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
- const StringPiece& path) {
- return AddFileReference(name, {}, path);
+ const StringPiece& path,
+ io::IFile* file) {
+ return AddFileReference(name, {}, path, file);
}
ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
const ResourceId& id,
- const StringPiece& path) {
- return AddValue(name, id, util::make_unique<FileReference>(table_->string_pool.MakeRef(path)));
+ const StringPiece& path,
+ io::IFile* file) {
+ auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
+ file_ref->file = file;
+ return AddValue(name, id, std::move(file_ref));
}
ResourceTableBuilder& ResourceTableBuilder::AddFileReference(const StringPiece& name,
const StringPiece& path,
- const ConfigDescription& config) {
- return AddValue(name, config, {},
- util::make_unique<FileReference>(table_->string_pool.MakeRef(path)));
+ const ConfigDescription& config,
+ io::IFile* file) {
+ auto file_ref = util::make_unique<FileReference>(table_->string_pool.MakeRef(path));
+ file_ref->file = file;
+ return AddValue(name, config, {}, std::move(file_ref));
}
ResourceTableBuilder& ResourceTableBuilder::AddValue(const StringPiece& name,
diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h
index 263fb55..4cdfc33 100644
--- a/tools/aapt2/test/Builders.h
+++ b/tools/aapt2/test/Builders.h
@@ -52,12 +52,15 @@
ResourceTableBuilder& AddString(const android::StringPiece& name, const ResourceId& id,
const ConfigDescription& config, const android::StringPiece& str);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
- const android::StringPiece& path);
+ const android::StringPiece& path,
+ io::IFile* file = nullptr);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name, const ResourceId& id,
- const android::StringPiece& path);
+ const android::StringPiece& path,
+ io::IFile* file = nullptr);
ResourceTableBuilder& AddFileReference(const android::StringPiece& name,
const android::StringPiece& path,
- const ConfigDescription& config);
+ const ConfigDescription& config,
+ io::IFile* file = nullptr);
ResourceTableBuilder& AddValue(const android::StringPiece& name, std::unique_ptr<Value> value);
ResourceTableBuilder& AddValue(const android::StringPiece& name, const ResourceId& id,
std::unique_ptr<Value> value);
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/Files.cpp b/tools/aapt2/util/Files.cpp
index bf8dc4d..5a8ff09 100644
--- a/tools/aapt2/util/Files.cpp
+++ b/tools/aapt2/util/Files.cpp
@@ -34,7 +34,7 @@
#ifdef _WIN32
// Windows includes.
-#include <direct.h>
+#include <windows.h>
#endif
using ::android::FileMap;
@@ -46,21 +46,29 @@
namespace aapt {
namespace file {
-FileType GetFileType(const std::string& path) {
-// TODO(adamlesinski): I'd like to move this to ::android::base::utf8 but Windows does some macro
-// trickery with 'stat' and things don't override very well.
#ifdef _WIN32
+FileType GetFileType(const std::string& path) {
std::wstring path_utf16;
if (!::android::base::UTF8PathToWindowsLongPath(path.c_str(), &path_utf16)) {
return FileType::kNonexistant;
}
- struct _stat64 sb;
- int result = _wstat64(path_utf16.c_str(), &sb);
+ DWORD result = GetFileAttributesW(path_utf16.c_str());
+ if (result == INVALID_FILE_ATTRIBUTES) {
+ return FileType::kNonexistant;
+ }
+
+ if (result & FILE_ATTRIBUTE_DIRECTORY) {
+ return FileType::kDirectory;
+ }
+
+ // Too many types to consider, just let open fail later.
+ return FileType::kRegular;
+}
#else
+FileType GetFileType(const std::string& path) {
struct stat sb;
int result = stat(path.c_str(), &sb);
-#endif
if (result == -1) {
if (errno == ENOENT || errno == ENOTDIR) {
@@ -91,6 +99,7 @@
return FileType::kUnknown;
}
}
+#endif
bool mkdirs(const std::string& path) {
constexpr const mode_t mode = S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP;
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/tools/aapt2/xml/XmlActionExecutor.cpp b/tools/aapt2/xml/XmlActionExecutor.cpp
index cc664a5..602a902 100644
--- a/tools/aapt2/xml/XmlActionExecutor.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor.cpp
@@ -16,6 +16,8 @@
#include "xml/XmlActionExecutor.h"
+using ::android::StringPiece;
+
namespace aapt {
namespace xml {
@@ -46,8 +48,8 @@
*msg << el->name << ">";
}
-bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag,
- Element* el) const {
+bool XmlNodeAction::Execute(XmlActionExecutorPolicy policy, std::vector<StringPiece>* bread_crumb,
+ SourcePathDiagnostics* diag, Element* el) const {
bool error = false;
for (const ActionFuncWithDiag& action : actions_) {
error |= !action(el, diag);
@@ -57,15 +59,21 @@
if (child_el->namespace_uri.empty()) {
std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(child_el->name);
if (iter != map_.end()) {
- error |= !iter->second.Execute(policy, diag, child_el);
+ // Use the iterator's copy of the element name, because the element may be modified.
+ bread_crumb->push_back(iter->first);
+ error |= !iter->second.Execute(policy, bread_crumb, diag, child_el);
+ bread_crumb->pop_back();
continue;
}
if (policy == XmlActionExecutorPolicy::kWhitelist) {
DiagMessage error_msg(child_el->line_number);
- error_msg << "unknown element ";
+ error_msg << "unexpected element ";
PrintElementToDiagMessage(child_el, &error_msg);
- error_msg << " found";
+ error_msg << " found in ";
+ for (const StringPiece& element : *bread_crumb) {
+ error_msg << "<" << element << ">";
+ }
diag->Error(error_msg);
error = true;
}
@@ -90,14 +98,15 @@
if (el->namespace_uri.empty()) {
std::map<std::string, XmlNodeAction>::const_iterator iter = map_.find(el->name);
if (iter != map_.end()) {
- return iter->second.Execute(policy, &source_diag, el);
+ std::vector<StringPiece> bread_crumb;
+ bread_crumb.push_back(iter->first);
+ return iter->second.Execute(policy, &bread_crumb, &source_diag, el);
}
if (policy == XmlActionExecutorPolicy::kWhitelist) {
DiagMessage error_msg(el->line_number);
- error_msg << "unknown element ";
+ error_msg << "unexpected root element ";
PrintElementToDiagMessage(el, &error_msg);
- error_msg << " found";
source_diag.Error(error_msg);
return false;
}
diff --git a/tools/aapt2/xml/XmlActionExecutor.h b/tools/aapt2/xml/XmlActionExecutor.h
index 1d70045..df70100 100644
--- a/tools/aapt2/xml/XmlActionExecutor.h
+++ b/tools/aapt2/xml/XmlActionExecutor.h
@@ -40,56 +40,46 @@
kWhitelist,
};
-/**
- * Contains the actions to perform at this XML node. This is a recursive data
- * structure that
- * holds XmlNodeActions for child XML nodes.
- */
+// Contains the actions to perform at this XML node. This is a recursive data structure that
+// holds XmlNodeActions for child XML nodes.
class XmlNodeAction {
public:
using ActionFuncWithDiag = std::function<bool(Element*, SourcePathDiagnostics*)>;
using ActionFunc = std::function<bool(Element*)>;
- /**
- * Find or create a child XmlNodeAction that will be performed for the child
- * element with the name `name`.
- */
- XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
+ // Find or create a child XmlNodeAction that will be performed for the child element with the
+ // name `name`.
+ XmlNodeAction& operator[](const std::string& name) {
+ return map_[name];
+ }
- /**
- * Add an action to be performed at this XmlNodeAction.
- */
+ // Add an action to be performed at this XmlNodeAction.
void Action(ActionFunc f);
void Action(ActionFuncWithDiag);
private:
friend class XmlActionExecutor;
- bool Execute(XmlActionExecutorPolicy policy, SourcePathDiagnostics* diag, Element* el) const;
+ bool Execute(XmlActionExecutorPolicy policy, std::vector<::android::StringPiece>* bread_crumb,
+ SourcePathDiagnostics* diag, Element* el) const;
std::map<std::string, XmlNodeAction> map_;
std::vector<ActionFuncWithDiag> actions_;
};
-/**
- * Allows the definition of actions to execute at specific XML elements defined
- * by their
- * hierarchy.
- */
+// Allows the definition of actions to execute at specific XML elements defined by their hierarchy.
class XmlActionExecutor {
public:
XmlActionExecutor() = default;
- /**
- * Find or create a root XmlNodeAction that will be performed for the root XML
- * element with the name `name`.
- */
- XmlNodeAction& operator[](const std::string& name) { return map_[name]; }
+ // Find or create a root XmlNodeAction that will be performed for the root XML element with the
+ // name `name`.
+ XmlNodeAction& operator[](const std::string& name) {
+ return map_[name];
+ }
- /**
- * Execute the defined actions for this XmlResource.
- * Returns true if all actions return true, otherwise returns false.
- */
+ // Execute the defined actions for this XmlResource.
+ // Returns true if all actions return true, otherwise returns false.
bool Execute(XmlActionExecutorPolicy policy, IDiagnostics* diag, XmlResource* doc) const;
private:
diff --git a/tools/aapt2/xml/XmlActionExecutor_test.cpp b/tools/aapt2/xml/XmlActionExecutor_test.cpp
index 0fe7ab0..d39854e 100644
--- a/tools/aapt2/xml/XmlActionExecutor_test.cpp
+++ b/tools/aapt2/xml/XmlActionExecutor_test.cpp
@@ -56,9 +56,13 @@
XmlActionExecutor executor;
executor["manifest"]["application"];
- std::unique_ptr<XmlResource> doc =
- test::BuildXmlDom("<manifest><application /><activity /></manifest>");
+ std::unique_ptr<XmlResource> doc;
StdErrDiagnostics diag;
+
+ doc = test::BuildXmlDom("<manifest><application /><activity /></manifest>");
+ ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
+
+ doc = test::BuildXmlDom("<manifest><application><activity /></application></manifest>");
ASSERT_FALSE(executor.Execute(XmlActionExecutorPolicy::kWhitelist, &diag, doc.get()));
}
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index 3522506..b0cf44a 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -258,8 +258,7 @@
}
}
-std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
- const Source& source) {
+std::unique_ptr<XmlResource> Inflate(const void* data, size_t len, std::string* out_error) {
// We import the android namespace because on Windows NO_ERROR is a macro, not
// an enum, which causes errors when qualifying it with android::
using namespace android;
@@ -270,7 +269,10 @@
std::unique_ptr<Element> pending_element;
ResXMLTree tree;
- if (tree.setTo(data, data_len) != NO_ERROR) {
+ if (tree.setTo(data, len) != NO_ERROR) {
+ if (out_error != nullptr) {
+ *out_error = "failed to initialize ResXMLTree";
+ }
return {};
}
@@ -361,6 +363,27 @@
return util::make_unique<XmlResource>(ResourceFile{}, std::move(string_pool), std::move(root));
}
+std::unique_ptr<XmlResource> XmlResource::Clone() const {
+ std::unique_ptr<XmlResource> cloned = util::make_unique<XmlResource>(file);
+ if (root != nullptr) {
+ cloned->root = root->CloneElement([&](const xml::Element& src, xml::Element* dst) {
+ dst->attributes.reserve(src.attributes.size());
+ for (const xml::Attribute& attr : src.attributes) {
+ xml::Attribute cloned_attr;
+ cloned_attr.name = attr.name;
+ cloned_attr.namespace_uri = attr.namespace_uri;
+ cloned_attr.value = attr.value;
+ cloned_attr.compiled_attribute = attr.compiled_attribute;
+ if (attr.compiled_value != nullptr) {
+ cloned_attr.compiled_value.reset(attr.compiled_value->Clone(&cloned->string_pool));
+ }
+ dst->attributes.push_back(std::move(cloned_attr));
+ }
+ });
+ }
+ return cloned;
+}
+
Element* FindRootElement(Node* node) {
if (node == nullptr) {
return nullptr;
@@ -383,12 +406,7 @@
}
Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) {
- for (auto& attr : attributes) {
- if (ns == attr.namespace_uri && name == attr.name) {
- return &attr;
- }
- }
- return nullptr;
+ return const_cast<Attribute*>(static_cast<const Element*>(this)->FindAttribute(ns, name));
}
const Attribute* Element::FindAttribute(const StringPiece& ns, const StringPiece& name) const {
@@ -404,17 +422,29 @@
return FindChildWithAttribute(ns, name, {}, {}, {});
}
+const Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) const {
+ return FindChildWithAttribute(ns, name, {}, {}, {});
+}
+
Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
const StringPiece& attr_ns, const StringPiece& attr_name,
const StringPiece& attr_value) {
- for (auto& child : children) {
- if (Element* el = NodeCast<Element>(child.get())) {
+ return const_cast<Element*>(static_cast<const Element*>(this)->FindChildWithAttribute(
+ ns, name, attr_ns, attr_name, attr_value));
+}
+
+const Element* Element::FindChildWithAttribute(const StringPiece& ns, const StringPiece& name,
+ const StringPiece& attr_ns,
+ const StringPiece& attr_name,
+ const StringPiece& attr_value) const {
+ for (const auto& child : children) {
+ if (const Element* el = NodeCast<Element>(child.get())) {
if (ns == el->namespace_uri && name == el->name) {
if (attr_ns.empty() && attr_name.empty()) {
return el;
}
- Attribute* attr = el->FindAttribute(attr_ns, attr_name);
+ const Attribute* attr = el->FindAttribute(attr_ns, attr_name);
if (attr && attr_value == attr->value) {
return el;
}
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index 063d7b9..cf06ba5 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -100,11 +100,21 @@
Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
const Attribute* FindAttribute(const android::StringPiece& ns,
const android::StringPiece& name) const;
+
Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
+ const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;
+
Element* FindChildWithAttribute(const android::StringPiece& ns, const android::StringPiece& name,
const android::StringPiece& attr_ns,
const android::StringPiece& attr_name,
const android::StringPiece& attr_value);
+
+ const Element* FindChildWithAttribute(const android::StringPiece& ns,
+ const android::StringPiece& name,
+ const android::StringPiece& attr_ns,
+ const android::StringPiece& attr_name,
+ const android::StringPiece& attr_value) const;
+
std::vector<Element*> GetChildElements();
// Due to overriding of subtypes not working with unique_ptr, define a convenience Clone method
@@ -139,16 +149,16 @@
StringPool string_pool;
std::unique_ptr<xml::Element> root;
+
+ std::unique_ptr<XmlResource> Clone() const;
};
// Inflates an XML DOM from an InputStream, logging errors to the logger.
-// Returns the root node on success, or nullptr on failure.
std::unique_ptr<XmlResource> Inflate(io::InputStream* in, IDiagnostics* diag, const Source& source);
-// Inflates an XML DOM from a binary ResXMLTree, logging errors to the logger.
-// Returns the root node on success, or nullptr on failure.
-std::unique_ptr<XmlResource> Inflate(const void* data, size_t data_len, IDiagnostics* diag,
- const Source& source);
+// Inflates an XML DOM from a binary ResXMLTree.
+std::unique_ptr<XmlResource> Inflate(const void* data, size_t len,
+ std::string* out_error = nullptr);
Element* FindRootElement(Node* node);
diff --git a/tools/aapt2/xml/XmlDom_test.cpp b/tools/aapt2/xml/XmlDom_test.cpp
index 34e6d3f..e5012d6 100644
--- a/tools/aapt2/xml/XmlDom_test.cpp
+++ b/tools/aapt2/xml/XmlDom_test.cpp
@@ -70,8 +70,7 @@
ASSERT_TRUE(flattener.Consume(context.get(), doc.get()));
auto block = util::Copy(buffer);
- std::unique_ptr<XmlResource> new_doc =
- Inflate(block.get(), buffer.size(), context->GetDiagnostics(), Source("test.xml"));
+ std::unique_ptr<XmlResource> new_doc = Inflate(block.get(), buffer.size(), nullptr);
ASSERT_THAT(new_doc, NotNull());
EXPECT_THAT(new_doc->root->name, StrEq("Layout"));
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index 135df40..674bee1 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -18,6 +18,7 @@
#include <frameworks/base/core/proto/android/os/incident.pb.h>
#include <map>
+#include <set>
#include <string>
using namespace android;
@@ -27,6 +28,60 @@
using namespace google::protobuf::internal;
using namespace std;
+/**
+ * Implementation details:
+ * This binary auto generates .cpp files for incident and incidentd.
+ *
+ * When argument "incident" is specified, it generates incident_section.cpp file.
+ *
+ * When argument "incidentd" is specified, it generates section_list.cpp file.
+ *
+ * In section_list.cpp file, it generates a SECTION_LIST array and a PRIVACY_POLICY_LIST array.
+ * For SECTION_LIST, it generates Section.h classes only for proto fields with section option enabled.
+ * For PRIVACY_POLICY_LIST, it generates Privacy.h classes only for proto fields with privacy option enabled.
+ *
+ * For Privacy struct, it is possible to have self recursion definitions since protobuf is defining "classes"
+ * So the logic to handle it becomes very complicated when Privacy tag of a message contains a list of Privacies
+ * of its sub-messages. The code also handles multiple depth of self recursion fields.
+ *
+ * For example here is a one level self recursion message WindowManager:
+ * message WindowState {
+ * string state = 1 [(privacy).dest = LOCAL];
+ * int32 display_id = 2;
+ * repeated WindowState child_windows = 3;
+ * }
+ *
+ * message WindowManager {
+ * WindowState my_window = 1;
+ * }
+ *
+ * When generating Privacy options for WindowManager, this tool will generate cpp syntax source code:
+ *
+ * #include "section_list.h"
+ * ...
+ * Privacy WindowState_state { 1, 9, NULL, LOCAL, NULL }; // first two integers are values for field id and proto type.
+ * Privacy WindowState_child_windows { 3, 11, NULL, DEFAULT, NULL }; // reserved for WindowState_LIST
+ * Privacy* WindowState_MSG_[] = {
+ * &WindowState_state,
+ * // display id is default, nothing is generated.
+ * &WindowState_child_windows,
+ * NULL // terminator of the array
+ * };
+ * Privacy WindowState_my_window { 1, 11, WindowState_my_window_LIST, DEFAULT, NULL };
+ *
+ * createList() {
+ * ...
+ * WindowState_child_windows.children = WindowState_my_window_LIST; // point to its own definition after the list is defined.
+ * ...
+ * }
+ *
+ * const Privacy** PRIVACY_POLICY_LIST = createList();
+ * const int PRIVACY_POLICY_COUNT = 1;
+ */
+
+// The assignments will be called when constructs PRIVACY_POLICY_LIST, has to be global variable
+vector<string> gSelfRecursionAssignments;
+
static inline void emptyline() {
printf("\n");
}
@@ -38,7 +93,7 @@
emptyline();
}
-// ================================================================================
+// ======================== incident_sections =============================
static bool generateIncidentSectionsCpp(Descriptor const* descriptor)
{
generateHead("incident_sections");
@@ -73,7 +128,7 @@
return true;
}
-// ================================================================================
+// ========================= section_list ===================================
static void splitAndPrint(const string& args) {
size_t base = 0;
size_t found;
@@ -88,12 +143,12 @@
}
}
-static const std::string replaceAll(const string& field_name, const char oldC, const string& newS) {
- if (field_name.find_first_of(oldC) == field_name.npos) return field_name.c_str();
+static string replaceAll(const string& fieldName, const char oldC, const string& newS) {
+ if (fieldName.find_first_of(oldC) == fieldName.npos) return fieldName.c_str();
size_t pos = 0, idx = 0;
- char* res = new char[field_name.size() * newS.size() + 1]; // assign a larger buffer
- while (pos != field_name.size()) {
- char cur = field_name[pos++];
+ char* res = new char[fieldName.size() * newS.size() + 1]; // assign a larger buffer
+ while (pos != fieldName.size()) {
+ char cur = fieldName[pos++];
if (cur != oldC) {
res[idx++] = cur;
continue;
@@ -104,92 +159,162 @@
}
}
res[idx] = '\0';
- std::string result(res);
+ string result(res);
delete [] res;
return result;
}
-static inline bool isDefaultDest(const FieldDescriptor* field) {
- return field->options().GetExtension(privacy).dest() == PrivacyFlags::default_instance().dest();
+static string getFieldName(const FieldDescriptor* field) {
+ return replaceAll(field->full_name(), '.', "__");
}
+static string getMessageTypeName(const Descriptor* descriptor) {
+ return replaceAll(descriptor->full_name(), '.', "_") + "_MSG_";
+}
+
+static inline SectionFlags getSectionFlags(const FieldDescriptor* field) {
+ return field->options().GetExtension(section);
+}
+
+static inline PrivacyFlags getPrivacyFlags(const FieldDescriptor* field) {
+ return field->options().GetExtension(privacy);
+}
+
+static inline bool isDefaultField(const FieldDescriptor* field) {
+ return getPrivacyFlags(field).dest() == PrivacyFlags::default_instance().dest();
+}
+
+static bool isDefaultMessageImpl(const Descriptor* descriptor, set<string>* parents) {
+ int N = descriptor->field_count();
+ parents->insert(descriptor->full_name());
+ for (int i=0; i<N; ++i) {
+ const FieldDescriptor* field = descriptor->field(i);
+ // look at if the current field is default or not, return false immediately
+ if (!isDefaultField(field)) return false;
+
+ switch (field->type()) {
+ case FieldDescriptor::TYPE_MESSAGE:
+ // if self recursion, don't go deep.
+ if (parents->find(field->message_type()->full_name()) != parents->end()) break;
+ // if is a default message, just continue
+ if (isDefaultMessageImpl(field->message_type(), parents)) break;
+ // sub message is not default, so this message is always not default
+ return false;
+ case FieldDescriptor::TYPE_STRING:
+ if (getPrivacyFlags(field).patterns_size() != 0) return false;
+ default:
+ continue;
+ }
+ }
+ parents->erase(descriptor->full_name());
+ return true;
+}
+
+static bool isDefaultMessage(const Descriptor* descriptor) {
+ set<string> parents;
+ return isDefaultMessageImpl(descriptor, &parents);
+}
+
+// This function is called for looking at privacy tags for a message type and recursively its sub-messages
+// It prints out each fields's privacy tags and a List of Privacy of the message itself (don't print default values)
// Returns false if the descriptor doesn't have any non default privacy flags set, including its submessages
-static bool generatePrivacyFlags(const Descriptor* descriptor, const char* alias, map<string, bool> &msgNames) {
+static bool generatePrivacyFlags(const Descriptor* descriptor, map<string, bool> &msgNames, set<string>* parents) {
bool hasDefaultFlags[descriptor->field_count()];
+
+ string messageTypeName = getMessageTypeName(descriptor);
+ // if the message is already defined, skip it.
+ if (msgNames.find(messageTypeName) != msgNames.end()) {
+ bool hasDefault = msgNames[messageTypeName];
+ return !hasDefault; // don't generate if it has default privacy.
+ }
+ // insert the message type name so sub-message will figure out if self-recursion occurs
+ parents->insert(messageTypeName);
+
// iterate though its field and generate sub flags first
for (int i=0; i<descriptor->field_count(); i++) {
hasDefaultFlags[i] = true; // set default to true
+
const FieldDescriptor* field = descriptor->field(i);
- const std::string field_name_str = replaceAll(field->full_name(), '.', "__");
- const char* field_name = field_name_str.c_str();
- // check if the same name is already defined
- if (msgNames.find(field_name) != msgNames.end()) {
- hasDefaultFlags[i] = msgNames[field_name];
+ const string fieldName = getFieldName(field);
+ // check if the same field name is already defined.
+ if (msgNames.find(fieldName) != msgNames.end()) {
+ hasDefaultFlags[i] = msgNames[fieldName];
continue;
};
- PrivacyFlags p = field->options().GetExtension(privacy);
+ PrivacyFlags p = getPrivacyFlags(field);
+ string fieldMessageName;
switch (field->type()) {
case FieldDescriptor::TYPE_MESSAGE:
- if (generatePrivacyFlags(field->message_type(), field_name, msgNames)) {
- printf("Privacy %s { %d, %d, %s_LIST, %d, NULL };\n", field_name, field->number(),
- field->type(), field_name, p.dest());
- } else if (isDefaultDest(field)) {
+ fieldMessageName = getMessageTypeName(field->message_type());
+ if (parents->find(fieldMessageName) != parents->end()) { // Self-Recursion proto definition
+ if (isDefaultField(field)) {
+ hasDefaultFlags[i] = isDefaultMessage(field->message_type());
+ } else {
+ hasDefaultFlags[i] = false;
+ }
+ if (!hasDefaultFlags[i]) {
+ printf("Privacy %s = { %d, %d, NULL, %d, NULL }; // self recursion field of %s\n",
+ fieldName.c_str(), field->number(), field->type(), p.dest(), fieldMessageName.c_str());
+ // generate the assignment and used to construct createList function later on.
+ gSelfRecursionAssignments.push_back(fieldName + ".children = " + fieldMessageName);
+ }
+ break;
+ } else if (generatePrivacyFlags(field->message_type(), msgNames, parents)) {
+ printf("Privacy %s = { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
+ field->type(), fieldMessageName.c_str(), p.dest());
+ } else if (isDefaultField(field)) {
// don't create a new privacy if the value is default.
break;
- } else{
- printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+ } else {
+ printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
field->type(), p.dest());
}
hasDefaultFlags[i] = false;
break;
case FieldDescriptor::TYPE_STRING:
- if (isDefaultDest(field) && p.patterns_size() == 0) break;
+ if (isDefaultField(field) && p.patterns_size() == 0) break;
- printf("const char* %s_patterns[] = {\n", field_name);
+ printf("const char* %s_patterns[] = {\n", fieldName.c_str());
for (int i=0; i<p.patterns_size(); i++) {
// the generated string need to escape backslash as well, need to dup it here
printf(" \"%s\",\n", replaceAll(p.patterns(i), '\\', "\\\\").c_str());
}
printf(" NULL };\n");
- printf("Privacy %s { %d, %d, NULL, %d, %s_patterns };\n", field_name, field->number(),
- field->type(), p.dest(), field_name);
+ printf("Privacy %s = { %d, %d, NULL, %d, %s_patterns };\n", fieldName.c_str(), field->number(),
+ field->type(), p.dest(), fieldName.c_str());
hasDefaultFlags[i] = false;
break;
default:
- if (isDefaultDest(field)) break;
- printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", field_name, field->number(),
+ if (isDefaultField(field)) break;
+ printf("Privacy %s = { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
field->type(), p.dest());
hasDefaultFlags[i] = false;
}
// add the field name to message map, true means it has default flags
- msgNames[field_name] = hasDefaultFlags[i];
+ msgNames[fieldName] = hasDefaultFlags[i];
}
bool allDefaults = true;
for (int i=0; i<descriptor->field_count(); i++) {
allDefaults &= hasDefaultFlags[i];
}
+
+ parents->erase(messageTypeName); // erase the message type name when exit the message.
+ msgNames[messageTypeName] = allDefaults; // store the privacy tags of the message here to avoid overhead.
+
if (allDefaults) return false;
emptyline();
-
- bool needConst = strcmp(alias, "PRIVACY_POLICY") == 0;
int policyCount = 0;
-
- printf("%sPrivacy* %s_LIST[] = {\n", needConst ? "const " : "", alias);
+ printf("Privacy* %s[] = {\n", messageTypeName.c_str());
for (int i=0; i<descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
if (hasDefaultFlags[i]) continue;
- printf(" &%s,\n", replaceAll(field->full_name(), '.', "__").c_str());
+ printf(" &%s,\n", getFieldName(field).c_str());
policyCount++;
}
- if (needConst) {
- printf("};\n\n");
- printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
- } else {
- printf(" NULL };\n");
- }
+ printf(" NULL };\n");
emptyline();
return true;
}
@@ -198,6 +323,8 @@
generateHead("section_list");
// generates SECTION_LIST
+ printf("// Generate SECTION_LIST.\n\n");
+
printf("const Section* SECTION_LIST[] = {\n");
for (int i=0; i<descriptor->field_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
@@ -205,7 +332,7 @@
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
continue;
}
- const SectionFlags s = field->options().GetExtension(section);
+ const SectionFlags s = getSectionFlags(field);
switch (s.type()) {
case SECTION_NONE:
continue;
@@ -225,16 +352,73 @@
}
}
printf(" NULL };\n");
+
+ emptyline();
+ printf("// =============================================================================\n");
emptyline();
- // generates PRIVACY_POLICY
+ // generates PRIVACY_POLICY_LIST
+ printf("// Generate PRIVACY_POLICY_LIST.\n\n");
map<string, bool> messageNames;
- if (!generatePrivacyFlags(descriptor, "PRIVACY_POLICY", messageNames)) {
- // if no privacy options set at all, define an empty list
- printf("const Privacy* PRIVACY_POLICY_LIST[] = {};\n");
- printf("const int PRIVACY_POLICY_COUNT = 0;\n");
+ set<string> parents;
+ bool skip[descriptor->field_count()];
+
+ for (int i=0; i<descriptor->field_count(); i++) {
+ const FieldDescriptor* field = descriptor->field(i);
+ const string fieldName = getFieldName(field);
+ PrivacyFlags p = getPrivacyFlags(field);
+
+ skip[i] = true;
+
+ if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
+ continue;
+ }
+ // generate privacy flags for each field.
+ if (generatePrivacyFlags(field->message_type(), messageNames, &parents)) {
+ printf("Privacy %s { %d, %d, %s, %d, NULL };\n", fieldName.c_str(), field->number(),
+ field->type(), getMessageTypeName(field->message_type()).c_str(), p.dest());
+ } else if (isDefaultField(field)) {
+ continue; // don't create a new privacy if the value is default.
+ } else {
+ printf("Privacy %s { %d, %d, NULL, %d, NULL };\n", fieldName.c_str(), field->number(),
+ field->type(), p.dest());
+ }
+ skip[i] = false;
}
+ // generate final PRIVACY_POLICY_LIST
+ emptyline();
+ int policyCount = 0;
+ if (gSelfRecursionAssignments.empty()) {
+ printf("Privacy* privacyArray[] = {\n");
+ for (int i=0; i<descriptor->field_count(); i++) {
+ if (skip[i]) continue;
+ printf(" &%s,\n", getFieldName(descriptor->field(i)).c_str());
+ policyCount++;
+ }
+ printf("};\n\n");
+ printf("const Privacy** PRIVACY_POLICY_LIST = const_cast<const Privacy**>(privacyArray);\n\n");
+ printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+ } else {
+ for (int i=0; i<descriptor->field_count(); i++) {
+ if (!skip[i]) policyCount++;
+ }
+
+ printf("static const Privacy** createList() {\n");
+ for (size_t i=0; i<gSelfRecursionAssignments.size(); ++i) {
+ printf(" %s;\n", gSelfRecursionAssignments[i].c_str());
+ }
+ printf(" Privacy** privacyArray = (Privacy**)malloc(%d * sizeof(Privacy**));\n", policyCount);
+ policyCount = 0; // reset
+ for (int i=0; i<descriptor->field_count(); i++) {
+ if (skip[i]) continue;
+ printf(" privacyArray[%d] = &%s;\n", policyCount++, getFieldName(descriptor->field(i)).c_str());
+ }
+ printf(" return const_cast<const Privacy**>(privacyArray);\n");
+ printf("}\n\n");
+ printf("const Privacy** PRIVACY_POLICY_LIST = createList();\n\n");
+ printf("const int PRIVACY_POLICY_COUNT = %d;\n", policyCount);
+ }
return true;
}
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 5d29268..f76196d 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -22,6 +22,7 @@
namespace android {
namespace stats_log_api_gen {
+using google::protobuf::EnumDescriptor;
using google::protobuf::FieldDescriptor;
using google::protobuf::FileDescriptor;
using google::protobuf::SourceLocation;
@@ -120,7 +121,7 @@
case FieldDescriptor::TYPE_UINT32:
return JAVA_TYPE_INT;
case FieldDescriptor::TYPE_ENUM:
- return JAVA_TYPE_INT;
+ return JAVA_TYPE_ENUM;
case FieldDescriptor::TYPE_SFIXED32:
return JAVA_TYPE_INT;
case FieldDescriptor::TYPE_SFIXED64:
@@ -208,7 +209,6 @@
errorCount++;
continue;
}
-
}
// Check that if there's a WorkSource, it's at position 1.
@@ -228,15 +228,26 @@
AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
- // Build the type signature
+ // Build the type signature and the atom data.
vector<java_type_t> signature;
for (map<int,const FieldDescriptor*>::const_iterator it = fields.begin();
it != fields.end(); it++) {
const FieldDescriptor* field = it->second;
java_type_t javaType = java_type(field);
- atomDecl.fields.push_back(AtomField(field->name(), javaType));
- signature.push_back(javaType);
+ AtomField atField(field->name(), javaType);
+ if (javaType == JAVA_TYPE_ENUM) {
+ // All enums are treated as ints when it comes to function signatures.
+ signature.push_back(JAVA_TYPE_INT);
+ const EnumDescriptor* enumDescriptor = field->enum_type();
+ for (int i = 0; i < enumDescriptor->value_count(); i++) {
+ atField.enumValues[enumDescriptor->value(i)->number()] =
+ enumDescriptor->value(i)->name().c_str();
+ }
+ } else {
+ signature.push_back(javaType);
+ }
+ atomDecl.fields.push_back(atField);
}
atoms->signatures.insert(signature);
@@ -261,5 +272,3 @@
} // namespace stats_log_api_gen
} // namespace android
-
-
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 50af7ea..2f840d7 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -22,10 +22,12 @@
#include <set>
#include <vector>
+#include <map>
namespace android {
namespace stats_log_api_gen {
+using std::map;
using std::set;
using std::string;
using std::vector;
@@ -44,6 +46,7 @@
JAVA_TYPE_FLOAT = 5,
JAVA_TYPE_DOUBLE = 6,
JAVA_TYPE_STRING = 7,
+ JAVA_TYPE_ENUM = 8,
JAVA_TYPE_OBJECT = -1,
JAVA_TYPE_BYTE_ARRAY = -2,
@@ -57,8 +60,13 @@
string name;
java_type_t javaType;
+ // If the field is of type enum, the following map contains the list of enum values.
+ map<int /* numeric value */, string /* value name */> enumValues;
+
inline AtomField() :name(), javaType(JAVA_TYPE_UNKNOWN) {}
- inline AtomField(const AtomField& that) :name(that.name), javaType(that.javaType) {}
+ inline AtomField(const AtomField& that) :name(that.name),
+ javaType(that.javaType),
+ enumValues(that.enumValues) {}
inline AtomField(string n, java_type_t jt) :name(n), javaType(jt) {}
inline ~AtomField() {}
};
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index aaea4f6..6350b72 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -56,6 +56,7 @@
case JAVA_TYPE_BOOLEAN:
return "bool";
case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
return "int32_t";
case JAVA_TYPE_LONG:
return "int64_t";
@@ -77,6 +78,7 @@
case JAVA_TYPE_BOOLEAN:
return "boolean";
case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
return "int";
case JAVA_TYPE_LONG:
return "long";
@@ -173,7 +175,7 @@
fprintf(out, " */\n");
fprintf(out, "\n");
fprintf(out, "/**\n");
- fprintf(out, " * Constants for event codes.\n");
+ fprintf(out, " * Constants for atom codes.\n");
fprintf(out, " */\n");
fprintf(out, "enum {\n");
@@ -240,9 +242,9 @@
fprintf(out, " * @hide\n");
fprintf(out, " */\n");
fprintf(out, "public final class StatsLog {\n");
- fprintf(out, " // Constants for event codes.\n");
+ fprintf(out, " // Constants for atom codes.\n");
- // Print constants
+ // Print constants for the atom codes.
for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
atom != atoms.decls.end(); atom++) {
string constant = make_constant_name(atom->name);
@@ -260,6 +262,27 @@
}
fprintf(out, "\n");
+ // Print constants for the enum values.
+ fprintf(out, " // Constants for enum values.\n\n");
+ for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+ atom != atoms.decls.end(); atom++) {
+ for (vector<AtomField>::const_iterator field = atom->fields.begin();
+ field != atom->fields.end(); field++) {
+ if (field->javaType == JAVA_TYPE_ENUM) {
+ fprintf(out, " // Values for %s.%s\n", atom->message.c_str(), field->name.c_str());
+ for (map<int, string>::const_iterator value = field->enumValues.begin();
+ value != field->enumValues.end(); value++) {
+ fprintf(out, " public static final int %s__%s__%s = %d;\n",
+ make_constant_name(atom->message).c_str(),
+ make_constant_name(field->name).c_str(),
+ make_constant_name(value->second).c_str(),
+ value->first);
+ }
+ fprintf(out, "\n");
+ }
+ }
+ }
+
// Print write methods
fprintf(out, " // Write methods\n");
for (set<vector<java_type_t>>::const_iterator signature = atoms.signatures.begin();
@@ -286,6 +309,7 @@
case JAVA_TYPE_BOOLEAN:
return "jboolean";
case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
return "jint";
case JAVA_TYPE_LONG:
return "jlong";
@@ -311,6 +335,7 @@
result += "_boolean";
break;
case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
result += "_int";
break;
case JAVA_TYPE_LONG:
@@ -340,6 +365,7 @@
case JAVA_TYPE_BOOLEAN:
return "Z";
case JAVA_TYPE_INT:
+ case JAVA_TYPE_ENUM:
return "I";
case JAVA_TYPE_LONG:
return "J";
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index 1bd2e3d..073f2cf 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -24,6 +24,7 @@
namespace android {
namespace stats_log_api_gen {
+using std::map;
using std::set;
using std::vector;
@@ -54,6 +55,29 @@
EXPECT_TRUE(set_contains_vector(s, count, __VA_ARGS__)); \
} while(0)
+/** Expects that the provided atom has no enum values for any field. */
+#define EXPECT_NO_ENUM_FIELD(atom) \
+ do { \
+ for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
+ field != atom->fields.end(); field++) { \
+ EXPECT_TRUE(field->enumValues.empty()); \
+ } \
+ } while(0)
+
+/** Expects that exactly one specific field has expected enum values. */
+#define EXPECT_HAS_ENUM_FIELD(atom, field_name, values) \
+ do { \
+ for (vector<AtomField>::const_iterator field = atom->fields.begin(); \
+ field != atom->fields.end(); field++) { \
+ if (field->name == field_name) { \
+ EXPECT_EQ(field->enumValues, values); \
+ } else { \
+ EXPECT_TRUE(field->enumValues.empty()); \
+ } \
+ } \
+ } while(0)
+
+
/**
* Test a correct collation, with all the types.
*/
@@ -94,21 +118,28 @@
EXPECT_EQ(1, atom->code);
EXPECT_EQ("int_atom", atom->name);
EXPECT_EQ("IntAtom", atom->message);
+ EXPECT_NO_ENUM_FIELD(atom);
atom++;
EXPECT_EQ(2, atom->code);
EXPECT_EQ("out_of_order_atom", atom->name);
EXPECT_EQ("OutOfOrderAtom", atom->message);
+ EXPECT_NO_ENUM_FIELD(atom);
atom++;
EXPECT_EQ(3, atom->code);
EXPECT_EQ("another_int_atom", atom->name);
EXPECT_EQ("AnotherIntAtom", atom->message);
+ EXPECT_NO_ENUM_FIELD(atom);
atom++;
EXPECT_EQ(4, atom->code);
EXPECT_EQ("all_types_atom", atom->name);
EXPECT_EQ("AllTypesAtom", atom->message);
+ map<int, string> enumValues;
+ enumValues[0] = "VALUE0";
+ enumValues[1] = "VALUE1";
+ EXPECT_HAS_ENUM_FIELD(atom, "enum_field", enumValues);
atom++;
EXPECT_TRUE(atom == atoms.decls.end());
@@ -125,7 +156,7 @@
}
/**
- * Test that atoms that have non-primitve types are rejected.
+ * Test that atoms that have non-primitive types are rejected.
*/
TEST(CollationTest, FailOnBadTypes) {
Atoms atoms;
@@ -165,7 +196,5 @@
EXPECT_EQ(1, errorCount);
}
-
} // namespace stats_log_api_gen
} // namespace android
-
diff --git a/tools/streaming_proto/Android.bp b/tools/streaming_proto/Android.bp
index 756549c..dc5c14e 100644
--- a/tools/streaming_proto/Android.bp
+++ b/tools/streaming_proto/Android.bp
@@ -21,10 +21,32 @@
name: "protoc-gen-stream-defaults",
srcs: [
"Errors.cpp",
+ "stream_proto_utils.cpp",
"string_utils.cpp",
],
+
+ shared_libs: ["libprotoc"],
}
+cc_library {
+ name: "streamingflags",
+ host_supported: true,
+ proto: {
+ export_proto_headers: true,
+ include_dirs: ["external/protobuf/src"],
+ },
+
+ target: {
+ host: {
+ proto: {
+ type: "full",
+ },
+ srcs: [
+ "stream.proto",
+ ],
+ },
+ },
+}
cc_binary_host {
name: "protoc-gen-javastream",
@@ -33,7 +55,6 @@
],
defaults: ["protoc-gen-stream-defaults"],
- shared_libs: ["libprotoc"],
}
cc_binary_host {
@@ -43,5 +64,5 @@
],
defaults: ["protoc-gen-stream-defaults"],
- shared_libs: ["libprotoc"],
+ static_libs: ["streamingflags"],
}
diff --git a/tools/streaming_proto/cpp/main.cpp b/tools/streaming_proto/cpp/main.cpp
index d4e1b7a..4816984 100644
--- a/tools/streaming_proto/cpp/main.cpp
+++ b/tools/streaming_proto/cpp/main.cpp
@@ -1,106 +1,23 @@
#include "Errors.h"
+#include "stream_proto_utils.h"
#include "string_utils.h"
-#include "google/protobuf/compiler/plugin.pb.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
+#include <frameworks/base/tools/streaming_proto/stream.pb.h>
#include <iomanip>
#include <iostream>
#include <sstream>
using namespace android::stream_proto;
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
using namespace google::protobuf::io;
using namespace std;
-/**
- * Position of the field type in a (long long) fieldId.
- */
-const uint64_t FIELD_TYPE_SHIFT = 32;
-
-//
-// FieldId flags for whether the field is single, repeated or packed.
-// TODO: packed is not supported yet.
-//
-const uint64_t FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_UNKNOWN = 0;
-const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 4ULL << FIELD_COUNT_SHIFT;
-
-// Indent
-const string INDENT = " ";
-
-/**
- * See if this is the file for this request, and not one of the imported ones.
- */
-static bool
-should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
-{
- const int N = request.file_to_generate_size();
- for (int i=0; i<N; i++) {
- if (request.file_to_generate(i) == file) {
- return true;
- }
- }
- return false;
-}
-
static string
make_filename(const FileDescriptorProto& file_descriptor)
{
return file_descriptor.name() + ".h";
}
-static string
-get_proto_type(const FieldDescriptorProto& field)
-{
- switch (field.type()) {
- case FieldDescriptorProto::TYPE_DOUBLE:
- return "double";
- case FieldDescriptorProto::TYPE_FLOAT:
- return "float";
- case FieldDescriptorProto::TYPE_INT64:
- return "int64";
- case FieldDescriptorProto::TYPE_UINT64:
- return "uint64";
- case FieldDescriptorProto::TYPE_INT32:
- return "int32";
- case FieldDescriptorProto::TYPE_FIXED64:
- return "fixed64";
- case FieldDescriptorProto::TYPE_FIXED32:
- return "fixed32";
- case FieldDescriptorProto::TYPE_BOOL:
- return "bool";
- case FieldDescriptorProto::TYPE_STRING:
- return "string";
- case FieldDescriptorProto::TYPE_GROUP:
- return "group<unsupported!>";
- case FieldDescriptorProto::TYPE_MESSAGE:
- return field.type_name();
- case FieldDescriptorProto::TYPE_BYTES:
- return "bytes";
- case FieldDescriptorProto::TYPE_UINT32:
- return "uint32";
- case FieldDescriptorProto::TYPE_ENUM:
- return field.type_name();
- case FieldDescriptorProto::TYPE_SFIXED32:
- return "sfixed32";
- case FieldDescriptorProto::TYPE_SFIXED64:
- return "sfixed64";
- case FieldDescriptorProto::TYPE_SINT32:
- return "sint32";
- case FieldDescriptorProto::TYPE_SINT64:
- return "sint64";
- default:
- // won't happen
- return "void";
- }
-}
-
static void
write_enum(stringstream& text, const EnumDescriptorProto& enu, const string& indent)
{
@@ -115,27 +32,6 @@
text << endl;
}
-static uint64_t
-get_field_id(const FieldDescriptorProto& field)
-{
- // Number
- uint64_t result = (uint64_t)field.number();
-
- // Type
- result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
-
- // Count
- if (field.options().packed()) {
- result |= FIELD_COUNT_PACKED;
- } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
- result |= FIELD_COUNT_REPEATED;
- } else {
- result |= FIELD_COUNT_SINGLE;
- }
-
- return result;
-}
-
static void
write_field(stringstream& text, const FieldDescriptorProto& field, const string& indent)
{
@@ -160,6 +56,12 @@
text << endl;
}
+static inline bool
+should_generate_fields_mapping(const DescriptorProto& message)
+{
+ return message.options().GetExtension(stream).enable_fields_mapping();
+}
+
static void
write_message(stringstream& text, const DescriptorProto& message, const string& indent)
{
@@ -167,8 +69,7 @@
const string indented = indent + INDENT;
text << indent << "// message " << message.name() << endl;
- text << indent << "class " << message.name() << " {" << endl;
- text << indent << "public:" << endl;
+ text << indent << "namespace " << message.name() << " {" << endl;
// Enums
N = message.enum_type_size();
@@ -188,12 +89,27 @@
write_field(text, message.field(i), indented);
}
- text << indent << "};" << endl;
+ if (should_generate_fields_mapping(message)) {
+ N = message.field_size();
+ text << indented << "const int _FIELD_COUNT = " << N << ";" << endl;
+ text << indented << "const char* _FIELD_NAMES[" << N << "] = {" << endl;
+ for (int i=0; i<N; i++) {
+ text << indented << INDENT << "\"" << message.field(i).name() << "\"," << endl;
+ }
+ text << indented << "};" << endl;
+ text << indented << "const uint64_t _FIELD_IDS[" << N << "] = {" << endl;
+ for (int i=0; i<N; i++) {
+ text << indented << INDENT << make_constant_name(message.field(i).name()) << "," << endl;
+ }
+ text << indented << "};" << endl << endl;
+ }
+
+ text << indent << "} //" << message.name() << endl;
text << endl;
}
static void
-write_cpp_file(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor)
+write_header_file(CodeGeneratorResponse* response, const FileDescriptorProto& file_descriptor)
{
stringstream text;
@@ -255,7 +171,7 @@
for (int i=0; i<N; i++) {
const FileDescriptorProto& file_descriptor = request.proto_file(i);
if (should_generate_for_file(request, file_descriptor.name())) {
- write_cpp_file(&response, file_descriptor);
+ write_header_file(&response, file_descriptor);
}
}
@@ -270,4 +186,4 @@
/* code */
return 0;
-}
\ No newline at end of file
+}
diff --git a/tools/streaming_proto/java/main.cpp b/tools/streaming_proto/java/main.cpp
index b7d594b..c9c50a5 100644
--- a/tools/streaming_proto/java/main.cpp
+++ b/tools/streaming_proto/java/main.cpp
@@ -1,11 +1,7 @@
#include "Errors.h"
-
+#include "stream_proto_utils.h"
#include "string_utils.h"
-#include "google/protobuf/compiler/plugin.pb.h"
-#include "google/protobuf/io/zero_copy_stream_impl.h"
-#include "google/protobuf/text_format.h"
-
#include <stdio.h>
#include <iomanip>
#include <iostream>
@@ -13,51 +9,9 @@
#include <map>
using namespace android::stream_proto;
-using namespace google::protobuf;
-using namespace google::protobuf::compiler;
using namespace google::protobuf::io;
using namespace std;
-const int FIELD_TYPE_SHIFT = 32;
-const uint64_t FIELD_TYPE_DOUBLE = 1L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FLOAT = 2L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_INT32 = 3L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_INT64 = 4L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_UINT32 = 5L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_UINT64 = 6L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SINT32 = 7L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SINT64 = 8L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FIXED32 = 9L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_FIXED64 = 10L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SFIXED32 = 11L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_SFIXED64 = 12L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_BOOL = 13L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_STRING = 14L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_BYTES = 15L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_ENUM = 16L << FIELD_TYPE_SHIFT;
-const uint64_t FIELD_TYPE_OBJECT = 17L << FIELD_TYPE_SHIFT;
-
-const int FIELD_COUNT_SHIFT = 40;
-const uint64_t FIELD_COUNT_SINGLE = 1L << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_REPEATED = 2L << FIELD_COUNT_SHIFT;
-const uint64_t FIELD_COUNT_PACKED = 5L << FIELD_COUNT_SHIFT;
-
-
-/**
- * See if this is the file for this request, and not one of the imported ones.
- */
-static bool
-should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
-{
- const int N = request.file_to_generate_size();
- for (int i=0; i<N; i++) {
- if (request.file_to_generate(i) == file) {
- return true;
- }
- }
- return false;
-}
-
/**
* If the descriptor gives us a class name, use that. Otherwise make one up from
* the filename of the .proto file.
@@ -112,7 +66,7 @@
static string
indent_more(const string& indent)
{
- return indent + " ";
+ return indent + INDENT;
}
/**
@@ -133,130 +87,6 @@
}
/**
- * Get the string name for a field.
- */
-static string
-get_proto_type(const FieldDescriptorProto& field)
-{
- switch (field.type()) {
- case FieldDescriptorProto::TYPE_DOUBLE:
- return "double";
- case FieldDescriptorProto::TYPE_FLOAT:
- return "float";
- case FieldDescriptorProto::TYPE_INT64:
- return "int64";
- case FieldDescriptorProto::TYPE_UINT64:
- return "uint64";
- case FieldDescriptorProto::TYPE_INT32:
- return "int32";
- case FieldDescriptorProto::TYPE_FIXED64:
- return "fixed64";
- case FieldDescriptorProto::TYPE_FIXED32:
- return "fixed32";
- case FieldDescriptorProto::TYPE_BOOL:
- return "bool";
- case FieldDescriptorProto::TYPE_STRING:
- return "string";
- case FieldDescriptorProto::TYPE_GROUP:
- return "group<unsupported!>";
- case FieldDescriptorProto::TYPE_MESSAGE:
- return field.type_name();
- case FieldDescriptorProto::TYPE_BYTES:
- return "bytes";
- case FieldDescriptorProto::TYPE_UINT32:
- return "uint32";
- case FieldDescriptorProto::TYPE_ENUM:
- return field.type_name();
- case FieldDescriptorProto::TYPE_SFIXED32:
- return "sfixed32";
- case FieldDescriptorProto::TYPE_SFIXED64:
- return "sfixed64";
- case FieldDescriptorProto::TYPE_SINT32:
- return "sint32";
- case FieldDescriptorProto::TYPE_SINT64:
- return "sint64";
- default:
- // won't happen
- return "void";
- }
-}
-
-static uint64_t
-get_field_id(const FieldDescriptorProto& field)
-{
- // Number
- uint64_t result = (uint32_t)field.number();
-
- // Type
- switch (field.type()) {
- case FieldDescriptorProto::TYPE_DOUBLE:
- result |= FIELD_TYPE_DOUBLE;
- break;
- case FieldDescriptorProto::TYPE_FLOAT:
- result |= FIELD_TYPE_FLOAT;
- break;
- case FieldDescriptorProto::TYPE_INT64:
- result |= FIELD_TYPE_INT64;
- break;
- case FieldDescriptorProto::TYPE_UINT64:
- result |= FIELD_TYPE_UINT64;
- break;
- case FieldDescriptorProto::TYPE_INT32:
- result |= FIELD_TYPE_INT32;
- break;
- case FieldDescriptorProto::TYPE_FIXED64:
- result |= FIELD_TYPE_FIXED64;
- break;
- case FieldDescriptorProto::TYPE_FIXED32:
- result |= FIELD_TYPE_FIXED32;
- break;
- case FieldDescriptorProto::TYPE_BOOL:
- result |= FIELD_TYPE_BOOL;
- break;
- case FieldDescriptorProto::TYPE_STRING:
- result |= FIELD_TYPE_STRING;
- break;
- case FieldDescriptorProto::TYPE_MESSAGE:
- result |= FIELD_TYPE_OBJECT;
- break;
- case FieldDescriptorProto::TYPE_BYTES:
- result |= FIELD_TYPE_BYTES;
- break;
- case FieldDescriptorProto::TYPE_UINT32:
- result |= FIELD_TYPE_UINT32;
- break;
- case FieldDescriptorProto::TYPE_ENUM:
- result |= FIELD_TYPE_ENUM;
- break;
- case FieldDescriptorProto::TYPE_SFIXED32:
- result |= FIELD_TYPE_SFIXED32;
- break;
- case FieldDescriptorProto::TYPE_SFIXED64:
- result |= FIELD_TYPE_SFIXED64;
- break;
- case FieldDescriptorProto::TYPE_SINT32:
- result |= FIELD_TYPE_SINT32;
- break;
- case FieldDescriptorProto::TYPE_SINT64:
- result |= FIELD_TYPE_SINT64;
- break;
- default:
- ;
- }
-
- // Count
- if (field.options().packed()) {
- result |= FIELD_COUNT_PACKED;
- } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
- result |= FIELD_COUNT_REPEATED;
- } else {
- result |= FIELD_COUNT_SINGLE;
- }
-
- return result;
-}
-
-/**
* Write a field.
*/
static void
diff --git a/tools/streaming_proto/stream.proto b/tools/streaming_proto/stream.proto
new file mode 100644
index 0000000..123506c
--- /dev/null
+++ b/tools/streaming_proto/stream.proto
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+import "google/protobuf/descriptor.proto";
+
+package android.stream_proto;
+
+// This option tells streaming proto plugin to compile .proto files with extra features.
+message StreamFlags {
+ // creates a mapping of field names of the message to its field ids
+ optional bool enable_fields_mapping = 1;
+}
+
+extend google.protobuf.MessageOptions {
+ // Flags used by streaming proto plugins
+ optional StreamFlags stream = 126856794;
+}
diff --git a/tools/streaming_proto/stream_proto_utils.cpp b/tools/streaming_proto/stream_proto_utils.cpp
new file mode 100644
index 0000000..e8f86bc
--- /dev/null
+++ b/tools/streaming_proto/stream_proto_utils.cpp
@@ -0,0 +1,102 @@
+#include "stream_proto_utils.h"
+
+namespace android {
+namespace stream_proto {
+
+/**
+ * Position of the field type in a (long long) fieldId.
+ */
+const uint64_t FIELD_TYPE_SHIFT = 32;
+
+//
+// FieldId flags for whether the field is single, repeated or packed.
+// TODO: packed is not supported yet.
+//
+const uint64_t FIELD_COUNT_SHIFT = 40;
+const uint64_t FIELD_COUNT_MASK = 0x0fULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_UNKNOWN = 0;
+const uint64_t FIELD_COUNT_SINGLE = 1ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_REPEATED = 2ULL << FIELD_COUNT_SHIFT;
+const uint64_t FIELD_COUNT_PACKED = 5ULL << FIELD_COUNT_SHIFT;
+
+uint64_t
+get_field_id(const FieldDescriptorProto& field)
+{
+ // Number
+ uint64_t result = (uint32_t)field.number();
+
+ // Type
+ result |= (uint64_t)field.type() << FIELD_TYPE_SHIFT;
+
+ // Count
+ if (field.options().packed()) {
+ result |= FIELD_COUNT_PACKED;
+ } else if (field.label() == FieldDescriptorProto::LABEL_REPEATED) {
+ result |= FIELD_COUNT_REPEATED;
+ } else {
+ result |= FIELD_COUNT_SINGLE;
+ }
+
+ return result;
+}
+
+string
+get_proto_type(const FieldDescriptorProto& field)
+{
+ switch (field.type()) {
+ case FieldDescriptorProto::TYPE_DOUBLE:
+ return "double";
+ case FieldDescriptorProto::TYPE_FLOAT:
+ return "float";
+ case FieldDescriptorProto::TYPE_INT64:
+ return "int64";
+ case FieldDescriptorProto::TYPE_UINT64:
+ return "uint64";
+ case FieldDescriptorProto::TYPE_INT32:
+ return "int32";
+ case FieldDescriptorProto::TYPE_FIXED64:
+ return "fixed64";
+ case FieldDescriptorProto::TYPE_FIXED32:
+ return "fixed32";
+ case FieldDescriptorProto::TYPE_BOOL:
+ return "bool";
+ case FieldDescriptorProto::TYPE_STRING:
+ return "string";
+ case FieldDescriptorProto::TYPE_GROUP:
+ return "group<unsupported!>";
+ case FieldDescriptorProto::TYPE_MESSAGE:
+ return field.type_name();
+ case FieldDescriptorProto::TYPE_BYTES:
+ return "bytes";
+ case FieldDescriptorProto::TYPE_UINT32:
+ return "uint32";
+ case FieldDescriptorProto::TYPE_ENUM:
+ return field.type_name();
+ case FieldDescriptorProto::TYPE_SFIXED32:
+ return "sfixed32";
+ case FieldDescriptorProto::TYPE_SFIXED64:
+ return "sfixed64";
+ case FieldDescriptorProto::TYPE_SINT32:
+ return "sint32";
+ case FieldDescriptorProto::TYPE_SINT64:
+ return "sint64";
+ default:
+ // won't happen
+ return "void";
+ }
+}
+
+bool
+should_generate_for_file(const CodeGeneratorRequest& request, const string& file)
+{
+ const int N = request.file_to_generate_size();
+ for (int i=0; i<N; i++) {
+ if (request.file_to_generate(i) == file) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // stream_proto
+} // android
diff --git a/tools/streaming_proto/stream_proto_utils.h b/tools/streaming_proto/stream_proto_utils.h
new file mode 100644
index 0000000..5297ecc
--- /dev/null
+++ b/tools/streaming_proto/stream_proto_utils.h
@@ -0,0 +1,29 @@
+#include <stdint.h>
+
+#include "google/protobuf/compiler/plugin.pb.h"
+#include "google/protobuf/io/zero_copy_stream_impl.h"
+
+namespace android {
+namespace stream_proto {
+
+using namespace google::protobuf;
+using namespace google::protobuf::compiler;
+using namespace std;
+
+/**
+ * Get encoded field id from a field.
+ */
+uint64_t get_field_id(const FieldDescriptorProto& field);
+
+/**
+ * Get the string name for a field.
+ */
+string get_proto_type(const FieldDescriptorProto& field);
+
+/**
+ * See if this is the file for this request, and not one of the imported ones.
+ */
+bool should_generate_for_file(const CodeGeneratorRequest& request, const string& file);
+
+} // stream_proto
+} // android
diff --git a/tools/streaming_proto/string_utils.h b/tools/streaming_proto/string_utils.h
index 03284d1..d6f195f 100644
--- a/tools/streaming_proto/string_utils.h
+++ b/tools/streaming_proto/string_utils.h
@@ -6,6 +6,9 @@
using namespace std;
+// Indent
+const string INDENT = " ";
+
/**
* Capitalizes the string, removes underscores and makes the next letter
* capitalized, and makes the letter following numbers capitalized.
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() {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index c2959d5..04efd56 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1803,18 +1803,14 @@
/**
* Enable or disable Wi-Fi.
- *
- * Note: This method will return false if wifi cannot be enabled (e.g., an incompatible mode
- * where the user has enabled tethering or Airplane Mode).
- *
- * Applications need to have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
- * permission to toggle wifi. Callers without the permissions will trigger a
- * {@link java.lang.SecurityException}.
+ * <p>
+ * Applications must have the {@link android.Manifest.permission#CHANGE_WIFI_STATE}
+ * permission to toggle wifi.
*
* @param enabled {@code true} to enable, {@code false} to disable.
- * @return {@code true} if the operation succeeds (or if the existing state
- * is the same as the requested state). False if wifi cannot be toggled on/off when the
- * request is made.
+ * @return {@code false} if the request cannot be satisfied; {@code true} indicates that wifi is
+ * either already in the requested state, or in progress toward the requested state.
+ * @throws {@link java.lang.SecurityException} if the caller is missing required permissions.
*/
public boolean setWifiEnabled(boolean enabled) {
try {
@@ -3441,6 +3437,7 @@
* Set wifi verbose log. Called from developer settings.
* @hide
*/
+ @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
public void enableVerboseLogging (int verbose) {
try {
mService.enableVerboseLogging(verbose);